1 /* Copyright (c) 1998-99, Be Incorporated, All Rights Reserved. 2 * Distributed under the terms of the Be Sample Code license. 3 * 4 * Copyright (c) 2000-2008, Ingo Weinhold <ingo_weinhold@gmx.de>, 5 * Copyright (c) 2000-2008, Stephan Aßmus <superstippi@gmx.de>, 6 * All Rights Reserved. Distributed under the terms of the MIT license. 7 */ 8 #include "AudioProducer.h" 9 10 #include <math.h> 11 #include <string.h> 12 #include <stdio.h> 13 14 #include <BufferGroup.h> 15 #include <Buffer.h> 16 #include <MediaDefs.h> 17 #include <ParameterWeb.h> 18 #include <TimeSource.h> 19 20 #include "AudioSupplier.h" 21 #include "EventQueue.h" 22 #include "MessageEvent.h" 23 24 #define DEBUG_TO_FILE 0 25 26 #if DEBUG_TO_FILE 27 # include <Entry.h> 28 # include <MediaFormats.h> 29 # include <MediaFile.h> 30 # include <MediaTrack.h> 31 #endif // DEBUG_TO_FILE 32 33 34 // debugging 35 //#define TRACE_AUDIO_PRODUCER 36 #ifdef TRACE_AUDIO_PRODUCER 37 # define TRACE(x...) printf(x) 38 # define ERROR(x...) fprintf(stderr, x) 39 #else 40 # define TRACE(x...) 41 # define ERROR(x...) fprintf(stderr, x) 42 #endif 43 44 45 #if DEBUG_TO_FILE 46 static BMediaFile* 47 init_media_file(media_format format, BMediaTrack** _track) 48 { 49 static BMediaFile* file = NULL; 50 static BMediaTrack* track = NULL; 51 if (file == NULL) { 52 entry_ref ref; 53 get_ref_for_path("/boot/home/Desktop/test.wav", &ref); 54 55 media_file_format fileFormat; 56 int32 cookie = 0; 57 while (get_next_file_format(&cookie, &fileFormat) == B_OK) { 58 if (strcmp(fileFormat.short_name, "wav") == 0) { 59 break; 60 } 61 } 62 file = new BMediaFile(&ref, &fileFormat); 63 64 media_codec_info info; 65 cookie = 0; 66 while (get_next_encoder(&cookie, &info) == B_OK) { 67 if (strcmp(info.short_name, "raw-audio") == 0) 68 break; 69 } 70 71 track = file->CreateTrack(&format, &info); 72 if (!track) 73 printf("failed to create track\n"); 74 75 file->CommitHeader(); 76 } 77 *_track = track; 78 return track != NULL ? file : NULL; 79 } 80 #endif // DEBUG_TO_FILE 81 82 83 84 // constructor 85 AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier, 86 bool lowLatency) 87 : BMediaNode(name), 88 BBufferProducer(B_MEDIA_RAW_AUDIO), 89 BMediaEventLooper(), 90 91 fBufferGroup(NULL), 92 fLatency(0), 93 fInternalLatency(0), 94 fLowLatency(lowLatency), 95 fOutputEnabled(true), 96 fFramesSent(0), 97 fStartTime(0), 98 fSupplier(supplier), 99 fRunning(false), 100 101 fPeakListener(NULL) 102 { 103 TRACE("%p->AudioProducer::AudioProducer(%s, %p, %d)\n", this, name, 104 supplier, lowLatency); 105 106 // initialize our preferred format object 107 fPreferredFormat.type = B_MEDIA_RAW_AUDIO; 108 fPreferredFormat.u.raw_audio.format 109 = media_raw_audio_format::B_AUDIO_FLOAT; 110 // = media_raw_audio_format::B_AUDIO_SHORT; 111 fPreferredFormat.u.raw_audio.channel_count = 2; 112 fPreferredFormat.u.raw_audio.frame_rate = 44100.0; 113 fPreferredFormat.u.raw_audio.byte_order 114 = (B_HOST_IS_BENDIAN) ? B_MEDIA_BIG_ENDIAN : B_MEDIA_LITTLE_ENDIAN; 115 116 // NOTE: the (buffer_size * 1000000) needs to be dividable by 117 // fPreferredFormat.u.raw_audio.frame_rate! 118 fPreferredFormat.u.raw_audio.buffer_size = 441 * 2 119 * (fPreferredFormat.u.raw_audio.format 120 & media_raw_audio_format::B_AUDIO_SIZE_MASK); 121 122 if (!fLowLatency) 123 fPreferredFormat.u.raw_audio.buffer_size *= 6; 124 125 // we're not connected yet 126 fOutput.destination = media_destination::null; 127 fOutput.format = fPreferredFormat; 128 // init the audio supplier 129 if (fSupplier) { 130 fSupplier->SetAudioProducer(this); 131 } 132 } 133 134 135 AudioProducer::~AudioProducer() 136 { 137 TRACE("%p->AudioProducer::~AudioProducer()\n", this); 138 139 #if DEBUG_TO_FILE 140 BMediaTrack* track; 141 if (BMediaFile* file = init_media_file(fPreferredFormat, &track)) { 142 printf("deleting file...\n"); 143 track->Flush(); 144 file->ReleaseTrack(track); 145 file->CloseFile(); 146 delete file; 147 } 148 #endif // DEBUG_TO_FILE 149 150 // Stop the BMediaEventLooper thread 151 Quit(); 152 TRACE("AudioProducer::~AudioProducer() done\n"); 153 } 154 155 156 BMediaAddOn* 157 AudioProducer::AddOn(int32* internalId) const 158 { 159 return NULL; 160 } 161 162 163 status_t 164 AudioProducer::FormatSuggestionRequested(media_type type, int32 quality, 165 media_format* _format) 166 { 167 TRACE("%p->AudioProducer::FormatSuggestionRequested()\n", this); 168 169 if (!_format) 170 return B_BAD_VALUE; 171 172 // this is the format we'll be returning (our preferred format) 173 *_format = fPreferredFormat; 174 175 // a wildcard type is okay; we can specialize it 176 if (type == B_MEDIA_UNKNOWN_TYPE) 177 type = B_MEDIA_RAW_AUDIO; 178 179 // we only support raw audio 180 if (type != B_MEDIA_RAW_AUDIO) 181 return B_MEDIA_BAD_FORMAT; 182 183 return B_OK; 184 } 185 186 status_t 187 AudioProducer::FormatProposal(const media_source& output, media_format* format) 188 { 189 TRACE("%p->AudioProducer::FormatProposal()\n", this); 190 191 // is this a proposal for our one output? 192 if (output != fOutput.source) { 193 TRACE(" -> B_MEDIA_BAD_SOURCE\n"); 194 return B_MEDIA_BAD_SOURCE; 195 } 196 197 // TODO: we might want to support different audio formats 198 // we only support floating-point raw audio, so we always return that, but 199 // we supply an error code depending on whether we found the proposal 200 // acceptable. 201 media_type requestedType = format->type; 202 *format = fPreferredFormat; 203 204 // raw audio or wildcard type, either is okay by us 205 if (requestedType != B_MEDIA_UNKNOWN_TYPE 206 && requestedType != B_MEDIA_RAW_AUDIO) { 207 TRACE(" -> B_MEDIA_BAD_FORMAT\n"); 208 return B_MEDIA_BAD_FORMAT; 209 } 210 211 return B_OK; 212 } 213 214 215 status_t 216 AudioProducer::FormatChangeRequested(const media_source& source, 217 const media_destination& destination, media_format* ioFormat, 218 int32* _deprecated_) 219 { 220 TRACE("%p->AudioProducer::FormatChangeRequested()\n", this); 221 222 if (destination != fOutput.destination) { 223 TRACE(" -> B_MEDIA_BAD_DESTINATION\n"); 224 return B_MEDIA_BAD_DESTINATION; 225 } 226 227 if (source != fOutput.source) { 228 TRACE(" -> B_MEDIA_BAD_SOURCE\n"); 229 return B_MEDIA_BAD_SOURCE; 230 } 231 232 fOutput.format = *ioFormat; 233 234 // notify our audio supplier of the format change 235 if (fSupplier) 236 fSupplier->SetFormat(fOutput.format); 237 238 return _AllocateBuffers(ioFormat); 239 } 240 241 242 status_t 243 AudioProducer::GetNextOutput(int32* cookie, media_output* _output) 244 { 245 TRACE("%p->AudioProducer::GetNextOutput(%ld)\n", this, *cookie); 246 247 // we have only a single output; if we supported multiple outputs, we'd 248 // iterate over whatever data structure we were using to keep track of 249 // them. 250 if (0 == *cookie) { 251 *_output = fOutput; 252 *cookie += 1; 253 return B_OK; 254 } 255 256 return B_BAD_INDEX; 257 } 258 259 260 status_t 261 AudioProducer::DisposeOutputCookie(int32 cookie) 262 { 263 // do nothing because we don't use the cookie for anything special 264 return B_OK; 265 } 266 267 268 status_t 269 AudioProducer::SetBufferGroup(const media_source& forSource, 270 BBufferGroup* newGroup) 271 { 272 TRACE("%p->AudioProducer::SetBufferGroup()\n", this); 273 274 if (forSource != fOutput.source) 275 return B_MEDIA_BAD_SOURCE; 276 277 if (newGroup == fBufferGroup) 278 return B_OK; 279 280 if (fUsingOurBuffers && fBufferGroup) 281 delete fBufferGroup; // waits for all buffers to recycle 282 283 if (newGroup != NULL) { 284 // we were given a valid group; just use that one from now on 285 fBufferGroup = newGroup; 286 fUsingOurBuffers = false; 287 } else { 288 // we were passed a NULL group pointer; that means we construct 289 // our own buffer group to use from now on 290 size_t size = fOutput.format.u.raw_audio.buffer_size; 291 int32 count = int32(fLatency / BufferDuration() + 1 + 1); 292 fBufferGroup = new BBufferGroup(size, count); 293 fUsingOurBuffers = true; 294 } 295 296 return B_OK; 297 } 298 299 300 status_t 301 AudioProducer::GetLatency(bigtime_t* _latency) 302 { 303 TRACE("%p->AudioProducer::GetLatency()\n", this); 304 305 // report our *total* latency: internal plus downstream plus scheduling 306 *_latency = EventLatency() + SchedulingLatency(); 307 return B_OK; 308 } 309 310 311 status_t 312 AudioProducer::PrepareToConnect(const media_source& what, 313 const media_destination& where, media_format* format, 314 media_source* _source, char* _name) 315 { 316 TRACE("%p->AudioProducer::PrepareToConnect()\n", this); 317 318 // trying to connect something that isn't our source? 319 if (what != fOutput.source) { 320 TRACE(" -> B_MEDIA_BAD_SOURCE\n"); 321 return B_MEDIA_BAD_SOURCE; 322 } 323 324 // are we already connected? 325 if (fOutput.destination != media_destination::null) { 326 TRACE(" -> B_MEDIA_ALREADY_CONNECTED\n"); 327 return B_MEDIA_ALREADY_CONNECTED; 328 } 329 330 // the format may not yet be fully specialized (the consumer might have 331 // passed back some wildcards). Finish specializing it now, and return an 332 // error if we don't support the requested format. 333 if (format->type != B_MEDIA_RAW_AUDIO) { 334 TRACE(" -> B_MEDIA_BAD_FORMAT\n"); 335 return B_MEDIA_BAD_FORMAT; 336 // TODO: we might want to support different audio formats 337 } else if (format->u.raw_audio.format 338 != fPreferredFormat.u.raw_audio.format) { 339 TRACE(" -> B_MEDIA_BAD_FORMAT\n"); 340 return B_MEDIA_BAD_FORMAT; 341 } 342 343 // !!! validate all other fields except for buffer_size here, because the 344 // consumer might have supplied different values from AcceptFormat()? 345 346 // check the buffer size, which may still be wildcarded 347 if (format->u.raw_audio.buffer_size 348 == media_raw_audio_format::wildcard.buffer_size) { 349 // pick something comfortable to suggest 350 // NOTE: the (buffer_size * 1000000) needs to be dividable by 351 // fPreferredFormat.u.raw_audio.frame_rate! 352 // TODO: this needs to depend on the other parameters 353 // (but it doesn't matter sincer the AudioProducer is not 354 // currently used like that) 355 TRACE(" -> adjusting buffer size, it was wildcard\n"); 356 format->u.raw_audio.buffer_size = 441 * 2 * sizeof(float); 357 } 358 359 // Now reserve the connection, and return information about it 360 fOutput.destination = where; 361 fOutput.format = *format; 362 *_source = fOutput.source; 363 strncpy(_name, fOutput.name, B_MEDIA_NAME_LENGTH); 364 TRACE(" -> B_OK\n"); 365 return B_OK; 366 } 367 368 369 static bigtime_t 370 estimate_internal_latency(const media_format& format) 371 { 372 bigtime_t startTime = system_time(); 373 // calculate the number of samples per buffer 374 int32 sampleSize = format.u.raw_audio.format 375 & media_raw_audio_format::B_AUDIO_SIZE_MASK; 376 int32 sampleCount = format.u.raw_audio.buffer_size / sampleSize; 377 // alloc float buffers of this size 378 const int bufferCount = 10; // number of input buffers 379 float* buffers[bufferCount + 1]; 380 for (int32 i = 0; i < bufferCount + 1; i++) 381 buffers[i] = new float[sampleCount]; 382 float* outBuffer = buffers[bufferCount]; 383 // fill all buffers save the last one with arbitrary data and merge them 384 // into the last one 385 for (int32 i = 0; i < bufferCount; i++) { 386 for (int32 k = 0; k < sampleCount; k++) { 387 buffers[i][k] = ((float)i * (float)k) 388 / float(bufferCount * sampleCount); 389 } 390 } 391 for (int32 k = 0; k < sampleCount; k++) { 392 outBuffer[k] = 0; 393 for (int32 i = 0; i < bufferCount; i++) 394 outBuffer[k] += buffers[i][k]; 395 outBuffer[k] /= bufferCount; 396 } 397 // cleanup 398 for (int32 i = 0; i < bufferCount + 1; i++) 399 delete[] buffers[i]; 400 return system_time() - startTime; 401 } 402 403 404 void 405 AudioProducer::Connect(status_t error, const media_source& source, 406 const media_destination& destination, const media_format& format, 407 char* _name) 408 { 409 TRACE("AudioProducer::Connect(%s)\n", strerror(error)); 410 411 // If something earlier failed, Connect() might still be called, but with 412 // a non-zero error code. When that happens we simply unreserve the 413 // connection and do nothing else. 414 if (error != B_OK) { 415 fOutput.destination = media_destination::null; 416 fOutput.format = fPreferredFormat; 417 return; 418 } 419 420 // Okay, the connection has been confirmed. Record the destination and 421 // format that we agreed on, and report our connection name again. 422 fOutput.destination = destination; 423 fOutput.format = format; 424 strncpy(_name, fOutput.name, B_MEDIA_NAME_LENGTH); 425 426 // tell our audio supplier about the format 427 if (fSupplier) { 428 TRACE("AudioProducer::Connect() fSupplier->SetFormat()\n"); 429 fSupplier->SetFormat(fOutput.format); 430 } 431 432 TRACE("AudioProducer::Connect() FindLatencyFor()\n"); 433 434 // Now that we're connected, we can determine our downstream latency. 435 // Do so, then make sure we get our events early enough. 436 media_node_id id; 437 FindLatencyFor(fOutput.destination, &fLatency, &id); 438 439 // Use a dry run to see how long it takes me to fill a buffer of data 440 size_t sampleSize = fOutput.format.u.raw_audio.format 441 & media_raw_audio_format::B_AUDIO_SIZE_MASK; 442 size_t samplesPerBuffer 443 = fOutput.format.u.raw_audio.buffer_size / sampleSize; 444 fInternalLatency = estimate_internal_latency(fOutput.format); 445 if (!fLowLatency) 446 fInternalLatency *= 32; 447 SetEventLatency(fLatency + fInternalLatency); 448 449 // reset our buffer duration, etc. to avoid later calculations 450 bigtime_t duration = bigtime_t(1000000) 451 * samplesPerBuffer / bigtime_t(fOutput.format.u.raw_audio.frame_rate 452 * fOutput.format.u.raw_audio.channel_count); 453 TRACE("AudioProducer::Connect() SetBufferDuration(%lld)\n", duration); 454 SetBufferDuration(duration); 455 456 TRACE("AudioProducer::Connect() _AllocateBuffers()\n"); 457 458 // Set up the buffer group for our connection, as long as nobody handed 459 // us a buffer group (via SetBufferGroup()) prior to this. That can 460 // happen, for example, if the consumer calls SetOutputBuffersFor() on 461 // us from within its Connected() method. 462 if (!fBufferGroup) 463 _AllocateBuffers(&fOutput.format); 464 465 TRACE("AudioProducer::Connect() done\n"); 466 } 467 468 469 void 470 AudioProducer::Disconnect(const media_source& what, 471 const media_destination& where) 472 { 473 TRACE("%p->AudioProducer::Disconnect()\n", this); 474 475 // Make sure that our connection is the one being disconnected 476 if ((where == fOutput.destination) && (what == fOutput.source)) { 477 fOutput.destination = media_destination::null; 478 fOutput.format = fPreferredFormat; 479 TRACE("AudioProducer: deleting buffer group...\n"); 480 // Always delete the buffer group, even if it is not ours. 481 // (See BeBook::SetBufferGroup()). 482 delete fBufferGroup; 483 TRACE("AudioProducer: buffer group deleted\n"); 484 fBufferGroup = NULL; 485 } 486 487 TRACE("%p->AudioProducer::Disconnect() done\n", this); 488 } 489 490 491 void 492 AudioProducer::LateNoticeReceived(const media_source& what, bigtime_t howMuch, 493 bigtime_t performanceTime) 494 { 495 ERROR("%p->AudioProducer::LateNoticeReceived(%lld, %lld)\n", this, howMuch, 496 performanceTime); 497 // If we're late, we need to catch up. Respond in a manner appropriate 498 // to our current run mode. 499 if (what == fOutput.source) { 500 if (RunMode() == B_RECORDING) { 501 // ... 502 } else if (RunMode() == B_INCREASE_LATENCY) { 503 fInternalLatency += howMuch; 504 SetEventLatency(fLatency + fInternalLatency); 505 } else { 506 size_t sampleSize 507 = fOutput.format.u.raw_audio.format 508 & media_raw_audio_format::B_AUDIO_SIZE_MASK; 509 size_t nSamples 510 = fOutput.format.u.raw_audio.buffer_size / sampleSize; 511 fFramesSent += nSamples; 512 } 513 } 514 } 515 516 517 void 518 AudioProducer::EnableOutput(const media_source& what, bool enabled, 519 int32* _deprecated_) 520 { 521 TRACE("%p->AudioProducer::EnableOutput(%d)\n", this, enabled); 522 523 if (what == fOutput.source) 524 fOutputEnabled = enabled; 525 } 526 527 528 status_t 529 AudioProducer::SetPlayRate(int32 numer, int32 denom) 530 { 531 return B_ERROR; 532 } 533 534 535 status_t 536 AudioProducer::HandleMessage(int32 message, const void *data, size_t size) 537 { 538 TRACE("%p->AudioProducer::HandleMessage()\n", this); 539 return B_ERROR; 540 } 541 542 543 void 544 AudioProducer::AdditionalBufferRequested(const media_source& source, 545 media_buffer_id prevBuffer, bigtime_t prevTime, 546 const media_seek_tag *prevTag) 547 { 548 TRACE("%p->AudioProducer::AdditionalBufferRequested()\n", this); 549 } 550 551 552 void 553 AudioProducer::LatencyChanged(const media_source& source, 554 const media_destination& destination, bigtime_t newLatency, uint32 flags) 555 { 556 TRACE("%p->AudioProducer::LatencyChanged(%lld)\n", this, newLatency); 557 558 if ((source == fOutput.source) && (destination == fOutput.destination)) { 559 fLatency = newLatency; 560 SetEventLatency(fLatency + fInternalLatency); 561 } 562 } 563 564 565 void 566 AudioProducer::NodeRegistered() 567 { 568 TRACE("%p->AudioProducer::NodeRegistered()\n", this); 569 570 // Start the BMediaEventLooper thread 571 SetPriority(B_REAL_TIME_PRIORITY); 572 Run(); 573 574 // set up as much information about our output as we can 575 fOutput.source.port = ControlPort(); 576 fOutput.source.id = 0; 577 fOutput.node = Node(); 578 ::strcpy(fOutput.name, "MediaPlayer Sound Output"); 579 } 580 581 582 void 583 AudioProducer::SetRunMode(run_mode mode) 584 { 585 TRACE("%p->AudioProducer::SetRunMode()\n", this); 586 587 if (B_OFFLINE == mode) 588 ReportError(B_NODE_FAILED_SET_RUN_MODE); 589 else 590 BBufferProducer::SetRunMode(mode); 591 } 592 593 594 void 595 AudioProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness, 596 bool realTimeEvent) 597 { 598 TRACE("%p->AudioProducer::HandleEvent()\n", this); 599 600 switch (event->type) { 601 case BTimedEventQueue::B_START: 602 TRACE("AudioProducer::HandleEvent(B_START)\n"); 603 if (RunState() != B_STARTED) { 604 fFramesSent = 0; 605 fStartTime = event->event_time; 606 printf("B_START: start time: %lld\n", fStartTime); 607 media_timed_event firstBufferEvent(fStartTime, 608 BTimedEventQueue::B_HANDLE_BUFFER); 609 EventQueue()->AddEvent(firstBufferEvent); 610 } 611 TRACE("AudioProducer::HandleEvent(B_START) done\n"); 612 break; 613 614 case BTimedEventQueue::B_STOP: 615 TRACE("AudioProducer::HandleEvent(B_STOP)\n"); 616 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS, true, 617 BTimedEventQueue::B_HANDLE_BUFFER); 618 TRACE("AudioProducer::HandleEvent(B_STOP) done\n"); 619 break; 620 621 case BTimedEventQueue::B_HANDLE_BUFFER: { 622 TRACE("AudioProducer::HandleEvent(B_HANDLE_BUFFER)\n"); 623 if ((RunState() == BMediaEventLooper::B_STARTED) 624 && (fOutput.destination != media_destination::null)) { 625 BBuffer* buffer = _FillNextBuffer(event->event_time); 626 if (buffer) { 627 status_t err = B_ERROR; 628 if (fOutputEnabled) 629 err = SendBuffer(buffer, fOutput.destination); 630 if (err) 631 buffer->Recycle(); 632 } 633 size_t sampleSize 634 = fOutput.format.u.raw_audio.format 635 & media_raw_audio_format::B_AUDIO_SIZE_MASK; 636 637 size_t nFrames = fOutput.format.u.raw_audio.buffer_size 638 / (sampleSize * fOutput.format.u.raw_audio.channel_count); 639 fFramesSent += nFrames; 640 641 bigtime_t nextEvent = fStartTime 642 + bigtime_t(double(fFramesSent) * 1000000.0 643 / double(fOutput.format.u.raw_audio.frame_rate)); 644 media_timed_event nextBufferEvent(nextEvent, 645 BTimedEventQueue::B_HANDLE_BUFFER); 646 EventQueue()->AddEvent(nextBufferEvent); 647 } else { 648 fprintf(stderr, "B_HANDLE_BUFFER, but not started!\n"); 649 } 650 TRACE("AudioProducer::HandleEvent(B_HANDLE_BUFFER) done\n"); 651 break; 652 } 653 default: 654 break; 655 } 656 } 657 658 659 void 660 AudioProducer::SetRunning(bool running) 661 { 662 TRACE("%p->AudioProducer::SetRunning(%d)\n", this, running); 663 664 fRunning = running; 665 } 666 667 668 void 669 AudioProducer::SetPeakListener(BHandler* handler) 670 { 671 fPeakListener = handler; 672 } 673 674 675 // #pragma mark - 676 677 678 status_t 679 AudioProducer::_AllocateBuffers(media_format* format) 680 { 681 TRACE("%p->AudioProducer::_AllocateBuffers()\n", this); 682 683 if (fBufferGroup && fUsingOurBuffers) { 684 delete fBufferGroup; 685 fBufferGroup = NULL; 686 } 687 size_t size = format->u.raw_audio.buffer_size; 688 int32 bufferDuration = BufferDuration(); 689 int32 count = 0; 690 if (bufferDuration > 0) { 691 count = (int32)((fLatency + fInternalLatency) 692 / bufferDuration + 2); 693 } 694 695 fBufferGroup = new BBufferGroup(size, count); 696 fUsingOurBuffers = true; 697 return fBufferGroup->InitCheck(); 698 } 699 700 701 BBuffer* 702 AudioProducer::_FillNextBuffer(bigtime_t eventTime) 703 { 704 BBuffer* buffer = fBufferGroup->RequestBuffer( 705 fOutput.format.u.raw_audio.buffer_size, BufferDuration()); 706 707 if (!buffer) { 708 ERROR("AudioProducer::_FillNextBuffer() - no buffer\n"); 709 return NULL; 710 } 711 712 size_t sampleSize = fOutput.format.u.raw_audio.format 713 & media_raw_audio_format::B_AUDIO_SIZE_MASK; 714 size_t numSamples = fOutput.format.u.raw_audio.buffer_size / sampleSize; 715 // number of sample in the buffer 716 717 // fill in the buffer header 718 media_header* hdr = buffer->Header(); 719 hdr->type = B_MEDIA_RAW_AUDIO; 720 hdr->time_source = TimeSource()->ID(); 721 buffer->SetSizeUsed(fOutput.format.u.raw_audio.buffer_size); 722 723 bigtime_t performanceTime = bigtime_t(double(fFramesSent) 724 * 1000000.0 / double(fOutput.format.u.raw_audio.frame_rate)); 725 726 // fill in data from audio supplier 727 int64 frameCount = numSamples / fOutput.format.u.raw_audio.channel_count; 728 bigtime_t startTime = performanceTime; 729 bigtime_t endTime = bigtime_t(double(fFramesSent + frameCount) 730 * 1000000.0 / fOutput.format.u.raw_audio.frame_rate); 731 732 if (!fSupplier || fSupplier->InitCheck() != B_OK 733 || fSupplier->GetFrames(buffer->Data(), frameCount, startTime, 734 endTime) != B_OK) { 735 ERROR("AudioProducer::_FillNextBuffer() - supplier error -> silence\n"); 736 memset(buffer->Data(), 0, buffer->SizeUsed()); 737 } 738 739 // stamp buffer 740 if (RunMode() == B_RECORDING) { 741 hdr->start_time = eventTime; 742 } else { 743 hdr->start_time = fStartTime + performanceTime; 744 } 745 746 #if DEBUG_TO_FILE 747 BMediaTrack* track; 748 if (BMediaFile* file = init_media_file(fOutput.format, &track)) { 749 track->WriteFrames(buffer->Data(), frameCount); 750 } 751 #endif // DEBUG_TO_FILE 752 753 if (fPeakListener 754 && fOutput.format.u.raw_audio.format 755 == media_raw_audio_format::B_AUDIO_FLOAT) { 756 // TODO: extend the peak notifier for other sample formats 757 int32 channels = fOutput.format.u.raw_audio.channel_count; 758 float max[channels]; 759 float min[channels]; 760 for (int32 i = 0; i < channels; i++) { 761 max[i] = -1.0; 762 min[i] = 1.0; 763 } 764 float* sample = (float*)buffer->Data(); 765 for (uint32 i = 0; i < frameCount; i++) { 766 for (int32 k = 0; k < channels; k++) { 767 if (*sample < min[k]) 768 min[k] = *sample; 769 if (*sample > max[k]) 770 max[k] = *sample; 771 sample++; 772 } 773 } 774 BMessage message(MSG_PEAK_NOTIFICATION); 775 for (int32 i = 0; i < channels; i++) { 776 float maxAbs = max_c(fabs(min[i]), fabs(max[i])); 777 message.AddFloat("max", maxAbs); 778 } 779 bigtime_t realTime = TimeSource()->RealTimeFor( 780 fStartTime + performanceTime, 0); 781 MessageEvent* event = new (std::nothrow) MessageEvent(realTime, 782 fPeakListener, message); 783 if (event != NULL) 784 EventQueue::Default().AddEvent(event); 785 } 786 787 return buffer; 788 } 789 790