From e625b68b04a400ba377ec0a5b958bde0bc6244ff Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:35 -0700 Subject: 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 --- arch/sandbox/cpu/sdl.c | 88 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 25 deletions(-) (limited to 'arch/sandbox/cpu/sdl.c') diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c index c7a8d945492..4dacdbf993f 100644 --- a/arch/sandbox/cpu/sdl.c +++ b/arch/sandbox/cpu/sdl.c @@ -13,6 +13,21 @@ enum { SAMPLE_RATE = 22050, }; +/** + * struct buf_info - a data buffer holding audio data + * + * @pos: Current position playing in audio buffer + * @size: Size of data in audio buffer (0=empty) + * @alloced: Allocated size of audio buffer (max size it can hold) + * @data: Audio data + */ +struct buf_info { + uint pos; + uint size; + uint alloced; + uint8_t *data; +}; + static struct sdl_info { SDL_Surface *screen; int width; @@ -20,12 +35,11 @@ static struct sdl_info { int depth; int pitch; uint frequency; - uint audio_pos; - uint audio_size; uint sample_rate; - uint8_t *audio_data; bool audio_active; bool inited; + int cur_buf; + struct buf_info buf[2]; } sdl; static void sandbox_sdl_poll_events(void) @@ -243,24 +257,37 @@ int sandbox_sdl_key_pressed(int keycode) void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len) { + struct buf_info *buf; int avail; + int i; - avail = sdl.audio_size - sdl.audio_pos; - if (avail < len) - len = avail; - - SDL_MixAudio(stream, sdl.audio_data + sdl.audio_pos, len, - SDL_MIX_MAXVOLUME); - sdl.audio_pos += len; - - /* Loop if we are at the end */ - if (sdl.audio_pos == sdl.audio_size) - sdl.audio_pos = 0; + for (i = 0; i < 2; i++) { + buf = &sdl.buf[sdl.cur_buf]; + avail = buf->size - buf->pos; + if (avail <= 0) { + sdl.cur_buf = 1 - sdl.cur_buf; + continue; + } + if (avail > len) + avail = len; + + SDL_MixAudio(stream, buf->data + buf->pos, avail, + SDL_MIX_MAXVOLUME); + buf->pos += avail; + len -= avail; + + /* Move to next buffer if we are at the end */ + if (buf->pos == buf->size) + buf->size = 0; + else + break; + } } int sandbox_sdl_sound_init(void) { SDL_AudioSpec wanted; + int i; if (sandbox_sdl_ensure_init()) return -1; @@ -276,13 +303,20 @@ int sandbox_sdl_sound_init(void) wanted.callback = sandbox_sdl_fill_audio; wanted.userdata = NULL; - sdl.audio_size = sizeof(uint16_t) * wanted.freq; - sdl.audio_data = malloc(sdl.audio_size); - if (!sdl.audio_data) { - printf("%s: Out of memory\n", __func__); - return -1; + for (i = 0; i < 2; i++) { + struct buf_info *buf = &sdl.buf[i]; + + buf->alloced = sizeof(uint16_t) * wanted.freq * wanted.channels; + buf->data = malloc(buf->alloced); + if (!buf->data) { + printf("%s: Out of memory\n", __func__); + if (i == 1) + free(sdl.buf[0].data); + return -1; + } + buf->pos = 0; + buf->size = 0; } - sdl.audio_pos = 0; if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) { printf("Unable to initialize SDL audio: %s\n", SDL_GetError()); @@ -296,23 +330,27 @@ int sandbox_sdl_sound_init(void) } sdl.audio_active = true; sdl.sample_rate = wanted.freq; + sdl.cur_buf = 0; return 0; err: - free(sdl.audio_data); + for (i = 0; i < 2; i++) + free(sdl.buf[i].data); return -1; } int sandbox_sdl_sound_start(uint frequency) { + struct buf_info *buf = &sdl.buf[0]; + if (!sdl.audio_active) return -1; sdl.frequency = frequency; - sound_create_square_wave(sdl.sample_rate, - (unsigned short *)sdl.audio_data, - sdl.audio_size, frequency); - sdl.audio_pos = 0; + sound_create_square_wave(sdl.sample_rate, (unsigned short *)buf->data, + buf->alloced, frequency); + buf->pos = 0; + buf->size = buf->alloced; SDL_PauseAudio(0); return 0; -- cgit v1.2.3 From 282e29eb4728c43fa42fcba816188cd5523bb6ee Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:45 -0700 Subject: dm: sandbox: sound: Convert to use driver model Update sandbox's device tree and config to use driver model for sound. Use the double buffer for sound output so that we don't need to wait for the sound to complete before returning. Signed-off-by: Simon Glass --- arch/sandbox/cpu/sdl.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'arch/sandbox/cpu/sdl.c') diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c index 4dacdbf993f..32fa1fffc9b 100644 --- a/arch/sandbox/cpu/sdl.c +++ b/arch/sandbox/cpu/sdl.c @@ -4,6 +4,7 @@ */ #include +#include #include #include #include @@ -40,6 +41,7 @@ static struct sdl_info { bool inited; int cur_buf; struct buf_info buf[2]; + bool running; } sdl; static void sandbox_sdl_poll_events(void) @@ -331,6 +333,7 @@ int sandbox_sdl_sound_init(void) sdl.audio_active = true; sdl.sample_rate = wanted.freq; sdl.cur_buf = 0; + sdl.running = 0; return 0; @@ -340,27 +343,39 @@ err: return -1; } -int sandbox_sdl_sound_start(uint frequency) +int sandbox_sdl_sound_play(const void *data, uint size) { - struct buf_info *buf = &sdl.buf[0]; + struct buf_info *buf; if (!sdl.audio_active) - return -1; - sdl.frequency = frequency; - sound_create_square_wave(sdl.sample_rate, (unsigned short *)buf->data, - buf->alloced, frequency); + return 0; + + buf = &sdl.buf[0]; + if (buf->size) + buf = &sdl.buf[1]; + while (buf->size) + usleep(1000); + + if (size > buf->alloced) + return -E2BIG; + + memcpy(buf->data, data, size); + buf->size = size; buf->pos = 0; - buf->size = buf->alloced; - SDL_PauseAudio(0); + if (!sdl.running) { + SDL_PauseAudio(0); + sdl.running = 1; + } return 0; } int sandbox_sdl_sound_stop(void) { - if (!sdl.audio_active) - return -1; - SDL_PauseAudio(1); + if (sdl.running) { + SDL_PauseAudio(1); + sdl.running = 0; + } return 0; } -- cgit v1.2.3 From f2b25c9bf8212139f43ded090c78d604babc4337 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:47 -0700 Subject: dm: sound: Complete migration to driver model All users of sound are converted to use driver model. Drop the old code and the CONFIG_DM_SOUND option. Signed-off-by: Simon Glass --- arch/sandbox/cpu/sdl.c | 1 - 1 file changed, 1 deletion(-) (limited to 'arch/sandbox/cpu/sdl.c') diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c index 32fa1fffc9b..47b706513e4 100644 --- a/arch/sandbox/cpu/sdl.c +++ b/arch/sandbox/cpu/sdl.c @@ -7,7 +7,6 @@ #include #include #include -#include #include enum { -- cgit v1.2.3 From e221cdcf44c80a6de78fd9285c5325db231ed20c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 10 Dec 2018 10:37:50 -0700 Subject: dm: sandbox: Allow selection of sample rate and channels At present these parameters are hard-coded in the sdl interface code. Allow them to be specified by the driver instead. Signed-off-by: Simon Glass --- arch/sandbox/cpu/sdl.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'arch/sandbox/cpu/sdl.c') diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c index 47b706513e4..f668f5379a4 100644 --- a/arch/sandbox/cpu/sdl.c +++ b/arch/sandbox/cpu/sdl.c @@ -9,10 +9,6 @@ #include #include -enum { - SAMPLE_RATE = 22050, -}; - /** * struct buf_info - a data buffer holding audio data * @@ -285,7 +281,7 @@ void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len) } } -int sandbox_sdl_sound_init(void) +int sandbox_sdl_sound_init(int rate, int channels) { SDL_AudioSpec wanted; int i; @@ -297,9 +293,9 @@ int sandbox_sdl_sound_init(void) return 0; /* Set the audio format */ - wanted.freq = SAMPLE_RATE; + wanted.freq = rate; wanted.format = AUDIO_S16; - wanted.channels = 1; /* 1 = mono, 2 = stereo */ + wanted.channels = channels; wanted.samples = 1024; /* Good low-latency value for callback */ wanted.callback = sandbox_sdl_fill_audio; wanted.userdata = NULL; -- cgit v1.2.3