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), 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 format.valid_bits); 268 269 TRACE("MixerCore::OutputFormatChanged:\n"); 270 TRACE(" fMixBufferFrameRate %ld\n", fMixBufferFrameRate); 271 TRACE(" fMixBufferFrameCount %ld\n", fMixBufferFrameCount); 272 TRACE(" fMixBufferChannelCount %ld\n", fMixBufferChannelCount); 273 for (int i = 0; i < fMixBufferChannelCount; i++) 274 TRACE(" fMixBufferChannelTypes[%i] %ld\n", i, fMixBufferChannelTypes[i]); 275 276 MixerInput *input; 277 for (int i = 0; (input = Input(i)); i++) 278 input->SetMixBufferFormat(fMixBufferFrameRate, fMixBufferFrameCount); 279 } 280 281 void 282 MixerCore::SetOutputBufferGroup(BBufferGroup *group) 283 { 284 ASSERT_LOCKED(); 285 fBufferGroup = group; 286 } 287 288 void 289 MixerCore::SetTimingInfo(BTimeSource *ts, bigtime_t downstream_latency) 290 { 291 ASSERT_LOCKED(); 292 if (fTimeSource) 293 fTimeSource->Release(); 294 295 fTimeSource = dynamic_cast<BTimeSource *>(ts->Acquire()); 296 fDownstreamLatency = downstream_latency; 297 298 TRACE("MixerCore::SetTimingInfo, now = %Ld, downstream latency %Ld\n", 299 fTimeSource->Now(), 300 fDownstreamLatency); 301 } 302 303 void 304 MixerCore::EnableOutput(bool enabled) 305 { 306 ASSERT_LOCKED(); 307 TRACE("MixerCore::EnableOutput %d\n", enabled); 308 fOutputEnabled = enabled; 309 310 if (fRunning && !fOutputEnabled) 311 StopMixThread(); 312 313 if (!fRunning && fOutput && fStarted && fOutputEnabled) 314 StartMixThread(); 315 } 316 317 318 uint32 319 MixerCore::OutputChannelCount() 320 { 321 return (fOutput) ? fOutput->GetOutputChannelCount() : 0; 322 } 323 324 325 bool 326 MixerCore::Start() 327 { 328 ASSERT_LOCKED(); 329 TRACE("MixerCore::Start\n"); 330 if (fStarted) 331 return false; 332 333 fStarted = true; 334 335 ASSERT(!fRunning); 336 337 // only start the mix thread if we have an output 338 if (fOutput && fOutputEnabled) 339 StartMixThread(); 340 341 return true; 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 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(_mix_thread_, "Yeah baby, very shagadelic", 120, this); 368 resume_thread(fMixThread); 369 } 370 371 void 372 MixerCore::StopMixThread() 373 { 374 ASSERT(fRunning == true); 375 ASSERT(fMixThread > 0); 376 ASSERT(fMixThreadWaitSem > 0); 377 378 status_t unused; 379 delete_sem(fMixThreadWaitSem); 380 wait_for_thread(fMixThread, &unused); 381 382 fMixThread = -1; 383 fMixThreadWaitSem = -1; 384 fRunning = false; 385 } 386 387 int32 388 MixerCore::_mix_thread_(void *arg) 389 { 390 static_cast<MixerCore *>(arg)->MixThread(); 391 return 0; 392 } 393 394 struct chan_info { 395 const char *base; 396 uint32 sample_offset; 397 float gain; 398 }; 399 400 void 401 MixerCore::MixThread() 402 { 403 bigtime_t event_time; 404 bigtime_t time_base; 405 bigtime_t latency; 406 bigtime_t start; 407 bigtime_t buffer_request_timeout; 408 int64 frame_base; 409 int64 frame_pos; 410 411 // The broken BeOS R5 multiaudio node starts with time 0, 412 // then publishes negative times for about 50ms, publishes 0 413 // again until it finally reaches time values > 0 414 if (!LockFromMixThread()) 415 return; 416 start = fTimeSource->Now(); 417 Unlock(); 418 while (start <= 0) { 419 TRACE("MixerCore: delaying MixThread start, timesource is at %Ld\n", start); 420 snooze(5000); 421 if (!LockFromMixThread()) 422 return; 423 start = fTimeSource->Now(); 424 Unlock(); 425 } 426 427 if (!LockFromMixThread()) 428 return; 429 latency = max(3600LL, bigtime_t(0.4 * buffer_duration(fOutput->MediaOutput().format.u.raw_audio))); 430 431 // XXX when the format changes while running, everything is wrong! 432 buffer_request_timeout = buffer_duration(fOutput->MediaOutput().format.u.raw_audio) / 2; 433 434 TRACE("MixerCore: starting MixThread at %Ld with latency %Ld and downstream latency %Ld, buffer_request_timeout %Ld\n", start, latency, fDownstreamLatency, buffer_request_timeout); 435 436 /* We must read from the input buffer at a position (pos) that is always a multiple of fMixBufferFrameCount. 437 */ 438 int64 temp = frames_for_duration(fMixBufferFrameRate, start ); 439 frame_base = ((temp / fMixBufferFrameCount) + 1) * fMixBufferFrameCount; 440 time_base = duration_for_frames(fMixBufferFrameRate, frame_base); 441 Unlock(); 442 443 TRACE("MixerCore: starting MixThread, start %Ld, time_base %Ld, frame_base %Ld\n", start, time_base, frame_base); 444 445 ASSERT(fMixBufferFrameCount > 0); 446 447 #if DEBUG 448 uint64 buffer_num = 0; 449 #endif 450 451 RtList<chan_info> InputChanInfos[MAX_CHANNEL_TYPES]; 452 RtList<chan_info> MixChanInfos[fMixBufferChannelCount]; // XXX this does not support changing output channel count 453 454 event_time = time_base; 455 frame_pos = 0; 456 for (;;) { 457 bigtime_t wait_until; 458 if (!LockFromMixThread()) 459 return; 460 wait_until = fTimeSource->RealTimeFor(event_time, 0) - latency - fDownstreamLatency; 461 Unlock(); 462 status_t rv; 463 rv = acquire_sem_etc(fMixThreadWaitSem, 1, B_ABSOLUTE_TIMEOUT, wait_until); 464 if (rv == B_INTERRUPTED) 465 continue; 466 if (rv != B_TIMED_OUT && rv < B_OK) 467 return; 468 469 if (!LockWithTimeout(10000)) { 470 ERROR("MixerCore: LockWithTimeout failed\n"); 471 continue; 472 } 473 474 // no inputs or output muted, skip further processing and just send an empty buffer 475 if (fInputs->IsEmpty() || fOutput->IsMuted()) { 476 int size = fOutput->MediaOutput().format.u.raw_audio.buffer_size; 477 BBuffer* buf = fBufferGroup->RequestBuffer(size, buffer_request_timeout); 478 if (buf) { 479 memset(buf->Data(), 0, size); 480 // fill in the buffer header 481 media_header* hdr = buf->Header(); 482 hdr->type = B_MEDIA_RAW_AUDIO; 483 hdr->size_used = size; 484 hdr->time_source = fTimeSource->ID(); 485 hdr->start_time = event_time; 486 if (B_OK != fNode->SendBuffer(buf, fOutput->MediaOutput().destination)) { 487 #if DEBUG 488 ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", buffer_num); 489 #else 490 ERROR("MixerCore: SendBuffer failed\n"); 491 #endif 492 buf->Recycle(); 493 } 494 } else { 495 #if DEBUG 496 ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n", buffer_num); 497 #else 498 ERROR("MixerCore: RequestBuffer failed\n"); 499 #endif 500 } 501 goto schedule_next_event; 502 } 503 504 int64 cur_framepos; 505 cur_framepos = frame_base + frame_pos; 506 507 // mix all data from all inputs into the mix buffer 508 ASSERT(cur_framepos % fMixBufferFrameCount == 0); 509 510 PRINT(4, "create new buffer event at %Ld, reading input frames at %Ld\n", event_time, cur_framepos); 511 512 MixerInput *input; 513 for (int i = 0; (input = Input(i)) != 0; i++) { 514 int count = input->GetMixerChannelCount(); 515 for (int chan = 0; chan < count; chan++) { 516 int type; 517 const float *base; 518 uint32 sample_offset; 519 float gain; 520 if (!input->GetMixerChannelInfo(chan, cur_framepos, event_time, &base, &sample_offset, &type, &gain)) 521 continue; 522 if (type < 0 || type >= MAX_CHANNEL_TYPES) 523 continue; 524 chan_info *info = InputChanInfos[type].Create(); 525 info->base = (const char *)base; 526 info->sample_offset = sample_offset; 527 info->gain = gain; 528 } 529 } 530 531 for (int chan = 0; chan < fMixBufferChannelCount; chan++) { 532 int sourcecount = fOutput->GetOutputChannelSourceCount(chan); 533 for (int i = 0; i < sourcecount; i++) { 534 int type; 535 float gain; 536 fOutput->GetOutputChannelSourceInfoAt(chan, i, &type, &gain); 537 if (type < 0 || type >= MAX_CHANNEL_TYPES) 538 continue; 539 int count = InputChanInfos[type].CountItems(); 540 for (int j = 0; j < count; j++) { 541 chan_info *info = InputChanInfos[type].ItemAt(j); 542 chan_info *newinfo = MixChanInfos[chan].Create(); 543 newinfo->base = info->base; 544 newinfo->sample_offset = info->sample_offset; 545 newinfo->gain = info->gain * gain; 546 } 547 } 548 } 549 550 memset(fMixBuffer, 0, fMixBufferChannelCount * fMixBufferFrameCount * sizeof(float)); 551 for (int chan = 0; chan < fMixBufferChannelCount; chan++) { 552 PRINT(5, "MixThread: chan %d has %d sources\n", chan, MixChanInfos[chan].CountItems()); 553 int count = MixChanInfos[chan].CountItems(); 554 for (int i = 0; i < count; i++) { 555 chan_info *info = MixChanInfos[chan].ItemAt(i); 556 PRINT(5, "MixThread: base %p, sample-offset %2d, gain %.3f\n", info->base, info->sample_offset, info->gain); 557 // This looks slightly ugly, but the current GCC will generate the fastest 558 // code this way. fMixBufferFrameCount is always > 0. 559 uint32 dst_sample_offset = fMixBufferChannelCount * sizeof(float); 560 uint32 src_sample_offset = info->sample_offset; 561 register char *dst = (char *)&fMixBuffer[chan]; 562 register char *src = (char *)info->base; 563 register float gain = info->gain; 564 register int j = fMixBufferFrameCount; 565 do { 566 *(float *)dst += *(const float *)src * gain; 567 dst += dst_sample_offset; 568 src += src_sample_offset; 569 } while (--j); 570 } 571 } 572 573 // request a buffer 574 BBuffer *buf; 575 buf = fBufferGroup->RequestBuffer( 576 fOutput->MediaOutput().format.u.raw_audio.buffer_size, 577 buffer_request_timeout); 578 if (buf) { 579 // copy data from mix buffer into output buffer 580 for (int i = 0; i < fMixBufferChannelCount; i++) { 581 fResampler[i]->Resample(reinterpret_cast<char *>(fMixBuffer) + i * sizeof(float), 582 fMixBufferChannelCount * sizeof(float), 583 fMixBufferFrameCount, 584 reinterpret_cast<char *>(buf->Data()) + (i * bytes_per_sample(fOutput->MediaOutput().format.u.raw_audio)), 585 bytes_per_frame(fOutput->MediaOutput().format.u.raw_audio), 586 frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio), 587 fOutputGain * fOutput->GetOutputChannelGain(i)); 588 } 589 PRINT(4, "send buffer, inframes %ld, outframes %ld\n", fMixBufferFrameCount, frames_per_buffer(fOutput->MediaOutput().format.u.raw_audio)); 590 591 // fill in the buffer header 592 media_header* hdr = buf->Header(); 593 hdr->type = B_MEDIA_RAW_AUDIO; 594 hdr->size_used = fOutput->MediaOutput().format.u.raw_audio.buffer_size; 595 hdr->time_source = fTimeSource->ID(); 596 hdr->start_time = event_time; 597 598 // swap byte order if necessary 599 fOutput->AdjustByteOrder(buf); 600 601 // send the buffer 602 status_t res = fNode->SendBuffer(buf, fOutput->MediaOutput().destination); 603 if (B_OK != res) { 604 #if DEBUG 605 ERROR("MixerCore: SendBuffer failed for buffer %Ld\n", buffer_num); 606 #else 607 ERROR("MixerCore: SendBuffer failed\n"); 608 #endif 609 buf->Recycle(); 610 } 611 } else { 612 #if DEBUG 613 ERROR("MixerCore: RequestBuffer failed for buffer %Ld\n", buffer_num); 614 #else 615 ERROR("MixerCore: RequestBuffer failed\n"); 616 #endif 617 } 618 619 // make all lists empty 620 for (int i = 0; i < MAX_CHANNEL_TYPES; i++) 621 InputChanInfos[i].MakeEmpty(); 622 for (int i = 0; i < fOutput->GetOutputChannelCount(); i++) 623 MixChanInfos[i].MakeEmpty(); 624 625 schedule_next_event: 626 // schedule next event 627 frame_pos += fMixBufferFrameCount; 628 event_time = time_base + bigtime_t((1000000LL * frame_pos) / fMixBufferFrameRate); 629 Unlock(); 630 #if DEBUG 631 buffer_num++; 632 #endif 633 } 634 } 635