|
@@ -41,15 +41,11 @@
|
|
|
|
|
|
typedef struct SDLVoiceOut {
|
|
typedef struct SDLVoiceOut {
|
|
HWVoiceOut hw;
|
|
HWVoiceOut hw;
|
|
-} SDLVoiceOut;
|
|
|
|
-
|
|
|
|
-static struct SDLAudioState {
|
|
|
|
int exit;
|
|
int exit;
|
|
int initialized;
|
|
int initialized;
|
|
- bool driver_created;
|
|
|
|
Audiodev *dev;
|
|
Audiodev *dev;
|
|
-} glob_sdl;
|
|
|
|
-typedef struct SDLAudioState SDLAudioState;
|
|
|
|
|
|
+ SDL_AudioDeviceID devid;
|
|
|
|
+} SDLVoiceOut;
|
|
|
|
|
|
static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
|
|
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;
|
|
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
|
|
#ifndef _WIN32
|
|
int err;
|
|
int err;
|
|
sigset_t new, old;
|
|
sigset_t new, old;
|
|
@@ -166,18 +163,19 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
|
|
err = sigfillset (&new);
|
|
err = sigfillset (&new);
|
|
if (err) {
|
|
if (err) {
|
|
dolog ("sdl_open: sigfillset failed: %s\n", strerror (errno));
|
|
dolog ("sdl_open: sigfillset failed: %s\n", strerror (errno));
|
|
- return -1;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
err = pthread_sigmask (SIG_BLOCK, &new, &old);
|
|
err = pthread_sigmask (SIG_BLOCK, &new, &old);
|
|
if (err) {
|
|
if (err) {
|
|
dolog ("sdl_open: pthread_sigmask failed: %s\n", strerror (err));
|
|
dolog ("sdl_open: pthread_sigmask failed: %s\n", strerror (err));
|
|
- return -1;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
#endif
|
|
#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
|
|
#ifndef _WIN32
|
|
@@ -190,30 +188,32 @@ static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt)
|
|
exit (EXIT_FAILURE);
|
|
exit (EXIT_FAILURE);
|
|
}
|
|
}
|
|
#endif
|
|
#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;
|
|
SDLVoiceOut *sdl = opaque;
|
|
- SDLAudioState *s = &glob_sdl;
|
|
|
|
HWVoiceOut *hw = &sdl->hw;
|
|
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) {
|
|
while (hw->pending_emul && len) {
|
|
size_t write_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 \
|
|
static ret_type glue(sdl_, name)args_decl \
|
|
{ \
|
|
{ \
|
|
ret_type ret; \
|
|
ret_type ret; \
|
|
|
|
+ glue(SDLVoice, dir) *sdl = (glue(SDLVoice, dir) *)hw; \
|
|
\
|
|
\
|
|
- SDL_LockAudio(); \
|
|
|
|
|
|
+ SDL_LockAudioDevice(sdl->devid); \
|
|
ret = glue(audio_generic_, name)args; \
|
|
ret = glue(audio_generic_, name)args; \
|
|
- SDL_UnlockAudio(); \
|
|
|
|
|
|
+ SDL_UnlockAudioDevice(sdl->devid); \
|
|
\
|
|
\
|
|
return ret; \
|
|
return ret; \
|
|
}
|
|
}
|
|
|
|
|
|
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
|
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,
|
|
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,
|
|
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
|
|
#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,
|
|
static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|
void *drv_opaque)
|
|
void *drv_opaque)
|
|
{
|
|
{
|
|
- SDLVoiceOut *sdl = (SDLVoiceOut *) hw;
|
|
|
|
- SDLAudioState *s = &glob_sdl;
|
|
|
|
|
|
+ SDLVoiceOut *sdl = (SDLVoiceOut *)hw;
|
|
SDL_AudioSpec req, obt;
|
|
SDL_AudioSpec req, obt;
|
|
int endianness;
|
|
int endianness;
|
|
int err;
|
|
int err;
|
|
AudioFormat effective_fmt;
|
|
AudioFormat effective_fmt;
|
|
- AudiodevSdlPerDirectionOptions *spdo = s->dev->u.sdl.out;
|
|
|
|
|
|
+ Audiodev *dev = drv_opaque;
|
|
|
|
+ AudiodevSdlPerDirectionOptions *spdo = dev->u.sdl.out;
|
|
struct audsettings obt_as;
|
|
struct audsettings obt_as;
|
|
|
|
|
|
req.freq = as->freq;
|
|
req.freq = as->freq;
|
|
@@ -288,16 +289,18 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|
*/
|
|
*/
|
|
req.samples = audio_buffer_samples(
|
|
req.samples = audio_buffer_samples(
|
|
qapi_AudiodevSdlPerDirectionOptions_base(spdo), as, 11610);
|
|
qapi_AudiodevSdlPerDirectionOptions_base(spdo), as, 11610);
|
|
- req.callback = sdl_callback;
|
|
|
|
|
|
+ req.callback = sdl_callback_out;
|
|
req.userdata = sdl;
|
|
req.userdata = sdl;
|
|
|
|
|
|
- if (sdl_open (&req, &obt)) {
|
|
|
|
|
|
+ sdl->dev = dev;
|
|
|
|
+ sdl->devid = sdl_open(&req, &obt, 0);
|
|
|
|
+ if (!sdl->devid) {
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
|
|
err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
|
|
if (err) {
|
|
if (err) {
|
|
- sdl_close (s);
|
|
|
|
|
|
+ sdl_close_out(sdl);
|
|
return -1;
|
|
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) *
|
|
hw->samples = (spdo->has_buffer_count ? spdo->buffer_count : 4) *
|
|
obt.samples;
|
|
obt.samples;
|
|
|
|
|
|
- s->initialized = 1;
|
|
|
|
- s->exit = 0;
|
|
|
|
|
|
+ sdl->initialized = 1;
|
|
|
|
+ sdl->exit = 0;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void sdl_enable_out(HWVoiceOut *hw, bool enable)
|
|
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)
|
|
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)) {
|
|
if (SDL_InitSubSystem (SDL_INIT_AUDIO)) {
|
|
sdl_logerr ("SDL failed to initialize audio subsystem\n");
|
|
sdl_logerr ("SDL failed to initialize audio subsystem\n");
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
- s->driver_created = true;
|
|
|
|
- s->dev = dev;
|
|
|
|
- return s;
|
|
|
|
|
|
+ return dev;
|
|
}
|
|
}
|
|
|
|
|
|
static void sdl_audio_fini (void *opaque)
|
|
static void sdl_audio_fini (void *opaque)
|
|
{
|
|
{
|
|
- SDLAudioState *s = opaque;
|
|
|
|
- sdl_close (s);
|
|
|
|
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
|
SDL_QuitSubSystem (SDL_INIT_AUDIO);
|
|
- s->driver_created = false;
|
|
|
|
- s->dev = NULL;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static struct audio_pcm_ops sdl_pcm_ops = {
|
|
static struct audio_pcm_ops sdl_pcm_ops = {
|