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