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