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: %lld, time interval: %lld - %lld)\n",
94		buffer, frameCount, startTime, endTime);
95
96	// Create a list of playing intervals which compose the supplied
97	// performance time interval.
98	BList playingIntervals;
99	status_t error = fPlaybackManager->LockWithTimeout(10000);
100	if (error == B_OK) {
101		bigtime_t intervalStartTime = startTime;
102		while (intervalStartTime < endTime) {
103			PlayingInterval* interval
104				= new (nothrow) PlayingInterval(intervalStartTime, endTime);
105			if (!interval) {
106				error = B_NO_MEMORY;
107				break;
108			}
109			fPlaybackManager->GetPlaylistTimeInterval(
110				interval->start_time, interval->end_time,
111				interval->x_start_time, interval->x_end_time,
112				interval->speed);
113			if (intervalStartTime == interval->end_time) {
114				delete interval;
115				error = B_ERROR;
116				ERROR("GetFrames() - zero duration audio interval! start "
117					"time: %lld\n", intervalStartTime);
118				break;
119			}
120			if (!playingIntervals.AddItem(interval)) {
121				delete interval;
122				error = B_NO_MEMORY;
123				ERROR("GetFrames() - Out of memory\n");
124				break;
125			}
126			intervalStartTime = interval->end_time;
127		}
128		fPlaybackManager->SetCurrentAudioTime(endTime);
129		fPlaybackManager->Unlock();
130	} else if (error == B_TIMED_OUT) {
131		TRACE("GetFrames() - LOCKING THE PLAYBACK MANAGER TIMED OUT!!!\n");
132	}
133
134	BAutolock _(fSupplierLock);
135
136	if (!fSupplier)
137		return B_ERROR;
138
139	// retrieve the audio data for each interval.
140	#ifdef TRACE_PROXY_AUDIO_SUPPLIER
141	int32 intervalIndex = 0;
142	#endif
143
144	int64 framesRead = 0;
145	while (!playingIntervals.IsEmpty()) {
146		PlayingInterval* interval
147			= (PlayingInterval*)playingIntervals.RemoveItem(0L);
148		if (error != B_OK) {
149			delete interval;
150			continue;
151		}
152
153		// get playing direction
154		int32 playingDirection = 0;
155		if (interval->speed > 0)
156			playingDirection = 1;
157		else if (interval->speed < 0)
158			playingDirection = -1;
159		float absSpeed = interval->speed * playingDirection;
160		int64 framesToRead = _AudioFrameForTime(interval->end_time)
161			- _AudioFrameForTime(interval->start_time);
162
163		TRACE("GetFrames() - interval (%ld) [%lld, %lld]: [%lld, %lld], "
164			"frames: %lld\n", intervalIndex,
165			interval->start_time, interval->end_time,
166			interval->x_start_time, interval->x_end_time,
167			framesToRead);
168
169		// not playing
170		if (absSpeed == 0)
171			_ReadSilence(buffer, framesToRead);
172		// playing
173		else {
174			fAudioResampler.SetInOffset(
175				_AudioFrameForTime(interval->x_start_time));
176			fAudioResampler.SetTimeScale(absSpeed);
177			error = fAudioResampler.Read(buffer, 0, framesToRead);
178			// backwards -> reverse frames
179			if (error == B_OK && interval->speed < 0)
180				_ReverseFrames(buffer, framesToRead);
181		}
182		// read silence on error
183		if (error != B_OK) {
184			_ReadSilence(buffer, framesToRead);
185			error = B_OK;
186		}
187		framesRead += framesToRead;
188		buffer = _SkipFrames(buffer, framesToRead);
189		delete interval;
190
191		#ifdef TRACE_PROXY_AUDIO_SUPPLIER
192		intervalIndex++;
193		#endif
194	}
195	// read silence on error
196	if (error != B_OK) {
197		_ReadSilence(buffer, frameCount);
198		error = B_OK;
199	}
200
201	TRACE("GetFrames() done\n");
202
203	return error;
204}
205
206
207void
208ProxyAudioSupplier::SetFormat(const media_format& format)
209{
210//printf("ProxyAudioSupplier::SetFormat()\n");
211	#ifdef TRACE_PROXY_AUDIO_SUPPLIER
212		char string[256];
213		string_for_format(format, string, 256);
214		TRACE("SetFormat(%s)\n", string);
215	#endif
216
217	BAutolock _(fSupplierLock);
218
219	fAudioResampler.SetFormat(format);
220
221	// In case SetSupplier was called before, we need
222	// to adapt to the new format, or maybe the format
223	// was still invalid.
224	SetSupplier(fSupplier, fVideoFrameRate);
225}
226
227
228const media_format&
229ProxyAudioSupplier::Format() const
230{
231	return fAudioResampler.Format();
232}
233
234
235status_t
236ProxyAudioSupplier::InitCheck() const
237{
238	status_t ret = AudioSupplier::InitCheck();
239	if (ret < B_OK)
240		return ret;
241	return B_OK;
242}
243
244
245void
246ProxyAudioSupplier::SetSupplier(AudioTrackSupplier* supplier,
247	float videoFrameRate)
248{
249//printf("ProxyAudioSupplier::SetSupplier(%p, %.1f)\n", supplier,
250//videoFrameRate);
251	TRACE("SetSupplier(%p, %.1f)\n", supplier, videoFrameRate);
252
253	BAutolock _(fSupplierLock);
254
255	fSupplier = supplier;
256	fVideoFrameRate = videoFrameRate;
257
258	delete fAdapter;
259	delete fVolumeConverter;
260
261	fAdapter = new AudioAdapter(fSupplier, Format());
262	fVolumeConverter = new AudioVolumeConverter(fAdapter, fVolume);
263
264	fAudioResampler.SetSource(fVolumeConverter);
265}
266
267
268void
269ProxyAudioSupplier::SetVolume(float volume)
270{
271	BAutolock _(fSupplierLock);
272	fVolume = volume;
273	if (fVolumeConverter)
274		fVolumeConverter->SetVolume(volume);
275}
276
277
278float
279ProxyAudioSupplier::Volume()
280{
281	BAutolock _(fSupplierLock);
282	return fVolume;
283}
284
285
286// #pragma mark - audio/video/frame/time conversion
287
288
289int64
290ProxyAudioSupplier::_AudioFrameForVideoFrame(int64 frame) const
291{
292	if (!fSupplier) {
293		return (int64)((double)frame * Format().u.raw_audio.frame_rate
294			/ fVideoFrameRate);
295	}
296	const media_format& format = fSupplier->Format();
297	return (int64)((double)frame * format.u.raw_audio.frame_rate
298		/ fVideoFrameRate);
299}
300
301
302int64
303ProxyAudioSupplier::_VideoFrameForAudioFrame(int64 frame) const
304{
305	if (!fSupplier) {
306		return (int64)((double)frame * fVideoFrameRate
307			/ Format().u.raw_audio.frame_rate);
308	}
309
310	const media_format& format = fSupplier->Format();
311	return (int64)((double)frame * fVideoFrameRate
312		/ format.u.raw_audio.frame_rate);
313}
314
315
316int64
317ProxyAudioSupplier::_AudioFrameForTime(bigtime_t time) const
318{
319	return (int64)((double)time * Format().u.raw_audio.frame_rate
320		/ 1000000.0);
321}
322
323
324int64
325ProxyAudioSupplier::_VideoFrameForTime(bigtime_t time) const
326{
327	return (int64)((double)time * fVideoFrameRate / 1000000.0);
328}
329
330
331// #pragma mark - utility
332
333
334void
335ProxyAudioSupplier::_ReadSilence(void* buffer, int64 frames) const
336{
337	memset(buffer, 0, (char*)_SkipFrames(buffer, frames) - (char*)buffer);
338}
339
340
341void
342ProxyAudioSupplier::_ReverseFrames(void* buffer, int64 frames) const
343{
344	int32 sampleSize = Format().u.raw_audio.format
345		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
346	int32 frameSize = sampleSize * Format().u.raw_audio.channel_count;
347	char* front = (char*)buffer;
348	char* back = (char*)buffer + (frames - 1) * frameSize;
349	while (front < back) {
350		for (int32 i = 0; i < frameSize; i++)
351			swap(front[i], back[i]);
352		front += frameSize;
353		back -= frameSize;
354	}
355}
356
357
358void*
359ProxyAudioSupplier::_SkipFrames(void* buffer, int64 frames) const
360{
361	int32 sampleSize = Format().u.raw_audio.format
362		& media_raw_audio_format::B_AUDIO_SIZE_MASK;
363	int32 frameSize = sampleSize * Format().u.raw_audio.channel_count;
364	return (char*)buffer + frames * frameSize;
365}
366
367