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
51const static bigtime_t kMaxLatency = 150000;
52	// 150 ms is the maximum latency we publish
53
54
55#if DEBUG_TO_FILE
56static BMediaFile*
57init_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
94static bigtime_t
95estimate_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
132AudioProducer::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
192AudioProducer::~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
213BMediaAddOn*
214AudioProducer::AddOn(int32* internalId) const
215{
216	return NULL;
217}
218
219
220status_t
221AudioProducer::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
240status_t
241AudioProducer::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
277status_t
278AudioProducer::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
301status_t
302AudioProducer::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
319status_t
320AudioProducer::DisposeOutputCookie(int32 cookie)
321{
322	// do nothing because we don't use the cookie for anything special
323	return B_OK;
324}
325
326
327status_t
328AudioProducer::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
359status_t
360AudioProducer::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
370status_t
371AudioProducer::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
409void
410AudioProducer::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
474void
475AudioProducer::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
496void
497AudioProducer::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
537void
538AudioProducer::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
548status_t
549AudioProducer::SetPlayRate(int32 numer, int32 denom)
550{
551	return B_ERROR;
552}
553
554
555status_t
556AudioProducer::HandleMessage(int32 message, const void *data, size_t size)
557{
558	TRACE("%p->AudioProducer::HandleMessage()\n", this);
559	return B_ERROR;
560}
561
562
563void
564AudioProducer::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
572void
573AudioProducer::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
585void
586AudioProducer::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
602void
603AudioProducer::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
614void
615AudioProducer::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
681void
682AudioProducer::SetPeakListener(BHandler* handler)
683{
684	fPeakListener = handler;
685}
686
687
688status_t
689AudioProducer::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
722status_t
723AudioProducer::_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
773status_t
774AudioProducer::_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
786status_t
787AudioProducer::_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
809BBuffer*
810AudioProducer::_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