xref: /haiku/src/kits/media/experimental/MediaClient.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 || output == NULL)
183 		return B_ERROR;
184 
185 	if (input->fOwner != this || output->fOwner != this)
186 		return B_ERROR;
187 
188 	input->fBind = NULL;
189 	output->fBind = NULL;
190 	return B_OK;
191 }
192 
193 
194 status_t
195 BMediaClient::Connect(BMediaConnection* ourConnection,
196 	BMediaConnection* theirConnection)
197 {
198 	CALLED();
199 
200 	return Connect(ourConnection, theirConnection->Connection());
201 }
202 
203 
204 status_t
205 BMediaClient::Connect(BMediaConnection* ourConnection,
206 	const media_connection& theirConnection)
207 {
208 	CALLED();
209 
210 	BMediaOutput* output = dynamic_cast<BMediaOutput*>(ourConnection);
211 	if (output != NULL && theirConnection.IsInput())
212 		return _ConnectInput(output, theirConnection);
213 
214 	BMediaInput* input = dynamic_cast<BMediaInput*>(ourConnection);
215 	if (input != NULL && theirConnection.IsOutput())
216 		return _ConnectOutput(input, theirConnection);
217 
218 	return B_ERROR;
219 }
220 
221 
222 status_t
223 BMediaClient::Connect(BMediaConnection* connection,
224 	const media_client& client)
225 {
226 	UNIMPLEMENTED();
227 
228 	return B_ERROR;
229 }
230 
231 
232 status_t
233 BMediaClient::Disconnect()
234 {
235 	CALLED();
236 
237 	for (int32 i = 0; i < CountInputs(); i++)
238 		InputAt(i)->Disconnect();
239 
240 	for (int32 i = 0; i < CountOutputs(); i++)
241 		OutputAt(i)->Disconnect();
242 
243 	return B_OK;
244 }
245 
246 
247 int32
248 BMediaClient::CountInputs() const
249 {
250 	CALLED();
251 
252 	return fInputs.CountItems();
253 }
254 
255 
256 int32
257 BMediaClient::CountOutputs() const
258 {
259 	CALLED();
260 
261 	return fOutputs.CountItems();
262 }
263 
264 
265 BMediaInput*
266 BMediaClient::InputAt(int32 index) const
267 {
268 	CALLED();
269 
270 	return fInputs.ItemAt(index)->Obj();
271 }
272 
273 
274 BMediaOutput*
275 BMediaClient::OutputAt(int32 index) const
276 {
277 	CALLED();
278 
279 	return fOutputs.ItemAt(index)->Obj();
280 }
281 
282 
283 BMediaInput*
284 BMediaClient::FindInput(const media_connection& input) const
285 {
286 	CALLED();
287 
288 	if (!input.IsInput())
289 		return NULL;
290 
291 	return _FindInput(input.destination);
292 }
293 
294 
295 BMediaOutput*
296 BMediaClient::FindOutput(const media_connection& output) const
297 {
298 	CALLED();
299 
300 	if (!output.IsOutput())
301 		return NULL;
302 
303 	return _FindOutput(output.source);
304 }
305 
306 
307 bool
308 BMediaClient::IsStarted() const
309 {
310 	CALLED();
311 
312 	return fRunning;
313 }
314 
315 
316 void
317 BMediaClient::ClientRegistered()
318 {
319 	CALLED();
320 }
321 
322 
323 status_t
324 BMediaClient::Start()
325 {
326 	CALLED();
327 
328 	status_t err = B_OK;
329 	for (int32 i = 0; i < CountOutputs(); i++) {
330 		media_node remoteNode = OutputAt(i)->Connection().remote_node;
331 		if (remoteNode.kind & B_TIME_SOURCE)
332 			err = BMediaRoster::CurrentRoster()->StartTimeSource(
333 				remoteNode, BTimeSource::RealTime());
334 		else
335 			err = BMediaRoster::CurrentRoster()->StartNode(
336 				remoteNode, fNode->TimeSource()->Now());
337 	}
338 
339 	return BMediaRoster::CurrentRoster()->StartNode(
340 		fNode->Node(), fNode->TimeSource()->Now());
341 }
342 
343 
344 status_t
345 BMediaClient::Stop()
346 {
347 	CALLED();
348 
349 	return BMediaRoster::CurrentRoster()->StopNode(
350 		fNode->Node(), fNode->TimeSource()->Now());
351 }
352 
353 
354 status_t
355 BMediaClient::Seek(bigtime_t mediaTime,
356 	bigtime_t performanceTime)
357 {
358 	CALLED();
359 
360 	return BMediaRoster::CurrentRoster()->SeekNode(fNode->Node(),
361 		mediaTime, performanceTime);
362 }
363 
364 
365 status_t
366 BMediaClient::Roll(bigtime_t start, bigtime_t stop, bigtime_t seek)
367 {
368 	CALLED();
369 
370 	return BMediaRoster::CurrentRoster()->RollNode(fNode->Node(),
371 		start, stop, seek);
372 }
373 
374 
375 bigtime_t
376 BMediaClient::CurrentTime() const
377 {
378 	CALLED();
379 
380 	return fCurrentTime;
381 }
382 
383 
384 BMediaAddOn*
385 BMediaClient::AddOn(int32* id) const
386 {
387 	CALLED();
388 
389 	return NULL;
390 }
391 
392 
393 void
394 BMediaClient::HandleStart(bigtime_t performanceTime)
395 {
396 	fRunning = true;
397 }
398 
399 
400 void
401 BMediaClient::HandleStop(bigtime_t performanceTime)
402 {
403 	fRunning = false;
404 }
405 
406 
407 void
408 BMediaClient::HandleSeek(bigtime_t mediaTime, bigtime_t performanceTime)
409 {
410 }
411 
412 
413 status_t
414 BMediaClient::FormatSuggestion(media_type type, int32 quality,
415 	media_format* format)
416 {
417 	return B_ERROR;
418 }
419 
420 
421 void
422 BMediaClient::_Init()
423 {
424 	CALLED();
425 
426 	BMediaRoster* roster = BMediaRoster::Roster(&fInitErr);
427 	if (fInitErr == B_OK && roster != NULL)
428 		fInitErr = roster->RegisterNode(fNode);
429 }
430 
431 
432 void
433 BMediaClient::_Deinit()
434 {
435 	CALLED();
436 
437 	if (IsStarted())
438 		Stop();
439 
440 	Disconnect();
441 
442 	// This will release the connections too.
443 	fInputs.MakeEmpty(true);
444 	fOutputs.MakeEmpty(true);
445 
446 	fNode->Release();
447 }
448 
449 
450 void
451 BMediaClient::_AddInput(BMediaInput* input)
452 {
453 	CALLED();
454 
455 	fInputs.AddItem(new InputReleaser(input));
456 }
457 
458 
459 void
460 BMediaClient::_AddOutput(BMediaOutput* output)
461 {
462 	CALLED();
463 
464 	fOutputs.AddItem(new OutputReleaser(output));
465 }
466 
467 
468 BMediaInput*
469 BMediaClient::_FindInput(const media_destination& dest) const
470 {
471 	CALLED();
472 
473 	for (int32 i = 0; i < CountInputs(); i++) {
474 		if (dest.id == InputAt(i)->_Destination().id)
475 			return InputAt(i);
476 	}
477 	return NULL;
478 }
479 
480 
481 BMediaOutput*
482 BMediaClient::_FindOutput(const media_source& source) const
483 {
484 	CALLED();
485 
486 	for (int32 i = 0; i < CountOutputs(); i++) {
487 		if (source.id == OutputAt(i)->_Source().id)
488 			return OutputAt(i);
489 	}
490 	return NULL;
491 }
492 
493 
494 status_t
495 BMediaClient::_ConnectInput(BMediaOutput* output,
496 	const media_connection& input)
497 {
498 	CALLED();
499 
500 	if (input.destination == media_destination::null)
501 		return B_MEDIA_BAD_DESTINATION;
502 
503 	media_output ourOutput = output->Connection()._BuildMediaOutput();
504 	media_input theirInput = input._BuildMediaInput();
505 	media_format format;
506 
507 	// NOTE: We want to set this data in the callbacks if possible.
508 	// The correct format should have been set in BMediaConnection::Connected.
509 	// TODO: Perhaps add some check assert?
510 
511 	status_t ret = BMediaRoster::CurrentRoster()->Connect(ourOutput.source,
512 		theirInput.destination, &format, &ourOutput, &theirInput,
513 		BMediaRoster::B_CONNECT_MUTED);
514 
515 #if 0
516 	if (ret == B_OK)
517 		output->fConnection.format = format;
518 #endif
519 
520 	return ret;
521 }
522 
523 
524 status_t
525 BMediaClient::_ConnectOutput(BMediaInput* input,
526 	const media_connection& output)
527 {
528 	CALLED();
529 
530 	if (output.source == media_source::null)
531 		return B_MEDIA_BAD_SOURCE;
532 
533 	media_input ourInput = input->Connection()._BuildMediaInput();
534 	media_output theirOutput = output._BuildMediaOutput();
535 	media_format format;
536 
537 	// NOTE: We want to set this data in the callbacks if possible.
538 	// The correct format should have been set in BMediaConnection::Connected.
539 	// TODO: Perhaps add some check assert?
540 
541 	status_t ret = BMediaRoster::CurrentRoster()->Connect(theirOutput.source,
542 		ourInput.destination, &format, &theirOutput, &ourInput,
543 		BMediaRoster::B_CONNECT_MUTED);
544 
545 #if 0
546 	if (ret == B_OK)
547 		input->fConnection.format = format;
548 #endif
549 
550 	return ret;
551 }
552 
553 
554 status_t
555 BMediaClient::_DisconnectConnection(BMediaConnection* conn)
556 {
557 	CALLED();
558 
559 	if (conn->Client() != this)
560 		return B_ERROR;
561 
562 	const media_connection& handle = conn->Connection();
563 	if (handle.IsInput()) {
564 		return BMediaRoster::CurrentRoster()->Disconnect(
565 			handle.remote_node.node, handle.source,
566 			handle._Node().node, handle.destination);
567 	} else {
568 		return BMediaRoster::CurrentRoster()->Disconnect(
569 			handle._Node().node, handle.source,
570 			handle.remote_node.node, handle.destination);
571 	}
572 
573 	return B_ERROR;
574 }
575 
576 
577 status_t
578 BMediaClient::_ReleaseConnection(BMediaConnection* conn)
579 {
580 	if (conn->Client() != this)
581 		return B_ERROR;
582 
583 	if (conn->Connection().IsInput()) {
584 		InputReleaser obj(dynamic_cast<BMediaInput*>(conn));
585 		fInputs.RemoveItem(&obj, false);
586 		return B_OK;
587 	} else {
588 		OutputReleaser obj(dynamic_cast<BMediaOutput*>(conn));
589 		fOutputs.RemoveItem(&obj, false);
590 		return B_OK;
591 	}
592 
593 	return B_ERROR;
594 }
595 
596 
597 void BMediaClient::_ReservedMediaClient0() {}
598 void BMediaClient::_ReservedMediaClient1() {}
599 void BMediaClient::_ReservedMediaClient2() {}
600 void BMediaClient::_ReservedMediaClient3() {}
601 void BMediaClient::_ReservedMediaClient4() {}
602 void BMediaClient::_ReservedMediaClient5() {}
603 void BMediaClient::_ReservedMediaClient6() {}
604 void BMediaClient::_ReservedMediaClient7() {}
605 void BMediaClient::_ReservedMediaClient8() {}
606 void BMediaClient::_ReservedMediaClient9() {}
607 void BMediaClient::_ReservedMediaClient10() {}
608