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