mirror of https://github.com/xemu-project/xemu.git
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>
This commit is contained in:
commit
825a215c00
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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, );
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
313
audio/sdlaudio.c
313
audio/sdlaudio.c
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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' } }
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue