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