1 /* 2 * Copyright 2015, Dario Casalinuovo. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include "MediaClientNode.h" 7 8 #include <MediaClient.h> 9 #include <MediaConnection.h> 10 #include <MediaRoster.h> 11 #include <scheduler.h> 12 #include <TimeSource.h> 13 14 #include <string.h> 15 16 #include "MediaDebug.h" 17 18 #define B_NEW_BUFFER (BTimedEventQueue::B_USER_EVENT + 1) 19 20 21 BMediaClientNode::BMediaClientNode(const char* name, 22 BMediaClient* owner, media_type type) 23 : 24 BMediaNode(name), 25 BBufferConsumer(type), 26 BBufferProducer(type), 27 BMediaEventLooper(), 28 fOwner(owner) 29 { 30 CALLED(); 31 32 // Configure the node to do the requested jobs 33 if (fOwner->Kinds() & B_MEDIA_PLAYER) 34 AddNodeKind(B_BUFFER_PRODUCER); 35 if (fOwner->Kinds() & B_MEDIA_RECORDER) 36 AddNodeKind(B_BUFFER_CONSUMER); 37 if (fOwner->Kinds() & B_MEDIA_CONTROLLABLE) 38 AddNodeKind(B_CONTROLLABLE); 39 } 40 41 42 status_t 43 BMediaClientNode::SendBuffer(BBuffer* buffer, BMediaConnection* conn) 44 { 45 return BBufferProducer::SendBuffer(buffer, conn->_Source(), conn->_Destination()); 46 } 47 48 49 BMediaAddOn* 50 BMediaClientNode::AddOn(int32* id) const 51 { 52 CALLED(); 53 54 return fOwner->AddOn(id); 55 } 56 57 58 void 59 BMediaClientNode::NodeRegistered() 60 { 61 CALLED(); 62 63 fOwner->ClientRegistered(); 64 65 Run(); 66 } 67 68 69 void 70 BMediaClientNode::SetRunMode(run_mode mode) 71 { 72 CALLED(); 73 74 int32 priority; 75 if (mode == BMediaNode::B_OFFLINE) 76 priority = B_OFFLINE_PROCESSING; 77 else { 78 switch(ConsumerType()) { 79 case B_MEDIA_RAW_AUDIO: 80 case B_MEDIA_ENCODED_AUDIO: 81 priority = B_AUDIO_RECORDING; 82 break; 83 84 case B_MEDIA_RAW_VIDEO: 85 case B_MEDIA_ENCODED_VIDEO: 86 priority = B_VIDEO_RECORDING; 87 break; 88 89 default: 90 priority = B_DEFAULT_MEDIA_PRIORITY; 91 } 92 } 93 94 SetPriority(suggest_thread_priority(priority)); 95 BMediaNode::SetRunMode(mode); 96 } 97 98 99 void 100 BMediaClientNode::Start(bigtime_t performanceTime) 101 { 102 CALLED(); 103 104 BMediaEventLooper::Start(performanceTime); 105 } 106 107 108 void 109 BMediaClientNode::Stop(bigtime_t performanceTime, bool immediate) 110 { 111 CALLED(); 112 113 BMediaEventLooper::Stop(performanceTime, immediate); 114 } 115 116 117 void 118 BMediaClientNode::Seek(bigtime_t mediaTime, bigtime_t performanceTime) 119 { 120 CALLED(); 121 122 BMediaEventLooper::Seek(mediaTime, performanceTime); 123 } 124 125 126 void 127 BMediaClientNode::TimeWarp(bigtime_t realTime, bigtime_t performanceTime) 128 { 129 CALLED(); 130 131 BMediaEventLooper::TimeWarp(realTime, performanceTime); 132 } 133 134 135 status_t 136 BMediaClientNode::HandleMessage(int32 message, 137 const void* data, size_t size) 138 { 139 CALLED(); 140 141 return B_ERROR; 142 } 143 144 145 status_t 146 BMediaClientNode::AcceptFormat(const media_destination& dest, 147 media_format* format) 148 { 149 CALLED(); 150 151 BMediaInput* conn = fOwner->_FindInput(dest); 152 if (conn == NULL) 153 return B_MEDIA_BAD_DESTINATION; 154 155 return conn->AcceptFormat(format); 156 } 157 158 159 status_t 160 BMediaClientNode::GetNextInput(int32* cookie, 161 media_input* input) 162 { 163 CALLED(); 164 165 if (fOwner->CountInputs() == 0) 166 return B_BAD_INDEX; 167 168 if (*cookie < 0 || *cookie >= fOwner->CountInputs()) { 169 *cookie = -1; 170 input = NULL; 171 } else { 172 BMediaInput* conn = fOwner->InputAt(*cookie); 173 if (conn != NULL) { 174 *input = conn->fConnection._BuildMediaInput(); 175 *cookie += 1; 176 return B_OK; 177 } 178 } 179 return B_BAD_INDEX; 180 } 181 182 183 void 184 BMediaClientNode::DisposeInputCookie(int32 cookie) 185 { 186 CALLED(); 187 } 188 189 190 void 191 BMediaClientNode::BufferReceived(BBuffer* buffer) 192 { 193 CALLED(); 194 195 EventQueue()->AddEvent(media_timed_event(buffer->Header()->start_time, 196 BTimedEventQueue::B_HANDLE_BUFFER, buffer, 197 BTimedEventQueue::B_RECYCLE_BUFFER)); 198 } 199 200 201 status_t 202 BMediaClientNode::GetLatencyFor(const media_destination& dest, 203 bigtime_t* latency, media_node_id* timesource) 204 { 205 CALLED(); 206 207 BMediaInput* conn = fOwner->_FindInput(dest); 208 if (conn == NULL) 209 return B_MEDIA_BAD_DESTINATION; 210 211 //*latency = conn->fLatency; 212 *timesource = TimeSource()->ID(); 213 return B_OK; 214 } 215 216 217 status_t 218 BMediaClientNode::Connected(const media_source& source, 219 const media_destination& dest, const media_format& format, 220 media_input* outInput) 221 { 222 CALLED(); 223 224 BMediaInput* conn = fOwner->_FindInput(dest); 225 if (conn == NULL) 226 return B_MEDIA_BAD_DESTINATION; 227 228 conn->fConnection.source = source; 229 conn->fConnection.format = format; 230 231 // Retrieve the node without using GetNodeFor that's pretty inefficient. 232 // Unfortunately we don't have an alternative which doesn't require us 233 // to release the cloned node. 234 // However, our node will not have flags set. Keep in mind this. 235 conn->fConnection.remote_node.node 236 = BMediaRoster::CurrentRoster()->NodeIDFor(source.port); 237 conn->fConnection.remote_node.port = source.port; 238 239 conn->Connected(format); 240 241 *outInput = conn->fConnection._BuildMediaInput(); 242 return B_OK; 243 } 244 245 246 void 247 BMediaClientNode::Disconnected(const media_source& source, 248 const media_destination& dest) 249 { 250 CALLED(); 251 252 BMediaInput* conn = fOwner->_FindInput(dest); 253 if (conn == NULL) 254 return; 255 256 if (conn->_Source() == source) { 257 // Cleanup the connection 258 conn->fConnection.source = media_source::null; 259 conn->fConnection.format = media_format(); 260 261 conn->fConnection.remote_node.node = -1; 262 conn->fConnection.remote_node.port = -1; 263 264 conn->Disconnected(); 265 } 266 } 267 268 269 status_t 270 BMediaClientNode::FormatChanged(const media_source& source, 271 const media_destination& dest, 272 int32 tag, const media_format& format) 273 { 274 CALLED(); 275 return B_ERROR; 276 } 277 278 279 status_t 280 BMediaClientNode::FormatSuggestionRequested(media_type type, 281 int32 quality, media_format* format) 282 { 283 CALLED(); 284 285 if (type != ConsumerType() 286 && type != ProducerType()) { 287 return B_MEDIA_BAD_FORMAT; 288 } 289 290 status_t ret = fOwner->FormatSuggestion(type, quality, format); 291 if (ret != B_OK) { 292 // In that case we return just a very generic format. 293 media_format outFormat; 294 outFormat.type = fOwner->MediaType(); 295 *format = outFormat; 296 return B_OK; 297 } 298 299 return ret; 300 } 301 302 303 status_t 304 BMediaClientNode::FormatProposal(const media_source& source, 305 media_format* format) 306 { 307 CALLED(); 308 309 BMediaOutput* conn = fOwner->_FindOutput(source); 310 if (conn == NULL) 311 return B_MEDIA_BAD_DESTINATION; 312 313 return conn->FormatProposal(format); 314 } 315 316 317 status_t 318 BMediaClientNode::FormatChangeRequested(const media_source& source, 319 const media_destination& dest, media_format* format, 320 int32* _deprecated_) 321 { 322 CALLED(); 323 324 return B_ERROR; 325 } 326 327 328 void 329 BMediaClientNode::LateNoticeReceived(const media_source& source, 330 bigtime_t late, bigtime_t when) 331 { 332 CALLED(); 333 334 } 335 336 337 status_t 338 BMediaClientNode::GetNextOutput(int32* cookie, media_output* output) 339 { 340 CALLED(); 341 342 if (fOwner->CountOutputs() == 0) 343 return B_BAD_INDEX; 344 345 if (*cookie < 0 || *cookie >= fOwner->CountOutputs()) { 346 *cookie = -1; 347 output = NULL; 348 } else { 349 BMediaOutput* conn = fOwner->OutputAt(*cookie); 350 if (conn != NULL) { 351 *output = conn->fConnection._BuildMediaOutput(); 352 *cookie += 1; 353 return B_OK; 354 } 355 } 356 return B_BAD_INDEX; 357 } 358 359 360 status_t 361 BMediaClientNode::DisposeOutputCookie(int32 cookie) 362 { 363 CALLED(); 364 365 return B_OK; 366 } 367 368 369 status_t 370 BMediaClientNode::SetBufferGroup(const media_source& source, BBufferGroup* group) 371 { 372 CALLED(); 373 374 BMediaOutput* conn = fOwner->_FindOutput(source); 375 if (conn == NULL) 376 return B_MEDIA_BAD_SOURCE; 377 378 if (group == conn->fBufferGroup) 379 return B_OK; 380 381 delete conn->fBufferGroup; 382 383 if (group != NULL) { 384 conn->fBufferGroup = group; 385 return B_OK; 386 } 387 388 conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), 3); 389 if (conn->fBufferGroup == NULL) 390 return B_NO_MEMORY; 391 392 return conn->fBufferGroup->InitCheck(); 393 } 394 395 396 status_t 397 BMediaClientNode::PrepareToConnect(const media_source& source, 398 const media_destination& dest, media_format* format, 399 media_source* out_source, char *name) 400 { 401 CALLED(); 402 403 BMediaOutput* conn = fOwner->_FindOutput(source); 404 if (conn == NULL) 405 return B_MEDIA_BAD_SOURCE; 406 407 if (conn->_Destination() != media_destination::null) 408 return B_MEDIA_ALREADY_CONNECTED; 409 410 if (fOwner->MediaType() != B_MEDIA_UNKNOWN_TYPE 411 && format->type != fOwner->MediaType()) { 412 return B_MEDIA_BAD_FORMAT; 413 } 414 415 conn->fConnection.destination = dest; 416 417 status_t err = conn->PrepareToConnect(format); 418 if (err != B_OK) 419 return err; 420 421 *out_source = conn->_Source(); 422 strcpy(name, conn->Name()); 423 424 return B_OK; 425 } 426 427 428 void 429 BMediaClientNode::Connect(status_t status, const media_source& source, 430 const media_destination& dest, const media_format& format, 431 char* name) 432 { 433 CALLED(); 434 435 BMediaOutput* conn = fOwner->_FindOutput(source); 436 if (conn == NULL) 437 return; 438 439 // Connection failed, return. 440 if (status != B_OK) 441 return; 442 443 conn->fConnection.destination = dest; 444 conn->fConnection.format = format; 445 446 // Retrieve the node without using GetNodeFor that's pretty inefficient. 447 // Unfortunately we don't have an alternative which doesn't require us 448 // to release the cloned node. 449 // However, our node will not have flags set. Keep in mind this. 450 conn->fConnection.remote_node.node 451 = BMediaRoster::CurrentRoster()->NodeIDFor(dest.port); 452 conn->fConnection.remote_node.port = dest.port; 453 454 strcpy(name, conn->Name()); 455 456 // TODO: add correct latency estimate 457 SetEventLatency(1000); 458 459 conn->fBufferGroup = new BBufferGroup(conn->BufferSize(), 3); 460 if (conn->fBufferGroup == NULL) 461 TRACE("Can't allocate the buffer group\n"); 462 463 conn->Connected(format); 464 } 465 466 467 void 468 BMediaClientNode::Disconnect(const media_source& source, 469 const media_destination& dest) 470 { 471 CALLED(); 472 473 BMediaOutput* conn = fOwner->_FindOutput(source); 474 if (conn == NULL) 475 return; 476 477 if (conn->_Destination() == dest) { 478 // Cleanup the connection 479 delete conn->fBufferGroup; 480 conn->fBufferGroup = NULL; 481 482 conn->fConnection.destination = media_destination::null; 483 conn->fConnection.format = media_format(); 484 485 conn->fConnection.remote_node.node = -1; 486 conn->fConnection.remote_node.port = -1; 487 488 conn->Disconnected(); 489 } 490 } 491 492 493 void 494 BMediaClientNode::EnableOutput(const media_source& source, 495 bool enabled, int32* _deprecated_) 496 { 497 CALLED(); 498 499 BMediaOutput* conn = fOwner->_FindOutput(source); 500 if (conn != NULL) 501 conn->_SetEnabled(enabled); 502 } 503 504 505 status_t 506 BMediaClientNode::GetLatency(bigtime_t* outLatency) 507 { 508 CALLED(); 509 510 return BBufferProducer::GetLatency(outLatency); 511 } 512 513 514 void 515 BMediaClientNode::LatencyChanged(const media_source& source, 516 const media_destination& dest, bigtime_t latency, uint32 flags) 517 { 518 CALLED(); 519 } 520 521 522 void 523 BMediaClientNode::ProducerDataStatus(const media_destination& dest, 524 int32 status, bigtime_t when) 525 { 526 CALLED(); 527 } 528 529 530 void 531 BMediaClientNode::HandleEvent(const media_timed_event* event, 532 bigtime_t late, bool realTimeEvent) 533 { 534 CALLED(); 535 536 switch (event->type) { 537 // This event is used for inputs which consumes buffers 538 // or binded connections which also send them to an output. 539 case BTimedEventQueue::B_HANDLE_BUFFER: 540 _HandleBuffer((BBuffer*)event->pointer); 541 break; 542 543 // This is used for connections which produce buffers only. 544 case B_NEW_BUFFER: 545 _ProduceNewBuffer(event, late); 546 break; 547 548 case BTimedEventQueue::B_START: 549 { 550 if (RunState() != B_STARTED) 551 fOwner->HandleStart(event->event_time); 552 553 fStartTime = event->event_time; 554 555 _ScheduleConnections(event->event_time); 556 break; 557 } 558 559 case BTimedEventQueue::B_STOP: 560 { 561 fOwner->HandleStop(event->event_time); 562 563 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, 564 BTimedEventQueue::B_HANDLE_BUFFER); 565 break; 566 } 567 568 case BTimedEventQueue::B_SEEK: 569 fOwner->HandleSeek(event->event_time, event->bigdata); 570 break; 571 572 case BTimedEventQueue::B_WARP: 573 // NOTE: We have no need to handle it 574 break; 575 } 576 } 577 578 579 BMediaClientNode::~BMediaClientNode() 580 { 581 CALLED(); 582 583 Quit(); 584 } 585 586 587 void 588 BMediaClientNode::_ScheduleConnections(bigtime_t eventTime) 589 { 590 for (int32 i = 0; i < fOwner->CountOutputs(); i++) { 591 BMediaOutput* output = fOwner->OutputAt(i); 592 593 if (output->HasBinding()) 594 continue; 595 596 media_timed_event firstBufferEvent(eventTime, 597 B_NEW_BUFFER); 598 599 output->fFramesSent = 0; 600 601 firstBufferEvent.pointer = (void*) output; 602 EventQueue()->AddEvent(firstBufferEvent); 603 } 604 } 605 606 607 void 608 BMediaClientNode::_HandleBuffer(BBuffer* buffer) 609 { 610 CALLED(); 611 612 media_destination dest; 613 dest.id = buffer->Header()->destination; 614 BMediaInput* conn = fOwner->_FindInput(dest); 615 616 if (conn != NULL) 617 conn->HandleBuffer(buffer); 618 619 // TODO: Investigate system level latency logging 620 621 if (conn->HasBinding()) { 622 BMediaOutput* output = dynamic_cast<BMediaOutput*>(conn->Binding()); 623 output->SendBuffer(buffer); 624 } 625 } 626 627 628 void 629 BMediaClientNode::_ProduceNewBuffer(const media_timed_event* event, 630 bigtime_t late) 631 { 632 CALLED(); 633 634 if (RunState() != BMediaEventLooper::B_STARTED) 635 return; 636 637 // The connection is get through the event 638 BMediaOutput* output 639 = dynamic_cast<BMediaOutput*>((BMediaConnection*)event->pointer); 640 if (output == NULL) 641 return; 642 643 if (output->_IsEnabled()) { 644 BBuffer* buffer = _GetNextBuffer(output, event->event_time); 645 646 if (buffer != NULL) { 647 if (output->SendBuffer(buffer) != B_OK) { 648 TRACE("BMediaClientNode: Failed to send buffer\n"); 649 // The output failed, let's recycle the buffer 650 buffer->Recycle(); 651 } 652 } 653 } 654 655 bigtime_t time = 0; 656 media_format format = output->fConnection.format; 657 if (format.IsAudio()) { 658 size_t nFrames = format.u.raw_audio.buffer_size 659 / ((format.u.raw_audio.format 660 & media_raw_audio_format::B_AUDIO_SIZE_MASK) 661 * format.u.raw_audio.channel_count); 662 output->fFramesSent += nFrames; 663 664 time = fStartTime + bigtime_t((1000000LL * output->fFramesSent) 665 / (int32)format.u.raw_audio.frame_rate); 666 } 667 668 media_timed_event nextEvent(time, B_NEW_BUFFER); 669 EventQueue()->AddEvent(nextEvent); 670 } 671 672 673 BBuffer* 674 BMediaClientNode::_GetNextBuffer(BMediaOutput* output, bigtime_t eventTime) 675 { 676 CALLED(); 677 678 BBuffer* buffer 679 = output->fBufferGroup->RequestBuffer(output->BufferSize(), 0); 680 if (buffer == NULL) { 681 TRACE("MediaClientNode:::_GetNextBuffer: Failed to get the buffer\n"); 682 return NULL; 683 } 684 685 media_header* header = buffer->Header(); 686 header->type = output->fConnection.format.type; 687 header->size_used = output->BufferSize(); 688 header->time_source = TimeSource()->ID(); 689 header->start_time = eventTime; 690 691 return buffer; 692 } 693