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 TRACE("MixerCore: delaying _MixThread start, timesource is at %" B_PRIdBIGTIME "\n", 488 performanceTime); 489 Unlock(); 490 snooze(5000); 491 while (!LockWithTimeout(10000)) { 492 if (!fRunning) 493 return; 494 } 495 } 496 } 497 Unlock(); 498 499 const bigtime_t start = fTimeSource->Now(); 500 501 bigtime_t eventLatency = max((bigtime_t)3600, bigtime_t(0.4 * buffer_duration( 502 fOutput->MediaOutput().format.u.raw_audio))); 503 504 // TODO: when the format changes while running, everything is wrong! 505 bigtime_t bufferRequestTimeout = buffer_duration( 506 fOutput->MediaOutput().format.u.raw_audio) / 2; 507 508 TRACE("MixerCore: starting _MixThread at %lld with latency %lld and " 509 "downstream latency %lld, bufferRequestTimeout %lld\n", start, 510 eventLatency, fDownstreamLatency, bufferRequestTimeout); 511 512 // We must read from the input buffer at a position (pos) that is always 513 // a multiple of fMixBufferFrameCount. 514 int64 temp = frames_for_duration(fMixBufferFrameRate, start); 515 const int64 frameBase = ((temp / fMixBufferFrameCount) + 1) 516 * fMixBufferFrameCount; 517 const bigtime_t timeBase = duration_for_frames(fMixBufferFrameRate, frameBase); 518 519 TRACE("MixerCore: starting _MixThread, start %lld, timeBase %lld, " 520 "frameBase %lld\n", start, timeBase, frameBase); 521 522 ASSERT(fMixBufferFrameCount > 0); 523 524 typedef RtList<chan_info> chan_info_list; 525 chan_info_list inputChanInfos[MAX_CHANNEL_TYPES]; 526 BStackOrHeapArray<chan_info_list, 16> mixChanInfos(fMixBufferChannelCount); 527 // TODO: this does not support changing output channel count 528 if (!mixChanInfos.IsValid()) { 529 ERROR("MixerCore::_MixThread mixChanInfos allocation failed\n"); 530 return; 531 } 532 533 int64 framePos = 0; 534 uint64 bufferIndex = 0; 535 bigtime_t eventTime = 0, nextRun = B_INFINITE_TIMEOUT; 536 while (fRunning) { 537 if (nextRun == B_INFINITE_TIMEOUT) { 538 eventTime = timeBase + bigtime_t((1000000LL * framePos) 539 / fMixBufferFrameRate); 540 nextRun = fTimeSource->RealTimeFor(eventTime, 0) 541 - eventLatency - fDownstreamLatency; 542 } 543 544 status_t status = acquire_sem_etc(fMixThreadWaitSem, 1, 545 B_ABSOLUTE_TIMEOUT, nextRun); 546 if (status != B_TIMED_OUT) { 547 if (status == B_OK || status == B_INTERRUPTED) 548 continue; 549 return; 550 } 551 nextRun = B_INFINITE_TIMEOUT; 552 553 if (!LockWithTimeout(10000)) { 554 ERROR("MixerCore: LockWithTimeout failed\n"); 555 continue; 556 } 557 558 // no inputs or output muted, skip further processing and just send an 559 // empty buffer 560 if (fInputs->IsEmpty() || fOutput->IsMuted()) { 561 int size = fOutput->MediaOutput().format.u.raw_audio.buffer_size; 562 BBuffer* buffer = fBufferGroup->RequestBuffer(size, 563 bufferRequestTimeout); 564 if (buffer != NULL) { 565 int middle = 0; 566 if (fOutput->MediaOutput().format.u.raw_audio.format 567 == media_raw_audio_format::B_AUDIO_UCHAR) 568 middle = 128; 569 memset(buffer->Data(), middle, size); 570 // fill in the buffer header 571 media_header* hdr = buffer->Header(); 572 hdr->type = B_MEDIA_RAW_AUDIO; 573 hdr->size_used = size; 574 hdr->time_source = fTimeSource->ID(); 575 hdr->start_time = eventTime; 576 if (fNode->SendBuffer(buffer, fOutput) != B_OK) { 577 ERROR("MixerCore: SendBuffer failed for buffer %lld\n", 578 bufferIndex); 579 buffer->Recycle(); 580 } 581 } else { 582 ERROR("MixerCore: RequestBuffer failed for buffer %lld\n", 583 bufferIndex); 584 } 585 586 bufferIndex++; 587 framePos += fMixBufferFrameCount; 588 589 Unlock(); 590 continue; 591 } 592 593 int64 currentFramePos; 594 currentFramePos = frameBase + framePos; 595 596 // mix all data from all inputs into the mix buffer 597 ASSERT(currentFramePos % fMixBufferFrameCount == 0); 598 599 PRINT(4, "create new buffer event at %lld, reading input frames at " 600 "%lld\n", eventTime, currentFramePos); 601 602 // Init the channel information for each MixerInput. 603 for (int i = 0; MixerInput* input = Input(i); i++) { 604 int count = input->GetMixerChannelCount(); 605 for (int channel = 0; channel < count; channel++) { 606 int type; 607 const float* base; 608 uint32 sampleOffset; 609 float gain; 610 if (!input->GetMixerChannelInfo(channel, currentFramePos, 611 eventTime, &base, &sampleOffset, &type, &gain)) { 612 continue; 613 } 614 if (type < 0 || type >= MAX_CHANNEL_TYPES) 615 continue; 616 chan_info* info = inputChanInfos[type].Create(); 617 info->base = (const char*)base; 618 info->sample_offset = sampleOffset; 619 info->gain = gain; 620 } 621 } 622 623 for (int channel = 0; channel < fMixBufferChannelCount; channel++) { 624 int sourceCount = fOutput->GetOutputChannelSourceCount(channel); 625 for (int i = 0; i < sourceCount; i++) { 626 int type; 627 float gain; 628 fOutput->GetOutputChannelSourceInfoAt(channel, i, &type, 629 &gain); 630 if (type < 0 || type >= MAX_CHANNEL_TYPES) 631 continue; 632 int count = inputChanInfos[type].CountItems(); 633 for (int j = 0; j < count; j++) { 634 chan_info* info = inputChanInfos[type].ItemAt(j); 635 chan_info* newInfo = mixChanInfos[channel].Create(); 636 newInfo->base = info->base; 637 newInfo->sample_offset = info->sample_offset; 638 newInfo->gain = info->gain * gain; 639 } 640 } 641 } 642 643 memset(fMixBuffer, 0, 644 fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float)); 645 for (int channel = 0; channel < fMixBufferChannelCount; channel++) { 646 PRINT(5, "_MixThread: channel %d has %d sources\n", channel, 647 mixChanInfos[channel].CountItems()); 648 649 int count = mixChanInfos[channel].CountItems(); 650 for (int i = 0; i < count; i++) { 651 chan_info* info = mixChanInfos[channel].ItemAt(i); 652 PRINT(5, "_MixThread: base %p, sample-offset %2d, gain %.3f\n", 653 info->base, info->sample_offset, info->gain); 654 // This looks slightly ugly, but the current GCC will generate 655 // the fastest code this way. 656 // fMixBufferFrameCount is always > 0. 657 uint32 dstSampleOffset 658 = fMixBufferChannelCount * sizeof(float); 659 uint32 srcSampleOffset = info->sample_offset; 660 char* dst = (char*)&fMixBuffer[channel]; 661 char* src = (char*)info->base; 662 float gain = info->gain; 663 int j = fMixBufferFrameCount; 664 do { 665 *(float*)dst += *(const float*)src * gain; 666 dst += dstSampleOffset; 667 src += srcSampleOffset; 668 } while (--j); 669 } 670 } 671 672 // request a buffer 673 BBuffer* buffer; 674 buffer = fBufferGroup->RequestBuffer( 675 fOutput->MediaOutput().format.u.raw_audio.buffer_size, 676 bufferRequestTimeout); 677 if (buffer != NULL) { 678 // copy data from mix buffer into output buffer 679 for (int i = 0; i < fMixBufferChannelCount; i++) { 680 fResampler[i]->Resample( 681 reinterpret_cast<char*>(fMixBuffer) + i * sizeof(float), 682 fMixBufferChannelCount * sizeof(float), 683 fMixBufferFrameCount, 684 reinterpret_cast<char*>(buffer->Data()) 685 + (i * bytes_per_sample( 686 fOutput->MediaOutput().format.u.raw_audio)), 687 bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio), 688 frames_per_buffer( 689 fOutput->MediaOutput().format.u.raw_audio), 690 fOutputGain * fOutput->GetOutputChannelGain(i)); 691 } 692 PRINT(4, "send buffer, inframes %ld, outframes %ld\n", 693 fMixBufferFrameCount, 694 frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio)); 695 696 // fill in the buffer header 697 media_header* hdr = buffer->Header(); 698 hdr->type = B_MEDIA_RAW_AUDIO; 699 hdr->size_used 700 = fOutput->MediaOutput().format.u.raw_audio.buffer_size; 701 hdr->time_source = fTimeSource->ID(); 702 hdr->start_time = eventTime; 703 704 // swap byte order if necessary 705 fOutput->AdjustByteOrder(buffer); 706 707 // send the buffer 708 status_t res = fNode->SendBuffer(buffer, fOutput); 709 if (res != B_OK) { 710 ERROR("MixerCore: SendBuffer failed for buffer %lld\n", 711 bufferIndex); 712 buffer->Recycle(); 713 } 714 } else { 715 ERROR("MixerCore: RequestBuffer failed for buffer %lld\n", 716 bufferIndex); 717 } 718 719 // make all lists empty 720 for (int i = 0; i < MAX_CHANNEL_TYPES; i++) 721 inputChanInfos[i].MakeEmpty(); 722 for (int i = 0; i < fOutput->GetOutputChannelCount(); i++) 723 mixChanInfos[i].MakeEmpty(); 724 725 bufferIndex++; 726 framePos += fMixBufferFrameCount; 727 728 Unlock(); 729 } 730 } 731