xref: /haiku/src/apps/mediaplayer/media_node_framework/audio/AudioProducer.cpp (revision 6d2f2ec177bf615a117a7428d71be4330545b320)
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