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