vfs: check userland buffers before reading them.
[haiku.git] / src / apps / mediaplayer / supplier / ProxyAudioSupplier.cpp
blobcbeb5ad818b28b93377a3d1204b155cee8b48df0
1 /*
2 * Copyright 2008 Stephan Aßmus <superstippi@gmx.de>
3 * All Rights Reserved. Distributed under the terms of the MIT license.
4 */
7 #include "ProxyAudioSupplier.h"
9 #include <algorithm>
10 #include <new>
11 #include <stdio.h>
12 #include <string.h>
14 #include <Autolock.h>
15 #include <List.h>
17 #include "AudioTrackSupplier.h"
18 #include "AudioAdapter.h"
19 #include "AudioVolumeConverter.h"
20 #include "PlaybackManager.h"
22 using std::nothrow;
23 using std::swap;
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
36 struct PlayingInterval {
37 PlayingInterval(bigtime_t startTime, bigtime_t endTime)
39 start_time(startTime),
40 end_time(endTime)
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;
52 ProxyAudioSupplier::ProxyAudioSupplier(PlaybackManager* playbackManager)
54 fSupplierLock("audio supplier lock"),
56 fPlaybackManager(playbackManager),
57 fVideoFrameRate(25.0),
58 fVolume(1.0),
60 fSupplier(NULL),
61 fAdapter(NULL),
62 fVolumeConverter(NULL),
63 fAudioResampler()
65 TRACE("ProxyAudioSupplier()\n");
69 ProxyAudioSupplier::~ProxyAudioSupplier()
71 TRACE("~ProxyAudioSupplier()\n");
72 delete fAdapter;
73 delete fVolumeConverter;
77 bigtime_t
78 ProxyAudioSupplier::InitialLatency() const
80 BAutolock _(fSupplierLock);
82 if (fSupplier == NULL)
83 return 0;
85 return fSupplier->InitialLatency();
89 status_t
90 ProxyAudioSupplier::GetFrames(void* buffer, int64 frameCount,
91 bigtime_t startTime, bigtime_t endTime)
93 TRACE("GetFrames(%p, frameCount: %" B_PRId64 ", time interval: %"
94 B_PRIdBIGTIME " - %" B_PRIdBIGTIME ")\n",
95 buffer, frameCount, startTime, endTime);
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;
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;
121 if (!playingIntervals.AddItem(interval)) {
122 delete interval;
123 error = B_NO_MEMORY;
124 ERROR("GetFrames() - Out of memory\n");
125 break;
127 intervalStartTime = interval->end_time;
129 fPlaybackManager->SetCurrentAudioTime(endTime);
130 fPlaybackManager->Unlock();
131 } else if (error == B_TIMED_OUT) {
132 TRACE("GetFrames() - LOCKING THE PLAYBACK MANAGER TIMED OUT!!!\n");
135 BAutolock _(fSupplierLock);
137 if (!fSupplier)
138 return B_ERROR;
140 // retrieve the audio data for each interval.
141 #ifdef TRACE_PROXY_AUDIO_SUPPLIER
142 int32 intervalIndex = 0;
143 #endif
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;
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);
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);
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);
183 // read silence on error
184 if (error != B_OK) {
185 _ReadSilence(buffer, framesToRead);
186 error = B_OK;
188 framesRead += framesToRead;
189 buffer = _SkipFrames(buffer, framesToRead);
190 delete interval;
192 #ifdef TRACE_PROXY_AUDIO_SUPPLIER
193 intervalIndex++;
194 #endif
196 // read silence on error
197 if (error != B_OK) {
198 _ReadSilence(buffer, frameCount);
199 error = B_OK;
202 TRACE("GetFrames() done\n");
204 return error;
208 void
209 ProxyAudioSupplier::SetFormat(const media_format& format)
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
218 BAutolock _(fSupplierLock);
220 fAudioResampler.SetFormat(format);
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);
229 const media_format&
230 ProxyAudioSupplier::Format() const
232 return fAudioResampler.Format();
236 status_t
237 ProxyAudioSupplier::InitCheck() const
239 status_t ret = AudioSupplier::InitCheck();
240 if (ret < B_OK)
241 return ret;
242 return B_OK;
246 void
247 ProxyAudioSupplier::SetSupplier(AudioTrackSupplier* supplier,
248 float videoFrameRate)
250 //printf("ProxyAudioSupplier::SetSupplier(%p, %.1f)\n", supplier,
251 //videoFrameRate);
252 TRACE("SetSupplier(%p, %.1f)\n", supplier, videoFrameRate);
254 BAutolock _(fSupplierLock);
256 fSupplier = supplier;
257 fVideoFrameRate = videoFrameRate;
259 delete fAdapter;
260 delete fVolumeConverter;
262 fAdapter = new AudioAdapter(fSupplier, Format());
263 fVolumeConverter = new AudioVolumeConverter(fAdapter, fVolume);
265 fAudioResampler.SetSource(fVolumeConverter);
269 void
270 ProxyAudioSupplier::SetVolume(float volume)
272 BAutolock _(fSupplierLock);
273 fVolume = volume;
274 if (fVolumeConverter)
275 fVolumeConverter->SetVolume(volume);
279 float
280 ProxyAudioSupplier::Volume()
282 BAutolock _(fSupplierLock);
283 return fVolume;
287 // #pragma mark - audio/video/frame/time conversion
290 int64
291 ProxyAudioSupplier::_AudioFrameForVideoFrame(int64 frame) const
293 if (!fSupplier) {
294 return (int64)((double)frame * Format().u.raw_audio.frame_rate
295 / fVideoFrameRate);
297 const media_format& format = fSupplier->Format();
298 return (int64)((double)frame * format.u.raw_audio.frame_rate
299 / fVideoFrameRate);
303 int64
304 ProxyAudioSupplier::_VideoFrameForAudioFrame(int64 frame) const
306 if (!fSupplier) {
307 return (int64)((double)frame * fVideoFrameRate
308 / Format().u.raw_audio.frame_rate);
311 const media_format& format = fSupplier->Format();
312 return (int64)((double)frame * fVideoFrameRate
313 / format.u.raw_audio.frame_rate);
317 int64
318 ProxyAudioSupplier::_AudioFrameForTime(bigtime_t time) const
320 return (int64)((double)time * Format().u.raw_audio.frame_rate
321 / 1000000.0);
325 int64
326 ProxyAudioSupplier::_VideoFrameForTime(bigtime_t time) const
328 return (int64)((double)time * fVideoFrameRate / 1000000.0);
332 // #pragma mark - utility
335 void
336 ProxyAudioSupplier::_ReadSilence(void* buffer, int64 frames) const
338 memset(buffer, 0, (char*)_SkipFrames(buffer, frames) - (char*)buffer);
342 void
343 ProxyAudioSupplier::_ReverseFrames(void* buffer, int64 frames) const
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;
359 void*
360 ProxyAudioSupplier::_SkipFrames(void* buffer, int64 frames) const
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;