xref: /haiku/src/apps/mediaplayer/supplier/ProxyAudioSupplier.cpp (revision b8ded2f89783a220c7b3019d48266a682cc79158)
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 {
PlayingIntervalPlayingInterval37 	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 
ProxyAudioSupplier(PlaybackManager * playbackManager)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 
~ProxyAudioSupplier()69 ProxyAudioSupplier::~ProxyAudioSupplier()
70 {
71 	TRACE("~ProxyAudioSupplier()\n");
72 	delete fAdapter;
73 	delete fVolumeConverter;
74 }
75 
76 
77 bigtime_t
InitialLatency() const78 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
GetFrames(void * buffer,int64 frameCount,bigtime_t startTime,bigtime_t endTime)90 ProxyAudioSupplier::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 
208 void
SetFormat(const media_format & format)209 ProxyAudioSupplier::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 
229 const media_format&
Format() const230 ProxyAudioSupplier::Format() const
231 {
232 	return fAudioResampler.Format();
233 }
234 
235 
236 status_t
InitCheck() const237 ProxyAudioSupplier::InitCheck() const
238 {
239 	status_t ret = AudioSupplier::InitCheck();
240 	if (ret < B_OK)
241 		return ret;
242 	return B_OK;
243 }
244 
245 
246 void
SetSupplier(AudioTrackSupplier * supplier,float videoFrameRate)247 ProxyAudioSupplier::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 
269 void
SetVolume(float volume)270 ProxyAudioSupplier::SetVolume(float volume)
271 {
272 	BAutolock _(fSupplierLock);
273 	fVolume = volume;
274 	if (fVolumeConverter)
275 		fVolumeConverter->SetVolume(volume);
276 }
277 
278 
279 float
Volume()280 ProxyAudioSupplier::Volume()
281 {
282 	BAutolock _(fSupplierLock);
283 	return fVolume;
284 }
285 
286 
287 // #pragma mark - audio/video/frame/time conversion
288 
289 
290 int64
_AudioFrameForVideoFrame(int64 frame) const291 ProxyAudioSupplier::_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 
303 int64
_VideoFrameForAudioFrame(int64 frame) const304 ProxyAudioSupplier::_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 
317 int64
_AudioFrameForTime(bigtime_t time) const318 ProxyAudioSupplier::_AudioFrameForTime(bigtime_t time) const
319 {
320 	return (int64)((double)time * Format().u.raw_audio.frame_rate
321 		/ 1000000.0);
322 }
323 
324 
325 int64
_VideoFrameForTime(bigtime_t time) const326 ProxyAudioSupplier::_VideoFrameForTime(bigtime_t time) const
327 {
328 	return (int64)((double)time * fVideoFrameRate / 1000000.0);
329 }
330 
331 
332 // #pragma mark - utility
333 
334 
335 void
_ReadSilence(void * buffer,int64 frames) const336 ProxyAudioSupplier::_ReadSilence(void* buffer, int64 frames) const
337 {
338 	memset(buffer, 0, (char*)_SkipFrames(buffer, frames) - (char*)buffer);
339 }
340 
341 
342 void
_ReverseFrames(void * buffer,int64 frames) const343 ProxyAudioSupplier::_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 
359 void*
_SkipFrames(void * buffer,int64 frames) const360 ProxyAudioSupplier::_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