1 /* 2 * Copyright 2003-2016 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Marcus Overhagen 7 * Dario Casalinuovo 8 */ 9 10 11 #include "MixerCore.h" 12 13 #include <string.h> 14 15 #include <Buffer.h> 16 #include <BufferGroup.h> 17 #include <BufferProducer.h> 18 #include <MediaNode.h> 19 #include <RealtimeAlloc.h> 20 #include <StackOrHeapArray.h> 21 #include <StopWatch.h> 22 #include <TimeSource.h> 23 24 #include "AudioMixer.h" 25 #include "Interpolate.h" 26 #include "MixerInput.h" 27 #include "MixerOutput.h" 28 #include "MixerUtils.h" 29 #include "Resampler.h" 30 #include "RtList.h" 31 32 33 #define DOUBLE_RATE_MIXING 0 34 35 #if DEBUG > 1 36 # define ASSERT_LOCKED() if (fLocker->IsLocked()) {} \ 37 else debugger("core not locked, meltdown occurred") 38 #else 39 # define ASSERT_LOCKED() ((void)0) 40 #endif 41 42 /*! Mixer channels are identified by a type number, each type number corresponds 43 to the one of the channel masks of enum media_multi_channels. 44 45 The mixer buffer uses either the same frame rate and same count of frames as 46 the output buffer, or the double frame rate and frame count. 47 48 All mixer input ring buffers must be an exact multiple of the mixer buffer 49 size, so that we do not get any buffer wrap around during reading from the 50 input buffers. 51 The mixer input is told by constructor (or after a format change by 52 SetMixBufferFormat() of the current mixer buffer propertys, and must 53 allocate a buffer that is an exact multiple, 54 */ 55 56 57 struct chan_info { 58 const char *base; 59 uint32 sample_offset; 60 float gain; 61 }; 62 63 64 MixerCore::MixerCore(AudioMixer *node) 65 : 66 fLocker(new BLocker("mixer core lock")), 67 fInputs(new BList), 68 fOutput(0), 69 fNextInputID(1), 70 fRunning(false), 71 fStarted(false), 72 fOutputEnabled(true), 73 fResampler(0), 74 fMixBuffer(0), 75 fMixBufferFrameRate(0), 76 fMixBufferFrameCount(0), 77 fMixBufferChannelCount(0), 78 fMixBufferChannelTypes(0), 79 fDoubleRateMixing(DOUBLE_RATE_MIXING), 80 fDownstreamLatency(1), 81 fSettings(new MixerSettings), 82 fNode(node), 83 fBufferGroup(0), 84 fTimeSource(0), 85 fMixThread(-1), 86 fMixThreadWaitSem(-1), 87 fHasEvent(false), 88 fOutputGain(1.0) 89 { 90 } 91 92 93 MixerCore::~MixerCore() 94 { 95 delete fSettings; 96 97 delete fLocker; 98 delete fInputs; 99 100 ASSERT(fMixThreadWaitSem == -1); 101 ASSERT(fMixThread == -1); 102 103 if (fMixBuffer) 104 rtm_free(fMixBuffer); 105 106 if (fTimeSource) 107 fTimeSource->Release(); 108 109 if (fResampler) { 110 for (int i = 0; i < fMixBufferChannelCount; i++) 111 delete fResampler[i]; 112 delete[] fResampler; 113 } 114 115 delete[] fMixBufferChannelTypes; 116 } 117 118 119 MixerSettings * 120 MixerCore::Settings() 121 { 122 return fSettings; 123 } 124 125 126 void 127 MixerCore::UpdateResamplingAlgorithm() 128 { 129 ASSERT_LOCKED(); 130 131 _UpdateResamplers(fOutput->MediaOutput().format.u.raw_audio); 132 133 for (int32 i = fInputs->CountItems() - 1; i >= 0; i--) { 134 MixerInput* input 135 = reinterpret_cast<MixerInput*>(fInputs->ItemAtFast(i)); 136 input->UpdateResamplingAlgorithm(); 137 } 138 } 139 140 141 void 142 MixerCore::SetOutputAttenuation(float gain) 143 { 144 ASSERT_LOCKED(); 145 fOutputGain = gain; 146 } 147 148 149 MixerInput* 150 MixerCore::AddInput(const media_input& input) 151 { 152 ASSERT_LOCKED(); 153 MixerInput* in = new MixerInput(this, input, fMixBufferFrameRate, 154 fMixBufferFrameCount); 155 fInputs->AddItem(in); 156 return in; 157 } 158 159 160 MixerOutput* 161 MixerCore::AddOutput(const media_output& output) 162 { 163 ASSERT_LOCKED(); 164 if (fOutput) { 165 ERROR("MixerCore::AddOutput: already connected\n"); 166 return fOutput; 167 } 168 fOutput = new MixerOutput(this, output); 169 // the output format might have been adjusted inside MixerOutput 170 _ApplyOutputFormat(); 171 172 ASSERT(!fRunning); 173 if (fStarted && fOutputEnabled) 174 StartMixThread(); 175 176 return fOutput; 177 } 178 179 180 bool 181 MixerCore::RemoveInput(int32 inputID) 182 { 183 ASSERT_LOCKED(); 184 MixerInput *input; 185 for (int i = 0; (input = Input(i)) != 0; i++) { 186 if (input->ID() == inputID) { 187 fInputs->RemoveItem(i); 188 delete input; 189 return true; 190 } 191 } 192 return false; 193 } 194 195 196 bool 197 MixerCore::RemoveOutput() 198 { 199 ASSERT_LOCKED(); 200 if (!fOutput) 201 return false; 202 203 if (fStarted) 204 StopMixThread(); 205 206 delete fOutput; 207 fOutput = 0; 208 fOutputEnabled = true; 209 return true; 210 } 211 212 213 int32 214 MixerCore::CreateInputID() 215 { 216 ASSERT_LOCKED(); 217 return fNextInputID++; 218 } 219 220 221 MixerInput * 222 MixerCore::Input(int i) 223 { 224 ASSERT_LOCKED(); 225 return (MixerInput *)fInputs->ItemAt(i); 226 } 227 228 229 MixerOutput * 230 MixerCore::Output() 231 { 232 ASSERT_LOCKED(); 233 return fOutput; 234 } 235 236 237 void 238 MixerCore::BufferReceived(BBuffer *buffer, bigtime_t lateness) 239 { 240 ASSERT_LOCKED(); 241 MixerInput *input; 242 int32 id = buffer->Header()->destination; 243 for (int i = 0; (input = Input(i)) != 0; i++) { 244 if (input->ID() == id) { 245 input->BufferReceived(buffer); 246 return; 247 } 248 } 249 ERROR("MixerCore::BufferReceived: received buffer for unknown id %ld\n", 250 id); 251 } 252 253 254 void 255 MixerCore::InputFormatChanged(int32 inputID, 256 const media_multi_audio_format &format) 257 { 258 ASSERT_LOCKED(); 259 ERROR("MixerCore::InputFormatChanged not handled\n"); 260 } 261 262 263 void 264 MixerCore::OutputFormatChanged(const media_multi_audio_format &format) 265 { 266 ASSERT_LOCKED(); 267 bool was_started = fStarted; 268 269 if (was_started) 270 Stop(); 271 272 fOutput->ChangeFormat(format); 273 _ApplyOutputFormat(); 274 275 if (was_started) 276 Start(); 277 } 278 279 280 void 281 MixerCore::SetOutputBufferGroup(BBufferGroup *group) 282 { 283 ASSERT_LOCKED(); 284 fBufferGroup = group; 285 } 286 287 288 void 289 MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency) 290 { 291 ASSERT_LOCKED(); 292 if (fTimeSource) 293 fTimeSource->Release(); 294 295 fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire()); 296 fDownstreamLatency = downstream_latency; 297 298 TRACE("MixerCore::SetTimingInfo, now = %Ld, downstream latency %Ld\n", 299 fTimeSource->Now(), fDownstreamLatency); 300 } 301 302 303 void 304 MixerCore::EnableOutput(bool enabled) 305 { 306 ASSERT_LOCKED(); 307 TRACE("MixerCore::EnableOutput %d\n", enabled); 308 fOutputEnabled = enabled; 309 310 if (fRunning && !fOutputEnabled) 311 StopMixThread(); 312 313 if (!fRunning && fOutput && fStarted && fOutputEnabled) 314 StartMixThread(); 315 } 316 317 318 uint32 319 MixerCore::OutputChannelCount() 320 { 321 return (fOutput) ? fOutput->GetOutputChannelCount() : 0; 322 } 323 324 325 bool 326 MixerCore::Start() 327 { 328 ASSERT_LOCKED(); 329 TRACE("MixerCore::Start\n"); 330 if (fStarted) 331 return false; 332 333 fStarted = true; 334 335 ASSERT(!fRunning); 336 337 // only start the mix thread if we have an output 338 if (fOutput && fOutputEnabled) 339 StartMixThread(); 340 341 return true; 342 } 343 344 345 bool 346 MixerCore::Stop() 347 { 348 ASSERT_LOCKED(); 349 TRACE("MixerCore::Stop\n"); 350 if (!fStarted) 351 return false; 352 353 if (fRunning) 354 StopMixThread(); 355 356 fStarted = false; 357 return true; 358 } 359 360 361 void 362 MixerCore::StartMixThread() 363 { 364 ASSERT(fOutputEnabled == true); 365 ASSERT(fRunning == false); 366 ASSERT(fOutput); 367 fRunning = true; 368 fMixThreadWaitSem = create_sem(0, "mix thread wait"); 369 fMixThread = spawn_thread(_MixThreadEntry, "Yeah baby, very shagadelic", 370 120, this); 371 resume_thread(fMixThread); 372 } 373 374 375 void 376 MixerCore::StopMixThread() 377 { 378 ASSERT(fRunning == true); 379 ASSERT(fMixThread > 0); 380 ASSERT(fMixThreadWaitSem > 0); 381 382 fRunning = false; 383 status_t unused; 384 delete_sem(fMixThreadWaitSem); 385 wait_for_thread(fMixThread, &unused); 386 387 fMixThread = -1; 388 fMixThreadWaitSem = -1; 389 } 390 391 392 // #pragma mark - private 393 394 395 void 396 MixerCore::_UpdateResamplers(const media_multi_audio_format& format) 397 { 398 ASSERT_LOCKED(); 399 400 if (fResampler != NULL) { 401 for (int i = 0; i < fMixBufferChannelCount; i++) 402 delete fResampler[i]; 403 delete[] fResampler; 404 } 405 406 fResampler = new Resampler*[fMixBufferChannelCount]; 407 for (int i = 0; i < fMixBufferChannelCount; i++) { 408 switch (Settings()->ResamplingAlgorithm()) { 409 case 2: 410 fResampler[i] = new Interpolate( 411 media_raw_audio_format::B_AUDIO_FLOAT, format.format); 412 break; 413 default: 414 fResampler[i] = new Resampler( 415 media_raw_audio_format::B_AUDIO_FLOAT, format.format); 416 } 417 } 418 } 419 420 421 void 422 MixerCore::_ApplyOutputFormat() 423 { 424 ASSERT_LOCKED(); 425 426 const media_multi_audio_format& format 427 = fOutput->MediaOutput().format.u.raw_audio; 428 429 if (fMixBuffer != NULL) 430 rtm_free(fMixBuffer); 431 432 delete[] fMixBufferChannelTypes; 433 434 fMixBufferFrameRate = (int32)(0.5 + format.frame_rate); 435 fMixBufferFrameCount = frames_per_buffer(format); 436 if (fDoubleRateMixing) { 437 fMixBufferFrameRate *= 2; 438 fMixBufferFrameCount *= 2; 439 } 440 fMixBufferChannelCount = format.channel_count; 441 ASSERT(fMixBufferChannelCount == fOutput->GetOutputChannelCount()); 442 fMixBufferChannelTypes = new int32 [format.channel_count]; 443 444 for (int i = 0; i < fMixBufferChannelCount; i++) { 445 fMixBufferChannelTypes[i] 446 = ChannelMaskToChannelType(GetChannelMask(i, format.channel_mask)); 447 } 448 449 fMixBuffer = (float*)rtm_alloc(NULL, sizeof(float) * fMixBufferFrameCount 450 * fMixBufferChannelCount); 451 ASSERT(fMixBuffer != NULL); 452 453 _UpdateResamplers(format); 454 455 TRACE("MixerCore::OutputFormatChanged:\n"); 456 TRACE(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate); 457 TRACE(" fMixBufferFrameCount %ld\n", fMixBufferFrameCount); 458 TRACE(" fMixBufferChannelCount %ld\n", fMixBufferChannelCount); 459 for (int i = 0; i < fMixBufferChannelCount; i++) 460 TRACE(" fMixBufferChannelTypes[%i] %ld\n", i, fMixBufferChannelTypes[i]); 461 462 MixerInput *input; 463 for (int i = 0; (input = Input(i)); i++) 464 input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount); 465 } 466 467 468 int32 469 MixerCore::_MixThreadEntry(void* arg) 470 { 471 static_cast<MixerCore*>(arg)->_MixThread(); 472 return 0; 473 } 474 475 476 void 477 MixerCore::_MixThread() 478 { 479 // The broken BeOS R5 multiaudio node starts with time 0, 480 // then publishes negative times for about 50ms, publishes 0 481 // again until it finally reaches time values > 0 482 if (!Lock()) 483 return; 484 bigtime_t start = fTimeSource->Now(); 485 Unlock(); 486 while (start <= 0) { 487 TRACE("MixerCore: delaying _MixThread start, timesource is at %Ld\n", 488 start); 489 snooze(5000); 490 if (!Lock()) 491 return; 492 start = fTimeSource->Now(); 493 Unlock(); 494 } 495 496 fEventLatency = max((bigtime_t)3600, bigtime_t(0.4 * buffer_duration( 497 fOutput->MediaOutput().format.u.raw_audio))); 498 499 // TODO: when the format changes while running, everything is wrong! 500 bigtime_t bufferRequestTimeout = buffer_duration( 501 fOutput->MediaOutput().format.u.raw_audio) / 2; 502 503 TRACE("MixerCore: starting _MixThread at %Ld with latency %Ld and " 504 "downstream latency %Ld, bufferRequestTimeout %Ld\n", start, latency, 505 fDownstreamLatency, bufferRequestTimeout); 506 507 // We must read from the input buffer at a position (pos) that is always 508 // a multiple of fMixBufferFrameCount. 509 int64 temp = frames_for_duration(fMixBufferFrameRate, start); 510 int64 frameBase = ((temp / fMixBufferFrameCount) + 1) 511 * fMixBufferFrameCount; 512 bigtime_t timeBase = duration_for_frames(fMixBufferFrameRate, frameBase); 513 514 TRACE("MixerCore: starting _MixThread, start %Ld, timeBase %Ld, " 515 "frameBase %Ld\n", start, timeBase, frameBase); 516 517 ASSERT(fMixBufferFrameCount > 0); 518 519 #if DEBUG 520 uint64 bufferIndex = 0; 521 #endif 522 523 typedef RtList<chan_info> chan_info_list; 524 chan_info_list inputChanInfos[MAX_CHANNEL_TYPES]; 525 BStackOrHeapArray<chan_info_list, 16> mixChanInfos(fMixBufferChannelCount); 526 // TODO: this does not support changing output channel count 527 if (!mixChanInfos.IsValid()) { 528 ERROR("MixerCore::_MixThread mixChanInfos allocation failed\n"); 529 return; 530 } 531 532 fEventTime = timeBase; 533 int64 framePos = 0; 534 status_t ret = B_ERROR; 535 536 while(fRunning == true) { 537 if (fHasEvent == false) 538 goto schedule_next_event; 539 540 ret = acquire_sem(fMixThreadWaitSem); 541 if (ret == B_INTERRUPTED) 542 continue; 543 else if (ret != B_OK) 544 return; 545 546 fHasEvent = false; 547 548 if (!LockWithTimeout(10000)) { 549 ERROR("MixerCore: LockWithTimeout failed\n"); 550 continue; 551 } 552 553 // no inputs or output muted, skip further processing and just send an 554 // empty buffer 555 if (fInputs->IsEmpty() || fOutput->IsMuted()) { 556 int size = fOutput->MediaOutput().format.u.raw_audio.buffer_size; 557 BBuffer* buffer = fBufferGroup->RequestBuffer(size, 558 bufferRequestTimeout); 559 if (buffer != NULL) { 560 memset(buffer->Data(), 0, size); 561 // fill in the buffer header 562 media_header* hdr = buffer->Header(); 563 hdr->type = B_MEDIA_RAW_AUDIO; 564 hdr->size_used = size; 565 hdr->time_source = fTimeSource->ID(); 566 hdr->start_time = fEventTime; 567 if (fNode->SendBuffer(buffer, fOutput) != B_OK) { 568 #if DEBUG 569 ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", 570 bufferIndex); 571 #else 572 ERROR("MixerCore: SendBuffer failed\n"); 573 #endif 574 buffer->Recycle(); 575 } 576 } else { 577 #if DEBUG 578 ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n", 579 bufferIndex); 580 #else 581 ERROR("MixerCore: RequestBuffer failed\n"); 582 #endif 583 } 584 goto schedule_next_event; 585 } 586 587 int64 currentFramePos; 588 currentFramePos = frameBase + framePos; 589 590 // mix all data from all inputs into the mix buffer 591 ASSERT(currentFramePos % fMixBufferFrameCount == 0); 592 593 PRINT(4, "create new buffer event at %Ld, reading input frames at " 594 "%Ld\n", fEventTime, currentFramePos); 595 596 // Init the channel information for each MixerInput. 597 for (int i = 0; MixerInput* input = Input(i); i++) { 598 int count = input->GetMixerChannelCount(); 599 for (int channel = 0; channel < count; channel++) { 600 int type; 601 const float* base; 602 uint32 sampleOffset; 603 float gain; 604 if (!input->GetMixerChannelInfo(channel, currentFramePos, 605 fEventTime, &base, &sampleOffset, &type, &gain)) { 606 continue; 607 } 608 if (type < 0 || type >= MAX_CHANNEL_TYPES) 609 continue; 610 chan_info* info = inputChanInfos[type].Create(); 611 info->base = (const char*)base; 612 info->sample_offset = sampleOffset; 613 info->gain = gain; 614 } 615 } 616 617 for (int channel = 0; channel < fMixBufferChannelCount; channel++) { 618 int sourceCount = fOutput->GetOutputChannelSourceCount(channel); 619 for (int i = 0; i < sourceCount; i++) { 620 int type; 621 float gain; 622 fOutput->GetOutputChannelSourceInfoAt(channel, i, &type, 623 &gain); 624 if (type < 0 || type >= MAX_CHANNEL_TYPES) 625 continue; 626 int count = inputChanInfos[type].CountItems(); 627 for (int j = 0; j < count; j++) { 628 chan_info* info = inputChanInfos[type].ItemAt(j); 629 chan_info* newInfo = mixChanInfos[channel].Create(); 630 newInfo->base = info->base; 631 newInfo->sample_offset = info->sample_offset; 632 newInfo->gain = info->gain * gain; 633 } 634 } 635 } 636 637 memset(fMixBuffer, 0, 638 fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float)); 639 for (int channel = 0; channel < fMixBufferChannelCount; channel++) { 640 PRINT(5, "_MixThread: channel %d has %d sources\n", channel, 641 mixChanInfos[channel].CountItems()); 642 643 int count = mixChanInfos[channel].CountItems(); 644 for (int i = 0; i < count; i++) { 645 chan_info* info = mixChanInfos[channel].ItemAt(i); 646 PRINT(5, "_MixThread: base %p, sample-offset %2d, gain %.3f\n", 647 info->base, info->sample_offset, info->gain); 648 // This looks slightly ugly, but the current GCC will generate 649 // the fastest code this way. 650 // fMixBufferFrameCount is always > 0. 651 uint32 dstSampleOffset 652 = fMixBufferChannelCount * sizeof(float); 653 uint32 srcSampleOffset = info->sample_offset; 654 register char* dst = (char*)&fMixBuffer[channel]; 655 register char* src = (char*)info->base; 656 register float gain = info->gain; 657 register int j = fMixBufferFrameCount; 658 do { 659 *(float*)dst += *(const float*)src * gain; 660 dst += dstSampleOffset; 661 src += srcSampleOffset; 662 } while (--j); 663 } 664 } 665 666 // request a buffer 667 BBuffer* buffer; 668 buffer = fBufferGroup->RequestBuffer( 669 fOutput->MediaOutput().format.u.raw_audio.buffer_size, 670 bufferRequestTimeout); 671 if (buffer != NULL) { 672 // copy data from mix buffer into output buffer 673 for (int i = 0; i < fMixBufferChannelCount; i++) { 674 fResampler[i]->Resample( 675 reinterpret_cast<char*>(fMixBuffer) + i * sizeof(float), 676 fMixBufferChannelCount * sizeof(float), 677 fMixBufferFrameCount, 678 reinterpret_cast<char*>(buffer->Data()) 679 + (i * bytes_per_sample( 680 fOutput->MediaOutput().format.u.raw_audio)), 681 bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio), 682 frames_per_buffer( 683 fOutput->MediaOutput().format.u.raw_audio), 684 fOutputGain * fOutput->GetOutputChannelGain(i)); 685 } 686 PRINT(4, "send buffer, inframes %ld, outframes %ld\n", 687 fMixBufferFrameCount, 688 frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio)); 689 690 // fill in the buffer header 691 media_header* hdr = buffer->Header(); 692 hdr->type = B_MEDIA_RAW_AUDIO; 693 hdr->size_used 694 = fOutput->MediaOutput().format.u.raw_audio.buffer_size; 695 hdr->time_source = fTimeSource->ID(); 696 hdr->start_time = fEventTime; 697 698 // swap byte order if necessary 699 fOutput->AdjustByteOrder(buffer); 700 701 // send the buffer 702 status_t res = fNode->SendBuffer(buffer, fOutput); 703 if (res != B_OK) { 704 #if DEBUG 705 ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", 706 bufferIndex); 707 #else 708 ERROR("MixerCore: SendBuffer failed\n"); 709 #endif 710 buffer->Recycle(); 711 } 712 } else { 713 #if DEBUG 714 ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n", 715 bufferIndex); 716 #else 717 ERROR("MixerCore: RequestBuffer failed\n"); 718 #endif 719 } 720 721 // make all lists empty 722 for (int i = 0; i < MAX_CHANNEL_TYPES; i++) 723 inputChanInfos[i].MakeEmpty(); 724 for (int i = 0; i < fOutput->GetOutputChannelCount(); i++) 725 mixChanInfos[i].MakeEmpty(); 726 727 schedule_next_event: 728 Unlock(); 729 730 // schedule next event 731 framePos += fMixBufferFrameCount; 732 fEventTime = timeBase + bigtime_t((1000000LL * framePos) 733 / fMixBufferFrameRate); 734 735 media_timed_event mixerEvent(PickEvent(), 736 MIXER_PROCESS_EVENT, 0, BTimedEventQueue::B_NO_CLEANUP); 737 738 ret = write_port(fNode->ControlPort(), MIXER_SCHEDULE_EVENT, 739 &mixerEvent, sizeof(mixerEvent)); 740 if (ret != B_OK) 741 TRACE("MixerCore::_MixThread: can't write to owner port\n"); 742 743 fHasEvent = true; 744 745 #if DEBUG 746 bufferIndex++; 747 #endif 748 } 749 } 750