1/*
2 * Copyright 2008 Stephan Aßmus <superstippi@gmx.de>
3 * All Rights Reserved. Distributed under the terms of the MIT license.
4 */
5
6
7#include "ProxyAudioSupplier.h"
8
9#include <algorithm>
10#include <new>
11#include <stdio.h>
12#include <string.h>
13
14#include <Autolock.h>
15#include <List.h>
16
17#include "AudioTrackSupplier.h"
18#include "AudioAdapter.h"
19#include "AudioVolumeConverter.h"
20#include "PlaybackManager.h"
21
22using std::nothrow;
23using std::swap;
24
25
26//#define TRACE_PROXY_AUDIO_SUPPLIER
27#ifdef TRACE_PROXY_AUDIO_SUPPLIER
28# define TRACE(x...)	printf("ProxyAudioSupplier::"); printf(x)
29# define ERROR(x...)	fprintf(stderr, "ProxyAudioSupplier::"); fprintf(stderr, x)
30#else
31# define TRACE(x...)
32# define ERROR(x...)	fprintf(stderr, "ProxyAudioSupplier::"); fprintf(stderr, x)
33#endif
34
35
36struct PlayingInterval {
37	PlayingInterval(bigtime_t startTime, bigtime_t endTime)
38		:
39		start_time(startTime),
40		end_time(endTime)
41	{
42	}
43
44	bigtime_t	start_time;
45	bigtime_t	end_time;
46	bigtime_t	x_start_time;
47	bigtime_t	x_end_time;
48	float		speed;
49};
50
51
52ProxyAudioSupplier::ProxyAudioSupplier(PlaybackManager* playbackManager)
53	:
54	fSupplierLock("audio supplier lock"),
55
56	fPlaybackManager(playbackManager),
57	fVideoFrameRate(25.0),
58	fVolume(1.0),
59
60	fSupplier(NULL),
61	fAdapter(NULL),
62	fVolumeConverter(NULL),
63	fAudioResampler()
64{
65	TRACE("ProxyAudioSupplier()\n");
66}
67
68
69ProxyAudioSupplier::~ProxyAudioSupplier()
70{
71	TRACE("~ProxyAudioSupplier()\n");
72	delete fAdapter;
73	delete fVolumeConverter;
74}
75
76
77bigtime_t
78ProxyAudioSupplier::InitialLatency() const
79{
80	BAutolock _(fSupplierLock);
81
82	if (fSupplier == NULL)
83		return 0;
84
85	return fSupplier->InitialLatency();
86}
87
88
89status_t
90ProxyAudioSupplier::GetFrames(void* buffer, int64 frameCount,
91	bigtime_t startTime, bigtime_t endTime)
92{
93	TRACE("GetFrames(%p, frameCount: %" B_PRId64 ", time interval: %"
94		B_PRIdBIGTIME " - %" B_PRIdBIGTIME ")\n",
95		buffer, frameCount, startTime, endTime);
96
97	// Create a list of playing intervals which compose the supplied
98	// performance time interval.
99	BList playingIntervals;
100	status_t error = fPlaybackManager->LockWithTimeout(10000);
101	if (error == B_OK) {
102		bigtime_t intervalStartTime = startTime;
103		while (intervalStartTime < endTime) {
104			PlayingInterval* interval
105				= new (nothrow) PlayingInterval(intervalStartTime, endTime);
106			if (!interval) {
107				error = B_NO_MEMORY;
108				break;
109			}
110			fPlaybackManager->GetPlaylistTimeInterval(
111				interval->start_time, interval->end_time,
112				interval->x_start_time, interval->x_end_time,
113				interval->speed);
114			if (intervalStartTime == interval->end_time) {
115				delete interval;
116				error = B_ERROR;
117				ERROR("GetFrames() - zero duration audio interval! start "
118					"time: %" B_PRIdBIGTIME "\n", intervalStartTime);
119				break;
120			}
121			if (!playingIntervals.AddItem(interval)) {
122				delete interval;
123				error = B_NO_MEMORY;
124				ERROR("GetFrames() - Out of memory\n");
125				break;
126			}
127			intervalStartTime = interval->end_time;
128		}
129		fPlaybackManager->SetCurrentAudioTime(endTime);
130		fPlaybackManager->Unlock();
131	} else if (error == B_TIMED_OUT) {
132		TRACE("GetFrames() - LOCKING THE PLAYBACK MANAGER TIMED OUT!!!\n");
133	}
134
135	BAutolock _(fSupplierLock);
136
137	if (!fSupplier)
138		return B_ERROR;
139
140	// retrieve the audio data for each interval.
141	#ifdef TRACE_PROXY_AUDIO_SUPPLIER
142	int32 intervalIndex = 0;
143	#endif
144
145	int64 framesRead = 0;
146	while (!playingIntervals.IsEmpty()) {
147		PlayingInterval* interval
148			= (PlayingInterval*)playingIntervals.RemoveItem((int32)0);
149		if (error != B_OK) {
150			delete interval;
151			continue;
152		}
153
154		// get playing direction
155		int32 playingDirection = 0;
156		if (interval->speed > 0)
157			playingDirection = 1;
158		else if (interval->speed < 0)
159			playingDirection = -1;
160		float absSpeed = interval->speed * playingDirection;
161		int64 framesToRead = _AudioFrameForTime(interval->end_time)
162			- _AudioFrameForTime(interval->start_time);
163
164		TRACE("GetFrames() - interval (%ld) [%lld, %lld]: [%lld, %lld], "
165			"frames: %lld\n", intervalIndex,
166			interval->start_time, interval->end_time,
167			interval->x_start_time, interval->x_end_time,
168			framesToRead);
169
170		// not playing
171		if (absSpeed == 0)
172			_ReadSilence(buffer, framesToRead);
173		// playing
174		else {
175			fAudioResampler.SetInOffset(
176				_AudioFrameForTime(interval->x_start_time));
177			fAudioResampler.SetTimeScale(absSpeed);
178			error = fAudioResampler.Read(buffer, 0, framesToRead);
179			// backwards -> reverse frames
180			if (error == B_OK && interval->speed < 0)
181				_ReverseFrames(buffer, framesToRead);
182		}
183		// read silence on error
184		if (error != B_OK) {
185			_ReadSilence(buffer, framesToRead);
186			error = B_OK;
187		}
188		framesRead += framesToRead;
189		buffer = _SkipFrames(buffer, framesToRead);
190		delete interval;
191
192		#ifdef TRACE_PROXY_AUDIO_SUPPLIER
193		intervalIndex++;
194		#endif
195	}
196	// read silence on error
197	if (error != B_OK) {
198		_ReadSilence(buffer, frameCount);
199		error = B_OK;
200	}
201
202	TRACE("GetFrames() done\n");
203
204	return error;
205}
206
207
208void
209ProxyAudioSupplier::SetFormat(const media_format& format)
210{
211//printf("ProxyAudioSupplier::SetFormat()\n");
212	#ifdef TRACE_PROXY_AUDIO_SUPPLIER
213		char string[256];
214		string_for_format(format, string, 256);
215		TRACE("SetFormat(%s)\n", string);
216	#endif
217
218	BAutolock _(fSupplierLock);
219
220	fAudioResampler.SetFormat(format);
221
222	// In case SetSupplier was called before, we need
223	// to adapt to the new format, or maybe the format
224	// was still invalid.
225	SetSupplier(fSupplier, fVideoFrameRate);
226}
227
228
229const media_format&
230ProxyAudioSupplier::Format() const
231{
232	return fAudioResampler.Format();
233}
234
235
236status_t
237ProxyAudioSupplier::InitCheck() const
238{
239	status_t ret = AudioSupplier::InitCheck();
240	if (ret < B_OK)
241		return ret;
242	return B_OK;
243}
244
245
246void
247ProxyAudioSupplier::SetSupplier(AudioTrackSupplier* supplier,
248	float videoFrameRate)
249{
250//printf("ProxyAudioSupplier::SetSupplier(%p, %.1f)\n", supplier,
251//videoFrameRate);
252	TRACE("SetSupplier(%p, %.1f)\n", supplier, videoFrameRate);
253
254	BAutolock _(fSupplierLock);
255
256	fSupplier = supplier;
257	fVideoFrameRate = videoFrameRate;
258
259	delete fAdapter;
260	delete fVolumeConverter;
261
262	fAdapter = new AudioAdapter(fSupplier, Format());
263	fVolumeConverter = new AudioVolumeConverter(fAdapter, fVolume);
264
265	fAudioResampler.SetSource(fVolumeConverter);
266}
267
268
269void
270ProxyAudioSupplier::SetVolume(float volume)
271{
272	BAutolock _(fSupplierLock);
273	fVolume = volume;
274	if (fVolumeConverter)
275		fVolumeConverter->SetVolume(volume);
276}
277
278
279float
280ProxyAudioSupplier::Volume()
281{
282	BAutolock _(fSupplierLock);
283	return fVolume;
284}
285
286
287// #pragma mark - audio/video/frame/time conversion
288
289
290int64
291ProxyAudioSupplier::_AudioFrameForVideoFrame(int64 frame) const
292{
293	if (!fSupplier) {
294		return (int64)((double)frame * Format().u.raw_audio.frame_rate
295			/ fVideoFrameRate);
296	}
297	const media_format& format = fSupplier->Format();
298	return (int64)((double)frame * format.u.raw_audio.frame_rate
299		/ fVideoFrameRate);
300}
301
302
303int64
304ProxyAudioSupplier::_VideoFrameForAudioFrame(int64 frame) const
305{
306	if (!fSupplier) {
307		return (int64)((double)frame * fVideoFrameRate
308			/ Format().u.raw_audio.frame_rate);
309	}
310
311	const media_format& format = fSupplier->Format();
312	return (int64)((double)frame * fVideoFrameRate
313		/ format.u.raw_audio.frame_rate);
314}
315
316
317int64
318ProxyAudioSupplier::_AudioFrameForTime(bigtime_t time) const
319{
320	return (int64)((double)time * Format().u.raw_audio.frame_rate
321		/ 1000000.0);
322}
323
324
325int64
326ProxyAudioSupplier::_VideoFrameForTime(bigtime_t time) const
327{
328	return (int64)((double)time * fVideoFrameRate / 1000000.0);
329}
330
331
332// #pragma mark - utility
333
334
335void
336ProxyAudioSupplier::_ReadSilence(void* buffer, int64 frames) const
337{
338	memset(buffer, 0, (char*)_SkipFrames(buffer, frames) - (char*)buffer);
339}
340
341
342void
343ProxyAudioSupplier::_ReverseFrames(void* buffer, int64 frames) const
344{
345	int32 sampleSize = Format().u.raw_audio.format
346		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
347	int32 frameSize = sampleSize * Format().u.raw_audio.channel_count;
348	char* front = (char*)buffer;
349	char* back = (char*)buffer + (frames - 1) * frameSize;
350	while (front < back) {
351		for (int32 i = 0; i < frameSize; i++)
352			swap(front[i], back[i]);
353		front += frameSize;
354		back -= frameSize;
355	}
356}
357
358
359void*
360ProxyAudioSupplier::_SkipFrames(void* buffer, int64 frames) const
361{
362	int32 sampleSize = Format().u.raw_audio.format
363		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
364	int32 frameSize = sampleSize * Format().u.raw_audio.channel_count;
365	return (char*)buffer + frames * frameSize;
366}
367
368