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 18namespace BPrivate { namespace media { 19 20 21class ConnReleaser { 22public: 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 37protected: 38 BMediaConnection* Obj() const 39 { 40 return fConn; 41 } 42 43private: 44 BMediaConnection* fConn; 45}; 46 47 48class InputReleaser : public ConnReleaser { 49public: 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 61class OutputReleaser : public ConnReleaser { 62public: 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 78BMediaClient::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 93BMediaClient::~BMediaClient() 94{ 95 CALLED(); 96 97 _Deinit(); 98} 99 100 101const media_client& 102BMediaClient::Client() const 103{ 104 return fClient; 105} 106 107 108status_t 109BMediaClient::InitCheck() const 110{ 111 CALLED(); 112 113 return fInitErr; 114} 115 116 117media_client_kinds 118BMediaClient::Kinds() const 119{ 120 CALLED(); 121 122 return fClient.Kinds(); 123} 124 125 126media_type 127BMediaClient::MediaType() const 128{ 129 CALLED(); 130 131 // Right now ConsumerType() and ProducerType() are the same. 132 return fNode->ConsumerType(); 133} 134 135 136status_t 137BMediaClient::RegisterInput(BMediaInput* input) 138{ 139 input->_ConnectionRegistered(this, ++fLastID); 140 _AddInput(input); 141 return B_OK; 142} 143 144 145status_t 146BMediaClient::RegisterOutput(BMediaOutput* output) 147{ 148 output->_ConnectionRegistered(this, ++fLastID); 149 _AddOutput(output); 150 return B_OK; 151} 152 153 154status_t 155BMediaClient::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 177status_t 178BMediaClient::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 194status_t 195BMediaClient::Connect(BMediaConnection* ourConnection, 196 BMediaConnection* theirConnection) 197{ 198 CALLED(); 199 200 return Connect(ourConnection, theirConnection->Connection()); 201} 202 203 204status_t 205BMediaClient::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 222status_t 223BMediaClient::Connect(BMediaConnection* connection, 224 const media_client& client) 225{ 226 UNIMPLEMENTED(); 227 228 return B_ERROR; 229} 230 231 232status_t 233BMediaClient::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 247int32 248BMediaClient::CountInputs() const 249{ 250 CALLED(); 251 252 return fInputs.CountItems(); 253} 254 255 256int32 257BMediaClient::CountOutputs() const 258{ 259 CALLED(); 260 261 return fOutputs.CountItems(); 262} 263 264 265BMediaInput* 266BMediaClient::InputAt(int32 index) const 267{ 268 CALLED(); 269 270 return fInputs.ItemAt(index)->Obj(); 271} 272 273 274BMediaOutput* 275BMediaClient::OutputAt(int32 index) const 276{ 277 CALLED(); 278 279 return fOutputs.ItemAt(index)->Obj(); 280} 281 282 283BMediaInput* 284BMediaClient::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 295BMediaOutput* 296BMediaClient::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 307bool 308BMediaClient::IsStarted() const 309{ 310 CALLED(); 311 312 return fRunning; 313} 314 315 316void 317BMediaClient::ClientRegistered() 318{ 319 CALLED(); 320} 321 322 323status_t 324BMediaClient::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 344status_t 345BMediaClient::Stop() 346{ 347 CALLED(); 348 349 return BMediaRoster::CurrentRoster()->StopNode( 350 fNode->Node(), fNode->TimeSource()->Now()); 351} 352 353 354status_t 355BMediaClient::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 365status_t 366BMediaClient::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 375bigtime_t 376BMediaClient::CurrentTime() const 377{ 378 CALLED(); 379 380 return fCurrentTime; 381} 382 383 384BMediaAddOn* 385BMediaClient::AddOn(int32* id) const 386{ 387 CALLED(); 388 389 return NULL; 390} 391 392 393void 394BMediaClient::HandleStart(bigtime_t performanceTime) 395{ 396 fRunning = true; 397} 398 399 400void 401BMediaClient::HandleStop(bigtime_t performanceTime) 402{ 403 fRunning = false; 404} 405 406 407void 408BMediaClient::HandleSeek(bigtime_t mediaTime, bigtime_t performanceTime) 409{ 410} 411 412 413status_t 414BMediaClient::FormatSuggestion(media_type type, int32 quality, 415 media_format* format) 416{ 417 return B_ERROR; 418} 419 420 421void 422BMediaClient::_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 432void 433BMediaClient::_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 450void 451BMediaClient::_AddInput(BMediaInput* input) 452{ 453 CALLED(); 454 455 fInputs.AddItem(new InputReleaser(input)); 456} 457 458 459void 460BMediaClient::_AddOutput(BMediaOutput* output) 461{ 462 CALLED(); 463 464 fOutputs.AddItem(new OutputReleaser(output)); 465} 466 467 468BMediaInput* 469BMediaClient::_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 481BMediaOutput* 482BMediaClient::_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 494status_t 495BMediaClient::_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 524status_t 525BMediaClient::_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 554status_t 555BMediaClient::_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 577status_t 578BMediaClient::_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 597void BMediaClient::_ReservedMediaClient0() {} 598void BMediaClient::_ReservedMediaClient1() {} 599void BMediaClient::_ReservedMediaClient2() {} 600void BMediaClient::_ReservedMediaClient3() {} 601void BMediaClient::_ReservedMediaClient4() {} 602void BMediaClient::_ReservedMediaClient5() {} 603void BMediaClient::_ReservedMediaClient6() {} 604void BMediaClient::_ReservedMediaClient7() {} 605void BMediaClient::_ReservedMediaClient8() {} 606void BMediaClient::_ReservedMediaClient9() {} 607void BMediaClient::_ReservedMediaClient10() {} 608