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