audio: bugfixes, mostly audio backend rewrite fallout
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABAgAGBQJePRWoAAoJEEy22O7T6HE4jbAQALWq/XyrQdK9kESICky6aymy xTFggLtDFtYXWemnJGILJB0HPxaXlmb0qKeaCwmCgsiWgErSH9RB1EW0v5Q6Pv4Z /l4ntJBnGy3tnDmAeu0RkH24u//tOV1Vwh5rxQIfEHYO1xsEAAEncXXXsjj3ddR0 X/9zObhvFjforIPVVf7YkflHGg6FIOXpAT0rqSs3Wbhyd0xWlCrnkcikQqAihdow mZcVYi+K0K4DXh/OFOmMPjj0OrzP4lQS1NREL9OIqzBUtTgP6ZN3fzFZbZyrHy/Z WdREW1SFhprjrhMK7AfZQ+27nHBSTFl9rpw/+3MN3E46aK7sjGbXJf2HOMf8k01Z sU173UEd8ZPy80HCTUR4gbTyKAzlwcyp4oVAnq5rwj4Zrn9uMRIzVLpXQhbKovyU i3KDOYkNrb0rbMriotuIzeDyY8/OC8JBB73bUNsSrH1S8gj4tq5KPidjjF5kViIN xXKiTPlkFd3BhDzBBx4Yk53tKLD9YqI1iup2jNzZR0EthQHo5xM0eArHlP9x+052 F29VsH1NZPIYTDK6//uXMwKSNdFiXWoH1RKl4W41Gq3k1NEC6covwoZR1nE4QG9+ TnTPKK6XAqM1whtwCzWRm07Hasy8ov4PdwqmYrvTKXVXMAT0NvsBHzKw2/j1etnc pwFEQBK8scEEkiE4Pa9l =7RFO -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/kraxel/tags/audio-20200207-pull-request' into staging audio: bugfixes, mostly audio backend rewrite fallout # gpg: Signature made Fri 07 Feb 2020 07:45:44 GMT # gpg: using RSA key 4CB6D8EED3E87138 # 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-20200207-pull-request: audio: proper support for float samples in mixeng coreaudio: fix coreaudio playback audio/dsound: fix invalid parameters error audio: audio_generic_get_buffer_in should honor *size ossaudio: disable poll mode can't be reached ossaudio: prevent SIGSEGV in oss_enable_out audio: fix bug 1858488 audio: prevent SIGSEGV in AUD_get_buffer_size_out paaudio: remove unused variables audio: fix audio_generic_read audio: fix audio_generic_write audio/oss: fix buffer pos calculation Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
b6bef1147f
@ -307,6 +307,13 @@ static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt, int endianness)
|
|||||||
return SND_PCM_FORMAT_U32_LE;
|
return SND_PCM_FORMAT_U32_LE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case AUDIO_FORMAT_F32:
|
||||||
|
if (endianness) {
|
||||||
|
return SND_PCM_FORMAT_FLOAT_BE;
|
||||||
|
} else {
|
||||||
|
return SND_PCM_FORMAT_FLOAT_LE;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
@ -370,6 +377,16 @@ static int alsa_to_audfmt (snd_pcm_format_t alsafmt, AudioFormat *fmt,
|
|||||||
*fmt = AUDIO_FORMAT_U32;
|
*fmt = AUDIO_FORMAT_U32;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SND_PCM_FORMAT_FLOAT_LE:
|
||||||
|
*endianness = 0;
|
||||||
|
*fmt = AUDIO_FORMAT_F32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SND_PCM_FORMAT_FLOAT_BE:
|
||||||
|
*endianness = 1;
|
||||||
|
*fmt = AUDIO_FORMAT_F32;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dolog ("Unrecognized audio format %d\n", alsafmt);
|
dolog ("Unrecognized audio format %d\n", alsafmt);
|
||||||
return -1;
|
return -1;
|
||||||
@ -906,6 +923,7 @@ static struct audio_pcm_ops alsa_pcm_ops = {
|
|||||||
.init_out = alsa_init_out,
|
.init_out = alsa_init_out,
|
||||||
.fini_out = alsa_fini_out,
|
.fini_out = alsa_fini_out,
|
||||||
.write = alsa_write,
|
.write = alsa_write,
|
||||||
|
.run_buffer_out = audio_generic_run_buffer_out,
|
||||||
.enable_out = alsa_enable_out,
|
.enable_out = alsa_enable_out,
|
||||||
|
|
||||||
.init_in = alsa_init_in,
|
.init_in = alsa_init_in,
|
||||||
|
133
audio/audio.c
133
audio/audio.c
@ -218,6 +218,9 @@ static void audio_print_settings (struct audsettings *as)
|
|||||||
case AUDIO_FORMAT_U32:
|
case AUDIO_FORMAT_U32:
|
||||||
AUD_log (NULL, "U32");
|
AUD_log (NULL, "U32");
|
||||||
break;
|
break;
|
||||||
|
case AUDIO_FORMAT_F32:
|
||||||
|
AUD_log (NULL, "F32");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
AUD_log (NULL, "invalid(%d)", as->fmt);
|
AUD_log (NULL, "invalid(%d)", as->fmt);
|
||||||
break;
|
break;
|
||||||
@ -252,6 +255,7 @@ static int audio_validate_settings (struct audsettings *as)
|
|||||||
case AUDIO_FORMAT_U16:
|
case AUDIO_FORMAT_U16:
|
||||||
case AUDIO_FORMAT_S32:
|
case AUDIO_FORMAT_S32:
|
||||||
case AUDIO_FORMAT_U32:
|
case AUDIO_FORMAT_U32:
|
||||||
|
case AUDIO_FORMAT_F32:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
invalid = 1;
|
invalid = 1;
|
||||||
@ -264,24 +268,28 @@ static int audio_validate_settings (struct audsettings *as)
|
|||||||
|
|
||||||
static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
|
static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as)
|
||||||
{
|
{
|
||||||
int bits = 8, sign = 0;
|
int bits = 8;
|
||||||
|
bool is_signed = false, is_float = false;
|
||||||
|
|
||||||
switch (as->fmt) {
|
switch (as->fmt) {
|
||||||
case AUDIO_FORMAT_S8:
|
case AUDIO_FORMAT_S8:
|
||||||
sign = 1;
|
is_signed = true;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case AUDIO_FORMAT_U8:
|
case AUDIO_FORMAT_U8:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUDIO_FORMAT_S16:
|
case AUDIO_FORMAT_S16:
|
||||||
sign = 1;
|
is_signed = true;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case AUDIO_FORMAT_U16:
|
case AUDIO_FORMAT_U16:
|
||||||
bits = 16;
|
bits = 16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AUDIO_FORMAT_F32:
|
||||||
|
is_float = true;
|
||||||
|
/* fall through */
|
||||||
case AUDIO_FORMAT_S32:
|
case AUDIO_FORMAT_S32:
|
||||||
sign = 1;
|
is_signed = true;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case AUDIO_FORMAT_U32:
|
case AUDIO_FORMAT_U32:
|
||||||
bits = 32;
|
bits = 32;
|
||||||
@ -292,33 +300,38 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
|
|||||||
}
|
}
|
||||||
return info->freq == as->freq
|
return info->freq == as->freq
|
||||||
&& info->nchannels == as->nchannels
|
&& info->nchannels == as->nchannels
|
||||||
&& info->sign == sign
|
&& info->is_signed == is_signed
|
||||||
|
&& info->is_float == is_float
|
||||||
&& info->bits == bits
|
&& info->bits == bits
|
||||||
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
|
&& info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
||||||
{
|
{
|
||||||
int bits = 8, sign = 0, mul;
|
int bits = 8, mul;
|
||||||
|
bool is_signed = false, is_float = false;
|
||||||
|
|
||||||
switch (as->fmt) {
|
switch (as->fmt) {
|
||||||
case AUDIO_FORMAT_S8:
|
case AUDIO_FORMAT_S8:
|
||||||
sign = 1;
|
is_signed = true;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case AUDIO_FORMAT_U8:
|
case AUDIO_FORMAT_U8:
|
||||||
mul = 1;
|
mul = 1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case AUDIO_FORMAT_S16:
|
case AUDIO_FORMAT_S16:
|
||||||
sign = 1;
|
is_signed = true;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case AUDIO_FORMAT_U16:
|
case AUDIO_FORMAT_U16:
|
||||||
bits = 16;
|
bits = 16;
|
||||||
mul = 2;
|
mul = 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AUDIO_FORMAT_F32:
|
||||||
|
is_float = true;
|
||||||
|
/* fall through */
|
||||||
case AUDIO_FORMAT_S32:
|
case AUDIO_FORMAT_S32:
|
||||||
sign = 1;
|
is_signed = true;
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case AUDIO_FORMAT_U32:
|
case AUDIO_FORMAT_U32:
|
||||||
bits = 32;
|
bits = 32;
|
||||||
@ -331,7 +344,8 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
|
|||||||
|
|
||||||
info->freq = as->freq;
|
info->freq = as->freq;
|
||||||
info->bits = bits;
|
info->bits = bits;
|
||||||
info->sign = sign;
|
info->is_signed = is_signed;
|
||||||
|
info->is_float = is_float;
|
||||||
info->nchannels = as->nchannels;
|
info->nchannels = as->nchannels;
|
||||||
info->bytes_per_frame = as->nchannels * mul;
|
info->bytes_per_frame = as->nchannels * mul;
|
||||||
info->bytes_per_second = info->freq * info->bytes_per_frame;
|
info->bytes_per_second = info->freq * info->bytes_per_frame;
|
||||||
@ -344,7 +358,7 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->sign) {
|
if (info->is_signed || info->is_float) {
|
||||||
memset(buf, 0x00, len * info->bytes_per_frame);
|
memset(buf, 0x00, len * info->bytes_per_frame);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -770,8 +784,9 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
|
|||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
|
static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info)
|
||||||
{
|
{
|
||||||
dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n",
|
dolog("%s: bits %d, sign %d, float %d, freq %d, nchan %d\n",
|
||||||
cap, info->bits, info->sign, info->freq, info->nchannels);
|
cap, info->bits, info->is_signed, info->is_float, info->freq,
|
||||||
|
info->nchannels);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -879,9 +894,9 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int AUD_get_buffer_size_out (SWVoiceOut *sw)
|
int AUD_get_buffer_size_out(SWVoiceOut *sw)
|
||||||
{
|
{
|
||||||
return sw->hw->mix_buf->size * sw->hw->info.bytes_per_frame;
|
return sw->hw->samples * sw->hw->info.bytes_per_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AUD_set_active_out (SWVoiceOut *sw, int on)
|
void AUD_set_active_out (SWVoiceOut *sw, int on)
|
||||||
@ -1076,10 +1091,8 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
|||||||
while (live) {
|
while (live) {
|
||||||
size_t size, decr, proc;
|
size_t size, decr, proc;
|
||||||
void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
|
void *buf = hw->pcm_ops->get_buffer_out(hw, &size);
|
||||||
if (!buf) {
|
if (!buf || size == 0) {
|
||||||
/* retrying will likely won't help, drop everything. */
|
break;
|
||||||
hw->mix_buf->pos = (hw->mix_buf->pos + live) % hw->mix_buf->size;
|
|
||||||
return clipped + live;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
decr = MIN(size / hw->info.bytes_per_frame, live);
|
decr = MIN(size / hw->info.bytes_per_frame, live);
|
||||||
@ -1097,6 +1110,10 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hw->pcm_ops->run_buffer_out) {
|
||||||
|
hw->pcm_ops->run_buffer_out(hw);
|
||||||
|
}
|
||||||
|
|
||||||
return clipped;
|
return clipped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1403,7 +1420,8 @@ void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
|||||||
}
|
}
|
||||||
assert(start >= 0 && start < hw->size_emul);
|
assert(start >= 0 && start < hw->size_emul);
|
||||||
|
|
||||||
*size = MIN(hw->pending_emul, hw->size_emul - start);
|
*size = MIN(*size, hw->pending_emul);
|
||||||
|
*size = MIN(*size, hw->size_emul - start);
|
||||||
return hw->buf_emul + start;
|
return hw->buf_emul + start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1413,6 +1431,28 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
|
|||||||
hw->pending_emul -= size;
|
hw->pending_emul -= size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void audio_generic_run_buffer_out(HWVoiceOut *hw)
|
||||||
|
{
|
||||||
|
while (hw->pending_emul) {
|
||||||
|
size_t write_len, written;
|
||||||
|
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(hw->pending_emul, hw->size_emul - start);
|
||||||
|
|
||||||
|
written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
|
||||||
|
hw->pending_emul -= written;
|
||||||
|
|
||||||
|
if (written < write_len) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||||
{
|
{
|
||||||
if (unlikely(!hw->buf_emul)) {
|
if (unlikely(!hw->buf_emul)) {
|
||||||
@ -1428,8 +1468,7 @@ void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
|||||||
return hw->buf_emul + hw->pos_emul;
|
return hw->buf_emul + hw->pos_emul;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
|
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
||||||
size_t size)
|
|
||||||
{
|
{
|
||||||
assert(buf == hw->buf_emul + hw->pos_emul &&
|
assert(buf == hw->buf_emul + hw->pos_emul &&
|
||||||
size + hw->pending_emul <= hw->size_emul);
|
size + hw->pending_emul <= hw->size_emul);
|
||||||
@ -1440,35 +1479,6 @@ size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size)
|
|
||||||
{
|
|
||||||
audio_generic_put_buffer_out_nowrite(hw, buf, size);
|
|
||||||
|
|
||||||
while (hw->pending_emul) {
|
|
||||||
size_t write_len, written;
|
|
||||||
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(hw->pending_emul, hw->size_emul - start);
|
|
||||||
|
|
||||||
written = hw->pcm_ops->write(hw, hw->buf_emul + start, write_len);
|
|
||||||
hw->pending_emul -= written;
|
|
||||||
|
|
||||||
if (written < write_len) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* fake we have written everything. non-written data remain in pending_emul,
|
|
||||||
* so we do not have to clip them multiple times
|
|
||||||
*/
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
|
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
size_t dst_size, copy_size;
|
size_t dst_size, copy_size;
|
||||||
@ -1476,17 +1486,17 @@ size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size)
|
|||||||
copy_size = MIN(size, dst_size);
|
copy_size = MIN(size, dst_size);
|
||||||
|
|
||||||
memcpy(dst, buf, copy_size);
|
memcpy(dst, buf, copy_size);
|
||||||
return hw->pcm_ops->put_buffer_out(hw, buf, copy_size);
|
return hw->pcm_ops->put_buffer_out(hw, dst, copy_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
|
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size)
|
||||||
{
|
{
|
||||||
size_t dst_size, copy_size;
|
size_t src_size, copy_size;
|
||||||
void *dst = hw->pcm_ops->get_buffer_in(hw, &dst_size);
|
void *src = hw->pcm_ops->get_buffer_in(hw, &src_size);
|
||||||
copy_size = MIN(size, dst_size);
|
copy_size = MIN(size, src_size);
|
||||||
|
|
||||||
memcpy(dst, buf, copy_size);
|
memcpy(buf, src, copy_size);
|
||||||
hw->pcm_ops->put_buffer_in(hw, buf, copy_size);
|
hw->pcm_ops->put_buffer_in(hw, src, copy_size);
|
||||||
return copy_size;
|
return copy_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1837,11 +1847,15 @@ CaptureVoiceOut *AUD_add_capture(
|
|||||||
|
|
||||||
cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
|
cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
|
||||||
|
|
||||||
|
if (hw->info.is_float) {
|
||||||
|
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
||||||
|
} else {
|
||||||
hw->clip = mixeng_clip
|
hw->clip = mixeng_clip
|
||||||
[hw->info.nchannels == 2]
|
[hw->info.nchannels == 2]
|
||||||
[hw->info.sign]
|
[hw->info.is_signed]
|
||||||
[hw->info.swap_endianness]
|
[hw->info.swap_endianness]
|
||||||
[audio_bits_to_index (hw->info.bits)];
|
[audio_bits_to_index(hw->info.bits)];
|
||||||
|
}
|
||||||
|
|
||||||
QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
|
QLIST_INSERT_HEAD (&s->cap_head, cap, entries);
|
||||||
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
QLIST_INSERT_HEAD (&cap->cb_head, cb, entries);
|
||||||
@ -2080,6 +2094,7 @@ int audioformat_bytes_per_sample(AudioFormat fmt)
|
|||||||
|
|
||||||
case AUDIO_FORMAT_U32:
|
case AUDIO_FORMAT_U32:
|
||||||
case AUDIO_FORMAT_S32:
|
case AUDIO_FORMAT_S32:
|
||||||
|
case AUDIO_FORMAT_F32:
|
||||||
return 4;
|
return 4;
|
||||||
|
|
||||||
case AUDIO_FORMAT__MAX:
|
case AUDIO_FORMAT__MAX:
|
||||||
|
@ -40,7 +40,8 @@ struct audio_callback {
|
|||||||
|
|
||||||
struct audio_pcm_info {
|
struct audio_pcm_info {
|
||||||
int bits;
|
int bits;
|
||||||
int sign;
|
bool is_signed;
|
||||||
|
bool is_float;
|
||||||
int freq;
|
int freq;
|
||||||
int nchannels;
|
int nchannels;
|
||||||
int bytes_per_frame;
|
int bytes_per_frame;
|
||||||
@ -152,6 +153,7 @@ struct audio_pcm_ops {
|
|||||||
int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
|
int (*init_out)(HWVoiceOut *hw, audsettings *as, void *drv_opaque);
|
||||||
void (*fini_out)(HWVoiceOut *hw);
|
void (*fini_out)(HWVoiceOut *hw);
|
||||||
size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
|
size_t (*write) (HWVoiceOut *hw, void *buf, size_t size);
|
||||||
|
void (*run_buffer_out)(HWVoiceOut *hw);
|
||||||
/*
|
/*
|
||||||
* get a buffer that after later can be passed to put_buffer_out; optional
|
* get a buffer that after later can be passed to put_buffer_out; optional
|
||||||
* returns the buffer, and writes it's size to size (in bytes)
|
* returns the buffer, and writes it's size to size (in bytes)
|
||||||
@ -178,10 +180,9 @@ struct audio_pcm_ops {
|
|||||||
|
|
||||||
void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size);
|
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_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size);
|
||||||
|
void audio_generic_run_buffer_out(HWVoiceOut *hw);
|
||||||
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
|
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size);
|
||||||
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
|
size_t audio_generic_put_buffer_out(HWVoiceOut *hw, void *buf, size_t size);
|
||||||
size_t audio_generic_put_buffer_out_nowrite(HWVoiceOut *hw, void *buf,
|
|
||||||
size_t size);
|
|
||||||
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
|
size_t audio_generic_write(HWVoiceOut *hw, void *buf, size_t size);
|
||||||
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
|
size_t audio_generic_read(HWVoiceIn *hw, void *buf, size_t size);
|
||||||
|
|
||||||
|
@ -153,15 +153,23 @@ static int glue (audio_pcm_sw_init_, TYPE) (
|
|||||||
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (sw->info.is_float) {
|
||||||
|
#ifdef DAC
|
||||||
|
sw->conv = mixeng_conv_float[sw->info.nchannels == 2];
|
||||||
|
#else
|
||||||
|
sw->clip = mixeng_clip_float[sw->info.nchannels == 2];
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
#ifdef DAC
|
#ifdef DAC
|
||||||
sw->conv = mixeng_conv
|
sw->conv = mixeng_conv
|
||||||
#else
|
#else
|
||||||
sw->clip = mixeng_clip
|
sw->clip = mixeng_clip
|
||||||
#endif
|
#endif
|
||||||
[sw->info.nchannels == 2]
|
[sw->info.nchannels == 2]
|
||||||
[sw->info.sign]
|
[sw->info.is_signed]
|
||||||
[sw->info.swap_endianness]
|
[sw->info.swap_endianness]
|
||||||
[audio_bits_to_index (sw->info.bits)];
|
[audio_bits_to_index(sw->info.bits)];
|
||||||
|
}
|
||||||
|
|
||||||
sw->name = g_strdup (name);
|
sw->name = g_strdup (name);
|
||||||
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
|
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
|
||||||
@ -276,15 +284,23 @@ static HW *glue(audio_pcm_hw_add_new_, TYPE)(AudioState *s,
|
|||||||
goto err1;
|
goto err1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hw->info.is_float) {
|
||||||
|
#ifdef DAC
|
||||||
|
hw->clip = mixeng_clip_float[hw->info.nchannels == 2];
|
||||||
|
#else
|
||||||
|
hw->conv = mixeng_conv_float[hw->info.nchannels == 2];
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
#ifdef DAC
|
#ifdef DAC
|
||||||
hw->clip = mixeng_clip
|
hw->clip = mixeng_clip
|
||||||
#else
|
#else
|
||||||
hw->conv = mixeng_conv
|
hw->conv = mixeng_conv
|
||||||
#endif
|
#endif
|
||||||
[hw->info.nchannels == 2]
|
[hw->info.nchannels == 2]
|
||||||
[hw->info.sign]
|
[hw->info.is_signed]
|
||||||
[hw->info.swap_endianness]
|
[hw->info.swap_endianness]
|
||||||
[audio_bits_to_index (hw->info.bits)];
|
[audio_bits_to_index(hw->info.bits)];
|
||||||
|
}
|
||||||
|
|
||||||
glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
|
glue(audio_pcm_hw_alloc_resources_, TYPE)(hw);
|
||||||
|
|
||||||
|
@ -411,7 +411,7 @@ static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name)
|
|||||||
}
|
}
|
||||||
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
COREAUDIO_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
||||||
(hw, size))
|
(hw, size))
|
||||||
COREAUDIO_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
|
COREAUDIO_WRAPPER_FUNC(put_buffer_out, size_t,
|
||||||
(HWVoiceOut *hw, void *buf, size_t size),
|
(HWVoiceOut *hw, void *buf, size_t size),
|
||||||
(hw, buf, size))
|
(hw, buf, size))
|
||||||
COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
|
COREAUDIO_WRAPPER_FUNC(write, size_t, (HWVoiceOut *hw, void *buf, size_t size),
|
||||||
@ -471,20 +471,6 @@ static OSStatus audioDeviceIOProc(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static UInt32 coreaudio_get_flags(struct audio_pcm_info *info,
|
|
||||||
struct audsettings *as)
|
|
||||||
{
|
|
||||||
UInt32 flags = info->sign ? kAudioFormatFlagIsSignedInteger : 0;
|
|
||||||
if (as->endianness) { /* 0 = little, 1 = big */
|
|
||||||
flags |= kAudioFormatFlagIsBigEndian;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags == 0) { /* must not be 0 */
|
|
||||||
flags = kAudioFormatFlagsAreAllClear;
|
|
||||||
}
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
||||||
void *drv_opaque)
|
void *drv_opaque)
|
||||||
{
|
{
|
||||||
@ -496,6 +482,7 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
Audiodev *dev = drv_opaque;
|
Audiodev *dev = drv_opaque;
|
||||||
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
|
AudiodevCoreaudioPerDirectionOptions *cpdo = dev->u.coreaudio.out;
|
||||||
int frames;
|
int frames;
|
||||||
|
struct audsettings fake_as;
|
||||||
|
|
||||||
/* create mutex */
|
/* create mutex */
|
||||||
err = pthread_mutex_init(&core->mutex, NULL);
|
err = pthread_mutex_init(&core->mutex, NULL);
|
||||||
@ -504,6 +491,9 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fake_as = *as;
|
||||||
|
as = &fake_as;
|
||||||
|
as->fmt = AUDIO_FORMAT_F32;
|
||||||
audio_pcm_init_info (&hw->info, as);
|
audio_pcm_init_info (&hw->info, as);
|
||||||
|
|
||||||
status = coreaudio_get_voice(&core->outputDeviceID);
|
status = coreaudio_get_voice(&core->outputDeviceID);
|
||||||
@ -572,15 +562,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
|
|
||||||
/* set Samplerate */
|
/* set Samplerate */
|
||||||
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
|
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
|
||||||
core->outputStreamBasicDescription.mFormatID = kAudioFormatLinearPCM;
|
|
||||||
core->outputStreamBasicDescription.mFormatFlags =
|
|
||||||
coreaudio_get_flags(&hw->info, as);
|
|
||||||
core->outputStreamBasicDescription.mBytesPerPacket =
|
|
||||||
core->outputStreamBasicDescription.mBytesPerFrame =
|
|
||||||
hw->info.nchannels * hw->info.bits / 8;
|
|
||||||
core->outputStreamBasicDescription.mFramesPerPacket = 1;
|
|
||||||
core->outputStreamBasicDescription.mChannelsPerFrame = hw->info.nchannels;
|
|
||||||
core->outputStreamBasicDescription.mBitsPerChannel = hw->info.bits;
|
|
||||||
|
|
||||||
status = coreaudio_set_streamformat(core->outputDeviceID,
|
status = coreaudio_set_streamformat(core->outputDeviceID,
|
||||||
&core->outputStreamBasicDescription);
|
&core->outputStreamBasicDescription);
|
||||||
@ -687,9 +668,12 @@ static void coreaudio_audio_fini (void *opaque)
|
|||||||
static struct audio_pcm_ops coreaudio_pcm_ops = {
|
static struct audio_pcm_ops coreaudio_pcm_ops = {
|
||||||
.init_out = coreaudio_init_out,
|
.init_out = coreaudio_init_out,
|
||||||
.fini_out = coreaudio_fini_out,
|
.fini_out = coreaudio_fini_out,
|
||||||
|
/* wrapper for audio_generic_write */
|
||||||
.write = coreaudio_write,
|
.write = coreaudio_write,
|
||||||
|
/* wrapper for audio_generic_get_buffer_out */
|
||||||
.get_buffer_out = coreaudio_get_buffer_out,
|
.get_buffer_out = coreaudio_get_buffer_out,
|
||||||
.put_buffer_out = coreaudio_put_buffer_out_nowrite,
|
/* wrapper for audio_generic_put_buffer_out */
|
||||||
|
.put_buffer_out = coreaudio_put_buffer_out,
|
||||||
.enable_out = coreaudio_enable_out
|
.enable_out = coreaudio_enable_out
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -244,6 +244,7 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
goto fail0;
|
goto fail0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ds->first_time = true;
|
||||||
obt_as.endianness = 0;
|
obt_as.endianness = 0;
|
||||||
audio_pcm_init_info (&hw->info, &obt_as);
|
audio_pcm_init_info (&hw->info, &obt_as);
|
||||||
|
|
||||||
|
@ -53,12 +53,14 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
HWVoiceOut hw;
|
HWVoiceOut hw;
|
||||||
LPDIRECTSOUNDBUFFER dsound_buffer;
|
LPDIRECTSOUNDBUFFER dsound_buffer;
|
||||||
|
bool first_time;
|
||||||
dsound *s;
|
dsound *s;
|
||||||
} DSoundVoiceOut;
|
} DSoundVoiceOut;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
HWVoiceIn hw;
|
HWVoiceIn hw;
|
||||||
LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
|
LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer;
|
||||||
|
bool first_time;
|
||||||
dsound *s;
|
dsound *s;
|
||||||
} DSoundVoiceIn;
|
} DSoundVoiceIn;
|
||||||
|
|
||||||
@ -414,21 +416,32 @@ static void *dsound_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
|||||||
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
|
DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;
|
||||||
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
DWORD ppos, act_size;
|
DWORD ppos, wpos, act_size;
|
||||||
size_t req_size;
|
size_t req_size;
|
||||||
int err;
|
int err;
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
hr = IDirectSoundBuffer_GetCurrentPosition(dsb, &ppos, NULL);
|
hr = IDirectSoundBuffer_GetCurrentPosition(
|
||||||
|
dsb, &ppos, ds->first_time ? &wpos : NULL);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dsound_logerr(hr, "Could not get playback buffer position\n");
|
dsound_logerr(hr, "Could not get playback buffer position\n");
|
||||||
*size = 0;
|
*size = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ds->first_time) {
|
||||||
|
hw->pos_emul = wpos;
|
||||||
|
ds->first_time = false;
|
||||||
|
}
|
||||||
|
|
||||||
req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
|
req_size = audio_ring_dist(ppos, hw->pos_emul, hw->size_emul);
|
||||||
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
|
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
|
||||||
|
|
||||||
|
if (req_size == 0) {
|
||||||
|
*size = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
|
err = dsound_lock_out(dsb, &hw->info, hw->pos_emul, req_size, &ret, NULL,
|
||||||
&act_size, NULL, false, ds->s);
|
&act_size, NULL, false, ds->s);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -508,18 +521,24 @@ static void *dsound_get_buffer_in(HWVoiceIn *hw, size_t *size)
|
|||||||
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;
|
||||||
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
DWORD cpos, act_size;
|
DWORD cpos, rpos, act_size;
|
||||||
size_t req_size;
|
size_t req_size;
|
||||||
int err;
|
int err;
|
||||||
void *ret;
|
void *ret;
|
||||||
|
|
||||||
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(dscb, &cpos, NULL);
|
hr = IDirectSoundCaptureBuffer_GetCurrentPosition(
|
||||||
|
dscb, &cpos, ds->first_time ? &rpos : NULL);
|
||||||
if (FAILED(hr)) {
|
if (FAILED(hr)) {
|
||||||
dsound_logerr(hr, "Could not get capture buffer position\n");
|
dsound_logerr(hr, "Could not get capture buffer position\n");
|
||||||
*size = 0;
|
*size = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ds->first_time) {
|
||||||
|
hw->pos_emul = rpos;
|
||||||
|
ds->first_time = false;
|
||||||
|
}
|
||||||
|
|
||||||
req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
|
req_size = audio_ring_dist(cpos, hw->pos_emul, hw->size_emul);
|
||||||
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
|
req_size = MIN(req_size, hw->size_emul - hw->pos_emul);
|
||||||
|
|
||||||
|
@ -267,6 +267,76 @@ f_sample *mixeng_clip[2][2][2][3] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef FLOAT_MIXENG
|
||||||
|
#define FLOAT_CONV_TO(x) (x)
|
||||||
|
#define FLOAT_CONV_FROM(x) (x)
|
||||||
|
#else
|
||||||
|
static const float float_scale = UINT_MAX;
|
||||||
|
#define FLOAT_CONV_TO(x) ((x) * float_scale)
|
||||||
|
|
||||||
|
#ifdef RECIPROCAL
|
||||||
|
static const float float_scale_reciprocal = 1.f / UINT_MAX;
|
||||||
|
#define FLOAT_CONV_FROM(x) ((x) * float_scale_reciprocal)
|
||||||
|
#else
|
||||||
|
#define FLOAT_CONV_FROM(x) ((x) / float_scale)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void conv_natural_float_to_mono(struct st_sample *dst, const void *src,
|
||||||
|
int samples)
|
||||||
|
{
|
||||||
|
float *in = (float *)src;
|
||||||
|
|
||||||
|
while (samples--) {
|
||||||
|
dst->r = dst->l = FLOAT_CONV_TO(*in++);
|
||||||
|
dst++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void conv_natural_float_to_stereo(struct st_sample *dst, const void *src,
|
||||||
|
int samples)
|
||||||
|
{
|
||||||
|
float *in = (float *)src;
|
||||||
|
|
||||||
|
while (samples--) {
|
||||||
|
dst->l = FLOAT_CONV_TO(*in++);
|
||||||
|
dst->r = FLOAT_CONV_TO(*in++);
|
||||||
|
dst++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_sample *mixeng_conv_float[2] = {
|
||||||
|
conv_natural_float_to_mono,
|
||||||
|
conv_natural_float_to_stereo,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void clip_natural_float_from_mono(void *dst, const struct st_sample *src,
|
||||||
|
int samples)
|
||||||
|
{
|
||||||
|
float *out = (float *)dst;
|
||||||
|
|
||||||
|
while (samples--) {
|
||||||
|
*out++ = FLOAT_CONV_FROM(src->l) + FLOAT_CONV_FROM(src->r);
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clip_natural_float_from_stereo(
|
||||||
|
void *dst, const struct st_sample *src, int samples)
|
||||||
|
{
|
||||||
|
float *out = (float *)dst;
|
||||||
|
|
||||||
|
while (samples--) {
|
||||||
|
*out++ = FLOAT_CONV_FROM(src->l);
|
||||||
|
*out++ = FLOAT_CONV_FROM(src->r);
|
||||||
|
src++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f_sample *mixeng_clip_float[2] = {
|
||||||
|
clip_natural_float_from_mono,
|
||||||
|
clip_natural_float_from_stereo,
|
||||||
|
};
|
||||||
|
|
||||||
void audio_sample_to_uint64(void *samples, int pos,
|
void audio_sample_to_uint64(void *samples, int pos,
|
||||||
uint64_t *left, uint64_t *right)
|
uint64_t *left, uint64_t *right)
|
||||||
|
@ -38,9 +38,14 @@ typedef struct st_sample st_sample;
|
|||||||
typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
|
typedef void (t_sample) (struct st_sample *dst, const void *src, int samples);
|
||||||
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
|
typedef void (f_sample) (void *dst, const struct st_sample *src, int samples);
|
||||||
|
|
||||||
|
/* indices: [stereo][signed][swap endiannes][8, 16 or 32-bits] */
|
||||||
extern t_sample *mixeng_conv[2][2][2][3];
|
extern t_sample *mixeng_conv[2][2][2][3];
|
||||||
extern f_sample *mixeng_clip[2][2][2][3];
|
extern f_sample *mixeng_clip[2][2][2][3];
|
||||||
|
|
||||||
|
/* indices: [stereo] */
|
||||||
|
extern t_sample *mixeng_conv_float[2];
|
||||||
|
extern f_sample *mixeng_clip_float[2];
|
||||||
|
|
||||||
void *st_rate_start (int inrate, int outrate);
|
void *st_rate_start (int inrate, int outrate);
|
||||||
void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
|
void st_rate_flow(void *opaque, st_sample *ibuf, st_sample *obuf,
|
||||||
size_t *isamp, size_t *osamp);
|
size_t *isamp, size_t *osamp);
|
||||||
|
@ -118,6 +118,7 @@ static struct audio_pcm_ops no_pcm_ops = {
|
|||||||
.init_out = no_init_out,
|
.init_out = no_init_out,
|
||||||
.fini_out = no_fini_out,
|
.fini_out = no_fini_out,
|
||||||
.write = no_write,
|
.write = no_write,
|
||||||
|
.run_buffer_out = audio_generic_run_buffer_out,
|
||||||
.enable_out = no_enable_out,
|
.enable_out = no_enable_out,
|
||||||
|
|
||||||
.init_in = no_init_in,
|
.init_in = no_init_in,
|
||||||
|
@ -382,6 +382,15 @@ static size_t oss_get_available_bytes(OSSVoiceOut *oss)
|
|||||||
return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
|
return audio_ring_dist(cntinfo.ptr, oss->hw.pos_emul, oss->hw.size_emul);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void oss_run_buffer_out(HWVoiceOut *hw)
|
||||||
|
{
|
||||||
|
OSSVoiceOut *oss = (OSSVoiceOut *)hw;
|
||||||
|
|
||||||
|
if (!oss->mmapped) {
|
||||||
|
audio_generic_run_buffer_out(hw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
static void *oss_get_buffer_out(HWVoiceOut *hw, size_t *size)
|
||||||
{
|
{
|
||||||
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
OSSVoiceOut *oss = (OSSVoiceOut *) hw;
|
||||||
@ -420,7 +429,7 @@ static size_t oss_write(HWVoiceOut *hw, void *buf, size_t len)
|
|||||||
size_t to_copy = MIN(len, hw->size_emul - hw->pos_emul);
|
size_t to_copy = MIN(len, hw->size_emul - hw->pos_emul);
|
||||||
memcpy(hw->buf_emul + hw->pos_emul, buf, to_copy);
|
memcpy(hw->buf_emul + hw->pos_emul, buf, to_copy);
|
||||||
|
|
||||||
hw->pos_emul = (hw->pos_emul + to_copy) % hw->pos_emul;
|
hw->pos_emul = (hw->pos_emul + to_copy) % hw->size_emul;
|
||||||
buf += to_copy;
|
buf += to_copy;
|
||||||
len -= to_copy;
|
len -= to_copy;
|
||||||
}
|
}
|
||||||
@ -570,20 +579,18 @@ static void oss_enable_out(HWVoiceOut *hw, bool enable)
|
|||||||
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
|
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
bool poll_mode = opdo->try_poll;
|
hw->poll_mode = opdo->try_poll;
|
||||||
|
|
||||||
ldebug("enabling voice\n");
|
ldebug("enabling voice\n");
|
||||||
if (poll_mode) {
|
if (hw->poll_mode) {
|
||||||
oss_poll_out(hw);
|
oss_poll_out(hw);
|
||||||
poll_mode = 0;
|
|
||||||
}
|
}
|
||||||
hw->poll_mode = poll_mode;
|
|
||||||
|
|
||||||
if (!oss->mmapped) {
|
if (!oss->mmapped) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->mix_buf->size);
|
audio_pcm_info_clear_buf(&hw->info, hw->buf_emul, hw->samples);
|
||||||
trig = PCM_ENABLE_OUTPUT;
|
trig = PCM_ENABLE_OUTPUT;
|
||||||
if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
|
if (ioctl(oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) {
|
||||||
oss_logerr(errno,
|
oss_logerr(errno,
|
||||||
@ -699,17 +706,15 @@ static void oss_enable_in(HWVoiceIn *hw, bool enable)
|
|||||||
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
|
AudiodevOssPerDirectionOptions *opdo = oss->dev->u.oss.out;
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
bool poll_mode = opdo->try_poll;
|
hw->poll_mode = opdo->try_poll;
|
||||||
|
|
||||||
if (poll_mode) {
|
if (hw->poll_mode) {
|
||||||
oss_poll_in(hw);
|
oss_poll_in(hw);
|
||||||
poll_mode = 0;
|
|
||||||
}
|
}
|
||||||
hw->poll_mode = poll_mode;
|
|
||||||
} else {
|
} else {
|
||||||
if (hw->poll_mode) {
|
if (hw->poll_mode) {
|
||||||
hw->poll_mode = 0;
|
|
||||||
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
|
qemu_set_fd_handler (oss->fd, NULL, NULL, NULL);
|
||||||
|
hw->poll_mode = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -748,6 +753,7 @@ static struct audio_pcm_ops oss_pcm_ops = {
|
|||||||
.init_out = oss_init_out,
|
.init_out = oss_init_out,
|
||||||
.fini_out = oss_fini_out,
|
.fini_out = oss_fini_out,
|
||||||
.write = oss_write,
|
.write = oss_write,
|
||||||
|
.run_buffer_out = oss_run_buffer_out,
|
||||||
.get_buffer_out = oss_get_buffer_out,
|
.get_buffer_out = oss_get_buffer_out,
|
||||||
.put_buffer_out = oss_put_buffer_out,
|
.put_buffer_out = oss_put_buffer_out,
|
||||||
.enable_out = oss_enable_out,
|
.enable_out = oss_enable_out,
|
||||||
|
@ -32,7 +32,6 @@ typedef struct {
|
|||||||
HWVoiceOut hw;
|
HWVoiceOut hw;
|
||||||
pa_stream *stream;
|
pa_stream *stream;
|
||||||
paaudio *g;
|
paaudio *g;
|
||||||
size_t samples;
|
|
||||||
} PAVoiceOut;
|
} PAVoiceOut;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -41,7 +40,6 @@ typedef struct {
|
|||||||
const void *read_data;
|
const void *read_data;
|
||||||
size_t read_length;
|
size_t read_length;
|
||||||
paaudio *g;
|
paaudio *g;
|
||||||
size_t samples;
|
|
||||||
} PAVoiceIn;
|
} PAVoiceIn;
|
||||||
|
|
||||||
static void qpa_conn_fini(PAConnection *c);
|
static void qpa_conn_fini(PAConnection *c);
|
||||||
@ -279,6 +277,9 @@ static pa_sample_format_t audfmt_to_pa (AudioFormat afmt, int endianness)
|
|||||||
case AUDIO_FORMAT_U32:
|
case AUDIO_FORMAT_U32:
|
||||||
format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
|
format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE;
|
||||||
break;
|
break;
|
||||||
|
case AUDIO_FORMAT_F32:
|
||||||
|
format = endianness ? PA_SAMPLE_FLOAT32BE : PA_SAMPLE_FLOAT32LE;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dolog ("Internal logic error: Bad audio format %d\n", afmt);
|
dolog ("Internal logic error: Bad audio format %d\n", afmt);
|
||||||
format = PA_SAMPLE_U8;
|
format = PA_SAMPLE_U8;
|
||||||
@ -304,6 +305,12 @@ static AudioFormat pa_to_audfmt (pa_sample_format_t fmt, int *endianness)
|
|||||||
case PA_SAMPLE_S32LE:
|
case PA_SAMPLE_S32LE:
|
||||||
*endianness = 0;
|
*endianness = 0;
|
||||||
return AUDIO_FORMAT_S32;
|
return AUDIO_FORMAT_S32;
|
||||||
|
case PA_SAMPLE_FLOAT32BE:
|
||||||
|
*endianness = 1;
|
||||||
|
return AUDIO_FORMAT_F32;
|
||||||
|
case PA_SAMPLE_FLOAT32LE:
|
||||||
|
*endianness = 0;
|
||||||
|
return AUDIO_FORMAT_F32;
|
||||||
default:
|
default:
|
||||||
dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
|
dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt);
|
||||||
return AUDIO_FORMAT_U8;
|
return AUDIO_FORMAT_U8;
|
||||||
@ -488,7 +495,7 @@ static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as,
|
|||||||
}
|
}
|
||||||
|
|
||||||
audio_pcm_init_info (&hw->info, &obt_as);
|
audio_pcm_init_info (&hw->info, &obt_as);
|
||||||
hw->samples = pa->samples = audio_buffer_samples(
|
hw->samples = audio_buffer_samples(
|
||||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
||||||
&obt_as, ppdo->buffer_length);
|
&obt_as, ppdo->buffer_length);
|
||||||
|
|
||||||
@ -536,7 +543,7 @@ static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
audio_pcm_init_info (&hw->info, &obt_as);
|
audio_pcm_init_info (&hw->info, &obt_as);
|
||||||
hw->samples = pa->samples = audio_buffer_samples(
|
hw->samples = audio_buffer_samples(
|
||||||
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
qapi_AudiodevPaPerDirectionOptions_base(ppdo),
|
||||||
&obt_as, ppdo->buffer_length);
|
&obt_as, ppdo->buffer_length);
|
||||||
|
|
||||||
|
@ -77,6 +77,14 @@ static int aud_to_sdlfmt (AudioFormat fmt)
|
|||||||
case AUDIO_FORMAT_U16:
|
case AUDIO_FORMAT_U16:
|
||||||
return AUDIO_U16LSB;
|
return AUDIO_U16LSB;
|
||||||
|
|
||||||
|
case AUDIO_FORMAT_S32:
|
||||||
|
return AUDIO_S32LSB;
|
||||||
|
|
||||||
|
/* no unsigned 32-bit support in SDL */
|
||||||
|
|
||||||
|
case AUDIO_FORMAT_F32:
|
||||||
|
return AUDIO_F32LSB;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
dolog ("Internal logic error: Bad audio format %d\n", fmt);
|
||||||
#ifdef DEBUG_AUDIO
|
#ifdef DEBUG_AUDIO
|
||||||
@ -119,6 +127,26 @@ static int sdl_to_audfmt(int sdlfmt, AudioFormat *fmt, int *endianness)
|
|||||||
*fmt = AUDIO_FORMAT_U16;
|
*fmt = AUDIO_FORMAT_U16;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AUDIO_S32LSB:
|
||||||
|
*endianness = 0;
|
||||||
|
*fmt = AUDIO_FORMAT_S32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUDIO_S32MSB:
|
||||||
|
*endianness = 1;
|
||||||
|
*fmt = AUDIO_FORMAT_S32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUDIO_F32LSB:
|
||||||
|
*endianness = 0;
|
||||||
|
*fmt = AUDIO_FORMAT_F32;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AUDIO_F32MSB:
|
||||||
|
*endianness = 1;
|
||||||
|
*fmt = AUDIO_FORMAT_F32;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
|
dolog ("Unrecognized SDL audio format %d\n", sdlfmt);
|
||||||
return -1;
|
return -1;
|
||||||
@ -227,7 +255,7 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
|
|||||||
|
|
||||||
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
SDL_WRAPPER_FUNC(get_buffer_out, void *, (HWVoiceOut *hw, size_t *size),
|
||||||
(hw, size), *size = 0, sdl_unlock)
|
(hw, size), *size = 0, sdl_unlock)
|
||||||
SDL_WRAPPER_FUNC(put_buffer_out_nowrite, size_t,
|
SDL_WRAPPER_FUNC(put_buffer_out, size_t,
|
||||||
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
|
(HWVoiceOut *hw, void *buf, size_t size), (hw, buf, size),
|
||||||
/*nothing*/, sdl_unlock_and_post)
|
/*nothing*/, sdl_unlock_and_post)
|
||||||
SDL_WRAPPER_FUNC(write, size_t,
|
SDL_WRAPPER_FUNC(write, size_t,
|
||||||
@ -320,9 +348,12 @@ static void sdl_audio_fini (void *opaque)
|
|||||||
static struct audio_pcm_ops sdl_pcm_ops = {
|
static struct audio_pcm_ops sdl_pcm_ops = {
|
||||||
.init_out = sdl_init_out,
|
.init_out = sdl_init_out,
|
||||||
.fini_out = sdl_fini_out,
|
.fini_out = sdl_fini_out,
|
||||||
|
/* wrapper for audio_generic_write */
|
||||||
.write = sdl_write,
|
.write = sdl_write,
|
||||||
|
/* wrapper for audio_generic_get_buffer_out */
|
||||||
.get_buffer_out = sdl_get_buffer_out,
|
.get_buffer_out = sdl_get_buffer_out,
|
||||||
.put_buffer_out = sdl_put_buffer_out_nowrite,
|
/* wrapper for audio_generic_put_buffer_out */
|
||||||
|
.put_buffer_out = sdl_put_buffer_out,
|
||||||
.enable_out = sdl_enable_out,
|
.enable_out = sdl_enable_out,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -197,6 +197,7 @@ static struct audio_pcm_ops wav_pcm_ops = {
|
|||||||
.init_out = wav_init_out,
|
.init_out = wav_init_out,
|
||||||
.fini_out = wav_fini_out,
|
.fini_out = wav_fini_out,
|
||||||
.write = wav_write_out,
|
.write = wav_write_out,
|
||||||
|
.run_buffer_out = audio_generic_run_buffer_out,
|
||||||
.enable_out = wav_enable_out,
|
.enable_out = wav_enable_out,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -276,7 +276,7 @@
|
|||||||
# Since: 4.0
|
# Since: 4.0
|
||||||
##
|
##
|
||||||
{ 'enum': 'AudioFormat',
|
{ 'enum': 'AudioFormat',
|
||||||
'data': [ 'u8', 's8', 'u16', 's16', 'u32', 's32' ] }
|
'data': [ 'u8', 's8', 'u16', 's16', 'u32', 's32', 'f32' ] }
|
||||||
|
|
||||||
##
|
##
|
||||||
# @AudiodevDriver:
|
# @AudiodevDriver:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user