xref: /haiku/src/apps/mediaplayer/supplier/ProxyAudioSupplier.cpp (revision 7a74a5df454197933bc6e80a542102362ee98703)
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 
22 using std::nothrow;
23 using 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 
36 struct 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 
52 ProxyAudioSupplier::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 
69 ProxyAudioSupplier::~ProxyAudioSupplier()
70 {
71 	TRACE("~ProxyAudioSupplier()\n");
72 	delete fAdapter;
73 	delete fVolumeConverter;
74 }
75 
76 
77 bigtime_t
78 ProxyAudioSupplier::InitialLatency() const
79 {
80 	BAutolock _(fSupplierLock);
81 
82 	if (fSupplier == NULL)
83 		return 0;
84 
85 	return fSupplier->InitialLatency();
86 }
87 
88 
89 status_t
90 ProxyAudioSupplier::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 
207 void
208 ProxyAudioSupplier::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 
228 const media_format&
229 ProxyAudioSupplier::Format() const
230 {
231 	return fAudioResampler.Format();
232 }
233 
234 
235 status_t
236 ProxyAudioSupplier::InitCheck() const
237 {
238 	status_t ret = AudioSupplier::InitCheck();
239 	if (ret < B_OK)
240 		return ret;
241 	return B_OK;
242 }
243 
244 
245 void
246 ProxyAudioSupplier::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 
268 void
269 ProxyAudioSupplier::SetVolume(float volume)
270 {
271 	BAutolock _(fSupplierLock);
272 	fVolume = volume;
273 	if (fVolumeConverter)
274 		fVolumeConverter->SetVolume(volume);
275 }
276 
277 
278 float
279 ProxyAudioSupplier::Volume()
280 {
281 	BAutolock _(fSupplierLock);
282 	return fVolume;
283 }
284 
285 
286 // #pragma mark - audio/video/frame/time conversion
287 
288 
289 int64
290 ProxyAudioSupplier::_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 
302 int64
303 ProxyAudioSupplier::_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 
316 int64
317 ProxyAudioSupplier::_AudioFrameForTime(bigtime_t time) const
318 {
319 	return (int64)((double)time * Format().u.raw_audio.frame_rate
320 		/ 1000000.0);
321 }
322 
323 
324 int64
325 ProxyAudioSupplier::_VideoFrameForTime(bigtime_t time) const
326 {
327 	return (int64)((double)time * fVideoFrameRate / 1000000.0);
328 }
329 
330 
331 // #pragma mark - utility
332 
333 
334 void
335 ProxyAudioSupplier::_ReadSilence(void* buffer, int64 frames) const
336 {
337 	memset(buffer, 0, (char*)_SkipFrames(buffer, frames) - (char*)buffer);
338 }
339 
340 
341 void
342 ProxyAudioSupplier::_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 
358 void*
359 ProxyAudioSupplier::_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