2 * Copyright 2010, Axel Dörfler, axeld@pinc-software.de.
3 * Copyright 2000-2010, Stephan Aßmus <superstippi@gmx.de>,
4 * Copyright 2000-2008, Ingo Weinhold <ingo_weinhold@gmx.de>,
5 * All Rights Reserved. Distributed under the terms of the MIT license.
7 * Copyright (c) 1998-99, Be Incorporated, All Rights Reserved.
8 * Distributed under the terms of the Be Sample Code license.
12 #include "AudioProducer.h"
18 #include <BufferGroup.h>
20 #include <MediaDefs.h>
21 #include <ParameterWeb.h>
22 #include <TimeSource.h>
24 #include "AudioSupplier.h"
25 #include "EventQueue.h"
26 #include "MessageEvent.h"
28 #define DEBUG_TO_FILE 0
32 # include <MediaFormats.h>
33 # include <MediaFile.h>
34 # include <MediaTrack.h>
35 #endif // DEBUG_TO_FILE
39 //#define TRACE_AUDIO_PRODUCER
40 #ifdef TRACE_AUDIO_PRODUCER
41 # define TRACE(x...) printf(x)
42 # define TRACE_BUFFER(x...)
43 # define ERROR(x...) fprintf(stderr, x)
46 # define TRACE_BUFFER(x...)
47 # define ERROR(x...) fprintf(stderr, x)
51 const static bigtime_t kMaxLatency
= 150000;
52 // 150 ms is the maximum latency we publish
57 init_media_file(media_format format
, BMediaTrack
** _track
)
59 static BMediaFile
* file
= NULL
;
60 static BMediaTrack
* track
= NULL
;
63 get_ref_for_path("/boot/home/Desktop/test.wav", &ref
);
65 media_file_format fileFormat
;
67 while (get_next_file_format(&cookie
, &fileFormat
) == B_OK
) {
68 if (strcmp(fileFormat
.short_name
, "wav") == 0)
71 file
= new BMediaFile(&ref
, &fileFormat
);
73 media_codec_info info
;
75 while (get_next_encoder(&cookie
, &info
) == B_OK
) {
76 if (strcmp(info
.short_name
, "raw-audio") == 0
77 || strcmp(info
.short_name
, "pcm") == 0) {
82 track
= file
->CreateTrack(&format
, &info
);
84 printf("failed to create track\n");
89 return track
!= NULL
? file
: NULL
;
91 #endif // DEBUG_TO_FILE
95 estimate_internal_latency(const media_format
& format
)
97 bigtime_t startTime
= system_time();
98 // calculate the number of samples per buffer
99 int32 sampleSize
= format
.u
.raw_audio
.format
100 & media_raw_audio_format::B_AUDIO_SIZE_MASK
;
101 int32 sampleCount
= format
.u
.raw_audio
.buffer_size
/ sampleSize
;
102 // alloc float buffers of this size
103 const int bufferCount
= 10; // number of input buffers
104 float* buffers
[bufferCount
+ 1];
105 for (int32 i
= 0; i
< bufferCount
+ 1; i
++)
106 buffers
[i
] = new float[sampleCount
];
107 float* outBuffer
= buffers
[bufferCount
];
108 // fill all buffers save the last one with arbitrary data and merge them
110 for (int32 i
= 0; i
< bufferCount
; i
++) {
111 for (int32 k
= 0; k
< sampleCount
; k
++) {
112 buffers
[i
][k
] = ((float)i
* (float)k
)
113 / float(bufferCount
* sampleCount
);
116 for (int32 k
= 0; k
< sampleCount
; k
++) {
118 for (int32 i
= 0; i
< bufferCount
; i
++)
119 outBuffer
[k
] += buffers
[i
][k
];
120 outBuffer
[k
] /= bufferCount
;
123 for (int32 i
= 0; i
< bufferCount
+ 1; i
++)
125 return system_time() - startTime
;
132 AudioProducer::AudioProducer(const char* name
, AudioSupplier
* supplier
,
136 BBufferProducer(B_MEDIA_RAW_AUDIO
),
143 fNextScheduledBuffer(0),
144 fLowLatency(lowLatency
),
145 fOutputEnabled(true),
152 TRACE("%p->AudioProducer::AudioProducer(%s, %p, %d)\n", this, name
,
153 supplier
, lowLatency
);
155 // initialize our preferred format object
156 fPreferredFormat
.type
= B_MEDIA_RAW_AUDIO
;
157 fPreferredFormat
.u
.raw_audio
.format
158 = media_raw_audio_format::B_AUDIO_FLOAT
;
159 // = media_raw_audio_format::B_AUDIO_SHORT;
160 fPreferredFormat
.u
.raw_audio
.byte_order
161 = (B_HOST_IS_BENDIAN
) ? B_MEDIA_BIG_ENDIAN
: B_MEDIA_LITTLE_ENDIAN
;
163 fPreferredFormat
.u
.raw_audio
.channel_count
= 2;
164 fPreferredFormat
.u
.raw_audio
.frame_rate
= 44100.0;
166 // NOTE: the (buffer_size * 1000000) needs to be dividable by
167 // fPreferredFormat.u.raw_audio.frame_rate!
168 fPreferredFormat
.u
.raw_audio
.buffer_size
= 441 * 4
169 * (fPreferredFormat
.u
.raw_audio
.format
170 & media_raw_audio_format::B_AUDIO_SIZE_MASK
);
173 fPreferredFormat
.u
.raw_audio
.buffer_size
*= 3;
175 fPreferredFormat
.u
.raw_audio
.channel_count
= 0;
176 fPreferredFormat
.u
.raw_audio
.frame_rate
= 0.0;
177 fPreferredFormat
.u
.raw_audio
.buffer_size
= 0;
180 // we're not connected yet
181 fOutput
.destination
= media_destination::null
;
182 fOutput
.format
= fPreferredFormat
;
184 // init the audio supplier
185 if (fSupplier
!= NULL
) {
186 fSupplier
->SetAudioProducer(this);
187 SetInitialLatency(fSupplier
->InitialLatency());
192 AudioProducer::~AudioProducer()
194 TRACE("%p->AudioProducer::~AudioProducer()\n", this);
198 if (BMediaFile
* file
= init_media_file(fPreferredFormat
, &track
)) {
199 printf("deleting file...\n");
201 file
->ReleaseTrack(track
);
205 #endif // DEBUG_TO_FILE
207 // Stop the BMediaEventLooper thread
209 TRACE("AudioProducer::~AudioProducer() done\n");
214 AudioProducer::AddOn(int32
* internalId
) const
221 AudioProducer::FormatSuggestionRequested(media_type type
, int32 quality
,
222 media_format
* _format
)
224 TRACE("%p->AudioProducer::FormatSuggestionRequested()\n", this);
229 // This is the format we'll be returning (our preferred format)
230 *_format
= fPreferredFormat
;
232 // A wildcard type is okay; we can specialize it, otherwise only raw audio
234 if (type
!= B_MEDIA_UNKNOWN_TYPE
&& type
!= B_MEDIA_RAW_AUDIO
)
235 return B_MEDIA_BAD_FORMAT
;
241 AudioProducer::FormatProposal(const media_source
& output
, media_format
* format
)
243 TRACE("%p->AudioProducer::FormatProposal()\n", this);
245 // is this a proposal for our one output?
246 if (output
!= fOutput
.source
) {
247 TRACE(" -> B_MEDIA_BAD_SOURCE\n");
248 return B_MEDIA_BAD_SOURCE
;
251 // Raw audio or wildcard type, either is okay by us. If the format is
252 // anything else, overwrite it with our preferred format. Also, we only support
253 // floating point audio in the host native byte order at the moment.
254 if ((format
->type
!= B_MEDIA_UNKNOWN_TYPE
255 && format
->type
!= B_MEDIA_RAW_AUDIO
)
256 || (format
->u
.raw_audio
.format
257 != media_raw_audio_format::wildcard
.format
258 && format
->u
.raw_audio
.format
259 != fPreferredFormat
.u
.raw_audio
.format
)
260 || (format
->u
.raw_audio
.byte_order
261 != media_raw_audio_format::wildcard
.byte_order
262 && format
->u
.raw_audio
.byte_order
263 != fPreferredFormat
.u
.raw_audio
.byte_order
)) {
264 TRACE(" -> B_MEDIA_BAD_FORMAT\n");
265 *format
= fPreferredFormat
;
266 return B_MEDIA_BAD_FORMAT
;
269 format
->type
= B_MEDIA_RAW_AUDIO
;
270 format
->u
.raw_audio
.format
= fPreferredFormat
.u
.raw_audio
.format
;
271 format
->u
.raw_audio
.byte_order
= fPreferredFormat
.u
.raw_audio
.byte_order
;
278 AudioProducer::FormatChangeRequested(const media_source
& source
,
279 const media_destination
& destination
, media_format
* ioFormat
,
282 TRACE("%p->AudioProducer::FormatChangeRequested()\n", this);
284 if (destination
!= fOutput
.destination
) {
285 TRACE(" -> B_MEDIA_BAD_DESTINATION\n");
286 return B_MEDIA_BAD_DESTINATION
;
289 if (source
!= fOutput
.source
) {
290 TRACE(" -> B_MEDIA_BAD_SOURCE\n");
291 return B_MEDIA_BAD_SOURCE
;
294 // TODO: Maybe we are supposed to specialize here only and not actually change yet?
295 // status_t ret = _SpecializeFormat(ioFormat);
297 return ChangeFormat(ioFormat
);
302 AudioProducer::GetNextOutput(int32
* cookie
, media_output
* _output
)
304 TRACE("%p->AudioProducer::GetNextOutput(%ld)\n", this, *cookie
);
306 // we have only a single output; if we supported multiple outputs, we'd
307 // iterate over whatever data structure we were using to keep track of
320 AudioProducer::DisposeOutputCookie(int32 cookie
)
322 // do nothing because we don't use the cookie for anything special
328 AudioProducer::SetBufferGroup(const media_source
& forSource
,
329 BBufferGroup
* newGroup
)
331 TRACE("%p->AudioProducer::SetBufferGroup()\n", this);
333 if (forSource
!= fOutput
.source
)
334 return B_MEDIA_BAD_SOURCE
;
336 if (newGroup
== fBufferGroup
)
339 if (fUsingOurBuffers
&& fBufferGroup
)
340 delete fBufferGroup
; // waits for all buffers to recycle
342 if (newGroup
!= NULL
) {
343 // we were given a valid group; just use that one from now on
344 fBufferGroup
= newGroup
;
345 fUsingOurBuffers
= false;
347 // we were passed a NULL group pointer; that means we construct
348 // our own buffer group to use from now on
349 size_t size
= fOutput
.format
.u
.raw_audio
.buffer_size
;
350 int32 count
= int32(fLatency
/ BufferDuration() + 1 + 1);
351 fBufferGroup
= new BBufferGroup(size
, count
);
352 fUsingOurBuffers
= true;
360 AudioProducer::GetLatency(bigtime_t
* _latency
)
362 TRACE("%p->AudioProducer::GetLatency()\n", this);
364 // report our *total* latency: internal plus downstream plus scheduling
365 *_latency
= EventLatency() + SchedulingLatency();
371 AudioProducer::PrepareToConnect(const media_source
& what
,
372 const media_destination
& where
, media_format
* format
,
373 media_source
* _source
, char* _name
)
375 TRACE("%p->AudioProducer::PrepareToConnect()\n", this);
377 // trying to connect something that isn't our source?
378 if (what
!= fOutput
.source
) {
379 TRACE(" -> B_MEDIA_BAD_SOURCE\n");
380 return B_MEDIA_BAD_SOURCE
;
383 // are we already connected?
384 if (fOutput
.destination
!= media_destination::null
) {
385 TRACE(" -> B_MEDIA_ALREADY_CONNECTED\n");
386 return B_MEDIA_ALREADY_CONNECTED
;
389 status_t ret
= _SpecializeFormat(format
);
391 TRACE(" -> format error: %s\n", strerror(ret
));
395 // Now reserve the connection, and return information about it
396 fOutput
.destination
= where
;
397 fOutput
.format
= *format
;
399 if (fSupplier
!= NULL
)
400 fSupplier
->SetFormat(fOutput
.format
);
402 *_source
= fOutput
.source
;
403 strncpy(_name
, fOutput
.name
, B_MEDIA_NAME_LENGTH
);
410 AudioProducer::Connect(status_t error
, const media_source
& source
,
411 const media_destination
& destination
, const media_format
& format
,
414 TRACE("AudioProducer::Connect(%s)\n", strerror(error
));
416 // If something earlier failed, Connect() might still be called, but with
417 // a non-zero error code. When that happens we simply unreserve the
418 // connection and do nothing else.
420 fOutput
.destination
= media_destination::null
;
421 fOutput
.format
= fPreferredFormat
;
425 // Okay, the connection has been confirmed. Record the destination and
426 // format that we agreed on, and report our connection name again.
427 fOutput
.destination
= destination
;
428 fOutput
.format
= format
;
429 strncpy(_name
, fOutput
.name
, B_MEDIA_NAME_LENGTH
);
431 // tell our audio supplier about the format
433 TRACE("AudioProducer::Connect() fSupplier->SetFormat()\n");
434 fSupplier
->SetFormat(fOutput
.format
);
437 TRACE("AudioProducer::Connect() FindLatencyFor()\n");
439 // Now that we're connected, we can determine our downstream latency.
440 // Do so, then make sure we get our events early enough.
442 FindLatencyFor(fOutput
.destination
, &fLatency
, &id
);
444 // Use a dry run to see how long it takes me to fill a buffer of data
445 size_t sampleSize
= fOutput
.format
.u
.raw_audio
.format
446 & media_raw_audio_format::B_AUDIO_SIZE_MASK
;
447 size_t samplesPerBuffer
448 = fOutput
.format
.u
.raw_audio
.buffer_size
/ sampleSize
;
449 fInternalLatency
= estimate_internal_latency(fOutput
.format
);
451 fInternalLatency
*= 32;
452 SetEventLatency(fLatency
+ fInternalLatency
);
454 // reset our buffer duration, etc. to avoid later calculations
455 bigtime_t duration
= bigtime_t(1000000)
456 * samplesPerBuffer
/ bigtime_t(fOutput
.format
.u
.raw_audio
.frame_rate
457 * fOutput
.format
.u
.raw_audio
.channel_count
);
458 TRACE("AudioProducer::Connect() SetBufferDuration(%lld)\n", duration
);
459 SetBufferDuration(duration
);
461 TRACE("AudioProducer::Connect() _AllocateBuffers()\n");
463 // Set up the buffer group for our connection, as long as nobody handed
464 // us a buffer group (via SetBufferGroup()) prior to this. That can
465 // happen, for example, if the consumer calls SetOutputBuffersFor() on
466 // us from within its Connected() method.
467 if (fBufferGroup
== NULL
)
468 _AllocateBuffers(fOutput
.format
);
470 TRACE("AudioProducer::Connect() done\n");
475 AudioProducer::Disconnect(const media_source
& what
,
476 const media_destination
& where
)
478 TRACE("%p->AudioProducer::Disconnect()\n", this);
480 // Make sure that our connection is the one being disconnected
481 if (where
== fOutput
.destination
&& what
== fOutput
.source
) {
482 fOutput
.destination
= media_destination::null
;
483 fOutput
.format
= fPreferredFormat
;
484 TRACE("AudioProducer: deleting buffer group...\n");
485 // Always delete the buffer group, even if it is not ours.
486 // (See BeBook::SetBufferGroup()).
488 TRACE("AudioProducer: buffer group deleted\n");
492 TRACE("%p->AudioProducer::Disconnect() done\n", this);
497 AudioProducer::LateNoticeReceived(const media_source
& what
, bigtime_t howMuch
,
498 bigtime_t performanceTime
)
500 TRACE("%p->AudioProducer::LateNoticeReceived(%lld, %lld)\n", this, howMuch
,
502 // If we're late, we need to catch up. Respond in a manner appropriate
503 // to our current run mode.
504 if (what
== fOutput
.source
) {
505 // Ignore the notices for buffers we already send out (or scheduled
506 // their event) before we processed the last notice
507 if (fLastLateNotice
> performanceTime
)
510 fLastLateNotice
= fNextScheduledBuffer
;
512 if (RunMode() == B_RECORDING
) {
514 } else if (RunMode() == B_INCREASE_LATENCY
) {
515 fInternalLatency
+= howMuch
;
517 // At some point a too large latency can get annoying
518 if (fInternalLatency
> kMaxLatency
)
519 fInternalLatency
= kMaxLatency
;
521 SetEventLatency(fLatency
+ fInternalLatency
);
523 // Skip one buffer ahead in the audio data.
525 = fOutput
.format
.u
.raw_audio
.format
526 & media_raw_audio_format::B_AUDIO_SIZE_MASK
;
527 size_t samplesPerBuffer
528 = fOutput
.format
.u
.raw_audio
.buffer_size
/ sampleSize
;
529 size_t framesPerBuffer
530 = samplesPerBuffer
/ fOutput
.format
.u
.raw_audio
.channel_count
;
531 fFramesSent
+= framesPerBuffer
;
538 AudioProducer::EnableOutput(const media_source
& what
, bool enabled
,
541 TRACE("%p->AudioProducer::EnableOutput(%d)\n", this, enabled
);
543 if (what
== fOutput
.source
)
544 fOutputEnabled
= enabled
;
549 AudioProducer::SetPlayRate(int32 numer
, int32 denom
)
556 AudioProducer::HandleMessage(int32 message
, const void *data
, size_t size
)
558 TRACE("%p->AudioProducer::HandleMessage()\n", this);
564 AudioProducer::AdditionalBufferRequested(const media_source
& source
,
565 media_buffer_id prevBuffer
, bigtime_t prevTime
,
566 const media_seek_tag
*prevTag
)
568 TRACE("%p->AudioProducer::AdditionalBufferRequested()\n", this);
573 AudioProducer::LatencyChanged(const media_source
& source
,
574 const media_destination
& destination
, bigtime_t newLatency
, uint32 flags
)
576 TRACE("%p->AudioProducer::LatencyChanged(%lld)\n", this, newLatency
);
578 if (source
== fOutput
.source
&& destination
== fOutput
.destination
) {
579 fLatency
= newLatency
;
580 SetEventLatency(fLatency
+ fInternalLatency
);
586 AudioProducer::NodeRegistered()
588 TRACE("%p->AudioProducer::NodeRegistered()\n", this);
590 // set up as much information about our output as we can
591 fOutput
.source
.port
= ControlPort();
592 fOutput
.source
.id
= 0;
593 fOutput
.node
= Node();
594 ::strcpy(fOutput
.name
, Name());
596 // Start the BMediaEventLooper thread
597 SetPriority(B_REAL_TIME_PRIORITY
);
603 AudioProducer::SetRunMode(run_mode mode
)
605 TRACE("%p->AudioProducer::SetRunMode()\n", this);
607 if (B_OFFLINE
== mode
)
608 ReportError(B_NODE_FAILED_SET_RUN_MODE
);
610 BBufferProducer::SetRunMode(mode
);
615 AudioProducer::HandleEvent(const media_timed_event
* event
, bigtime_t lateness
,
618 TRACE_BUFFER("%p->AudioProducer::HandleEvent()\n", this);
620 switch (event
->type
) {
621 case BTimedEventQueue::B_START
:
622 TRACE("AudioProducer::HandleEvent(B_START)\n");
623 if (RunState() != B_STARTED
) {
625 fStartTime
= event
->event_time
+ fSupplier
->InitialLatency();
626 media_timed_event
firstBufferEvent(
627 fStartTime
- fSupplier
->InitialLatency(),
628 BTimedEventQueue::B_HANDLE_BUFFER
);
629 EventQueue()->AddEvent(firstBufferEvent
);
631 TRACE("AudioProducer::HandleEvent(B_START) done\n");
634 case BTimedEventQueue::B_STOP
:
635 TRACE("AudioProducer::HandleEvent(B_STOP)\n");
636 EventQueue()->FlushEvents(0, BTimedEventQueue::B_ALWAYS
, true,
637 BTimedEventQueue::B_HANDLE_BUFFER
);
638 TRACE("AudioProducer::HandleEvent(B_STOP) done\n");
641 case BTimedEventQueue::B_HANDLE_BUFFER
:
643 TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER)\n");
644 if (RunState() == BMediaEventLooper::B_STARTED
645 && fOutput
.destination
!= media_destination::null
) {
646 BBuffer
* buffer
= _FillNextBuffer(event
->event_time
);
647 if (buffer
!= NULL
) {
648 status_t err
= B_ERROR
;
649 if (fOutputEnabled
) {
650 err
= SendBuffer(buffer
, fOutput
.source
,
651 fOutput
.destination
);
656 size_t sampleSize
= fOutput
.format
.u
.raw_audio
.format
657 & media_raw_audio_format::B_AUDIO_SIZE_MASK
;
659 size_t nFrames
= fOutput
.format
.u
.raw_audio
.buffer_size
660 / (sampleSize
* fOutput
.format
.u
.raw_audio
.channel_count
);
661 fFramesSent
+= nFrames
;
663 fNextScheduledBuffer
= fStartTime
664 + bigtime_t(double(fFramesSent
) * 1000000.0
665 / double(fOutput
.format
.u
.raw_audio
.frame_rate
));
666 media_timed_event
nextBufferEvent(fNextScheduledBuffer
,
667 BTimedEventQueue::B_HANDLE_BUFFER
);
668 EventQueue()->AddEvent(nextBufferEvent
);
670 ERROR("B_HANDLE_BUFFER, but not started!\n");
672 TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER) done\n");
682 AudioProducer::SetPeakListener(BHandler
* handler
)
684 fPeakListener
= handler
;
689 AudioProducer::ChangeFormat(media_format
* format
)
691 TRACE("AudioProducer::ChangeFormat()\n");
693 format
->u
.raw_audio
.buffer_size
694 = media_raw_audio_format::wildcard
.buffer_size
;
696 status_t ret
= _SpecializeFormat(format
);
698 TRACE(" _SpecializeFormat(): %s\n", strerror(ret
));
702 ret
= BBufferProducer::ProposeFormatChange(format
, fOutput
.destination
);
704 TRACE(" ProposeFormatChange(): %s\n", strerror(ret
));
708 ret
= BBufferProducer::ChangeFormat(fOutput
.source
, fOutput
.destination
,
711 TRACE(" ChangeFormat(): %s\n", strerror(ret
));
715 return _ChangeFormat(*format
);
723 AudioProducer::_SpecializeFormat(media_format
* format
)
725 // the format may not yet be fully specialized (the consumer might have
726 // passed back some wildcards). Finish specializing it now, and return an
727 // error if we don't support the requested format.
728 if (format
->type
!= B_MEDIA_RAW_AUDIO
) {
729 TRACE(" not raw audio\n");
730 return B_MEDIA_BAD_FORMAT
;
731 // TODO: we might want to support different audio formats
732 } else if (format
->u
.raw_audio
.format
733 != fPreferredFormat
.u
.raw_audio
.format
) {
734 TRACE(" format does not match\n");
735 return B_MEDIA_BAD_FORMAT
;
738 if (format
->u
.raw_audio
.channel_count
739 == media_raw_audio_format::wildcard
.channel_count
) {
740 format
->u
.raw_audio
.channel_count
= 2;
741 TRACE(" -> adjusting channel count, it was wildcard\n");
744 if (format
->u
.raw_audio
.frame_rate
745 == media_raw_audio_format::wildcard
.frame_rate
) {
746 format
->u
.raw_audio
.frame_rate
= 44100.0;
747 TRACE(" -> adjusting frame rate, it was wildcard\n");
750 // check the buffer size, which may still be wildcarded
751 if (format
->u
.raw_audio
.buffer_size
752 == media_raw_audio_format::wildcard
.buffer_size
) {
753 // pick something comfortable to suggest
754 TRACE(" -> adjusting buffer size, it was wildcard\n");
756 // NOTE: the (buffer_size * 1000000) needs to be dividable by
757 // format->u.raw_audio.frame_rate! (We assume frame rate is a multiple of
758 // 25, which it usually is.)
759 format
->u
.raw_audio
.buffer_size
760 = uint32(format
->u
.raw_audio
.frame_rate
/ 25.0)
761 * format
->u
.raw_audio
.channel_count
762 * (format
->u
.raw_audio
.format
763 & media_raw_audio_format::B_AUDIO_SIZE_MASK
);
766 format
->u
.raw_audio
.buffer_size
*= 3;
774 AudioProducer::_ChangeFormat(const media_format
& format
)
776 fOutput
.format
= format
;
778 // notify our audio supplier of the format change
780 fSupplier
->SetFormat(format
);
782 return _AllocateBuffers(format
);
787 AudioProducer::_AllocateBuffers(const media_format
& format
)
789 TRACE("%p->AudioProducer::_AllocateBuffers()\n", this);
791 if (fBufferGroup
&& fUsingOurBuffers
) {
795 size_t size
= format
.u
.raw_audio
.buffer_size
;
796 int32 bufferDuration
= BufferDuration();
798 if (bufferDuration
> 0) {
799 count
= (int32
)((fLatency
+ fInternalLatency
)
800 / bufferDuration
+ 2);
803 fBufferGroup
= new BBufferGroup(size
, count
);
804 fUsingOurBuffers
= true;
805 return fBufferGroup
->InitCheck();
810 AudioProducer::_FillNextBuffer(bigtime_t eventTime
)
812 fBufferGroup
->WaitForBuffers();
813 BBuffer
* buffer
= fBufferGroup
->RequestBuffer(
814 fOutput
.format
.u
.raw_audio
.buffer_size
, BufferDuration());
816 if (buffer
== NULL
) {
817 static bool errorPrinted
= false;
819 ERROR("AudioProducer::_FillNextBuffer() - no buffer "
820 "(size: %" B_PRIuSIZE
", duration: %" B_PRIiBIGTIME
")\n",
821 fOutput
.format
.u
.raw_audio
.buffer_size
, BufferDuration());
827 size_t sampleSize
= fOutput
.format
.u
.raw_audio
.format
828 & media_raw_audio_format::B_AUDIO_SIZE_MASK
;
829 size_t numSamples
= fOutput
.format
.u
.raw_audio
.buffer_size
/ sampleSize
;
830 // number of sample in the buffer
832 // fill in the buffer header
833 media_header
* header
= buffer
->Header();
834 header
->type
= B_MEDIA_RAW_AUDIO
;
835 header
->time_source
= TimeSource()->ID();
836 buffer
->SetSizeUsed(fOutput
.format
.u
.raw_audio
.buffer_size
);
838 // fill in data from audio supplier
839 int64 frameCount
= numSamples
/ fOutput
.format
.u
.raw_audio
.channel_count
;
840 bigtime_t startTime
= bigtime_t(double(fFramesSent
)
841 * 1000000.0 / fOutput
.format
.u
.raw_audio
.frame_rate
);
842 bigtime_t endTime
= bigtime_t(double(fFramesSent
+ frameCount
)
843 * 1000000.0 / fOutput
.format
.u
.raw_audio
.frame_rate
);
845 if (fSupplier
== NULL
|| fSupplier
->InitCheck() != B_OK
846 || fSupplier
->GetFrames(buffer
->Data(), frameCount
, startTime
,
848 ERROR("AudioProducer::_FillNextBuffer() - supplier error -> silence\n");
849 memset(buffer
->Data(), 0, buffer
->SizeUsed());
853 if (RunMode() == B_RECORDING
)
854 header
->start_time
= eventTime
;
856 header
->start_time
= fStartTime
+ startTime
;
860 if (init_media_file(fOutput
.format
, &track
) != NULL
)
861 track
->WriteFrames(buffer
->Data(), frameCount
);
862 #endif // DEBUG_TO_FILE
865 && fOutput
.format
.u
.raw_audio
.format
866 == media_raw_audio_format::B_AUDIO_FLOAT
) {
867 // TODO: extend the peak notifier for other sample formats
868 int32 channels
= fOutput
.format
.u
.raw_audio
.channel_count
;
871 for (int32 i
= 0; i
< channels
; i
++) {
875 float* sample
= (float*)buffer
->Data();
876 for (uint32 i
= 0; i
< frameCount
; i
++) {
877 for (int32 k
= 0; k
< channels
; k
++) {
878 if (*sample
< min
[k
])
880 if (*sample
> max
[k
])
885 BMessage
message(MSG_PEAK_NOTIFICATION
);
886 for (int32 i
= 0; i
< channels
; i
++) {
887 float maxAbs
= max_c(fabs(min
[i
]), fabs(max
[i
]));
888 message
.AddFloat("max", maxAbs
);
890 bigtime_t realTime
= TimeSource()->RealTimeFor(
891 fStartTime
+ startTime
, 0);
892 MessageEvent
* event
= new (std::nothrow
) MessageEvent(realTime
,
893 fPeakListener
, message
);
895 EventQueue::Default().AddEvent(event
);