xref: /haiku/src/kits/media/experimental/MediaClient.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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 	if (err != B_OK)
341 		return err;
342 
343 	return BMediaRoster::CurrentRoster()->StartNode(
344 		fNode->Node(), fNode->TimeSource()->Now());
345 }
346 
347 
348 status_t
349 BMediaClient::Stop()
350 {
351 	CALLED();
352 
353 	return BMediaRoster::CurrentRoster()->StopNode(
354 		fNode->Node(), fNode->TimeSource()->Now());
355 }
356 
357 
358 status_t
359 BMediaClient::Seek(bigtime_t mediaTime,
360 	bigtime_t performanceTime)
361 {
362 	CALLED();
363 
364 	return BMediaRoster::CurrentRoster()->SeekNode(fNode->Node(),
365 		mediaTime, performanceTime);
366 }
367 
368 
369 status_t
370 BMediaClient::Roll(bigtime_t start, bigtime_t stop, bigtime_t seek)
371 {
372 	CALLED();
373 
374 	return BMediaRoster::CurrentRoster()->RollNode(fNode->Node(),
375 		start, stop, seek);
376 }
377 
378 
379 bigtime_t
380 BMediaClient::CurrentTime() const
381 {
382 	CALLED();
383 
384 	return fCurrentTime;
385 }
386 
387 
388 BMediaAddOn*
389 BMediaClient::AddOn(int32* id) const
390 {
391 	CALLED();
392 
393 	return NULL;
394 }
395 
396 
397 void
398 BMediaClient::HandleStart(bigtime_t performanceTime)
399 {
400 	fRunning = true;
401 }
402 
403 
404 void
405 BMediaClient::HandleStop(bigtime_t performanceTime)
406 {
407 	fRunning = false;
408 }
409 
410 
411 void
412 BMediaClient::HandleSeek(bigtime_t mediaTime, bigtime_t performanceTime)
413 {
414 }
415 
416 
417 status_t
418 BMediaClient::FormatSuggestion(media_type type, int32 quality,
419 	media_format* format)
420 {
421 	return B_ERROR;
422 }
423 
424 
425 void
426 BMediaClient::_Init()
427 {
428 	CALLED();
429 
430 	BMediaRoster* roster = BMediaRoster::Roster(&fInitErr);
431 	if (fInitErr == B_OK && roster != NULL)
432 		fInitErr = roster->RegisterNode(fNode);
433 }
434 
435 
436 void
437 BMediaClient::_Deinit()
438 {
439 	CALLED();
440 
441 	if (IsStarted())
442 		Stop();
443 
444 	Disconnect();
445 
446 	// This will release the connections too.
447 	fInputs.MakeEmpty(true);
448 	fOutputs.MakeEmpty(true);
449 
450 	fNode->Release();
451 }
452 
453 
454 void
455 BMediaClient::_AddInput(BMediaInput* input)
456 {
457 	CALLED();
458 
459 	fInputs.AddItem(new InputReleaser(input));
460 }
461 
462 
463 void
464 BMediaClient::_AddOutput(BMediaOutput* output)
465 {
466 	CALLED();
467 
468 	fOutputs.AddItem(new OutputReleaser(output));
469 }
470 
471 
472 BMediaInput*
473 BMediaClient::_FindInput(const media_destination& dest) const
474 {
475 	CALLED();
476 
477 	for (int32 i = 0; i < CountInputs(); i++) {
478 		if (dest.id == InputAt(i)->_Destination().id)
479 			return InputAt(i);
480 	}
481 	return NULL;
482 }
483 
484 
485 BMediaOutput*
486 BMediaClient::_FindOutput(const media_source& source) const
487 {
488 	CALLED();
489 
490 	for (int32 i = 0; i < CountOutputs(); i++) {
491 		if (source.id == OutputAt(i)->_Source().id)
492 			return OutputAt(i);
493 	}
494 	return NULL;
495 }
496 
497 
498 status_t
499 BMediaClient::_ConnectInput(BMediaOutput* output,
500 	const media_connection& input)
501 {
502 	CALLED();
503 
504 	if (input.destination == media_destination::null)
505 		return B_MEDIA_BAD_DESTINATION;
506 
507 	media_output ourOutput = output->Connection()._BuildMediaOutput();
508 	media_input theirInput = input._BuildMediaInput();
509 	media_format format;
510 
511 	// NOTE: We want to set this data in the callbacks if possible.
512 	// The correct format should have been set in BMediaConnection::Connected.
513 	// TODO: Perhaps add some check assert?
514 
515 	status_t ret = BMediaRoster::CurrentRoster()->Connect(ourOutput.source,
516 		theirInput.destination, &format, &ourOutput, &theirInput,
517 		BMediaRoster::B_CONNECT_MUTED);
518 
519 #if 0
520 	if (ret == B_OK)
521 		output->fConnection.format = format;
522 #endif
523 
524 	return ret;
525 }
526 
527 
528 status_t
529 BMediaClient::_ConnectOutput(BMediaInput* input,
530 	const media_connection& output)
531 {
532 	CALLED();
533 
534 	if (output.source == media_source::null)
535 		return B_MEDIA_BAD_SOURCE;
536 
537 	media_input ourInput = input->Connection()._BuildMediaInput();
538 	media_output theirOutput = output._BuildMediaOutput();
539 	media_format format;
540 
541 	// NOTE: We want to set this data in the callbacks if possible.
542 	// The correct format should have been set in BMediaConnection::Connected.
543 	// TODO: Perhaps add some check assert?
544 
545 	status_t ret = BMediaRoster::CurrentRoster()->Connect(theirOutput.source,
546 		ourInput.destination, &format, &theirOutput, &ourInput,
547 		BMediaRoster::B_CONNECT_MUTED);
548 
549 #if 0
550 	if (ret == B_OK)
551 		input->fConnection.format = format;
552 #endif
553 
554 	return ret;
555 }
556 
557 
558 status_t
559 BMediaClient::_DisconnectConnection(BMediaConnection* conn)
560 {
561 	CALLED();
562 
563 	if (conn->Client() != this)
564 		return B_ERROR;
565 
566 	const media_connection& handle = conn->Connection();
567 	if (handle.IsInput()) {
568 		return BMediaRoster::CurrentRoster()->Disconnect(
569 			handle.remote_node.node, handle.source,
570 			handle._Node().node, handle.destination);
571 	} else {
572 		return BMediaRoster::CurrentRoster()->Disconnect(
573 			handle._Node().node, handle.source,
574 			handle.remote_node.node, handle.destination);
575 	}
576 
577 	return B_ERROR;
578 }
579 
580 
581 status_t
582 BMediaClient::_ReleaseConnection(BMediaConnection* conn)
583 {
584 	if (conn->Client() != this)
585 		return B_ERROR;
586 
587 	if (conn->Connection().IsInput()) {
588 		InputReleaser obj = InputReleaser(dynamic_cast<BMediaInput*>(conn));
589 		fInputs.RemoveItem(&obj);
590 		return B_OK;
591 	} else {
592 		OutputReleaser obj = OutputReleaser(dynamic_cast<BMediaOutput*>(conn));
593 		fOutputs.RemoveItem(&obj);
594 		return B_OK;
595 	}
596 
597 	return B_ERROR;
598 }
599 
600 
601 void BMediaClient::_ReservedMediaClient0() {}
602 void BMediaClient::_ReservedMediaClient1() {}
603 void BMediaClient::_ReservedMediaClient2() {}
604 void BMediaClient::_ReservedMediaClient3() {}
605 void BMediaClient::_ReservedMediaClient4() {}
606 void BMediaClient::_ReservedMediaClient5() {}
607 void BMediaClient::_ReservedMediaClient6() {}
608 void BMediaClient::_ReservedMediaClient7() {}
609 void BMediaClient::_ReservedMediaClient8() {}
610 void BMediaClient::_ReservedMediaClient9() {}
611 void BMediaClient::_ReservedMediaClient10() {}
612