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