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