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