audio: improvements for sdl, pulse, fsound.

audio: cleanups & codestyle fixes.
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmABlrgACgkQTLbY7tPo
 cTiMOhAAxRVnh7jyf/A9i5lDkQ6QG26zdbFK/zmbicSWYXeRRu4hbxC0zEUQki88
 4YCMr/dmuG0Tkhyjwo4Zoaq56sE3EqQqzjPOT14zSfojHrLBTNLxWRzsWMaPdTeY
 jvwu/2C8tqibPWX/cyimoc05PIFL+CS2lasoqDXjmA5pP1KDBwFX9wQxu5cRF5f3
 203Pc2cDSgTnyDE38MM8+S3ocZDqmrnxmpF81q/ivv1vPx3gwWyHCguOHaOh1Dnx
 0SsQm4xn7p5bzOZ81+aZyL+sbBJIc/KsPx5K+984+mUZsOjN3rbq8bhHThMB1Cfk
 iWAt7+nUuaj9jcXKbwkusURVSjAVqXN7yQEi2fPZ1woAOlMq7mxEvn3UQgvUA1r6
 PyIVQtdrna8Td4PUih8x3Ooa6tIRe1oDYSuQkhrKnlX0lYY+r1nLveDrmCFyNyLz
 5Re56t0AcScEiTbOFSnjaxbcLa0d/zfOalilEt2+xjPAy0QPGxxRPd0fI1NW96gG
 JClUP8VTCPKkKY7qCqKvqTPzoAqeiG6FJ+Qv2YghnWuql3z19pumHh5eYKsZndOx
 1v1vJxzay4UgLAbp+p4fxytkQ8/de9hotnZAkVooEK1nF1YEAWCLK08mva4HGR4m
 oTXLBz18slX8ugfZ8Eg1viHzXdkUTWcpEoGUq4ryjS7bzSvO/oI=
 =hwBn
 -----END PGP SIGNATURE-----

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>
master
Peter Maydell 2021-01-15 22:21:21 +00:00
commit 825a215c00
17 changed files with 480 additions and 244 deletions

View File

@ -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,
};

View File

@ -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, );

View File

@ -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);

View File

@ -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 */

View File

@ -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;
}

View File

@ -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;
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 16:
as->fmt = AUDIO_FORMAT_S16;
break;
case 32:
as->fmt = AUDIO_FORMAT_S32;
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);
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;
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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;

View File

@ -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
};

View File

@ -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
};

View File

@ -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
};

View File

@ -207,6 +207,46 @@ 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:
pa_threaded_mainloop_unlock(c->mainloop);
*size = 0;
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);
@ -214,18 +254,15 @@ static void *qpa_get_buffer_out(HWVoiceOut *hw, size_t *size)
CHECK_DEAD_GOTO(c, p->stream, unlock_and_fail,
"pa_threaded_mainloop_lock 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");
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 ret;
return length;
unlock_and_fail:
pa_threaded_mainloop_unlock(c->mainloop);
*size = 0;
return NULL;
return 0;
}
static size_t qpa_write(HWVoiceOut *hw, void *data, size_t length)
@ -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,

View File

@ -41,15 +41,19 @@
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;
typedef struct SDLVoiceIn {
HWVoiceIn hw;
int exit;
int initialized;
Audiodev *dev;
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;
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);
memcpy(buf, hw->buf_emul + start, write_len);
hw->pending_emul -= write_len;
len -= write_len;
buf += write_len;
}
assert(start >= 0 && start < hw->size_emul);
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;
}
/* 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);
}
}
#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; \
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, 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_fini_in(HWVoiceIn *hw)
{
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)
{
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 = {
@ -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)

View File

@ -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,

View File

@ -301,6 +301,37 @@
'*out': 'AudiodevPaPerDirectionOptions',
'*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:
#
@ -385,6 +416,6 @@
'jack': 'AudiodevJackOptions',
'oss': 'AudiodevOssOptions',
'pa': 'AudiodevPaOptions',
'sdl': 'AudiodevGenericOptions',
'sdl': 'AudiodevSdlOptions',
'spice': 'AudiodevGenericOptions',
'wav': 'AudiodevWavOptions' } }

View File

@ -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