xref: /haiku/src/kits/media/experimental/MediaClient.cpp (revision f2762b2d5658b0b6c9ff62997a1485194cc77e7c)
1 /*
2  * Copyright 2015, Dario Casalinuovo. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 #include "MediaClient.h"
7 
8 #include <MediaConnection.h>
9 
10 #include <MediaRoster.h>
11 #include <TimeSource.h>
12 
13 #include "MediaClientNode.h"
14 
15 #include "MediaDebug.h"
16 
17 
18 namespace BPrivate { namespace media {
19 
20 
21 class ConnReleaser {
22 public:
23 	ConnReleaser(BMediaConnection* conn)
24 		:
25 		fConn(conn) {}
26 
27 	virtual ~ConnReleaser()
28 	{
29 		fConn->Release();
30 	}
31 
32 	bool operator== (const ConnReleaser &c1)
33 	{
34 		return c1.fConn == this->fConn;
35 	}
36 
37 protected:
38 	BMediaConnection* Obj() const
39 	{
40 		return fConn;
41 	}
42 
43 private:
44 	BMediaConnection* fConn;
45 };
46 
47 
48 class InputReleaser : public ConnReleaser {
49 public:
50 	InputReleaser(BMediaInput* input)
51 		:
52 		ConnReleaser(input) {}
53 
54 	BMediaInput* Obj() const
55 	{
56 		return dynamic_cast<BMediaInput*>(ConnReleaser::Obj());
57 	}
58 };
59 
60 
61 class OutputReleaser : public ConnReleaser {
62 public:
63 	OutputReleaser(BMediaOutput* output)
64 		:
65 		ConnReleaser(output) {}
66 
67 	BMediaOutput* Obj() const
68 	{
69 		return dynamic_cast<BMediaOutput*>(ConnReleaser::Obj());
70 	}
71 };
72 
73 
74 }
75 }
76 
77 
78 BMediaClient::BMediaClient(const char* name,
79 	media_type type, media_client_kinds kinds)
80 	:
81 	fLastID(-1)
82 {
83 	CALLED();
84 
85 	fNode = new BMediaClientNode(name, this, type);
86 	_Init();
87 
88 	fClient.node = fNode->Node();
89 	fClient.kinds = kinds;
90 }
91 
92 
93 BMediaClient::~BMediaClient()
94 {
95 	CALLED();
96 
97 	_Deinit();
98 }
99 
100 
101 const media_client&
102 BMediaClient::Client() const
103 {
104 	return fClient;
105 }
106 
107 
108 status_t
109 BMediaClient::InitCheck() const
110 {
111 	CALLED();
112 
113 	return fInitErr;
114 }
115 
116 
117 media_client_kinds
118 BMediaClient::Kinds() const
119 {
120 	CALLED();
121 
122 	return fClient.Kinds();
123 }
124 
125 
126 media_type
127 BMediaClient::MediaType() const
128 {
129 	CALLED();
130 
131 	// Right now ConsumerType() and ProducerType() are the same.
132 	return fNode->ConsumerType();
133 }
134 
135 
136 status_t
137 BMediaClient::RegisterInput(BMediaInput* input)
138 {
139 	input->_ConnectionRegistered(this, ++fLastID);
140 	_AddInput(input);
141 	return B_OK;
142 }
143 
144 
145 status_t
146 BMediaClient::RegisterOutput(BMediaOutput* output)
147 {
148 	output->_ConnectionRegistered(this, ++fLastID);
149 	_AddOutput(output);
150 	return B_OK;
151 }
152 
153 
154 status_t
155 BMediaClient::Bind(BMediaInput* input, BMediaOutput* output)
156 {
157 	CALLED();
158 
159 	if (input == NULL
160 		|| output == NULL)
161 		return B_ERROR;
162 
163 	if (input->fOwner != this || output->fOwner != this)
164 		return B_ERROR;
165 
166 	// TODO: Implement binding one input to more outputs.
167 	if (input->fBind != NULL
168 		|| output->fBind != NULL)
169 		return B_ERROR;
170 
171 	input->fBind = output;
172 	output->fBind = input;
173 	return B_OK;
174 }
175 
176 
177 status_t
178 BMediaClient::Unbind(BMediaInput* input, BMediaOutput* output)
179 {
180 	CALLED();
181 
182 	if (input == NULL
183 		|| input == NULL)
184 		return B_ERROR;
185 
186 	if (input->fOwner != this || output->fOwner != this)
187 		return B_ERROR;
188 
189 	input->fBind = NULL;
190 	output->fBind = NULL;
191 	return B_OK;
192 }
193 
194 
195 status_t
196 BMediaClient::Connect(BMediaConnection* ourConnection,
197 	BMediaConnection* theirConnection)
198 {
199 	CALLED();
200 
201 	return Connect(ourConnection, theirConnection->Connection());
202 }
203 
204 
205 status_t
206 BMediaClient::Connect(BMediaConnection* ourConnection,
207 	const media_connection& theirConnection)
208 {
209 	CALLED();
210 
211 	BMediaOutput* output = dynamic_cast<BMediaOutput*>(ourConnection);
212 	if (output != NULL && theirConnection.IsInput())
213 		return _ConnectInput(output, theirConnection);
214 
215 	BMediaInput* input = dynamic_cast<BMediaInput*>(ourConnection);
216 	if (input != NULL && theirConnection.IsOutput())
217 		return _ConnectOutput(input, theirConnection);
218 
219 	return B_ERROR;
220 }
221 
222 
223 status_t
224 BMediaClient::Connect(BMediaConnection* connection,
225 	const media_client& client)
226 {
227 	UNIMPLEMENTED();
228 
229 	return B_ERROR;
230 }
231 
232 
233 status_t
234 BMediaClient::Disconnect()
235 {
236 	CALLED();
237 
238 	for (int32 i = 0; i < CountInputs(); i++)
239 		InputAt(i)->Disconnect();
240 
241 	for (int32 i = 0; i < CountOutputs(); i++)
242 		OutputAt(i)->Disconnect();
243 
244 	return B_OK;
245 }
246 
247 
248 int32
249 BMediaClient::CountInputs() const
250 {
251 	CALLED();
252 
253 	return fInputs.CountItems();
254 }
255 
256 
257 int32
258 BMediaClient::CountOutputs() const
259 {
260 	CALLED();
261 
262 	return fOutputs.CountItems();
263 }
264 
265 
266 BMediaInput*
267 BMediaClient::InputAt(int32 index) const
268 {
269 	CALLED();
270 
271 	return fInputs.ItemAt(index)->Obj();
272 }
273 
274 
275 BMediaOutput*
276 BMediaClient::OutputAt(int32 index) const
277 {
278 	CALLED();
279 
280 	return fOutputs.ItemAt(index)->Obj();
281 }
282 
283 
284 BMediaInput*
285 BMediaClient::FindInput(const media_connection& input) const
286 {
287 	CALLED();
288 
289 	if (!input.IsInput())
290 		return NULL;
291 
292 	return _FindInput(input.destination);
293 }
294 
295 
296 BMediaOutput*
297 BMediaClient::FindOutput(const media_connection& output) const
298 {
299 	CALLED();
300 
301 	if (!output.IsOutput())
302 		return NULL;
303 
304 	return _FindOutput(output.source);
305 }
306 
307 
308 bool
309 BMediaClient::IsStarted() const
310 {
311 	CALLED();
312 
313 	return fRunning;
314 }
315 
316 
317 void
318 BMediaClient::ClientRegistered()
319 {
320 	CALLED();
321 }
322 
323 
324 status_t
325 BMediaClient::Start()
326 {
327 	CALLED();
328 
329 	status_t err = B_OK;
330 	for (int32 i = 0; i < CountOutputs(); i++) {
331 		media_node remoteNode = OutputAt(i)->Connection().remote_node;
332 		if (remoteNode.kind & B_TIME_SOURCE)
333 			err = BMediaRoster::CurrentRoster()->StartTimeSource(
334 				remoteNode, BTimeSource::RealTime());
335 		else
336 			err = BMediaRoster::CurrentRoster()->StartNode(
337 				remoteNode, fNode->TimeSource()->Now());
338 	}
339 
340 	return BMediaRoster::CurrentRoster()->StartNode(
341 		fNode->Node(), fNode->TimeSource()->Now());
342 }
343 
344 
345 status_t
346 BMediaClient::Stop()
347 {
348 	CALLED();
349 
350 	return BMediaRoster::CurrentRoster()->StopNode(
351 		fNode->Node(), fNode->TimeSource()->Now());
352 }
353 
354 
355 status_t
356 BMediaClient::Seek(bigtime_t mediaTime,
357 	bigtime_t performanceTime)
358 {
359 	CALLED();
360 
361 	return BMediaRoster::CurrentRoster()->SeekNode(fNode->Node(),
362 		mediaTime, performanceTime);
363 }
364 
365 
366 status_t
367 BMediaClient::Roll(bigtime_t start, bigtime_t stop, bigtime_t seek)
368 {
369 	CALLED();
370 
371 	return BMediaRoster::CurrentRoster()->RollNode(fNode->Node(),
372 		start, stop, seek);
373 }
374 
375 
376 bigtime_t
377 BMediaClient::CurrentTime() const
378 {
379 	CALLED();
380 
381 	return fCurrentTime;
382 }
383 
384 
385 BMediaAddOn*
386 BMediaClient::AddOn(int32* id) const
387 {
388 	CALLED();
389 
390 	return NULL;
391 }
392 
393 
394 void
395 BMediaClient::HandleStart(bigtime_t performanceTime)
396 {
397 	fRunning = true;
398 }
399 
400 
401 void
402 BMediaClient::HandleStop(bigtime_t performanceTime)
403 {
404 	fRunning = false;
405 }
406 
407 
408 void
409 BMediaClient::HandleSeek(bigtime_t mediaTime, bigtime_t performanceTime)
410 {
411 }
412 
413 
414 status_t
415 BMediaClient::FormatSuggestion(media_type type, int32 quality,
416 	media_format* format)
417 {
418 	return B_ERROR;
419 }
420 
421 
422 void
423 BMediaClient::_Init()
424 {
425 	CALLED();
426 
427 	BMediaRoster* roster = BMediaRoster::Roster(&fInitErr);
428 	if (fInitErr == B_OK && roster != NULL)
429 		fInitErr = roster->RegisterNode(fNode);
430 }
431 
432 
433 void
434 BMediaClient::_Deinit()
435 {
436 	CALLED();
437 
438 	if (IsStarted())
439 		Stop();
440 
441 	Disconnect();
442 
443 	// This will release the connections too.
444 	fInputs.MakeEmpty(true);
445 	fOutputs.MakeEmpty(true);
446 
447 	fNode->Release();
448 }
449 
450 
451 void
452 BMediaClient::_AddInput(BMediaInput* input)
453 {
454 	CALLED();
455 
456 	fInputs.AddItem(new InputReleaser(input));
457 }
458 
459 
460 void
461 BMediaClient::_AddOutput(BMediaOutput* output)
462 {
463 	CALLED();
464 
465 	fOutputs.AddItem(new OutputReleaser(output));
466 }
467 
468 
469 BMediaInput*
470 BMediaClient::_FindInput(const media_destination& dest) const
471 {
472 	CALLED();
473 
474 	for (int32 i = 0; i < CountInputs(); i++) {
475 		if (dest.id == InputAt(i)->_Destination().id)
476 			return InputAt(i);
477 	}
478 	return NULL;
479 }
480 
481 
482 BMediaOutput*
483 BMediaClient::_FindOutput(const media_source& source) const
484 {
485 	CALLED();
486 
487 	for (int32 i = 0; i < CountOutputs(); i++) {
488 		if (source.id == OutputAt(i)->_Source().id)
489 			return OutputAt(i);
490 	}
491 	return NULL;
492 }
493 
494 
495 status_t
496 BMediaClient::_ConnectInput(BMediaOutput* output,
497 	const media_connection& input)
498 {
499 	CALLED();
500 
501 	if (input.destination == media_destination::null)
502 		return B_MEDIA_BAD_DESTINATION;
503 
504 	media_output ourOutput = output->Connection()._BuildMediaOutput();
505 	media_input theirInput = input._BuildMediaInput();
506 	media_format format;
507 
508 	// NOTE: We want to set this data in the callbacks if possible.
509 	// The correct format should have been set in BMediaConnection::Connected.
510 	// TODO: Perhaps add some check assert?
511 
512 	status_t ret = BMediaRoster::CurrentRoster()->Connect(ourOutput.source,
513 		theirInput.destination, &format, &ourOutput, &theirInput,
514 		BMediaRoster::B_CONNECT_MUTED);
515 
516 #if 0
517 	if (ret == B_OK)
518 		output->fConnection.format = format;
519 #endif
520 
521 	return ret;
522 }
523 
524 
525 status_t
526 BMediaClient::_ConnectOutput(BMediaInput* input,
527 	const media_connection& output)
528 {
529 	CALLED();
530 
531 	if (output.source == media_source::null)
532 		return B_MEDIA_BAD_SOURCE;
533 
534 	media_input ourInput = input->Connection()._BuildMediaInput();
535 	media_output theirOutput = output._BuildMediaOutput();
536 	media_format format;
537 
538 	// NOTE: We want to set this data in the callbacks if possible.
539 	// The correct format should have been set in BMediaConnection::Connected.
540 	// TODO: Perhaps add some check assert?
541 
542 	status_t ret = BMediaRoster::CurrentRoster()->Connect(theirOutput.source,
543 		ourInput.destination, &format, &theirOutput, &ourInput,
544 		BMediaRoster::B_CONNECT_MUTED);
545 
546 #if 0
547 	if (ret == B_OK)
548 		input->fConnection.format = format;
549 #endif
550 
551 	return ret;
552 }
553 
554 
555 status_t
556 BMediaClient::_DisconnectConnection(BMediaConnection* conn)
557 {
558 	CALLED();
559 
560 	if (conn->Client() != this)
561 		return B_ERROR;
562 
563 	const media_connection& handle = conn->Connection();
564 	if (handle.IsInput()) {
565 		return BMediaRoster::CurrentRoster()->Disconnect(
566 			handle.remote_node.node, handle.source,
567 			handle._Node().node, handle.destination);
568 	} else {
569 		return BMediaRoster::CurrentRoster()->Disconnect(
570 			handle._Node().node, handle.source,
571 			handle.remote_node.node, handle.destination);
572 	}
573 
574 	return B_ERROR;
575 }
576 
577 
578 status_t
579 BMediaClient::_ReleaseConnection(BMediaConnection* conn)
580 {
581 	if (conn->Client() != this)
582 		return B_ERROR;
583 
584 	if (conn->Connection().IsInput()) {
585 		InputReleaser obj = InputReleaser(dynamic_cast<BMediaInput*>(conn));
586 		fInputs.RemoveItem(&obj);
587 		return B_OK;
588 	} else {
589 		OutputReleaser obj = OutputReleaser(dynamic_cast<BMediaOutput*>(conn));
590 		fOutputs.RemoveItem(&obj);
591 		return B_OK;
592 	}
593 
594 	return B_ERROR;
595 }
596 
597 
598 void BMediaClient::_ReservedMediaClient0() {}
599 void BMediaClient::_ReservedMediaClient1() {}
600 void BMediaClient::_ReservedMediaClient2() {}
601 void BMediaClient::_ReservedMediaClient3() {}
602 void BMediaClient::_ReservedMediaClient4() {}
603 void BMediaClient::_ReservedMediaClient5() {}
604 void BMediaClient::_ReservedMediaClient6() {}
605 void BMediaClient::_ReservedMediaClient7() {}
606 void BMediaClient::_ReservedMediaClient8() {}
607 void BMediaClient::_ReservedMediaClient9() {}
608 void BMediaClient::_ReservedMediaClient10() {}
609