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.
6 *
7 * Copyright (c) 1998-99, Be Incorporated, All Rights Reserved.
8 * Distributed under the terms of the Be Sample Code license.
9 */
10
11
12 #include "AudioProducer.h"
13
14 #include <math.h>
15 #include <string.h>
16 #include <stdio.h>
17
18 #include <BufferGroup.h>
19 #include <Buffer.h>
20 #include <MediaDefs.h>
21 #include <ParameterWeb.h>
22 #include <TimeSource.h>
23
24 #include "AudioSupplier.h"
25 #include "EventQueue.h"
26 #include "MessageEvent.h"
27
28 #define DEBUG_TO_FILE 0
29
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
36
37
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
49
50
51 const static bigtime_t kMaxLatency = 150000;
52 // 150 ms is the maximum latency we publish
53
54
55 #if DEBUG_TO_FILE
56 static BMediaFile*
init_media_file(media_format format,BMediaTrack ** _track)57 init_media_file(media_format format, BMediaTrack** _track)
58 {
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);
64
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;
70 }
71 file = new BMediaFile(&ref, &fileFormat);
72
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;
79 }
80 }
81
82 track = file->CreateTrack(&format, &info);
83 if (track == NULL)
84 printf("failed to create track\n");
85
86 file->CommitHeader();
87 }
88 *_track = track;
89 return track != NULL ? file : NULL;
90 }
91 #endif // DEBUG_TO_FILE
92
93
94 static bigtime_t
estimate_internal_latency(const media_format & format)95 estimate_internal_latency(const media_format& format)
96 {
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);
114 }
115 }
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;
121 }
122 // cleanup
123 for (int32 i = 0; i < bufferCount + 1; i++)
124 delete[] buffers[i];
125 return system_time() - startTime;
126 }
127
128
129 // #pragma mark -
130
131
AudioProducer(const char * name,AudioSupplier * supplier,bool lowLatency)132 AudioProducer::AudioProducer(const char* name, AudioSupplier* supplier,
133 bool lowLatency)
134 :
135 BMediaNode(name),
136 BBufferProducer(B_MEDIA_RAW_AUDIO),
137 BMediaEventLooper(),
138
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),
149
150 fPeakListener(NULL)
151 {
152 TRACE("%p->AudioProducer::AudioProducer(%s, %p, %d)\n", this, name,
153 supplier, lowLatency);
154
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;
165
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);
171
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
179
180 // we're not connected yet
181 fOutput.destination = media_destination::null;
182 fOutput.format = fPreferredFormat;
183
184 // init the audio supplier
185 if (fSupplier != NULL) {
186 fSupplier->SetAudioProducer(this);
187 SetInitialLatency(fSupplier->InitialLatency());
188 }
189 }
190
191
~AudioProducer()192 AudioProducer::~AudioProducer()
193 {
194 TRACE("%p->AudioProducer::~AudioProducer()\n", this);
195
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;
204 }
205 #endif // DEBUG_TO_FILE
206
207 // Stop the BMediaEventLooper thread
208 Quit();
209 TRACE("AudioProducer::~AudioProducer() done\n");
210 }
211
212
213 BMediaAddOn*
AddOn(int32 * internalId) const214 AudioProducer::AddOn(int32* internalId) const
215 {
216 return NULL;
217 }
218
219
220 status_t
FormatSuggestionRequested(media_type type,int32 quality,media_format * _format)221 AudioProducer::FormatSuggestionRequested(media_type type, int32 quality,
222 media_format* _format)
223 {
224 TRACE("%p->AudioProducer::FormatSuggestionRequested()\n", this);
225
226 if (!_format)
227 return B_BAD_VALUE;
228
229 // This is the format we'll be returning (our preferred format)
230 *_format = fPreferredFormat;
231
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;
236
237 return B_OK;
238 }
239
240 status_t
FormatProposal(const media_source & output,media_format * format)241 AudioProducer::FormatProposal(const media_source& output, media_format* format)
242 {
243 TRACE("%p->AudioProducer::FormatProposal()\n", this);
244
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;
249 }
250
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;
267 }
268
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;
272
273 return B_OK;
274 }
275
276
277 status_t
FormatChangeRequested(const media_source & source,const media_destination & destination,media_format * ioFormat,int32 * _deprecated_)278 AudioProducer::FormatChangeRequested(const media_source& source,
279 const media_destination& destination, media_format* ioFormat,
280 int32* _deprecated_)
281 {
282 TRACE("%p->AudioProducer::FormatChangeRequested()\n", this);
283
284 if (destination != fOutput.destination) {
285 TRACE(" -> B_MEDIA_BAD_DESTINATION\n");
286 return B_MEDIA_BAD_DESTINATION;
287 }
288
289 if (source != fOutput.source) {
290 TRACE(" -> B_MEDIA_BAD_SOURCE\n");
291 return B_MEDIA_BAD_SOURCE;
292 }
293
294 // TODO: Maybe we are supposed to specialize here only and not actually change yet?
295 // status_t ret = _SpecializeFormat(ioFormat);
296
297 return ChangeFormat(ioFormat);
298 }
299
300
301 status_t
GetNextOutput(int32 * cookie,media_output * _output)302 AudioProducer::GetNextOutput(int32* cookie, media_output* _output)
303 {
304 TRACE("%p->AudioProducer::GetNextOutput(%ld)\n", this, *cookie);
305
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;
313 }
314
315 return B_BAD_INDEX;
316 }
317
318
319 status_t
DisposeOutputCookie(int32 cookie)320 AudioProducer::DisposeOutputCookie(int32 cookie)
321 {
322 // do nothing because we don't use the cookie for anything special
323 return B_OK;
324 }
325
326
327 status_t
SetBufferGroup(const media_source & forSource,BBufferGroup * newGroup)328 AudioProducer::SetBufferGroup(const media_source& forSource,
329 BBufferGroup* newGroup)
330 {
331 TRACE("%p->AudioProducer::SetBufferGroup()\n", this);
332
333 if (forSource != fOutput.source)
334 return B_MEDIA_BAD_SOURCE;
335
336 if (newGroup == fBufferGroup)
337 return B_OK;
338
339 if (fUsingOurBuffers && fBufferGroup)
340 delete fBufferGroup; // waits for all buffers to recycle
341
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;
353 }
354
355 return B_OK;
356 }
357
358
359 status_t
GetLatency(bigtime_t * _latency)360 AudioProducer::GetLatency(bigtime_t* _latency)
361 {
362 TRACE("%p->AudioProducer::GetLatency()\n", this);
363
364 // report our *total* latency: internal plus downstream plus scheduling
365 *_latency = EventLatency() + SchedulingLatency();
366 return B_OK;
367 }
368
369
370 status_t
PrepareToConnect(const media_source & what,const media_destination & where,media_format * format,media_source * _source,char * _name)371 AudioProducer::PrepareToConnect(const media_source& what,
372 const media_destination& where, media_format* format,
373 media_source* _source, char* _name)
374 {
375 TRACE("%p->AudioProducer::PrepareToConnect()\n", this);
376
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;
381 }
382
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;
387 }
388
389 status_t ret = _SpecializeFormat(format);
390 if (ret != B_OK) {
391 TRACE(" -> format error: %s\n", strerror(ret));
392 return ret;
393 }
394
395 // Now reserve the connection, and return information about it
396 fOutput.destination = where;
397 fOutput.format = *format;
398
399 if (fSupplier != NULL)
400 fSupplier->SetFormat(fOutput.format);
401
402 *_source = fOutput.source;
403 strncpy(_name, fOutput.name, B_MEDIA_NAME_LENGTH);
404 TRACE(" -> B_OK\n");
405 return B_OK;
406 }
407
408
409 void
Connect(status_t error,const media_source & source,const media_destination & destination,const media_format & format,char * _name)410 AudioProducer::Connect(status_t error, const media_source& source,
411 const media_destination& destination, const media_format& format,
412 char* _name)
413 {
414 TRACE("AudioProducer::Connect(%s)\n", strerror(error));
415
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;
423 }
424
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);
430
431 // tell our audio supplier about the format
432 if (fSupplier) {
433 TRACE("AudioProducer::Connect() fSupplier->SetFormat()\n");
434 fSupplier->SetFormat(fOutput.format);
435 }
436
437 TRACE("AudioProducer::Connect() FindLatencyFor()\n");
438
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);
443
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);
453
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);
460
461 TRACE("AudioProducer::Connect() _AllocateBuffers()\n");
462
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);
469
470 TRACE("AudioProducer::Connect() done\n");
471 }
472
473
474 void
Disconnect(const media_source & what,const media_destination & where)475 AudioProducer::Disconnect(const media_source& what,
476 const media_destination& where)
477 {
478 TRACE("%p->AudioProducer::Disconnect()\n", this);
479
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;
490 }
491
492 TRACE("%p->AudioProducer::Disconnect() done\n", this);
493 }
494
495
496 void
LateNoticeReceived(const media_source & what,bigtime_t howMuch,bigtime_t performanceTime)497 AudioProducer::LateNoticeReceived(const media_source& what, bigtime_t howMuch,
498 bigtime_t performanceTime)
499 {
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;
509
510 fLastLateNotice = fNextScheduledBuffer;
511
512 if (RunMode() == B_RECORDING) {
513 // ...
514 } else if (RunMode() == B_INCREASE_LATENCY) {
515 fInternalLatency += howMuch;
516
517 // At some point a too large latency can get annoying
518 if (fInternalLatency > kMaxLatency)
519 fInternalLatency = kMaxLatency;
520
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;
532 }
533 }
534 }
535
536
537 void
EnableOutput(const media_source & what,bool enabled,int32 * _deprecated_)538 AudioProducer::EnableOutput(const media_source& what, bool enabled,
539 int32* _deprecated_)
540 {
541 TRACE("%p->AudioProducer::EnableOutput(%d)\n", this, enabled);
542
543 if (what == fOutput.source)
544 fOutputEnabled = enabled;
545 }
546
547
548 status_t
SetPlayRate(int32 numer,int32 denom)549 AudioProducer::SetPlayRate(int32 numer, int32 denom)
550 {
551 return B_ERROR;
552 }
553
554
555 status_t
HandleMessage(int32 message,const void * data,size_t size)556 AudioProducer::HandleMessage(int32 message, const void *data, size_t size)
557 {
558 TRACE("%p->AudioProducer::HandleMessage()\n", this);
559 return B_ERROR;
560 }
561
562
563 void
AdditionalBufferRequested(const media_source & source,media_buffer_id prevBuffer,bigtime_t prevTime,const media_seek_tag * prevTag)564 AudioProducer::AdditionalBufferRequested(const media_source& source,
565 media_buffer_id prevBuffer, bigtime_t prevTime,
566 const media_seek_tag *prevTag)
567 {
568 TRACE("%p->AudioProducer::AdditionalBufferRequested()\n", this);
569 }
570
571
572 void
LatencyChanged(const media_source & source,const media_destination & destination,bigtime_t newLatency,uint32 flags)573 AudioProducer::LatencyChanged(const media_source& source,
574 const media_destination& destination, bigtime_t newLatency, uint32 flags)
575 {
576 TRACE("%p->AudioProducer::LatencyChanged(%lld)\n", this, newLatency);
577
578 if (source == fOutput.source && destination == fOutput.destination) {
579 fLatency = newLatency;
580 SetEventLatency(fLatency + fInternalLatency);
581 }
582 }
583
584
585 void
NodeRegistered()586 AudioProducer::NodeRegistered()
587 {
588 TRACE("%p->AudioProducer::NodeRegistered()\n", this);
589
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());
595
596 // Start the BMediaEventLooper thread
597 SetPriority(B_REAL_TIME_PRIORITY);
598 Run();
599 }
600
601
602 void
SetRunMode(run_mode mode)603 AudioProducer::SetRunMode(run_mode mode)
604 {
605 TRACE("%p->AudioProducer::SetRunMode()\n", this);
606
607 if (B_OFFLINE == mode)
608 ReportError(B_NODE_FAILED_SET_RUN_MODE);
609 else
610 BBufferProducer::SetRunMode(mode);
611 }
612
613
614 void
HandleEvent(const media_timed_event * event,bigtime_t lateness,bool realTimeEvent)615 AudioProducer::HandleEvent(const media_timed_event* event, bigtime_t lateness,
616 bool realTimeEvent)
617 {
618 TRACE_BUFFER("%p->AudioProducer::HandleEvent()\n", this);
619
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);
630 }
631 TRACE("AudioProducer::HandleEvent(B_START) done\n");
632 break;
633
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;
640
641 case BTimedEventQueue::B_HANDLE_BUFFER:
642 {
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);
652 }
653 if (err != B_OK)
654 buffer->Recycle();
655 }
656 size_t sampleSize = fOutput.format.u.raw_audio.format
657 & media_raw_audio_format::B_AUDIO_SIZE_MASK;
658
659 size_t nFrames = fOutput.format.u.raw_audio.buffer_size
660 / (sampleSize * fOutput.format.u.raw_audio.channel_count);
661 fFramesSent += nFrames;
662
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");
671 }
672 TRACE_BUFFER("AudioProducer::HandleEvent(B_HANDLE_BUFFER) done\n");
673 break;
674 }
675 default:
676 break;
677 }
678 }
679
680
681 void
SetPeakListener(BHandler * handler)682 AudioProducer::SetPeakListener(BHandler* handler)
683 {
684 fPeakListener = handler;
685 }
686
687
688 status_t
ChangeFormat(media_format * format)689 AudioProducer::ChangeFormat(media_format* format)
690 {
691 TRACE("AudioProducer::ChangeFormat()\n");
692
693 format->u.raw_audio.buffer_size
694 = media_raw_audio_format::wildcard.buffer_size;
695
696 status_t ret = _SpecializeFormat(format);
697 if (ret != B_OK) {
698 TRACE(" _SpecializeFormat(): %s\n", strerror(ret));
699 return ret;
700 }
701
702 ret = BBufferProducer::ProposeFormatChange(format, fOutput.destination);
703 if (ret != B_OK) {
704 TRACE(" ProposeFormatChange(): %s\n", strerror(ret));
705 return ret;
706 }
707
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;
713 }
714
715 return _ChangeFormat(*format);
716 }
717
718
719 // #pragma mark -
720
721
722 status_t
_SpecializeFormat(media_format * format)723 AudioProducer::_SpecializeFormat(media_format* format)
724 {
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;
736 }
737
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");
742 }
743
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");
748 }
749
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");
755
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);
764
765 if (!fLowLatency)
766 format->u.raw_audio.buffer_size *= 3;
767 }
768
769 return B_OK;
770 }
771
772
773 status_t
_ChangeFormat(const media_format & format)774 AudioProducer::_ChangeFormat(const media_format& format)
775 {
776 fOutput.format = format;
777
778 // notify our audio supplier of the format change
779 if (fSupplier)
780 fSupplier->SetFormat(format);
781
782 return _AllocateBuffers(format);
783 }
784
785
786 status_t
_AllocateBuffers(const media_format & format)787 AudioProducer::_AllocateBuffers(const media_format& format)
788 {
789 TRACE("%p->AudioProducer::_AllocateBuffers()\n", this);
790
791 if (fBufferGroup && fUsingOurBuffers) {
792 delete fBufferGroup;
793 fBufferGroup = NULL;
794 }
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);
801 }
802
803 fBufferGroup = new BBufferGroup(size, count);
804 fUsingOurBuffers = true;
805 return fBufferGroup->InitCheck();
806 }
807
808
809 BBuffer*
_FillNextBuffer(bigtime_t eventTime)810 AudioProducer::_FillNextBuffer(bigtime_t eventTime)
811 {
812 fBufferGroup->WaitForBuffers();
813 BBuffer* buffer = fBufferGroup->RequestBuffer(
814 fOutput.format.u.raw_audio.buffer_size, BufferDuration());
815
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;
823 }
824 return NULL;
825 }
826
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
831
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);
837
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);
844
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());
850 }
851
852 // stamp buffer
853 if (RunMode() == B_RECORDING)
854 header->start_time = eventTime;
855 else
856 header->start_time = fStartTime + startTime;
857
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
863
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;
874 }
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++;
883 }
884 }
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);
889 }
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);
896 }
897
898 return buffer;
899 }
900
901