sdlaudio: replace legacy functions with modern ones
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>
This commit is contained in:
parent
e02d178f78
commit
ce31f099fb
107
audio/sdlaudio.c
107
audio/sdlaudio.c
@ -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, ...)
|
||||
{
|
||||
@ -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;
|
||||
@ -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
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 = {
|
||||
|
Loading…
Reference in New Issue
Block a user