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