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