summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Maydell2021-01-15 23:21:21 +0100
committerPeter Maydell2021-01-15 23:21:21 +0100
commit825a215c003cd028e26c7d19aa5049d957345f43 (patch)
treea3bedcc1d73490abbe5994b065289147f8d0b10e
parentMerge remote-tracking branch 'remotes/kraxel/tags/ui-20210115-pull-request' i... (diff)
parentaudio: space prohibited between function name and parenthesis'(' (diff)
downloadqemu-825a215c003cd028e26c7d19aa5049d957345f43.tar.gz
qemu-825a215c003cd028e26c7d19aa5049d957345f43.tar.xz
qemu-825a215c003cd028e26c7d19aa5049d957345f43.zip
Merge remote-tracking branch 'remotes/kraxel/tags/audio-20210115-pull-request' into staging
audio: improvements for sdl, pulse, fsound. audio: cleanups & codestyle fixes. # gpg: Signature made Fri 15 Jan 2021 13:20:56 GMT # gpg: using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <kraxel@redhat.com>" [full] # gpg: aka "Gerd Hoffmann <gerd@kraxel.org>" [full] # gpg: aka "Gerd Hoffmann (private) <kraxel@gmail.com>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/audio-20210115-pull-request: (30 commits) audio: space prohibited between function name and parenthesis'(' audio: Suspect code indent for conditional statements audio: Don't use '%#' in format strings audio: Fix lines over 90 characters audio: foo* bar" should be "foo *bar". audio: Add spaces around operator/delete redundant spaces audio: Add braces for statements/fix braces' position dsoundaudio: fix log message dsoundaudio: enable f32 audio sample format dsoundaudio: rename dsound_open() dsoundaudio: replace GetForegroundWindow() paaudio: send recorded data in smaller chunks paaudio: limit minreq to 75% of audio timer_rate paaudio: comment bugs in functions qpa_init_* paaudio: remove unneeded code paaudio: wait until the playback stream is ready paaudio: wait for PA_STREAM_READY in qpa_write() paaudio: avoid to clip samples multiple times audio: remove remaining unused plive code sdlaudio: enable (in|out).mixing-engine=off ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--audio/alsaaudio.c18
-rw-r--r--audio/audio.c74
-rw-r--r--audio/audio_int.h2
-rw-r--r--audio/audio_legacy.c3
-rw-r--r--audio/audio_template.h26
-rw-r--r--audio/audio_win_int.c73
-rw-r--r--audio/coreaudio.c17
-rw-r--r--audio/dsound_template.h2
-rw-r--r--audio/dsoundaudio.c56
-rw-r--r--audio/jackaudio.c3
-rw-r--r--audio/noaudio.c1
-rw-r--r--audio/ossaudio.c13
-rw-r--r--audio/paaudio.c73
-rw-r--r--audio/sdlaudio.c305
-rw-r--r--audio/spiceaudio.c1
-rw-r--r--qapi/audio.json33
-rw-r--r--qemu-options.hx8
17 files changed, 472 insertions, 236 deletions
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c
index a8e62542f9..fcc2f62864 100644
--- a/audio/alsaaudio.c
+++ b/audio/alsaaudio.c
@@ -278,32 +278,28 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
case AUDIO_FORMAT_S16:
if (endianness) {
return SND_PCM_FORMAT_S16_BE;
- }
- else {
+ } else {
return SND_PCM_FORMAT_S16_LE;
}
case AUDIO_FORMAT_U16:
if (endianness) {
return SND_PCM_FORMAT_U16_BE;
- }
- else {
+ } else {
return SND_PCM_FORMAT_U16_LE;
}
case AUDIO_FORMAT_S32:
if (endianness) {
return SND_PCM_FORMAT_S32_BE;
- }
- else {
+ } else {
return SND_PCM_FORMAT_S32_LE;
}
case AUDIO_FORMAT_U32:
if (endianness) {
return SND_PCM_FORMAT_U32_BE;
- }
- else {
+ } else {
return SND_PCM_FORMAT_U32_LE;
}
@@ -599,7 +595,7 @@ static int alsa_open(bool in, struct alsa_params_req *req,
}
#ifdef DEBUG
- alsa_dump_info(req, obt, obtfmt, pdo);
+ alsa_dump_info(req, obt, obtfmt, apdo);
#endif
return 0;
@@ -722,8 +718,7 @@ static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl)
alsa_logerr (err, "Could not stop %s\n", typ);
return -1;
}
- }
- else {
+ } else {
err = snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr (err, "Could not prepare handle for %s\n", typ);
@@ -929,6 +924,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
.init_in = alsa_init_in,
.fini_in = alsa_fini_in,
.read = alsa_read,
+ .run_buffer_in = audio_generic_run_buffer_in,
.enable_in = alsa_enable_in,
};
diff --git a/audio/audio.c b/audio/audio.c
index b48471bb3f..6734c8af70 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -344,8 +344,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
if (info->is_signed || info->is_float) {
memset(buf, 0x00, len * info->bytes_per_frame);
- }
- else {
+ } else {
switch (info->bits) {
case 8:
memset(buf, 0x80, len * info->bytes_per_frame);
@@ -584,8 +583,7 @@ static size_t audio_pcm_sw_get_rpos_in(SWVoiceIn *sw)
rpos = hw->conv_buf->pos - live;
if (rpos >= 0) {
return rpos;
- }
- else {
+ } else {
return hw->conv_buf->size + rpos;
}
}
@@ -788,10 +786,14 @@ static int audio_is_timer_needed(AudioState *s)
HWVoiceOut *hwo = NULL;
while ((hwo = audio_pcm_hw_find_any_enabled_out(s, hwo))) {
- if (!hwo->poll_mode) return 1;
+ if (!hwo->poll_mode) {
+ return 1;
+ }
}
while ((hwi = audio_pcm_hw_find_any_enabled_in(s, hwi))) {
- if (!hwi->poll_mode) return 1;
+ if (!hwi->poll_mode) {
+ return 1;
+ }
}
return 0;
}
@@ -908,8 +910,7 @@ void AUD_set_active_out (SWVoiceOut *sw, int on)
audio_reset_timer (s);
}
}
- }
- else {
+ } else {
if (hw->enabled) {
int nb_active = 0;
@@ -956,8 +957,7 @@ void AUD_set_active_in (SWVoiceIn *sw, int on)
}
}
sw->total_hw_samples_acquired = hw->total_samples_captured;
- }
- else {
+ } else {
if (hw->enabled) {
int nb_active = 0;
@@ -1132,7 +1132,7 @@ static void audio_run_out (AudioState *s)
while ((hw = audio_pcm_hw_find_any_enabled_out(s, hw))) {
size_t played, live, prev_rpos, free;
- int nb_live, cleanup_required;
+ int nb_live;
live = audio_pcm_hw_get_live_out (hw, &nb_live);
if (!nb_live) {
@@ -1194,7 +1194,6 @@ static void audio_run_out (AudioState *s)
audio_capture_mix_and_clear (hw, prev_rpos, played);
}
- cleanup_required = 0;
for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) {
if (!sw->active && sw->empty) {
continue;
@@ -1210,7 +1209,6 @@ static void audio_run_out (AudioState *s)
if (!sw->total_hw_samples_mixed) {
sw->empty = 1;
- cleanup_required |= !sw->active && !sw->callback.fn;
}
if (sw->active) {
@@ -1220,19 +1218,6 @@ static void audio_run_out (AudioState *s)
}
}
}
-
- if (cleanup_required) {
- SWVoiceOut *sw1;
-
- sw = hw->sw_head.lh_first;
- while (sw) {
- sw1 = sw->entries.le_next;
- if (!sw->active && !sw->callback.fn) {
- audio_close_out (sw);
- }
- sw = sw1;
- }
- }
}
}
@@ -1241,6 +1226,10 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
size_t conv = 0;
STSampleBuffer *conv_buf = hw->conv_buf;
+ if (hw->pcm_ops->run_buffer_in) {
+ hw->pcm_ops->run_buffer_in(hw);
+ }
+
while (samples) {
size_t proc;
size_t size = samples * hw->info.bytes_per_frame;
@@ -1381,14 +1370,11 @@ void audio_run(AudioState *s, const char *msg)
#endif
}
-void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
+void audio_generic_run_buffer_in(HWVoiceIn *hw)
{
- ssize_t start;
-
if (unlikely(!hw->buf_emul)) {
- size_t calc_size = hw->conv_buf->size * hw->info.bytes_per_frame;
- hw->buf_emul = g_malloc(calc_size);
- hw->size_emul = calc_size;
+ hw->size_emul = hw->samples * hw->info.bytes_per_frame;
+ hw->buf_emul = g_malloc(hw->size_emul);
hw->pos_emul = hw->pending_emul = 0;
}
@@ -1403,8 +1389,12 @@ void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
break;
}
}
+}
+
+void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
+{
+ ssize_t start = (ssize_t)hw->pos_emul - hw->pending_emul;
- start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
if (start < 0) {
start += hw->size_emul;
}
@@ -1446,10 +1436,8 @@ void audio_generic_run_buffer_out(HWVoiceOut *hw)
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
{
if (unlikely(!hw->buf_emul)) {
- size_t calc_size = hw->mix_buf->size * hw->info.bytes_per_frame;
-
- hw->buf_emul = g_malloc(calc_size);
- hw->size_emul = calc_size;
+ hw->size_emul = hw->samples * hw->info.bytes_per_frame;
+ hw->buf_emul = g_malloc(hw->size_emul);
hw->pos_emul = hw->pending_emul = 0;
}
@@ -1505,6 +1493,10 @@ size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
{
size_t total = 0;
+ if (hw->pcm_ops->run_buffer_in) {
+ hw->pcm_ops->run_buffer_in(hw);
+ }
+
while (total < size) {
size_t src_size = size - total;
void *src = hw->pcm_ops->get_buffer_in(hw, &src_size);
@@ -1540,8 +1532,7 @@ static int audio_driver_init(AudioState *s, struct audio_driver *drv,
audio_init_nb_voices_in(s, drv);
s->drv = drv;
return 0;
- }
- else {
+ } else {
if (msg) {
dolog("Could not init `%s' audio driver\n", drv->name);
}
@@ -1856,8 +1847,7 @@ CaptureVoiceOut *AUD_add_capture(
if (cap) {
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
return cap;
- }
- else {
+ } else {
HWVoiceOut *hw;
CaptureVoiceOut *cap;
@@ -2003,7 +1993,7 @@ void audio_create_pdos(Audiodev *dev)
CASE(JACK, jack, Jack);
CASE(OSS, oss, Oss);
CASE(PA, pa, Pa);
- CASE(SDL, sdl, );
+ CASE(SDL, sdl, Sdl);
CASE(SPICE, spice, );
CASE(WAV, wav, );
diff --git a/audio/audio_int.h b/audio/audio_int.h
index 4775857bf2..06f0913835 100644
--- a/audio/audio_int.h
+++ b/audio/audio_int.h
@@ -172,12 +172,14 @@ struct audio_pcm_ops {
int (*init_in) (HWVoiceIn *hw, audsettings *as, void *drv_opaque);
void (*fini_in) (HWVoiceIn *hw);
size_t (*read) (HWVoiceIn *hw, void *buf, size_t size);
+ void (*run_buffer_in)(HWVoiceIn *hw);
void *(*get_buffer_in)(HWVoiceIn *hw, size_t *size);
void (*put_buffer_in)(HWVoiceIn *hw, void *buf, size_t size);
void (*enable_in)(HWVoiceIn *hw, bool enable);
void (*volume_in)(HWVoiceIn *hw, Volume *vol);
};
+void audio_generic_run_buffer_in(HWVoiceIn *hw);
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
void audio_generic_run_buffer_out(HWVoiceOut *hw);
diff --git a/audio/audio_legacy.c b/audio/audio_legacy.c
index ffdbd0bcce..0fe827b057 100644
--- a/audio/audio_legacy.c
+++ b/audio/audio_legacy.c
@@ -286,7 +286,8 @@ static void handle_sdl(Audiodev *dev)
{
/* SDL is output only */
get_samples_to_usecs("QEMU_SDL_SAMPLES", &dev->u.sdl.out->buffer_length,
- &dev->u.sdl.out->has_buffer_length, dev->u.sdl.out);
+ &dev->u.sdl.out->has_buffer_length,
+ qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.out));
}
/* wav */
diff --git a/audio/audio_template.h b/audio/audio_template.h
index 8dd48ce14e..c6714946aa 100644
--- a/audio/audio_template.h
+++ b/audio/audio_template.h
@@ -47,8 +47,7 @@ static void glue(audio_init_nb_voices_, TYPE)(AudioState *s,
#ifdef DAC
dolog ("Driver `%s' does not support " NAME "\n", drv->name);
#endif
- }
- else {
+ } else {
dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n",
drv->name,
glue (s->nb_hw_voices_, TYPE),
@@ -204,13 +203,13 @@ static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp)
if (!hw->sw_head.lh_first) {
#ifdef DAC
- audio_detach_capture (hw);
+ audio_detach_capture(hw);
#endif
- QLIST_REMOVE (hw, entries);
- glue (hw->pcm_ops->fini_, TYPE) (hw);
- glue (s->nb_hw_voices_, TYPE) += 1;
- glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
- g_free (hw);
+ QLIST_REMOVE(hw, entries);
+ glue(hw->pcm_ops->fini_, TYPE) (hw);
+ glue(s->nb_hw_voices_, TYPE) += 1;
+ glue(audio_pcm_hw_free_resources_ , TYPE) (hw);
+ g_free(hw);
*hwp = NULL;
}
}
@@ -337,7 +336,7 @@ AudiodevPerDirectionOptions *glue(audio_get_pdo_, TYPE)(Audiodev *dev)
case AUDIODEV_DRIVER_PA:
return qapi_AudiodevPaPerDirectionOptions_base(dev->u.pa.TYPE);
case AUDIODEV_DRIVER_SDL:
- return dev->u.sdl.TYPE;
+ return qapi_AudiodevSdlPerDirectionOptions_base(dev->u.sdl.TYPE);
case AUDIODEV_DRIVER_SPICE:
return dev->u.spice.TYPE;
case AUDIODEV_DRIVER_WAV:
@@ -387,8 +386,7 @@ static SW *glue(audio_pcm_create_voice_pair_, TYPE)(
if (pdo->fixed_settings) {
hw_as = audiodev_to_audsettings(pdo);
- }
- else {
+ } else {
hw_as = *as;
}
@@ -498,8 +496,7 @@ SW *glue (AUD_open_, TYPE) (
if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) {
goto fail;
}
- }
- else {
+ } else {
sw = glue(audio_pcm_create_voice_pair_, TYPE)(s, name, as);
if (!sw) {
dolog ("Failed to create voice `%s'\n", name);
@@ -553,8 +550,7 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
if (cur_ts >= old_ts) {
delta = cur_ts - old_ts;
- }
- else {
+ } else {
delta = UINT64_MAX - old_ts + cur_ts;
}
diff --git a/audio/audio_win_int.c b/audio/audio_win_int.c
index b938fd667b..5ea8157dfc 100644
--- a/audio/audio_win_int.c
+++ b/audio/audio_win_int.c
@@ -5,6 +5,7 @@
#define AUDIO_CAP "win-int"
#include <windows.h>
+#include <mmreg.h>
#include <mmsystem.h>
#include "audio.h"
@@ -16,7 +17,6 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
{
memset (wfx, 0, sizeof (*wfx));
- wfx->wFormatTag = WAVE_FORMAT_PCM;
wfx->nChannels = as->nchannels;
wfx->nSamplesPerSec = as->freq;
wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2);
@@ -26,11 +26,13 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
switch (as->fmt) {
case AUDIO_FORMAT_S8:
case AUDIO_FORMAT_U8:
+ wfx->wFormatTag = WAVE_FORMAT_PCM;
wfx->wBitsPerSample = 8;
break;
case AUDIO_FORMAT_S16:
case AUDIO_FORMAT_U16:
+ wfx->wFormatTag = WAVE_FORMAT_PCM;
wfx->wBitsPerSample = 16;
wfx->nAvgBytesPerSec <<= 1;
wfx->nBlockAlign <<= 1;
@@ -38,13 +40,21 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
case AUDIO_FORMAT_S32:
case AUDIO_FORMAT_U32:
+ wfx->wFormatTag = WAVE_FORMAT_PCM;
+ wfx->wBitsPerSample = 32;
+ wfx->nAvgBytesPerSec <<= 2;
+ wfx->nBlockAlign <<= 2;
+ break;
+
+ case AUDIO_FORMAT_F32:
+ wfx->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
wfx->wBitsPerSample = 32;
wfx->nAvgBytesPerSec <<= 2;
wfx->nBlockAlign <<= 2;
break;
default:
- dolog ("Internal logic error: Bad audio format %d\n", as->freq);
+ dolog("Internal logic error: Bad audio format %d\n", as->fmt);
return -1;
}
@@ -54,12 +64,6 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx,
int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
struct audsettings *as)
{
- if (wfx->wFormatTag != WAVE_FORMAT_PCM) {
- dolog ("Invalid wave format, tag is not PCM, but %d\n",
- wfx->wFormatTag);
- return -1;
- }
-
if (!wfx->nSamplesPerSec) {
dolog ("Invalid wave format, frequency is zero\n");
return -1;
@@ -83,23 +87,42 @@ int waveformat_to_audio_settings (WAVEFORMATEX *wfx,
return -1;
}
- switch (wfx->wBitsPerSample) {
- case 8:
- as->fmt = AUDIO_FORMAT_U8;
- break;
-
- case 16:
- as->fmt = AUDIO_FORMAT_S16;
- break;
-
- case 32:
- as->fmt = AUDIO_FORMAT_S32;
- break;
-
- default:
- dolog ("Invalid wave format, bits per sample is not "
- "8, 16 or 32, but %d\n",
- wfx->wBitsPerSample);
+ if (wfx->wFormatTag == WAVE_FORMAT_PCM) {
+ switch (wfx->wBitsPerSample) {
+ case 8:
+ as->fmt = AUDIO_FORMAT_U8;
+ break;
+
+ case 16:
+ as->fmt = AUDIO_FORMAT_S16;
+ break;
+
+ case 32:
+ as->fmt = AUDIO_FORMAT_S32;
+ break;
+
+ default:
+ dolog("Invalid PCM wave format, bits per sample is not "
+ "8, 16 or 32, but %d\n",
+ wfx->wBitsPerSample);
+ return -1;
+ }
+ } else if (wfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT) {
+ switch (wfx->wBitsPerSample) {
+ case 32:
+ as->fmt = AUDIO_FORMAT_F32;
+ break;
+
+ default:
+ dolog("Invalid IEEE_FLOAT wave format, bits per sample is not "
+ "32, but %d\n",
+ wfx->wBitsPerSample);
+ return -1;
+ }
+ } else {
+ dolog("Invalid wave format, tag is not PCM and not IEEE_FLOAT, "
+ "but %d\n",
+ wfx->wFormatTag);
return -1;
}
diff --git a/audio/coreaudio.c b/audio/coreaudio.c
index 79a9d40bf8..b7c02e0e51 100644
--- a/audio/coreaudio.c
+++ b/audio/coreaudio.c
@@ -270,7 +270,7 @@ static void coreaudio_logstatus (OSStatus status)
{
const char *str = "BUG";
- switch(status) {
+ switch (status) {
case kAudioHardwareNoError:
str = "kAudioHardwareNoError";
break;
@@ -421,12 +421,12 @@ COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
/* callback to feed audiooutput buffer */
static OSStatus audioDeviceIOProc(
AudioDeviceID inDevice,
- const AudioTimeStamp* inNow,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* inInputTime,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* inOutputTime,
- void* hwptr)
+ const AudioTimeStamp *inNow,
+ const AudioBufferList *inInputData,
+ const AudioTimeStamp *inInputTime,
+ AudioBufferList *outOutputData,
+ const AudioTimeStamp *inOutputTime,
+ void *hwptr)
{
UInt32 frameCount, pending_frames;
void *out = outOutputData->mBuffers[0].mData;
@@ -524,8 +524,7 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
} else if (frameRange.mMaximum < frames) {
core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum;
dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum);
- }
- else {
+ } else {
core->audioDevicePropertyBufferFrameSize = frames;
}
diff --git a/audio/dsound_template.h b/audio/dsound_template.h
index 9c5ce625ab..0678f2de38 100644
--- a/audio/dsound_template.h
+++ b/audio/dsound_template.h
@@ -205,7 +205,7 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
NULL
);
#else
- bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2;
+ bd.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
hr = IDirectSound_CreateSoundBuffer (
s->dsound,
&bd,
diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c
index 4cdf19ab67..cfc79c129e 100644
--- a/audio/dsoundaudio.c
+++ b/audio/dsoundaudio.c
@@ -89,7 +89,9 @@ static void dsound_log_hresult (HRESULT hr)
#endif
#ifdef DSERR_ALLOCATED
case DSERR_ALLOCATED:
- str = "The request failed because resources, such as a priority level, were already in use by another caller";
+ str = "The request failed because resources, "
+ "such as a priority level, were already in use "
+ "by another caller";
break;
#endif
#ifdef DSERR_ALREADYINITIALIZED
@@ -104,7 +106,8 @@ static void dsound_log_hresult (HRESULT hr)
#endif
#ifdef DSERR_BADSENDBUFFERGUID
case DSERR_BADSENDBUFFERGUID:
- str = "The GUID specified in an audiopath file does not match a valid mix-in buffer";
+ str = "The GUID specified in an audiopath file "
+ "does not match a valid mix-in buffer";
break;
#endif
#ifdef DSERR_BUFFERLOST
@@ -114,26 +117,35 @@ static void dsound_log_hresult (HRESULT hr)
#endif
#ifdef DSERR_BUFFERTOOSMALL
case DSERR_BUFFERTOOSMALL:
- str = "The buffer size is not great enough to enable effects processing";
+ str = "The buffer size is not great enough to "
+ "enable effects processing";
break;
#endif
#ifdef DSERR_CONTROLUNAVAIL
case DSERR_CONTROLUNAVAIL:
- str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC";
+ str = "The buffer control (volume, pan, and so on) "
+ "requested by the caller is not available. "
+ "Controls must be specified when the buffer is created, "
+ "using the dwFlags member of DSBUFFERDESC";
break;
#endif
#ifdef DSERR_DS8_REQUIRED
case DSERR_DS8_REQUIRED:
- str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface";
+ str = "A DirectSound object of class CLSID_DirectSound8 or later "
+ "is required for the requested functionality. "
+ "For more information, see IDirectSound8 Interface";
break;
#endif
#ifdef DSERR_FXUNAVAILABLE
case DSERR_FXUNAVAILABLE:
- str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software";
+ str = "The effects requested could not be found on the system, "
+ "or they are in the wrong order or in the wrong location; "
+ "for example, an effect expected in hardware "
+ "was found in software";
break;
#endif
#ifdef DSERR_GENERIC
- case DSERR_GENERIC :
+ case DSERR_GENERIC:
str = "An undetermined error occurred inside the DirectSound subsystem";
break;
#endif
@@ -154,7 +166,8 @@ static void dsound_log_hresult (HRESULT hr)
#endif
#ifdef DSERR_NODRIVER
case DSERR_NODRIVER:
- str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID";
+ str = "No sound driver is available for use, "
+ "or the given GUID is not a valid DirectSound device ID";
break;
#endif
#ifdef DSERR_NOINTERFACE
@@ -169,12 +182,14 @@ static void dsound_log_hresult (HRESULT hr)
#endif
#ifdef DSERR_OTHERAPPHASPRIO
case DSERR_OTHERAPPHASPRIO:
- str = "Another application has a higher priority level, preventing this call from succeeding";
+ str = "Another application has a higher priority level, "
+ "preventing this call from succeeding";
break;
#endif
#ifdef DSERR_OUTOFMEMORY
case DSERR_OUTOFMEMORY:
- str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request";
+ str = "The DirectSound subsystem could not allocate "
+ "sufficient memory to complete the caller's request";
break;
#endif
#ifdef DSERR_PRIOLEVELNEEDED
@@ -189,7 +204,9 @@ static void dsound_log_hresult (HRESULT hr)
#endif
#ifdef DSERR_UNINITIALIZED
case DSERR_UNINITIALIZED:
- str = "The Initialize method has not been called or has not been called successfully before other methods were called";
+ str = "The Initialize method has not been called "
+ "or has not been called successfully "
+ "before other methods were called";
break;
#endif
#ifdef DSERR_UNSUPPORTED
@@ -198,7 +215,7 @@ static void dsound_log_hresult (HRESULT hr)
break;
#endif
default:
- AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr);
+ AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT 0x%lx)\n", hr);
return;
}
@@ -342,12 +359,12 @@ static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb,
dsound_unlock_out (dsb, p1, p2, blen1, blen2);
}
-static int dsound_open (dsound *s)
+static int dsound_set_cooperative_level(dsound *s)
{
HRESULT hr;
HWND hwnd;
- hwnd = GetForegroundWindow ();
+ hwnd = GetDesktopWindow();
hr = IDirectSound_SetCooperativeLevel (
s->dsound,
hwnd,
@@ -404,8 +421,7 @@ static void dsound_enable_out(HWVoiceOut *hw, bool enable)
dsound_logerr (hr, "Could not stop playing buffer\n");
return;
}
- }
- else {
+ } else {
dolog ("warning: Voice is not playing\n");
}
}
@@ -509,8 +525,7 @@ static void dsound_enable_in(HWVoiceIn *hw, bool enable)
dsound_logerr (hr, "Could not stop capturing\n");
return;
}
- }
- else {
+ } else {
dolog ("warning: Voice is not capturing\n");
}
}
@@ -659,8 +674,7 @@ static void *dsound_audio_init(Audiodev *dev)
);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not create DirectSoundCapture instance\n");
- }
- else {
+ } else {
hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL);
if (FAILED (hr)) {
dsound_logerr (hr, "Could not initialize DirectSoundCapture\n");
@@ -673,7 +687,7 @@ static void *dsound_audio_init(Audiodev *dev)
}
}
- err = dsound_open (s);
+ err = dsound_set_cooperative_level(s);
if (err) {
dsound_audio_fini (s);
return NULL;
diff --git a/audio/jackaudio.c b/audio/jackaudio.c
index 3b7c18443d..3031c4e29b 100644
--- a/audio/jackaudio.c
+++ b/audio/jackaudio.c
@@ -277,7 +277,7 @@ static int qjack_process(jack_nframes_t nframes, void *arg)
if (likely(c->enabled)) {
qjack_buffer_read_l(&c->fifo, buffers, nframes);
} else {
- for(int i = 0; i < c->nchannels; ++i) {
+ for (int i = 0; i < c->nchannels; ++i) {
memset(buffers[i], 0, nframes * sizeof(float));
}
}
@@ -657,6 +657,7 @@ static struct audio_pcm_ops jack_pcm_ops = {
.init_in = qjack_init_in,
.fini_in = qjack_fini_in,
.read = qjack_read,
+ .run_buffer_in = audio_generic_run_buffer_in,
.enable_in = qjack_enable_in
};
diff --git a/audio/noaudio.c b/audio/noaudio.c
index 05798ea210..aac87dbc93 100644
--- a/audio/noaudio.c
+++ b/audio/noaudio.c
@@ -124,6 +124,7 @@ static struct audio_pcm_ops no_pcm_ops = {
.init_in = no_init_in,
.fini_in = no_fini_in,
.read = no_read,
+ .run_buffer_in = audio_generic_run_buffer_in,
.enable_in = no_enable_in
};
diff --git a/audio/ossaudio.c b/audio/ossaudio.c
index a7dcaa31ad..60eff66424 100644
--- a/audio/ossaudio.c
+++ b/audio/ossaudio.c
@@ -142,16 +142,14 @@ static int aud_to_ossfmt (AudioFormat fmt, int endianness)
case AUDIO_FORMAT_S16:
if (endianness) {
return AFMT_S16_BE;
- }
- else {
+ } else {
return AFMT_S16_LE;
}
case AUDIO_FORMAT_U16:
if (endianness) {
return AFMT_U16_BE;
- }
- else {
+ } else {
return AFMT_U16_LE;
}
@@ -542,16 +540,14 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
int trig = 0;
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n");
- }
- else {
+ } else {
trig = PCM_ENABLE_OUTPUT;
if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
oss_logerr (
errno,
"SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n"
);
- }
- else {
+ } else {
oss->mmapped = 1;
}
}
@@ -762,6 +758,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
.init_in = oss_init_in,
.fini_in = oss_fini_in,
.read = oss_read,
+ .run_buffer_in = audio_generic_run_buffer_in,
.enable_in = oss_enable_in
};
diff --git a/audio/paaudio.c b/audio/paaudio.c
index b052084698..c97b22e970 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -207,19 +207,34 @@ static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
PAVoiceOut *p = (PAVoiceOut *) hw;
PAConnection *c = p->g->conn;
void *ret;
+ size_t l;
int r;
pa_threaded_mainloop_lock(c->mainloop);
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
"pa_threaded_mainloop_lock failed\n");
+ if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
+ /* wait for stream to become ready */
+ l = 0;
+ ret = NULL;
+ goto unlock;
+ }
+
+ l = pa_stream_writable_size(p->stream);
+ CHECK_SUCCESS_GOTO(c, l != (size_t) -1, unlock_and_fail,
+ "pa_stream_writable_size failed\n");
*size = -1;
r = pa_stream_begin_write(p->stream, &ret, size);
CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail,
"pa_stream_begin_write failed\n");
+unlock:
pa_threaded_mainloop_unlock(c->mainloop);
+ if (*size > l) {
+ *size = l;
+ }
return ret;
unlock_and_fail:
@@ -228,6 +243,28 @@ unlock_and_fail:
return NULL;
}
+static size_t qpa_put_buffer_out(HWVoiceOut *hw, void *data, size_t length)
+{
+ PAVoiceOut *p = (PAVoiceOut *)hw;
+ PAConnection *c = p->g->conn;
+ int r;
+
+ pa_threaded_mainloop_lock(c->mainloop);
+
+ CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
+ "pa_threaded_mainloop_lock failed\n");
+
+ r = pa_stream_write(p->stream, data, length, NULL, 0LL, PA_SEEK_RELATIVE);
+ CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, "pa_stream_write failed\n");
+
+ pa_threaded_mainloop_unlock(c->mainloop);
+ return length;
+
+unlock_and_fail:
+ pa_threaded_mainloop_unlock(c->mainloop);
+ return 0;
+}
+
static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
{
PAVoiceOut *p = (PAVoiceOut *) hw;
@@ -239,6 +276,11 @@ static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
"pa_threaded_mainloop_lock failed\n");
+ if (pa_stream_get_state(p->stream) != PA_STREAM_READY) {
+ /* wait for stream to become ready */
+ l = 0;
+ goto unlock;
+ }
l = pa_stream_writable_size(p->stream);
@@ -252,6 +294,7 @@ static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
r = pa_stream_write(p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE);
CHECK_SUCCESS_GOTO(c, r >= 0, unlock_and_fail, "pa_stream_write failed\n");
+unlock:
pa_threaded_mainloop_unlock(c->mainloop);
return l;
@@ -437,7 +480,7 @@ static pa_stream *qpa_simple_new (
}
if (r < 0) {
- goto fail;
+ goto fail;
}
pa_threaded_mainloop_unlock(c->mainloop);
@@ -474,7 +517,8 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
ss.rate = as->freq;
ba.tlength = pa_usec_to_bytes(ppdo->latency, &ss);
- ba.minreq = -1;
+ ba.minreq = pa_usec_to_bytes(MIN(ppdo->latency >> 2,
+ (g->dev->timer_period >> 2) * 3), &ss);
ba.maxlength = -1;
ba.prebuf = -1;
@@ -495,9 +539,12 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
}
audio_pcm_init_info (&hw->info, &obt_as);
+ /*
+ * This is wrong. hw->samples counts in frames. hw->samples will be
+ * number of channels times larger than expected.
+ */
hw->samples = audio_buffer_samples(
- qapi_AudiodevPaPerDirectionOptions_base(ppdo),
- &obt_as, ppdo->buffer_length);
+ qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
return 0;
@@ -521,8 +568,9 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
ss.channels = as->nchannels;
ss.rate = as->freq;
- ba.fragsize = pa_usec_to_bytes(ppdo->latency, &ss);
- ba.maxlength = pa_usec_to_bytes(ppdo->latency * 2, &ss);
+ ba.fragsize = pa_usec_to_bytes((g->dev->timer_period >> 1) * 3, &ss);
+ ba.maxlength = pa_usec_to_bytes(
+ MAX(ppdo->latency, g->dev->timer_period * 3), &ss);
ba.minreq = -1;
ba.prebuf = -1;
@@ -543,9 +591,12 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
}
audio_pcm_init_info (&hw->info, &obt_as);
+ /*
+ * This is wrong. hw->samples counts in frames. hw->samples will be
+ * number of channels times larger than expected.
+ */
hw->samples = audio_buffer_samples(
- qapi_AudiodevPaPerDirectionOptions_base(ppdo),
- &obt_as, ppdo->buffer_length);
+ qapi_AudiodevPaPerDirectionOptions_base(ppdo), &obt_as, 46440);
return 0;
@@ -695,10 +746,6 @@ static void qpa_volume_in(HWVoiceIn *hw, Volume *vol)
static int qpa_validate_per_direction_opts(Audiodev *dev,
AudiodevPaPerDirectionOptions *pdo)
{
- if (!pdo->has_buffer_length) {
- pdo->has_buffer_length = true;
- pdo->buffer_length = 46440;
- }
if (!pdo->has_latency) {
pdo->has_latency = true;
pdo->latency = 15000;
@@ -861,7 +908,7 @@ static struct audio_pcm_ops qpa_pcm_ops = {
.fini_out = qpa_fini_out,
.write = qpa_write,
.get_buffer_out = qpa_get_buffer_out,
- .put_buffer_out = qpa_write, /* pa handles it */
+ .put_buffer_out = qpa_put_buffer_out,
.volume_out = qpa_volume_out,
.init_in = qpa_init_in,
diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c
index 21b7a0484b..c68c62a3e4 100644
--- a/audio/sdlaudio.c
+++ b/audio/sdlaudio.c
@@ -41,15 +41,19 @@
typedef struct SDLVoiceOut {
HWVoiceOut hw;
+ int exit;
+ int initialized;
+ Audiodev *dev;
+ SDL_AudioDeviceID devid;
} SDLVoiceOut;
-static struct SDLAudioState {
+typedef struct SDLVoiceIn {
+ HWVoiceIn hw;
int exit;
int initialized;
- bool driver_created;
Audiodev *dev;
-} glob_sdl;
-typedef struct SDLAudioState SDLAudioState;
+ SDL_AudioDeviceID devid;
+} SDLVoiceIn;
static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...)
{
@@ -155,9 +159,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 +171,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,112 +196,175 @@ 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) {
- return;
- }
+ if (!sdl->exit) {
- /* dolog ("in callback samples=%zu live=%zu\n", samples, sdl->live); */
+ /* dolog("callback_out: len=%d avail=%zu\n", len, hw->pending_emul); */
- while (hw->pending_emul && len) {
- size_t write_len;
- ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;
- if (start < 0) {
- start += hw->size_emul;
- }
- assert(start >= 0 && start < hw->size_emul);
+ while (hw->pending_emul && len) {
+ size_t write_len;
+ ssize_t start = (ssize_t)hw->pos_emul - hw->pending_emul;
+ if (start < 0) {
+ start += hw->size_emul;
+ }
+ assert(start >= 0 && start < hw->size_emul);
- write_len = MIN(MIN(hw->pending_emul, len),
- hw->size_emul - start);
+ write_len = MIN(MIN(hw->pending_emul, len),
+ hw->size_emul - start);
- memcpy(buf, hw->buf_emul + start, write_len);
- hw->pending_emul -= write_len;
- len -= write_len;
- buf += write_len;
+ memcpy(buf, hw->buf_emul + start, write_len);
+ hw->pending_emul -= write_len;
+ len -= write_len;
+ buf += write_len;
+ }
}
/* clear remaining buffer that we couldn't fill with data */
if (len) {
- memset(buf, 0, len);
+ audio_pcm_info_clear_buf(&hw->info, buf,
+ len / hw->info.bytes_per_frame);
+ }
+}
+
+static void sdl_close_in(SDLVoiceIn *sdl)
+{
+ 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_in(void *opaque, Uint8 *buf, int len)
+{
+ SDLVoiceIn *sdl = opaque;
+ HWVoiceIn *hw = &sdl->hw;
+
+ if (sdl->exit) {
+ return;
+ }
+
+ /* dolog("callback_in: len=%d pending=%zu\n", len, hw->pending_emul); */
+
+ while (hw->pending_emul < hw->size_emul && len) {
+ size_t read_len = MIN(len, MIN(hw->size_emul - hw->pos_emul,
+ hw->size_emul - hw->pending_emul));
+
+ memcpy(hw->buf_emul + hw->pos_emul, buf, read_len);
+
+ hw->pending_emul += read_len;
+ hw->pos_emul = (hw->pos_emul + read_len) % hw->size_emul;
+ len -= read_len;
+ buf += read_len;
}
}
-#define SDL_WRAPPER_FUNC(name, ret_type, args_decl, args, fail, unlock) \
- static ret_type glue(sdl_, name)args_decl \
- { \
- ret_type ret; \
- \
- SDL_LockAudio(); \
- \
- ret = glue(audio_generic_, name)args; \
- \
- SDL_UnlockAudio(); \
- return ret; \
+#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_LockAudioDevice(sdl->devid); \
+ ret = glue(audio_generic_, name)args; \
+ SDL_UnlockAudioDevice(sdl->devid); \
+ \
+ return ret; \
+ }
+
+#define SDL_WRAPPER_VOID_FUNC(name, args_decl, args, dir) \
+ static void glue(sdl_, name)args_decl \
+ { \
+ glue(SDLVoice, dir) *sdl = (glue(SDLVoice, dir) *)hw; \
+ \
+ SDL_LockAudioDevice(sdl->devid); \
+ glue(audio_generic_, name)args; \
+ SDL_UnlockAudioDevice(sdl->devid); \
}
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
- (hw, size), *size = 0, sdl_unlock)
+ (hw, size), Out)
SDL_WRAPPER_FUNC(put_buffer_out, size_t,
- (HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
- /*nothing*/, sdl_unlock_and_post)
+ (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),
- /*nothing*/, sdl_unlock_and_post)
-
+ (HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size), Out)
+SDL_WRAPPER_FUNC(read, size_t, (HWVoiceIn *hw, void *buf, size_t size),
+ (hw, buf, size), In)
+SDL_WRAPPER_FUNC(get_buffer_in, void *, (HWVoiceIn *hw, size_t *size),
+ (hw, size), In)
+SDL_WRAPPER_VOID_FUNC(put_buffer_in, (HWVoiceIn *hw, void *buf, size_t size),
+ (hw, buf, size), In)
#undef SDL_WRAPPER_FUNC
+#undef SDL_WRAPPER_VOID_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;
+ Audiodev *dev = drv_opaque;
+ AudiodevSdlPerDirectionOptions *spdo = dev->u.sdl.out;
struct audsettings obt_as;
req.freq = as->freq;
req.format = aud_to_sdlfmt (as->fmt);
req.channels = as->nchannels;
- req.samples = audio_buffer_samples(s->dev->u.sdl.out, as, 11610);
- req.callback = sdl_callback;
+ /*
+ * This is wrong. SDL samples are QEMU frames. The buffer size will be
+ * the requested buffer size multiplied by the number of channels.
+ */
+ req.samples = audio_buffer_samples(
+ qapi_AudiodevSdlPerDirectionOptions_base(spdo), as, 11610);
+ 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;
}
@@ -305,44 +374,97 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,
obt_as.endianness = endianness;
audio_pcm_init_info (&hw->info, &obt_as);
- hw->samples = obt.samples;
+ hw->samples = (spdo->has_buffer_count ? spdo->buffer_count : 4) *
+ obt.samples;
- s->initialized = 1;
- s->exit = 0;
- SDL_PauseAudio (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)
+static void sdl_fini_in(HWVoiceIn *hw)
{
- SDLAudioState *s = &glob_sdl;
- if (s->driver_created) {
- sdl_logerr("Can't create multiple sdl backends\n");
- return NULL;
+ SDLVoiceIn *sdl = (SDLVoiceIn *)hw;
+
+ sdl_close_in(sdl);
+}
+
+static int sdl_init_in(HWVoiceIn *hw, audsettings *as, void *drv_opaque)
+{
+ SDLVoiceIn *sdl = (SDLVoiceIn *)hw;
+ SDL_AudioSpec req, obt;
+ int endianness;
+ int err;
+ AudioFormat effective_fmt;
+ Audiodev *dev = drv_opaque;
+ AudiodevSdlPerDirectionOptions *spdo = dev->u.sdl.in;
+ struct audsettings obt_as;
+
+ req.freq = as->freq;
+ req.format = aud_to_sdlfmt(as->fmt);
+ req.channels = as->nchannels;
+ /* SDL samples are QEMU frames */
+ req.samples = audio_buffer_frames(
+ qapi_AudiodevSdlPerDirectionOptions_base(spdo), as, 11610);
+ req.callback = sdl_callback_in;
+ req.userdata = sdl;
+
+ sdl->dev = dev;
+ sdl->devid = sdl_open(&req, &obt, 1);
+ if (!sdl->devid) {
+ return -1;
}
+ err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness);
+ if (err) {
+ sdl_close_in(sdl);
+ return -1;
+ }
+
+ obt_as.freq = obt.freq;
+ obt_as.nchannels = obt.channels;
+ obt_as.fmt = effective_fmt;
+ obt_as.endianness = endianness;
+
+ audio_pcm_init_info(&hw->info, &obt_as);
+ hw->samples = (spdo->has_buffer_count ? spdo->buffer_count : 4) *
+ obt.samples;
+ hw->size_emul = hw->samples * hw->info.bytes_per_frame;
+ hw->buf_emul = g_malloc(hw->size_emul);
+ hw->pos_emul = hw->pending_emul = 0;
+
+ sdl->initialized = 1;
+ sdl->exit = 0;
+ return 0;
+}
+
+static void sdl_enable_in(HWVoiceIn *hw, bool enable)
+{
+ SDLVoiceIn *sdl = (SDLVoiceIn *)hw;
+
+ SDL_PauseAudioDevice(sdl->devid, !enable);
+}
+
+static void *sdl_audio_init(Audiodev *dev)
+{
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 = {
@@ -355,6 +477,15 @@ static struct audio_pcm_ops sdl_pcm_ops = {
/* wrapper for audio_generic_put_buffer_out */
.put_buffer_out = sdl_put_buffer_out,
.enable_out = sdl_enable_out,
+ .init_in = sdl_init_in,
+ .fini_in = sdl_fini_in,
+ /* wrapper for audio_generic_read */
+ .read = sdl_read,
+ /* wrapper for audio_generic_get_buffer_in */
+ .get_buffer_in = sdl_get_buffer_in,
+ /* wrapper for audio_generic_put_buffer_in */
+ .put_buffer_in = sdl_put_buffer_in,
+ .enable_in = sdl_enable_in,
};
static struct audio_driver sdl_audio_driver = {
@@ -364,10 +495,10 @@ static struct audio_driver sdl_audio_driver = {
.fini = sdl_audio_fini,
.pcm_ops = &sdl_pcm_ops,
.can_be_default = 1,
- .max_voices_out = 1,
- .max_voices_in = 0,
- .voice_size_out = sizeof (SDLVoiceOut),
- .voice_size_in = 0
+ .max_voices_out = INT_MAX,
+ .max_voices_in = INT_MAX,
+ .voice_size_out = sizeof(SDLVoiceOut),
+ .voice_size_in = sizeof(SDLVoiceIn),
};
static void register_audio_sdl(void)
diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c
index 8967cca129..999bfbde47 100644
--- a/audio/spiceaudio.c
+++ b/audio/spiceaudio.c
@@ -293,6 +293,7 @@ static struct audio_pcm_ops audio_callbacks = {
.init_in = line_in_init,
.fini_in = line_in_fini,
.read = line_in_read,
+ .run_buffer_in = audio_generic_run_buffer_in,
.enable_in = line_in_enable,
#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2))
.volume_in = line_in_volume,
diff --git a/qapi/audio.json b/qapi/audio.json
index 072ed79def..9cba0df8a4 100644
--- a/qapi/audio.json
+++ b/qapi/audio.json
@@ -302,6 +302,37 @@
'*server': 'str' } }
##
+# @AudiodevSdlPerDirectionOptions:
+#
+# Options of the SDL audio backend that are used for both playback and
+# recording.
+#
+# @buffer-count: number of buffers (default 4)
+#
+# Since: 6.0
+##
+{ 'struct': 'AudiodevSdlPerDirectionOptions',
+ 'base': 'AudiodevPerDirectionOptions',
+ 'data': {
+ '*buffer-count': 'uint32' } }
+
+##
+# @AudiodevSdlOptions:
+#
+# Options of the SDL audio backend.
+#
+# @in: options of the recording stream
+#
+# @out: options of the playback stream
+#
+# Since: 6.0
+##
+{ 'struct': 'AudiodevSdlOptions',
+ 'data': {
+ '*in': 'AudiodevSdlPerDirectionOptions',
+ '*out': 'AudiodevSdlPerDirectionOptions' } }
+
+##
# @AudiodevWavOptions:
#
# Options of the wav audio backend.
@@ -385,6 +416,6 @@
'jack': 'AudiodevJackOptions',
'oss': 'AudiodevOssOptions',
'pa': 'AudiodevPaOptions',
- 'sdl': 'AudiodevGenericOptions',
+ 'sdl': 'AudiodevSdlOptions',
'spice': 'AudiodevGenericOptions',
'wav': 'AudiodevWavOptions' } }
diff --git a/qemu-options.hx b/qemu-options.hx
index 05fe35ceb6..9dc90ffbfb 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -588,6 +588,7 @@ DEF("audiodev", HAS_ARG, QEMU_OPTION_audiodev,
#endif
#ifdef CONFIG_AUDIO_SDL
"-audiodev sdl,id=id[,prop[=value][,...]]\n"
+ " in|out.buffer-count= number of buffers\n"
#endif
#ifdef CONFIG_SPICE
"-audiodev spice,id=id[,prop[=value][,...]]\n"
@@ -745,7 +746,12 @@ SRST
``-audiodev sdl,id=id[,prop[=value][,...]]``
Creates a backend using SDL. This backend is available on most
systems, but you should use your platform's native backend if
- possible. This backend has no backend specific properties.
+ possible.
+
+ SDL specific options are:
+
+ ``in|out.buffer-count=count``
+ Sets the count of the buffers.
``-audiodev spice,id=id[,prop[=value][,...]]``
Creates a backend that sends audio through SPICE. This backend