Skip to content

Commit

Permalink
sdlaudio: replace legacy functions with modern ones
Browse files Browse the repository at this point in the history
With the modern audio functions it's possible to add new
features like audio recording.

As a side effect this patch fixes a bug where SDL2 can't be used
on Windows. This bug was reported on the qemu-devel mailing list at

https://lists.nongnu.org/archive/html/qemu-devel/2020-01/msg04043.html

Signed-off-by: Volker Rümelin <vr_qemu@t-online.de>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Message-id: 9315afe5-5958-c0b4-ea1e-14769511a9d5@t-online.de
Message-Id: <20210110100239.27588-7-vr_qemu@t-online.de>
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
  • Loading branch information
Volker Rümelin authored and kraxel committed Jan 15, 2021
1 parent e02d178 commit ce31f09
Showing 1 changed file with 50 additions and 57 deletions.
107 changes: 50 additions & 57 deletions audio/sdlaudio.c
Expand Up @@ -41,15 +41,11 @@

typedef struct SDLVoiceOut {
HWVoiceOut hw;
} SDLVoiceOut;

static struct SDLAudioState {
int exit;
int initialized;
bool driver_created;
Audiodev *dev;
} glob_sdl;
typedef struct SDLAudioState SDLAudioState;
SDL_AudioDeviceID devid;
} SDLVoiceOut;

static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
{
Expand Down Expand Up @@ -155,9 +151,10 @@ static int sdl_to_audfmt(int sdlfmt, AudioFormat *fmt, int *endianness)
return 0;
}

static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
static SDL_AudioDeviceID sdl_open(SDL_AudioSpec *req, SDL_AudioSpec *obt,
int rec)
{
int status;
SDL_AudioDeviceID devid;
#ifndef _WIN32
int err;
sigset_t new, old;
Expand All @@ -166,18 +163,19 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
err = sigfillset (&new);
if (err) {
dolog ("sdl_open: sigfillset failed: %s\n", strerror (errno));
return -1;
return 0;
}
err = pthread_sigmask (SIG_BLOCK, &new, &old);
if (err) {
dolog ("sdl_open: pthread_sigmask failed: %s\n", strerror (err));
return -1;
return 0;
}
#endif

status = SDL_OpenAudio (req, obt);
if (status) {
sdl_logerr ("SDL_OpenAudio failed\n");
devid = SDL_OpenAudioDevice(NULL, rec, req, obt, 0);
if (!devid) {
sdl_logerr("SDL_OpenAudioDevice for %s failed\n",
rec ? "recording" : "playback");
}

#ifndef _WIN32
Expand All @@ -190,30 +188,32 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
exit (EXIT_FAILURE);
}
#endif
return status;
return devid;
}

static void sdl_close (SDLAudioState *s)
static void sdl_close_out(SDLVoiceOut *sdl)
{
if (s->initialized) {
SDL_LockAudio();
s->exit = 1;
SDL_UnlockAudio();
SDL_PauseAudio (1);
SDL_CloseAudio ();
s->initialized = 0;
if (sdl->initialized) {
SDL_LockAudioDevice(sdl->devid);
sdl->exit = 1;
SDL_UnlockAudioDevice(sdl->devid);
SDL_PauseAudioDevice(sdl->devid, 1);
sdl->initialized = 0;
}
if (sdl->devid) {
SDL_CloseAudioDevice(sdl->devid);
sdl->devid = 0;
}
}

static void sdl_callback (void *opaque, Uint8 *buf, int len)
static void sdl_callback_out(void *opaque, Uint8 *buf, int len)
{
SDLVoiceOut *sdl = opaque;
SDLAudioState *s = &glob_sdl;
HWVoiceOut *hw = &sdl->hw;

if (!s->exit) {
if (!sdl->exit) {

/* dolog("callback: len=%d avail=%zu\n", len, hw->pending_emul); */
/* dolog("callback_out: len=%d avail=%zu\n", len, hw->pending_emul); */

while (hw->pending_emul && len) {
size_t write_len;
Expand All @@ -240,43 +240,44 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
}
}

#define SDL_WRAPPER_FUNC(name, ret_type, args_decl, args) \
#define SDL_WRAPPER_FUNC(name, ret_type, args_decl, args, dir) \
static ret_type glue(sdl_, name)args_decl \
{ \
ret_type ret; \
glue(SDLVoice, dir) *sdl = (glue(SDLVoice, dir) *)hw; \
\
SDL_LockAudio(); \
SDL_LockAudioDevice(sdl->devid); \
ret = glue(audio_generic_, name)args; \
SDL_UnlockAudio(); \
SDL_UnlockAudioDevice(sdl->devid); \
\
return ret; \
}

SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
(hw, size))
(hw, size), Out)
SDL_WRAPPER_FUNC(put_buffer_out, size_t,
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size))
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size), Out)
SDL_WRAPPER_FUNC(write, size_t,
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size))
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size), Out)
#undef SDL_WRAPPER_FUNC

static void sdl_fini_out (HWVoiceOut *hw)
static void sdl_fini_out(HWVoiceOut *hw)
{
(void) hw;
SDLVoiceOut *sdl = (SDLVoiceOut *)hw;

sdl_close (&glob_sdl);
sdl_close_out(sdl);
}

static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
void *drv_opaque)
{
SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
SDLAudioState *s = &glob_sdl;
SDLVoiceOut *sdl = (SDLVoiceOut *)hw;
SDL_AudioSpec req, obt;
int endianness;
int err;
AudioFormat effective_fmt;
AudiodevSdlPerDirectionOptions *spdo = s->dev->u.sdl.out;
Audiodev *dev = drv_opaque;
AudiodevSdlPerDirectionOptions *spdo = dev->u.sdl.out;
struct audsettings obt_as;

req.freq = as->freq;
Expand All @@ -288,16 +289,18 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
*/
req.samples = audio_buffer_samples(
qapi_AudiodevSdlPerDirectionOptions_base(spdo), as, 11610);
req.callback = sdl_callback;
req.callback = sdl_callback_out;
req.userdata = sdl;

if (sdl_open (&req, &obt)) {
sdl->dev = dev;
sdl->devid = sdl_open(&req, &obt, 0);
if (!sdl->devid) {
return -1;
}

err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
if (err) {
sdl_close (s);
sdl_close_out(sdl);
return -1;
}

Expand All @@ -310,41 +313,31 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
hw->samples = (spdo->has_buffer_count ? spdo->buffer_count : 4) *
obt.samples;

s->initialized = 1;
s->exit = 0;
sdl->initialized = 1;
sdl->exit = 0;
return 0;
}

static void sdl_enable_out(HWVoiceOut *hw, bool enable)
{
SDL_PauseAudio(!enable);
SDLVoiceOut *sdl = (SDLVoiceOut *)hw;

SDL_PauseAudioDevice(sdl->devid, !enable);
}

static void *sdl_audio_init(Audiodev *dev)
{
SDLAudioState *s = &glob_sdl;
if (s->driver_created) {
sdl_logerr("Can't create multiple sdl backends\n");
return NULL;
}

if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
sdl_logerr ("SDL failed to initialize audio subsystem\n");
return NULL;
}

s->driver_created = true;
s->dev = dev;
return s;
return dev;
}

static void sdl_audio_fini (void *opaque)
{
SDLAudioState *s = opaque;
sdl_close (s);
SDL_QuitSubSystem (SDL_INIT_AUDIO);
s->driver_created = false;
s->dev = NULL;
}

static struct audio_pcm_ops sdl_pcm_ops = {
Expand Down

0 comments on commit ce31f09

Please sign in to comment.