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