audio: bugfix collection.

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEoDKM/7k6F6eZAf59TLbY7tPocTgFAmDLQtgACgkQTLbY7tPo
 cThtSg//VdvGkZjJuEUgcDWqgW1lsf+bXuCQxGl0e9wmTvhn4avxw6vn2Dqb7Ygz
 8T2f7FFIN+O8pb6cl3LFbp/sBnl0OoEpTRjw6M6ehBLiPDy/jmik9nbgngKtSRp6
 9ug5ixHmVPhOHDdbVInkRiOjxdVolRwPK9g0grAhlX0cyq7vtMWFT3DQ2zqn6v6y
 591ODWM+WgkCEyoD/TDr+Wq7DJjXSfYaFk/G8i3lz6uD22cnoLOW4L3PcInGzyJz
 GswDEUuNlblNDq1iVySeZXJfewkFIXvebgzkDCST8tGj469R1P+lZzSRiTO44HG5
 Ys62fBGEEmOzj9nIqrQBu043QU89xSKWb1FlIskPhbxjOCmCWPRD9guhHpVozxHV
 QUvClG7SeRJ6hnAfFfsuJ5PWqnbCG7ppbouOckB/iGaf2ow3cNwZQUtd2/YzJPiH
 8+4mrA+pxOaWPRK4Slg927Bz4HKVPAbb2fy9w+ppAX4vE4IgqxduWJQfW9i8FFhz
 3tR9nNM+X2qsSYqA66i5O6LJ/LqStSZB+4v2pTb9GLvM2ZPCvbTSKQWtDX2IZexf
 YvOuIouK6r+bMxXbKYT3zjd7QylqMp+5aXSqP6S4Y8rsN+KT8xKyQoep4WPNCLA/
 djxqOgsOpRMC5YSk5JCTa1NHGTrEJmmniWJdrA/tg2F7FwZx0HY=
 =gyKd
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kraxel/tags/audio-20210617-pull-request' into staging

audio: bugfix collection.

# gpg: Signature made Thu 17 Jun 2021 13:40:56 BST
# 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-20210617-pull-request:
  coreaudio: Fix output stream format settings
  audio: Fix format specifications of debug logs
  hw/audio/sb16: Avoid assertion by restricting I/O sampling rate range
  jackaudio: avoid that the client name contains the word (NULL)
  audio: move code to audio/audio.c
  paaudio: remove unused stream flags
  alsaaudio: remove #ifdef DEBUG to avoid bit rot

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2021-06-18 09:54:42 +01:00
commit 3ccf6cd0e3
10 changed files with 102 additions and 54 deletions

View File

@ -2221,6 +2221,7 @@ F: qapi/audio.json
F: tests/qtest/ac97-test.c F: tests/qtest/ac97-test.c
F: tests/qtest/es1370-test.c F: tests/qtest/es1370-test.c
F: tests/qtest/intel-hda-test.c F: tests/qtest/intel-hda-test.c
F: tests/qtest/fuzz-sb16-test.c
Block layer core Block layer core
M: Kevin Wolf <kwolf@redhat.com> M: Kevin Wolf <kwolf@redhat.com>

View File

@ -34,6 +34,8 @@
#define AUDIO_CAP "alsa" #define AUDIO_CAP "alsa"
#include "audio_int.h" #include "audio_int.h"
#define DEBUG_ALSA 0
struct pollhlp { struct pollhlp {
snd_pcm_t *handle; snd_pcm_t *handle;
struct pollfd *pfds; struct pollfd *pfds;
@ -587,16 +589,12 @@ static int alsa_open(bool in, struct alsa_params_req *req,
*handlep = handle; *handlep = handle;
if (obtfmt != req->fmt || if (DEBUG_ALSA || obtfmt != req->fmt ||
obt->nchannels != req->nchannels || obt->nchannels != req->nchannels || obt->freq != req->freq) {
obt->freq != req->freq) {
dolog ("Audio parameters for %s\n", typ); dolog ("Audio parameters for %s\n", typ);
alsa_dump_info(req, obt, obtfmt, apdo); alsa_dump_info(req, obt, obtfmt, apdo);
} }
#ifdef DEBUG
alsa_dump_info(req, obt, obtfmt, apdo);
#endif
return 0; return 0;
err: err:

View File

@ -32,6 +32,7 @@
#include "qapi/qapi-visit-audio.h" #include "qapi/qapi-visit-audio.h"
#include "qemu/cutils.h" #include "qemu/cutils.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu-common.h"
#include "sysemu/replay.h" #include "sysemu/replay.h"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "ui/qemu-spice.h" #include "ui/qemu-spice.h"
@ -704,7 +705,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
if (live == hwsamples) { if (live == hwsamples) {
#ifdef DEBUG_OUT #ifdef DEBUG_OUT
dolog ("%s is full %d\n", sw->name, live); dolog ("%s is full %zu\n", sw->name, live);
#endif #endif
return 0; return 0;
} }
@ -994,7 +995,7 @@ static size_t audio_get_avail (SWVoiceIn *sw)
} }
ldebug ( ldebug (
"%s: get_avail live %d ret %" PRId64 "\n", "%s: get_avail live %zu ret %" PRId64 "\n",
SW_NAME (sw), SW_NAME (sw),
live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame
); );
@ -1021,7 +1022,7 @@ static size_t audio_get_free(SWVoiceOut *sw)
dead = sw->hw->mix_buf->size - live; dead = sw->hw->mix_buf->size - live;
#ifdef DEBUG_OUT #ifdef DEBUG_OUT
dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n", dolog ("%s: get_free live %zu dead %zu ret %" PRId64 "\n",
SW_NAME (sw), SW_NAME (sw),
live, dead, (((int64_t) dead << 32) / sw->ratio) * live, dead, (((int64_t) dead << 32) / sw->ratio) *
sw->info.bytes_per_frame); sw->info.bytes_per_frame);
@ -2172,6 +2173,14 @@ const char *audio_get_id(QEMUSoundCard *card)
} }
} }
const char *audio_application_name(void)
{
const char *vm_name;
vm_name = qemu_get_vm_name();
return vm_name ? vm_name : "qemu";
}
void audio_rate_start(RateCtl *rate) void audio_rate_start(RateCtl *rate)
{ {
memset(rate, 0, sizeof(RateCtl)); memset(rate, 0, sizeof(RateCtl));

View File

@ -243,6 +243,8 @@ void *audio_calloc (const char *funcname, int nmemb, size_t size);
void audio_run(AudioState *s, const char *msg); void audio_run(AudioState *s, const char *msg);
const char *audio_application_name(void);
typedef struct RateCtl { typedef struct RateCtl {
int64_t start_ticks; int64_t start_ticks;
int64_t bytes_sent; int64_t bytes_sent;

View File

@ -39,7 +39,6 @@ typedef struct coreaudioVoiceOut {
int frameSizeSetting; int frameSizeSetting;
uint32_t bufferCount; uint32_t bufferCount;
UInt32 audioDevicePropertyBufferFrameSize; UInt32 audioDevicePropertyBufferFrameSize;
AudioStreamBasicDescription outputStreamBasicDescription;
AudioDeviceIOProcID ioprocid; AudioDeviceIOProcID ioprocid;
bool enabled; bool enabled;
} coreaudioVoiceOut; } coreaudioVoiceOut;
@ -114,24 +113,6 @@ static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize)
framesize); framesize);
} }
static OSStatus coreaudio_get_streamformat(AudioDeviceID id,
AudioStreamBasicDescription *d)
{
UInt32 size = sizeof(*d);
AudioObjectPropertyAddress addr = {
kAudioDevicePropertyStreamFormat,
kAudioDevicePropertyScopeOutput,
kAudioObjectPropertyElementMaster
};
return AudioObjectGetPropertyData(id,
&addr,
0,
NULL,
&size,
d);
}
static OSStatus coreaudio_set_streamformat(AudioDeviceID id, static OSStatus coreaudio_set_streamformat(AudioDeviceID id,
AudioStreamBasicDescription *d) AudioStreamBasicDescription *d)
{ {
@ -373,6 +354,17 @@ static OSStatus init_out_device(coreaudioVoiceOut *core)
OSStatus status; OSStatus status;
AudioValueRange frameRange; AudioValueRange frameRange;
AudioStreamBasicDescription streamBasicDescription = {
.mBitsPerChannel = core->hw.info.bits,
.mBytesPerFrame = core->hw.info.bytes_per_frame,
.mBytesPerPacket = core->hw.info.bytes_per_frame,
.mChannelsPerFrame = core->hw.info.nchannels,
.mFormatFlags = kLinearPCMFormatFlagIsFloat,
.mFormatID = kAudioFormatLinearPCM,
.mFramesPerPacket = 1,
.mSampleRate = core->hw.info.freq
};
status = coreaudio_get_voice(&core->outputDeviceID); status = coreaudio_get_voice(&core->outputDeviceID);
if (status != kAudioHardwareNoError) { if (status != kAudioHardwareNoError) {
coreaudio_playback_logerr (status, coreaudio_playback_logerr (status,
@ -432,29 +424,16 @@ static OSStatus init_out_device(coreaudioVoiceOut *core)
} }
core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize; core->hw.samples = core->bufferCount * core->audioDevicePropertyBufferFrameSize;
/* get StreamFormat */
status = coreaudio_get_streamformat(core->outputDeviceID,
&core->outputStreamBasicDescription);
if (status == kAudioHardwareBadObjectError) {
return 0;
}
if (status != kAudioHardwareNoError) {
coreaudio_playback_logerr (status,
"Could not get Device Stream properties\n");
core->outputDeviceID = kAudioDeviceUnknown;
return status;
}
/* set Samplerate */ /* set Samplerate */
status = coreaudio_set_streamformat(core->outputDeviceID, status = coreaudio_set_streamformat(core->outputDeviceID,
&core->outputStreamBasicDescription); &streamBasicDescription);
if (status == kAudioHardwareBadObjectError) { if (status == kAudioHardwareBadObjectError) {
return 0; return 0;
} }
if (status != kAudioHardwareNoError) { if (status != kAudioHardwareNoError) {
coreaudio_playback_logerr (status, coreaudio_playback_logerr (status,
"Could not set samplerate %lf\n", "Could not set samplerate %lf\n",
core->outputStreamBasicDescription.mSampleRate); streamBasicDescription.mSampleRate);
core->outputDeviceID = kAudioDeviceUnknown; core->outputDeviceID = kAudioDeviceUnknown;
return status; return status;
} }
@ -598,7 +577,6 @@ static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as,
qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610); qapi_AudiodevCoreaudioPerDirectionOptions_base(cpdo), as, 11610);
core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4; core->bufferCount = cpdo->has_buffer_count ? cpdo->buffer_count : 4;
core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq;
status = AudioObjectAddPropertyListener(kAudioObjectSystemObject, status = AudioObjectAddPropertyListener(kAudioObjectSystemObject,
&voice_addr, handle_voice_change, &voice_addr, handle_voice_change,

View File

@ -26,7 +26,6 @@
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu/atomic.h" #include "qemu/atomic.h"
#include "qemu/main-loop.h" #include "qemu/main-loop.h"
#include "qemu-common.h"
#include "audio.h" #include "audio.h"
#define AUDIO_CAP "jack" #define AUDIO_CAP "jack"
@ -412,7 +411,7 @@ static int qjack_client_init(QJackClient *c)
snprintf(client_name, sizeof(client_name), "%s-%s", snprintf(client_name, sizeof(client_name), "%s-%s",
c->out ? "out" : "in", c->out ? "out" : "in",
c->opt->client_name ? c->opt->client_name : qemu_get_vm_name()); c->opt->client_name ? c->opt->client_name : audio_application_name());
if (c->opt->exact_name) { if (c->opt->exact_name) {
options |= JackUseExactName; options |= JackUseExactName;

View File

@ -2,7 +2,6 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "qemu-common.h"
#include "audio.h" #include "audio.h"
#include "qapi/opts-visitor.h" #include "qapi/opts-visitor.h"
@ -463,10 +462,7 @@ static pa_stream *qpa_simple_new (
pa_stream_set_state_callback(stream, stream_state_cb, c); pa_stream_set_state_callback(stream, stream_state_cb, c);
flags = flags = PA_STREAM_EARLY_REQUESTS;
PA_STREAM_INTERPOLATE_TIMING
| PA_STREAM_AUTO_TIMING_UPDATE
| PA_STREAM_EARLY_REQUESTS;
if (dev) { if (dev) {
/* don't move the stream if the user specified a sink/source */ /* don't move the stream if the user specified a sink/source */
@ -756,7 +752,6 @@ static int qpa_validate_per_direction_opts(Audiodev *dev,
/* common */ /* common */
static void *qpa_conn_init(const char *server) static void *qpa_conn_init(const char *server)
{ {
const char *vm_name;
PAConnection *c = g_malloc0(sizeof(PAConnection)); PAConnection *c = g_malloc0(sizeof(PAConnection));
QTAILQ_INSERT_TAIL(&pa_conns, c, list); QTAILQ_INSERT_TAIL(&pa_conns, c, list);
@ -765,9 +760,8 @@ static void *qpa_conn_init(const char *server)
goto fail; goto fail;
} }
vm_name = qemu_get_vm_name();
c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop), c->context = pa_context_new(pa_threaded_mainloop_get_api(c->mainloop),
vm_name ? vm_name : "qemu"); audio_application_name());
if (!c->context) { if (!c->context) {
goto fail; goto fail;
} }

View File

@ -115,6 +115,9 @@ struct SB16State {
PortioList portio_list; PortioList portio_list;
}; };
#define SAMPLE_RATE_MIN 5000
#define SAMPLE_RATE_MAX 45000
static void SB_audio_callback (void *opaque, int free); static void SB_audio_callback (void *opaque, int free);
static int magic_of_irq (int irq) static int magic_of_irq (int irq)
@ -241,6 +244,17 @@ static void dma_cmd8 (SB16State *s, int mask, int dma_len)
int tmp = (256 - s->time_const); int tmp = (256 - s->time_const);
s->freq = (1000000 + (tmp / 2)) / tmp; s->freq = (1000000 + (tmp / 2)) / tmp;
} }
if (s->freq < SAMPLE_RATE_MIN) {
qemu_log_mask(LOG_GUEST_ERROR,
"sampling range too low: %d, increasing to %u\n",
s->freq, SAMPLE_RATE_MIN);
s->freq = SAMPLE_RATE_MIN;
} else if (s->freq > SAMPLE_RATE_MAX) {
qemu_log_mask(LOG_GUEST_ERROR,
"sampling range too high: %d, decreasing to %u\n",
s->freq, SAMPLE_RATE_MAX);
s->freq = SAMPLE_RATE_MAX;
}
if (dma_len != -1) { if (dma_len != -1) {
s->block_size = dma_len << s->fmt_stereo; s->block_size = dma_len << s->fmt_stereo;

View File

@ -0,0 +1,52 @@
/*
* QTest fuzzer-generated testcase for sb16 audio device
*
* Copyright (c) 2021 Philippe Mathieu-Daudé <f4bug@amsat.org>
*
* SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "qemu/osdep.h"
#include "libqos/libqtest.h"
/*
* This used to trigger the assert in audio_calloc
* https://bugs.launchpad.net/qemu/+bug/1910603
*/
static void test_fuzz_sb16_0x1c(void)
{
QTestState *s = qtest_init("-M q35 -display none "
"-device sb16,audiodev=snd0 "
"-audiodev none,id=snd0");
qtest_outw(s, 0x22c, 0x41);
qtest_outb(s, 0x22c, 0x00);
qtest_outw(s, 0x22c, 0x1004);
qtest_outw(s, 0x22c, 0x001c);
qtest_quit(s);
}
static void test_fuzz_sb16_0x91(void)
{
QTestState *s = qtest_init("-M pc -display none "
"-device sb16,audiodev=none "
"-audiodev id=none,driver=none");
qtest_outw(s, 0x22c, 0xf141);
qtest_outb(s, 0x22c, 0x00);
qtest_outb(s, 0x22c, 0x24);
qtest_outb(s, 0x22c, 0x91);
qtest_quit(s);
}
int main(int argc, char **argv)
{
const char *arch = qtest_get_arch();
g_test_init(&argc, &argv, NULL);
if (strcmp(arch, "i386") == 0) {
qtest_add_func("fuzz/test_fuzz_sb16/1c", test_fuzz_sb16_0x1c);
qtest_add_func("fuzz/test_fuzz_sb16/91", test_fuzz_sb16_0x91);
}
return g_test_run();
}

View File

@ -20,6 +20,7 @@ slow_qtests = {
qtests_generic = \ qtests_generic = \
(config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \ (config_all_devices.has_key('CONFIG_MEGASAS_SCSI_PCI') ? ['fuzz-megasas-test'] : []) + \
(config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \
(config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \
[ [
'cdrom-test', 'cdrom-test',
'device-introspect-test', 'device-introspect-test',