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 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