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 fOutputGain(1.0) 88 { 89 } 90 91 92 MixerCore::~MixerCore() 93 { 94 delete fSettings; 95 96 delete fLocker; 97 delete fInputs; 98 99 ASSERT(fMixThreadWaitSem == -1); 100 ASSERT(fMixThread == -1); 101 102 if (fMixBuffer) 103 rtm_free(fMixBuffer); 104 105 if (fTimeSource) 106 fTimeSource->Release(); 107 108 if (fResampler) { 109 for (int i = 0; i < fMixBufferChannelCount; i++) 110 delete fResampler[i]; 111 delete[] fResampler; 112 } 113 114 delete[] fMixBufferChannelTypes; 115 } 116 117 118 MixerSettings * 119 MixerCore::Settings() 120 { 121 return fSettings; 122 } 123 124 125 void 126 MixerCore::UpdateResamplingAlgorithm() 127 { 128 ASSERT_LOCKED(); 129 130 _UpdateResamplers(fOutput->MediaOutput().format.u.raw_audio); 131 132 for (int32 i = fInputs->CountItems() - 1; i >= 0; i--) { 133 MixerInput* input 134 = reinterpret_cast<MixerInput*>(fInputs->ItemAtFast(i)); 135 input->UpdateResamplingAlgorithm(); 136 } 137 } 138 139 140 void 141 MixerCore::SetOutputAttenuation(float gain) 142 { 143 ASSERT_LOCKED(); 144 fOutputGain = gain; 145 } 146 147 148 MixerInput* 149 MixerCore::AddInput(const media_input& input) 150 { 151 ASSERT_LOCKED(); 152 MixerInput* in = new MixerInput(this, input, fMixBufferFrameRate, 153 fMixBufferFrameCount); 154 fInputs->AddItem(in); 155 return in; 156 } 157 158 159 MixerOutput* 160 MixerCore::AddOutput(const media_output& output) 161 { 162 ASSERT_LOCKED(); 163 if (fOutput != NULL) { 164 ERROR("MixerCore::AddOutput: already connected\n"); 165 return fOutput; 166 } 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 == NULL) 201 return false; 202 203 if (fRunning) 204 _StopMixThread(); 205 206 delete fOutput; 207 fOutput = NULL; 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 268 if (fRunning) 269 _StopMixThread(); 270 271 fOutput->ChangeFormat(format); 272 _ApplyOutputFormat(); 273 274 if (fStarted) 275 _StartMixThread(); 276 } 277 278 279 void 280 MixerCore::SetOutputBufferGroup(BBufferGroup *group) 281 { 282 ASSERT_LOCKED(); 283 fBufferGroup = group; 284 } 285 286 287 void 288 MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency) 289 { 290 ASSERT_LOCKED(); 291 if (fTimeSource) 292 fTimeSource->Release(); 293 294 fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire()); 295 fDownstreamLatency = downstream_latency; 296 297 TRACE("MixerCore::SetTimingInfo, now = %lld, downstream latency %lld\n", 298 fTimeSource->Now(), fDownstreamLatency); 299 } 300 301 302 void 303 MixerCore::EnableOutput(bool enabled) 304 { 305 ASSERT_LOCKED(); 306 TRACE("MixerCore::EnableOutput %d\n", enabled); 307 fOutputEnabled = enabled; 308 309 if (fRunning && !fOutputEnabled) 310 _StopMixThread(); 311 312 if (!fRunning && fOutput != NULL && fStarted && fOutputEnabled) 313 _StartMixThread(); 314 } 315 316 317 uint32 318 MixerCore::OutputChannelCount() 319 { 320 return (fOutput) ? fOutput->GetOutputChannelCount() : 0; 321 } 322 323 324 bool 325 MixerCore::Start() 326 { 327 ASSERT_LOCKED(); 328 TRACE("MixerCore::Start\n"); 329 if (fStarted) 330 return false; 331 332 fStarted = true; 333 334 ASSERT(!fRunning); 335 336 // only start the mix thread if we have an output 337 if (fOutput != NULL && fOutputEnabled) 338 _StartMixThread(); 339 340 return true; 341 } 342 343 344 bool 345 MixerCore::Stop() 346 { 347 ASSERT_LOCKED(); 348 TRACE("MixerCore::Stop\n"); 349 if (!fStarted) 350 return false; 351 352 if (fRunning) 353 _StopMixThread(); 354 355 fStarted = false; 356 return true; 357 } 358 359 360 void 361 MixerCore::_StartMixThread() 362 { 363 ASSERT(fOutputEnabled); 364 ASSERT(!fRunning); 365 ASSERT(fOutput != NULL); 366 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); 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 if (!Lock()) 480 return; 481 { 482 // Delay starting the mixer until we have a valid time source. 483 bigtime_t performanceTime, realTime; 484 float drift; 485 while (fTimeSource->GetTime(&performanceTime, &realTime, &drift) != B_OK 486 || performanceTime <= 0 || realTime <= 0 487 || (realTime + 1 * 1000 * 1000) <= system_time()) { 488 TRACE("MixerCore: delaying _MixThread start, timesource is at %" B_PRIdBIGTIME "\n", 489 performanceTime); 490 Unlock(); 491 snooze(5000); 492 while (!LockWithTimeout(10000)) { 493 if (!fRunning) 494 return; 495 } 496 } 497 } 498 Unlock(); 499 500 const bigtime_t start = fTimeSource->Now(); 501 502 bigtime_t eventLatency = max((bigtime_t)3600, bigtime_t(0.4 * buffer_duration( 503 fOutput->MediaOutput().format.u.raw_audio))); 504 505 // TODO: when the format changes while running, everything is wrong! 506 bigtime_t bufferRequestTimeout = buffer_duration( 507 fOutput->MediaOutput().format.u.raw_audio) / 2; 508 509 TRACE("MixerCore: starting _MixThread at %lld with latency %lld and " 510 "downstream latency %lld, bufferRequestTimeout %lld\n", start, 511 eventLatency, fDownstreamLatency, bufferRequestTimeout); 512 513 // We must read from the input buffer at a position (pos) that is always 514 // a multiple of fMixBufferFrameCount. 515 int64 temp = frames_for_duration(fMixBufferFrameRate, start); 516 const int64 frameBase = ((temp / fMixBufferFrameCount) + 1) 517 * fMixBufferFrameCount; 518 const bigtime_t timeBase = duration_for_frames(fMixBufferFrameRate, frameBase); 519 520 TRACE("MixerCore: starting _MixThread, start %lld, timeBase %lld, " 521 "frameBase %lld\n", start, timeBase, frameBase); 522 523 ASSERT(fMixBufferFrameCount > 0); 524 525 typedef RtList<chan_info> chan_info_list; 526 chan_info_list inputChanInfos[MAX_CHANNEL_TYPES]; 527 BStackOrHeapArray<chan_info_list, 16> mixChanInfos(fMixBufferChannelCount); 528 // TODO: this does not support changing output channel count 529 if (!mixChanInfos.IsValid()) { 530 ERROR("MixerCore::_MixThread mixChanInfos allocation failed\n"); 531 return; 532 } 533 534 int64 framePos = 0; 535 uint64 bufferIndex = 0; 536 bigtime_t eventTime = 0, nextRun = B_INFINITE_TIMEOUT; 537 while (fRunning) { 538 if (nextRun == B_INFINITE_TIMEOUT) { 539 eventTime = timeBase + bigtime_t((1000000LL * framePos) 540 / fMixBufferFrameRate); 541 nextRun = fTimeSource->RealTimeFor(eventTime, 0) 542 - eventLatency - fDownstreamLatency; 543 } 544 545 status_t status = acquire_sem_etc(fMixThreadWaitSem, 1, 546 B_ABSOLUTE_TIMEOUT, nextRun); 547 if (status != B_TIMED_OUT) { 548 if (status == B_OK || status == B_INTERRUPTED) 549 continue; 550 return; 551 } 552 nextRun = B_INFINITE_TIMEOUT; 553 554 if (!LockWithTimeout(10000)) { 555 ERROR("MixerCore: LockWithTimeout failed\n"); 556 continue; 557 } 558 559 // no inputs or output muted, skip further processing and just send an 560 // empty buffer 561 if (fInputs->IsEmpty() || fOutput->IsMuted()) { 562 int size = fOutput->MediaOutput().format.u.raw_audio.buffer_size; 563 BBuffer* buffer = fBufferGroup->RequestBuffer(size, 564 bufferRequestTimeout); 565 if (buffer != NULL) { 566 int middle = 0; 567 if (fOutput->MediaOutput().format.u.raw_audio.format 568 == media_raw_audio_format::B_AUDIO_UCHAR) 569 middle = 128; 570 memset(buffer->Data(), middle, size); 571 // fill in the buffer header 572 media_header* hdr = buffer->Header(); 573 hdr->type = B_MEDIA_RAW_AUDIO; 574 hdr->size_used = size; 575 hdr->time_source = fTimeSource->ID(); 576 hdr->start_time = eventTime; 577 if (fNode->SendBuffer(buffer, fOutput) != B_OK) { 578 ERROR("MixerCore: SendBuffer failed for buffer %lld\n", 579 bufferIndex); 580 buffer->Recycle(); 581 } 582 } else { 583 ERROR("MixerCore: RequestBuffer failed for buffer %lld\n", 584 bufferIndex); 585 } 586 587 bufferIndex++; 588 framePos += fMixBufferFrameCount; 589 590 Unlock(); 591 continue; 592 } 593 594 int64 currentFramePos; 595 currentFramePos = frameBase + framePos; 596 597 // mix all data from all inputs into the mix buffer 598 ASSERT(currentFramePos % fMixBufferFrameCount == 0); 599 600 PRINT(4, "create new buffer event at %lld, reading input frames at " 601 "%lld\n", eventTime, currentFramePos); 602 603 // Init the channel information for each MixerInput. 604 for (int i = 0; MixerInput* input = Input(i); i++) { 605 int count = input->GetMixerChannelCount(); 606 for (int channel = 0; channel < count; channel++) { 607 int type; 608 const float* base; 609 uint32 sampleOffset; 610 float gain; 611 if (!input->GetMixerChannelInfo(channel, currentFramePos, 612 eventTime, &base, &sampleOffset, &type, &gain)) { 613 continue; 614 } 615 if (type < 0 || type >= MAX_CHANNEL_TYPES) 616 continue; 617 chan_info* info = inputChanInfos[type].Create(); 618 info->base = (const char*)base; 619 info->sample_offset = sampleOffset; 620 info->gain = gain; 621 } 622 } 623 624 for (int channel = 0; channel < fMixBufferChannelCount; channel++) { 625 int sourceCount = fOutput->GetOutputChannelSourceCount(channel); 626 for (int i = 0; i < sourceCount; i++) { 627 int type; 628 float gain; 629 fOutput->GetOutputChannelSourceInfoAt(channel, i, &type, 630 &gain); 631 if (type < 0 || type >= MAX_CHANNEL_TYPES) 632 continue; 633 int count = inputChanInfos[type].CountItems(); 634 for (int j = 0; j < count; j++) { 635 chan_info* info = inputChanInfos[type].ItemAt(j); 636 chan_info* newInfo = mixChanInfos[channel].Create(); 637 newInfo->base = info->base; 638 newInfo->sample_offset = info->sample_offset; 639 newInfo->gain = info->gain * gain; 640 } 641 } 642 } 643 644 memset(fMixBuffer, 0, 645 fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float)); 646 for (int channel = 0; channel < fMixBufferChannelCount; channel++) { 647 PRINT(5, "_MixThread: channel %d has %d sources\n", channel, 648 mixChanInfos[channel].CountItems()); 649 650 int count = mixChanInfos[channel].CountItems(); 651 for (int i = 0; i < count; i++) { 652 chan_info* info = mixChanInfos[channel].ItemAt(i); 653 PRINT(5, "_MixThread: base %p, sample-offset %2d, gain %.3f\n", 654 info->base, info->sample_offset, info->gain); 655 // This looks slightly ugly, but the current GCC will generate 656 // the fastest code this way. 657 // fMixBufferFrameCount is always > 0. 658 uint32 dstSampleOffset 659 = fMixBufferChannelCount * sizeof(float); 660 uint32 srcSampleOffset = info->sample_offset; 661 char* dst = (char*)&fMixBuffer[channel]; 662 char* src = (char*)info->base; 663 float gain = info->gain; 664 int j = fMixBufferFrameCount; 665 do { 666 *(float*)dst += *(const float*)src * gain; 667 dst += dstSampleOffset; 668 src += srcSampleOffset; 669 } while (--j); 670 } 671 } 672 673 // request a buffer 674 BBuffer* buffer; 675 buffer = fBufferGroup->RequestBuffer( 676 fOutput->MediaOutput().format.u.raw_audio.buffer_size, 677 bufferRequestTimeout); 678 if (buffer != NULL) { 679 // copy data from mix buffer into output buffer 680 for (int i = 0; i < fMixBufferChannelCount; i++) { 681 fResampler[i]->Resample( 682 reinterpret_cast<char*>(fMixBuffer) + i * sizeof(float), 683 fMixBufferChannelCount * sizeof(float), 684 fMixBufferFrameCount, 685 reinterpret_cast<char*>(buffer->Data()) 686 + (i * bytes_per_sample( 687 fOutput->MediaOutput().format.u.raw_audio)), 688 bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio), 689 frames_per_buffer( 690 fOutput->MediaOutput().format.u.raw_audio), 691 fOutputGain * fOutput->GetOutputChannelGain(i)); 692 } 693 PRINT(4, "send buffer, inframes %ld, outframes %ld\n", 694 fMixBufferFrameCount, 695 frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio)); 696 697 // fill in the buffer header 698 media_header* hdr = buffer->Header(); 699 hdr->type = B_MEDIA_RAW_AUDIO; 700 hdr->size_used 701 = fOutput->MediaOutput().format.u.raw_audio.buffer_size; 702 hdr->time_source = fTimeSource->ID(); 703 hdr->start_time = eventTime; 704 705 // swap byte order if necessary 706 fOutput->AdjustByteOrder(buffer); 707 708 // send the buffer 709 status_t res = fNode->SendBuffer(buffer, fOutput); 710 if (res != B_OK) { 711 ERROR("MixerCore: SendBuffer failed for buffer %lld\n", 712 bufferIndex); 713 buffer->Recycle(); 714 } 715 } else { 716 ERROR("MixerCore: RequestBuffer failed for buffer %lld\n", 717 bufferIndex); 718 } 719 720 // make all lists empty 721 for (int i = 0; i < MAX_CHANNEL_TYPES; i++) 722 inputChanInfos[i].MakeEmpty(); 723 for (int i = 0; i < fOutput->GetOutputChannelCount(); i++) 724 mixChanInfos[i].MakeEmpty(); 725 726 bufferIndex++; 727 framePos += fMixBufferFrameCount; 728 729 Unlock(); 730 } 731 } 732