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