Commit e625b68b04a400ba377ec0a5b958bde0bc6244ff
1 parent
e96fa6c911
Exists in
smarc_8mq_lf_v2020.04
and in
12 other branches
dm: sandbox: Update sound to use two buffers
At present we use a single buffer for sound which means we cannot be playing one sound while queueing up the next. This wouldn't matter except that a long sound (more than a second) has to be created as a single buffer, thus using a lot of memory. To better mimic what real sound drivers do, add support for double buffering in sandbox. Signed-off-by: Simon Glass <sjg@chromium.org>
Showing 1 changed file with 63 additions and 25 deletions Side-by-side Diff
arch/sandbox/cpu/sdl.c
... | ... | @@ -13,6 +13,21 @@ |
13 | 13 | SAMPLE_RATE = 22050, |
14 | 14 | }; |
15 | 15 | |
16 | +/** | |
17 | + * struct buf_info - a data buffer holding audio data | |
18 | + * | |
19 | + * @pos: Current position playing in audio buffer | |
20 | + * @size: Size of data in audio buffer (0=empty) | |
21 | + * @alloced: Allocated size of audio buffer (max size it can hold) | |
22 | + * @data: Audio data | |
23 | + */ | |
24 | +struct buf_info { | |
25 | + uint pos; | |
26 | + uint size; | |
27 | + uint alloced; | |
28 | + uint8_t *data; | |
29 | +}; | |
30 | + | |
16 | 31 | static struct sdl_info { |
17 | 32 | SDL_Surface *screen; |
18 | 33 | int width; |
19 | 34 | |
20 | 35 | |
... | ... | @@ -20,12 +35,11 @@ |
20 | 35 | int depth; |
21 | 36 | int pitch; |
22 | 37 | uint frequency; |
23 | - uint audio_pos; | |
24 | - uint audio_size; | |
25 | 38 | uint sample_rate; |
26 | - uint8_t *audio_data; | |
27 | 39 | bool audio_active; |
28 | 40 | bool inited; |
41 | + int cur_buf; | |
42 | + struct buf_info buf[2]; | |
29 | 43 | } sdl; |
30 | 44 | |
31 | 45 | static void sandbox_sdl_poll_events(void) |
32 | 46 | |
33 | 47 | |
34 | 48 | |
35 | 49 | |
36 | 50 | |
... | ... | @@ -243,24 +257,37 @@ |
243 | 257 | |
244 | 258 | void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len) |
245 | 259 | { |
260 | + struct buf_info *buf; | |
246 | 261 | int avail; |
262 | + int i; | |
247 | 263 | |
248 | - avail = sdl.audio_size - sdl.audio_pos; | |
249 | - if (avail < len) | |
250 | - len = avail; | |
264 | + for (i = 0; i < 2; i++) { | |
265 | + buf = &sdl.buf[sdl.cur_buf]; | |
266 | + avail = buf->size - buf->pos; | |
267 | + if (avail <= 0) { | |
268 | + sdl.cur_buf = 1 - sdl.cur_buf; | |
269 | + continue; | |
270 | + } | |
271 | + if (avail > len) | |
272 | + avail = len; | |
251 | 273 | |
252 | - SDL_MixAudio(stream, sdl.audio_data + sdl.audio_pos, len, | |
253 | - SDL_MIX_MAXVOLUME); | |
254 | - sdl.audio_pos += len; | |
274 | + SDL_MixAudio(stream, buf->data + buf->pos, avail, | |
275 | + SDL_MIX_MAXVOLUME); | |
276 | + buf->pos += avail; | |
277 | + len -= avail; | |
255 | 278 | |
256 | - /* Loop if we are at the end */ | |
257 | - if (sdl.audio_pos == sdl.audio_size) | |
258 | - sdl.audio_pos = 0; | |
279 | + /* Move to next buffer if we are at the end */ | |
280 | + if (buf->pos == buf->size) | |
281 | + buf->size = 0; | |
282 | + else | |
283 | + break; | |
284 | + } | |
259 | 285 | } |
260 | 286 | |
261 | 287 | int sandbox_sdl_sound_init(void) |
262 | 288 | { |
263 | 289 | SDL_AudioSpec wanted; |
290 | + int i; | |
264 | 291 | |
265 | 292 | if (sandbox_sdl_ensure_init()) |
266 | 293 | return -1; |
267 | 294 | |
... | ... | @@ -276,13 +303,20 @@ |
276 | 303 | wanted.callback = sandbox_sdl_fill_audio; |
277 | 304 | wanted.userdata = NULL; |
278 | 305 | |
279 | - sdl.audio_size = sizeof(uint16_t) * wanted.freq; | |
280 | - sdl.audio_data = malloc(sdl.audio_size); | |
281 | - if (!sdl.audio_data) { | |
282 | - printf("%s: Out of memory\n", __func__); | |
283 | - return -1; | |
306 | + for (i = 0; i < 2; i++) { | |
307 | + struct buf_info *buf = &sdl.buf[i]; | |
308 | + | |
309 | + buf->alloced = sizeof(uint16_t) * wanted.freq * wanted.channels; | |
310 | + buf->data = malloc(buf->alloced); | |
311 | + if (!buf->data) { | |
312 | + printf("%s: Out of memory\n", __func__); | |
313 | + if (i == 1) | |
314 | + free(sdl.buf[0].data); | |
315 | + return -1; | |
316 | + } | |
317 | + buf->pos = 0; | |
318 | + buf->size = 0; | |
284 | 319 | } |
285 | - sdl.audio_pos = 0; | |
286 | 320 | |
287 | 321 | if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { |
288 | 322 | printf("Unable to initialize SDL audio: %s\n", SDL_GetError()); |
289 | 323 | |
290 | 324 | |
291 | 325 | |
... | ... | @@ -296,23 +330,27 @@ |
296 | 330 | } |
297 | 331 | sdl.audio_active = true; |
298 | 332 | sdl.sample_rate = wanted.freq; |
333 | + sdl.cur_buf = 0; | |
299 | 334 | |
300 | 335 | return 0; |
301 | 336 | |
302 | 337 | err: |
303 | - free(sdl.audio_data); | |
338 | + for (i = 0; i < 2; i++) | |
339 | + free(sdl.buf[i].data); | |
304 | 340 | return -1; |
305 | 341 | } |
306 | 342 | |
307 | 343 | int sandbox_sdl_sound_start(uint frequency) |
308 | 344 | { |
345 | + struct buf_info *buf = &sdl.buf[0]; | |
346 | + | |
309 | 347 | if (!sdl.audio_active) |
310 | 348 | return -1; |
311 | 349 | sdl.frequency = frequency; |
312 | - sound_create_square_wave(sdl.sample_rate, | |
313 | - (unsigned short *)sdl.audio_data, | |
314 | - sdl.audio_size, frequency); | |
315 | - sdl.audio_pos = 0; | |
350 | + sound_create_square_wave(sdl.sample_rate, (unsigned short *)buf->data, | |
351 | + buf->alloced, frequency); | |
352 | + buf->pos = 0; | |
353 | + buf->size = buf->alloced; | |
316 | 354 | SDL_PauseAudio(0); |
317 | 355 | |
318 | 356 | return 0; |