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