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