vfs: check userland buffers before reading them.
[haiku.git] / src / apps / mediaplayer / media_node_framework / audio / AudioProducer.cpp
blob036763a0df75a2c38dd0cf22217afa19d62575b5
1 /*
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.
9 */
12 #include "AudioProducer.h"
14 #include <math.h>
15 #include <string.h>
16 #include <stdio.h>
18 #include <BufferGroup.h>
19 #include <Buffer.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
30 #if DEBUG_TO_FILE
31 # include <Entry.h>
32 # include <MediaFormats.h>
33 # include <MediaFile.h>
34 # include <MediaTrack.h>
35 #endif // DEBUG_TO_FILE
38 // debugging
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)
44 #else
45 # define TRACE(x...)
46 # define TRACE_BUFFER(x...)
47 # define ERROR(x...) fprintf(stderr, x)
48 #endif
51 const static bigtime_t kMaxLatency = 150000;
52 // 150 ms is the maximum latency we publish
55 #if DEBUG_TO_FILE
56 static BMediaFile*
57 init_media_file(media_format format, BMediaTrack** _track)
59 static BMediaFile* file = NULL;
60 static BMediaTrack* track = NULL;
61 if (file == NULL) {
62 entry_ref ref;
63 get_ref_for_path("/boot/home/Desktop/test.wav", &ref);
65 media_file_format fileFormat;
66 int32 cookie = 0;
67 while (get_next_file_format(&cookie, &fileFormat) == B_OK) {
68 if (strcmp(fileFormat.short_name, "wav") == 0)
69 break;
71 file = new BMediaFile(&ref, &fileFormat);
73 media_codec_info info;
74 cookie = 0;
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) {
78 break;
82 track = file->CreateTrack(&format, &info);
83 if (track == NULL)
84 printf("failed to create track\n");
86 file->CommitHeader();
88 *_track = track;
89 return track != NULL ? file : NULL;
91 #endif // DEBUG_TO_FILE
94 static bigtime_t
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
109 // into the last one
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++) {
117 outBuffer[k] = 0;
118 for (int32 i = 0; i < bufferCount; i++)
119 outBuffer[k] += buffers[i][k];
120 outBuffer[k] /= bufferCount;
122 // cleanup
123 for (int32 i = 0; i < bufferCount + 1; i++)
124 delete[] buffers[i];
125 return system_time() - startTime;
129 // #pragma mark -
132 AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier,
133 bool lowLatency)
135 BMediaNode(name),
136 BBufferProducer(B_MEDIA_RAW_AUDIO),
137 BMediaEventLooper(),
139 fBufferGroup(NULL),
140 fLatency(0),
141 fInternalLatency(0),
142 fLastLateNotice(0),
143 fNextScheduledBuffer(0),
144 fLowLatency(lowLatency),
145 fOutputEnabled(true),
146 fFramesSent(0),
147 fStartTime(0),
148 fSupplier(supplier),
150 fPeakListener(NULL)
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;
162 #if 0
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);
172 if (!fLowLatency)
173 fPreferredFormat.u.raw_audio.buffer_size *= 3;
174 #else
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;
178 #endif
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);
196 #if DEBUG_TO_FILE
197 BMediaTrack* track;
198 if (BMediaFile* file = init_media_file(fPreferredFormat, &track)) {
199 printf("deleting file...\n");
200 track->Flush();
201 file->ReleaseTrack(track);
202 file->CloseFile();
203 delete file;
205 #endif // DEBUG_TO_FILE
207 // Stop the BMediaEventLooper thread
208 Quit();
209 TRACE("AudioProducer::~AudioProducer() done\n");
213 BMediaAddOn*
214 AudioProducer::AddOn(int32* internalId) const
216 return NULL;
220 status_t
221 AudioProducer::FormatSuggestionRequested(media_type type, int32 quality,
222 media_format* _format)
224 TRACE("%p->AudioProducer::FormatSuggestionRequested()\n", this);
226 if (!_format)
227 return B_BAD_VALUE;
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
233 // is supported
234 if (type != B_MEDIA_UNKNOWN_TYPE && type != B_MEDIA_RAW_AUDIO)
235 return B_MEDIA_BAD_FORMAT;
237 return B_OK;
240 status_t
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;
273 return B_OK;
277 status_t
278 AudioProducer::FormatChangeRequested(const media_source& source,
279 const media_destination& destination, media_format* ioFormat,
280 int32* _deprecated_)
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);
301 status_t
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
308 // them.
309 if (0 == *cookie) {
310 *_output = fOutput;
311 *cookie += 1;
312 return B_OK;
315 return B_BAD_INDEX;
319 status_t
320 AudioProducer::DisposeOutputCookie(int32 cookie)
322 // do nothing because we don't use the cookie for anything special
323 return B_OK;
327 status_t
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)
337 return B_OK;
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;
346 } else {
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;
355 return B_OK;
359 status_t
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();
366 return B_OK;
370 status_t
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);
390 if (ret != B_OK) {
391 TRACE(" -> format error: %s\n", strerror(ret));
392 return 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);
404 TRACE(" -> B_OK\n");
405 return B_OK;
409 void
410 AudioProducer::Connect(status_t error, const media_source& source,
411 const media_destination& destination, const media_format& format,
412 char* _name)
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.
419 if (error != B_OK) {
420 fOutput.destination = media_destination::null;
421 fOutput.format = fPreferredFormat;
422 return;
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
432 if (fSupplier) {
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.
441 media_node_id id;
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);
450 if (!fLowLatency)
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");
474 void
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()).
487 delete fBufferGroup;
488 TRACE("AudioProducer: buffer group deleted\n");
489 fBufferGroup = NULL;
492 TRACE("%p->AudioProducer::Disconnect() done\n", this);
496 void
497 AudioProducer::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
498 bigtime_t performanceTime)
500 TRACE("%p->AudioProducer::LateNoticeReceived(%lld, %lld)\n", this, howMuch,
501 performanceTime);
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)
508 return;
510 fLastLateNotice = fNextScheduledBuffer;
512 if (RunMode() == B_RECORDING) {
513 // ...
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);
522 } else {
523 // Skip one buffer ahead in the audio data.
524 size_t sampleSize
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;
537 void
538 AudioProducer::EnableOutput(const media_source& what, bool enabled,
539 int32* _deprecated_)
541 TRACE("%p->AudioProducer::EnableOutput(%d)\n", this, enabled);
543 if (what == fOutput.source)
544 fOutputEnabled = enabled;
548 status_t
549 AudioProducer::SetPlayRate(int32 numer, int32 denom)
551 return B_ERROR;
555 status_t
556 AudioProducer::HandleMessage(int32 message, const void *data, size_t size)
558 TRACE("%p->AudioProducer::HandleMessage()\n", this);
559 return B_ERROR;
563 void
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);
572 void
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);
585 void
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);
598 Run();
602 void
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);
609 else
610 BBufferProducer::SetRunMode(mode);
614 void
615 AudioProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness,
616 bool realTimeEvent)
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) {
624 fFramesSent = 0;
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");
632 break;
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");
639 break;
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);
653 if (err != B_OK)
654 buffer->Recycle();
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);
669 } else {
670 ERROR("B_HANDLE_BUFFER, but not started!\n");
672 TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER) done\n");
673 break;
675 default:
676 break;
681 void
682 AudioProducer::SetPeakListener(BHandler* handler)
684 fPeakListener = handler;
688 status_t
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);
697 if (ret != B_OK) {
698 TRACE(" _SpecializeFormat(): %s\n", strerror(ret));
699 return ret;
702 ret = BBufferProducer::ProposeFormatChange(format, fOutput.destination);
703 if (ret != B_OK) {
704 TRACE(" ProposeFormatChange(): %s\n", strerror(ret));
705 return ret;
708 ret = BBufferProducer::ChangeFormat(fOutput.source, fOutput.destination,
709 format);
710 if (ret != B_OK) {
711 TRACE(" ChangeFormat(): %s\n", strerror(ret));
712 return ret;
715 return _ChangeFormat(*format);
719 // #pragma mark -
722 status_t
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);
765 if (!fLowLatency)
766 format->u.raw_audio.buffer_size *= 3;
769 return B_OK;
773 status_t
774 AudioProducer::_ChangeFormat(const media_format& format)
776 fOutput.format = format;
778 // notify our audio supplier of the format change
779 if (fSupplier)
780 fSupplier->SetFormat(format);
782 return _AllocateBuffers(format);
786 status_t
787 AudioProducer::_AllocateBuffers(const media_format& format)
789 TRACE("%p->AudioProducer::_AllocateBuffers()\n", this);
791 if (fBufferGroup && fUsingOurBuffers) {
792 delete fBufferGroup;
793 fBufferGroup = NULL;
795 size_t size = format.u.raw_audio.buffer_size;
796 int32 bufferDuration = BufferDuration();
797 int32 count = 0;
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();
809 BBuffer*
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;
818 if (!errorPrinted) {
819 ERROR("AudioProducer::_FillNextBuffer() - no buffer "
820 "(size: %" B_PRIuSIZE ", duration: %" B_PRIiBIGTIME ")\n",
821 fOutput.format.u.raw_audio.buffer_size, BufferDuration());
822 errorPrinted = true;
824 return NULL;
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,
847 endTime) != B_OK) {
848 ERROR("AudioProducer::_FillNextBuffer() - supplier error -> silence\n");
849 memset(buffer->Data(), 0, buffer->SizeUsed());
852 // stamp buffer
853 if (RunMode() == B_RECORDING)
854 header->start_time = eventTime;
855 else
856 header->start_time = fStartTime + startTime;
858 #if DEBUG_TO_FILE
859 BMediaTrack* track;
860 if (init_media_file(fOutput.format, &track) != NULL)
861 track->WriteFrames(buffer->Data(), frameCount);
862 #endif // DEBUG_TO_FILE
864 if (fPeakListener
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;
869 float max[channels];
870 float min[channels];
871 for (int32 i = 0; i < channels; i++) {
872 max[i] = -1.0;
873 min[i] = 1.0;
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])
879 min[k] = *sample;
880 if (*sample > max[k])
881 max[k] = *sample;
882 sample++;
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);
894 if (event != NULL)
895 EventQueue::Default().AddEvent(event);
898 return buffer;