-audiodev option
cover -audiodev option
Note: this patch depends on my not-yet-merged audio cleanup patches:
https://lists.nongnu.org/archive/html/qemu-devel/2015-06/msg02558.html
This series of patches adds a new -audiodev command line option to specify audio subsytem parameters instead of environment variables. This will later allow us to specify multiple audio backends. The syntax is something like this:
-audiodev driver_name,property=value,...
like:
-audiodev alsa,frequency=8000,channels=1
The first 6 commits are cleanup commits of the audio backends. The next commit adds a qapi Audiodev struct that describes the audio backend options. The next 4 commits are some miscellaneous additions that are needed by the last commit which finally adds the -audiodev option.
For users with esoteric platforms or needs please check I did not break anything accidentally. For easier testing, pull https://github.com/DirtYiCE/qemu.git tag audio-cmdline-v1.
Please review.
Kővágó, Zoltán (12):
audio: remove LOG_TO_MONITOR along with default_mon
audio: remove plive
dsoundaudio: remove *_retries kludges
dsoundaudio: remove primary buffer
alsaaudio: use trace events instead of verbose
ossaudio: use trace events instead of debug config flag
qapi: qapi for audio backends
qapi: support nested structs in OptsVisitor
opts: do not print separator before first item in qemu_opts_print
qapi: AllocVisitor
audio: use qapi AudioFormat instead of audfmt_e
audio: -audiodev command line option
Makefile | 4 +- audio/Makefile.objs | 2 +- audio/alsaaudio.c | 397 +++++---------- audio/audio.c | 831 +++++++++----------------------- audio/audio.h | 32 +- audio/audio_int.h | 7 +- audio/audio_legacy.c | 319 ++++++++++++ audio/audio_template.h | 54 +-- audio/audio_win_int.c | 18 +- audio/coreaudio.c | 49 +- audio/dsound_template.h | 41 +- audio/dsoundaudio.c | 228 ++------- audio/noaudio.c | 3 +- audio/ossaudio.c | 208 +++----- audio/paaudio.c | 109 ++--- audio/sdlaudio.c | 50 +- audio/spiceaudio.c | 11 +- audio/wavaudio.c | 76 +-- audio/wavcapture.c | 2 +- block.c | 2 +- hw/arm/omap2.c | 2 +- hw/audio/ac97.c | 2 +- hw/audio/adlib.c | 2 +- hw/audio/cs4231a.c | 6 +- hw/audio/es1370.c | 4 +- hw/audio/gus.c | 2 +- hw/audio/hda-codec.c | 18 +- hw/audio/lm4549.c | 6 +- hw/audio/milkymist-ac97.c | 2 +- hw/audio/pcspk.c | 2 +- hw/audio/sb16.c | 14 +- hw/audio/wm8750.c | 4 +- hw/input/tsc210x.c | 2 +- hw/usb/dev-audio.c | 2 +- include/monitor/monitor.h | 1 - include/qapi/alloc-visitor.h | 18 + monitor.c | 4 - qapi-schema.json | 3 + qapi/Makefile.objs | 1 + qapi/alloc-visitor.c | 62 +++ qapi/audio.json | 217 +++++++++ qapi/opts-visitor.c | 144 ++++-- qemu-options.hx | 218 ++++++++- tests/qapi-schema/qapi-schema-test.json | 9 +- tests/test-opts-visitor.c | 34 ++ trace-events | 16 + ui/vnc.c | 14 +- util/qemu-option.c | 5 +- vl.c | 9 +- 49 files changed, 1663 insertions(+), 1603 deletions(-) create mode 100644 audio/audio_legacy.c create mode 100644 include/qapi/alloc-visitor.h create mode 100644 qapi/alloc-visitor.c create mode 100644 qapi/audio.json
Signature · 1 line
2.4.2
PATCH 1/12 audio: remove LOG_TO_MONITOR along with default_mon
Setting QEMU_AUDIO_LOG_TO_MONITOR=1 can crash qemu (if qemu tries to log to the monitor before it's being initialized), and also nothing else in qemu logs to the monitor.
This log to monitor feature was the last thing that used the default_mon variable, so I removed it too (as using it can cause problems).
--- audio/audio.c | 23 +++-------------------- include/monitor/monitor.h | 1 - monitor.c | 4 ---- 3 files changed, 3 insertions(+), 25 deletions(-)
audio/audio.c +3 -20
@@ -67,7 +67,6 @@ static struct {int64_t ticks; } period;int plive; -int log_to_monitor;int try_poll_in;int try_poll_out; } conf = {
@@ -97,7 +96,6 @@ static struct { .period = { .hertz = 100 }, .plive = 0, - .log_to_monitor = 0, .try_poll_in = 1, .try_poll_out = 1, };
@@ -331,20 +329,11 @@ static const char *audio_get_conf_str (const char *key,void AUD_vlog (const char *cap,const char *fmt,va_list ap) { -if (conf.log_to_monitor) { -if (cap) { -monitor_printf (default_mon,"%s: " , cap); - } - -monitor_vprintf (default_mon, fmt, ap); +if (cap) { +fprintf (stderr,"%s: " , cap); } -else { -if (cap) { -fprintf (stderr,"%s: " , cap); - } -vfprintf (stderr, fmt, ap); - } +vfprintf (stderr, fmt, ap); }void AUD_log (const char *cap,const char *fmt, ...)
@@ -1654,12 +1643,6 @@ static struct audio_option audio_options[] = { .valp = &conf.plive, .descr = "(undocumented)" }, - { - .name = "LOG_TO_MONITOR", - .tag = AUD_OPT_BOOL, - .valp = &conf.log_to_monitor, - .descr = "Print logging messages to monitor instead of stderr" - }, {/* End of list */ } };
include/monitor/monitor.h +0 -1
@@ -8,7 +8,6 @@#include "qemu/readline.h" extern Monitor *cur_mon; -extern Monitor *default_mon;/* flags for monitor_init */ #define MONITOR_IS_DEFAULT 0x01
monitor.c +0 -4
@@ -226,7 +226,6 @@ static mon_cmd_t info_cmds[];static const mon_cmd_t qmp_cmds[];Monitor *cur_mon; -Monitor *default_mon;static void monitor_command_cb (void *opaque,const char *cmdline,void *readline_opaque);
@@ -5270,9 +5269,6 @@ void monitor_init(CharDriverState *chr, int flags)qemu_mutex_lock (&monitor_lock);QLIST_INSERT_HEAD (&mon_list, mon, entry);qemu_mutex_unlock (&monitor_lock); - -if (!default_mon || (flags &MONITOR_IS_DEFAULT )) - default_mon = mon; } static void bdrv_password_cb(void *opaque, const char *password,
Signature · 1 line
2.4.2
PATCH 2/12 audio: remove plive
In reply to Kővágó, ZoltánIt was useless even 3 years ago, so it can probably safely go away:
https://lists.nongnu.org/archive/html/qemu-devel/2012-03/msg02427.html
--- audio/audio.c | 12 ------------ audio/audio_template.h | 41 ----------------------------------------- 2 files changed, 53 deletions(-)
audio/audio.c +0 -12
@@ -30,7 +30,6 @@#define AUDIO_CAP "audio"#include "audio_int.h" -/* #define DEBUG_PLIVE */ /* #define DEBUG_LIVE */ /* #define DEBUG_OUT */ /* #define DEBUG_CAPTURE */
@@ -66,7 +65,6 @@ static struct {int hertz;int64_t ticks; } period; -int plive;int try_poll_in;int try_poll_out; } conf = {
@@ -95,7 +93,6 @@ static struct { }, .period = { .hertz = 100 }, - .plive = 0, .try_poll_in = 1, .try_poll_out = 1, };
@@ -1443,9 +1440,6 @@ static void audio_run_out (AudioState *s)while (sw) { sw1 = sw->entries.le_next;if (!sw->active && !sw->callback.fn) { -#ifdef DEBUG_PLIVE -dolog ("Finishing with old voice\n" ); -#endif audio_close_out (sw); } sw = sw1;
@@ -1637,12 +1631,6 @@ static struct audio_option audio_options[] = { .valp = &conf.period.hertz, .descr = "Timer period in HZ (0 - use lowest possible)" }, - { - .name = "PLIVE", - .tag = AUD_OPT_BOOL, - .valp = &conf.plive, - .descr = "(undocumented)" - }, {/* End of list */ } };
audio/audio_template.h +0 -41
59 lines not on this page · raw message
Signature · 1 line
2.4.2
PATCH 3/12 dsoundaudio: remove *_retries kludges
In reply to Kővágó, ZoltánAccording to MSDN this may happen when the window is not in the foreground, but the default is 1 since a long time (which means no retries), so it should be ok. I've found no problems during testing it on Windows 7 and wine, so this was probably only the case with some old Windows versions.
--- audio/dsound_template.h | 35 +++++-------------------- audio/dsoundaudio.c | 68 ++++++++++--------------------------------------- 2 files changed, 20 insertions(+), 83 deletions(-)
audio/dsound_template.h +7 -28
@@ -72,48 +72,27 @@ static int glue (dsound_lock_, TYPE) ( ) {HRESULT hr; -int i;LPVOID p1 =NULL , p2 =NULL ;DWORD blen1 =0 , blen2 =0 ;DWORD flag; -DSoundConf *conf = &s->conf;#ifdef DSBTYPE_IN flag = entire ?DSCBLOCK_ENTIREBUFFER :0 ;#else flag = entire ?DSBLOCK_ENTIREBUFFER :0 ;#endif -for (i =0 ; i < conf->lock_retries; ++i) { - hr =glue (IFACE , _Lock) ( - buf, - pos, - len, - &p1, - &blen1, - &p2, - &blen2, - flag - ); + hr =glue (IFACE , _Lock)(buf, pos, len, &p1, &blen1, &p2, &blen2, flag); -if (FAILED (hr)) { +if (FAILED (hr)) {#ifndef DSBTYPE_IN -if (hr ==DSERR_BUFFERLOST ) { -if (glue (dsound_restore_,TYPE ) (buf, s)) { -dsound_logerr (hr,"Could not lock " NAME "\n" ); - goto fail; - } -continue ; +if (hr ==DSERR_BUFFERLOST ) { +if (glue (dsound_restore_,TYPE ) (buf, s)) { +dsound_logerr (hr,"Could not lock " NAME "\n" ); } -#endif -dsound_logerr (hr,"Could not lock " NAME "\n" ); goto fail; } - -break ; - } - -if (i == conf->lock_retries) { -dolog ("%d attempts to lock " NAME " failed\n" , i); +#endif +dsound_logerr (hr,"Could not lock " NAME "\n" ); goto fail; }
audio/dsoundaudio.c +13 -55
103 lines not on this page · raw message
Signature · 1 line
2.4.2
PATCH 4/12 dsoundaudio: remove primary buffer
In reply to Kővágó, ZoltánEnabling this option just creates a playback buffer with the specified settings, and then ignores it. It's probably some outdated hack to set audio formats on windows. (The first created stream dictates all other streams settings, at least on some Windows versions). Setting DAC_FIXED_SETTINGS should have the same effect as setting (the now removed) primary buffer.
--- audio/dsoundaudio.c | 104 ---------------------------------------------------- 1 file changed, 104 deletions(-)
audio/dsoundaudio.c +0 -104
@@ -42,17 +42,14 @@/* #define DEBUG_DSOUND */ typedef struct { -int set_primary;int bufsize_in;int bufsize_out; -struct audsettings settings;int latency_millis; }DSoundConf ;typedef struct {LPDIRECTSOUND dsound;LPDIRECTSOUNDCAPTURE dsound_capture; -LPDIRECTSOUNDBUFFER dsound_primary_buffer;struct audsettings settings;DSoundConf conf; }dsound ;
@@ -387,27 +384,10 @@ static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb,dsound_unlock_out (dsb, p1, p2, blen1, blen2); } -static void dsound_close (dsound *s) -{ -HRESULT hr; - -if (s->dsound_primary_buffer) { - hr =IDirectSoundBuffer_Release (s->dsound_primary_buffer); -if (FAILED (hr)) { -dsound_logerr (hr,"Could not release primary buffer\n" ); - } - s->dsound_primary_buffer =NULL ; - } -} -static int dsound_open (dsound *s) { -int err;HRESULT hr; -WAVEFORMATEX wfx; -DSBUFFERDESC dsbd;HWND hwnd; -DSoundConf *conf = &s->conf; hwnd =GetForegroundWindow (); hr = IDirectSound_SetCooperativeLevel (
@@ -422,63 +402,7 @@ static int dsound_open (dsound *s)return -1 ; } -if (!conf->set_primary) { -return 0 ; - } - - err =waveformat_from_audio_settings (&wfx, &conf->settings); -if (err) { -return -1 ; - } - -memset (&dsbd,0 ,sizeof (dsbd)); - dsbd.dwSize =sizeof (dsbd); - dsbd.dwFlags =DSBCAPS_PRIMARYBUFFER ; - dsbd.dwBufferBytes =0 ; - dsbd.lpwfxFormat =NULL ; - - hr =IDirectSound_CreateSoundBuffer ( - s->dsound, - &dsbd, - &s->dsound_primary_buffer, -NULL - ); -if (FAILED (hr)) { -dsound_logerr (hr,"Could not create primary playback buffer\n" ); -return -1 ; - } - - hr =IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx); -if (FAILED (hr)) { -dsound_logerr (hr,"Could not set primary playback buffer format\n" ); - } - - hr =IDirectSoundBuffer_GetFormat ( - s->dsound_primary_buffer, - &wfx, -sizeof (wfx), -NULL - ); -if (FAILED (hr)) { -dsound_logerr (hr,"Could not get primary playback buffer format\n" ); - goto fail0; - } - -#ifdef DEBUG_DSOUND -dolog ("Primary\n" ); -print_wave_format (&wfx); -#endif - - err =waveformat_to_audio_settings (&wfx, &s->settings); -if (err) { - goto fail0; - } -return 0 ; - - fail0: -dsound_close (s); -return -1 ; }static int dsound_ctl_out (HWVoiceOut *hw,int cmd, ...)
@@ -823,12 +747,8 @@ static int dsound_run_in (HWVoiceIn *hw) }static DSoundConf glob_conf = { - .set_primary =0 , .bufsize_in =16384 , .bufsize_out =16384 , - .settings.freq =44100 , - .settings.nchannels =2 , - .settings.fmt =AUD_FMT_S16 , .latency_millis =10 };
@@ -935,36 +855,12 @@ static void *dsound_audio_init (void)static struct audio_option dsound_options[] = { { - .name ="SET_PRIMARY" , - .tag =AUD_OPT_BOOL , - .valp = &glob_conf.set_primary, - .descr ="Set the parameters of primary buffer" - }, - { .name ="LATENCY_MILLIS" , .tag =AUD_OPT_INT , .valp = &glob_conf.latency_millis, .descr ="(undocumented)" }, { - .name ="PRIMARY_FREQ" , - .tag =AUD_OPT_INT , - .valp = &glob_conf.settings.freq, - .descr ="Primary buffer frequency" - }, - { - .name ="PRIMARY_CHANNELS" , - .tag =AUD_OPT_INT , - .valp = &glob_conf.settings.nchannels, - .descr ="Primary buffer number of channels (1 - mono, 2 - stereo)" - }, - { - .name ="PRIMARY_FMT" , - .tag =AUD_OPT_FMT , - .valp = &glob_conf.settings.fmt, - .descr ="Primary buffer format" - }, - { .name ="BUFSIZE_OUT" , .tag =AUD_OPT_INT , .valp = &glob_conf.bufsize_out,
Signature · 1 line
2.4.2
PATCH 5/12 alsaaudio: use trace events instead of verbose
In reply to Kővágó, Zoltán--- audio/alsaaudio.c | 60 +++++++++++++------------------------------------------ trace-events | 12 +++++++++++ 2 files changed, 26 insertions(+), 46 deletions(-)
audio/alsaaudio.c +14 -46
@@ -25,6 +25,7 @@#include "qemu-common.h" #include "qemu/main-loop.h" #include "audio.h" +#include "trace.h" #if QEMU_GNUC_PREREQ (4 ,3 )#pragma GCC diagnostic ignored "-Waddress"
@@ -49,7 +50,6 @@ typedef struct ALSAConf {int buffer_size_out_overridden;int period_size_out_overridden; -int verbose; } ALSAConf;struct pollhlp {
@@ -180,7 +180,6 @@ static void alsa_poll_handler (void *opaque)snd_pcm_state_t state;struct pollhlp *hlp = opaque;unsigned short revents; -ALSAConf *conf = hlp->conf; count =poll (hlp->pfds, hlp->count,0 );if (count <0 ) {
@@ -202,9 +201,7 @@ static void alsa_poll_handler (void *opaque) }if (!(revents & hlp->mask)) { -if (conf->verbose) { -dolog ("revents = %d\n" , revents); - } +trace_alsa_revents (revents);return ; }
@@ -239,7 +236,6 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask) {int i, count, err;struct pollfd *pfds; -ALSAConf *conf = hlp->conf; count =snd_pcm_poll_descriptors_count (handle);if (count <=0 ) {
@@ -268,16 +264,11 @@ static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask) NULL, hlp); }if (pfds[i].events &POLLOUT ) { -if (conf->verbose) { -dolog ("POLLOUT %d %d\n" , i, pfds[i].fd); - } +trace_alsa_pollout (i, pfds[i].fd); err =qemu_set_fd_handler (pfds[i].fd,NULL , alsa_poll_handler, hlp); } -if (conf->verbose) { -dolog ("Set handler events=%#x index=%d fd=%d err=%d\n" , - pfds[i].events, i, pfds[i].fd, err); - } +trace_alsa_set_handler (pfds[i].events, i, pfds[i].fd, err);if (err) { dolog ("Failed to set handler events=%#x index=%d fd=%d err=%d\n",
@@ -521,7 +512,7 @@ static int alsa_open (int in, struct alsa_params_req *req, } err =snd_pcm_hw_params_set_format (handle, hw_params, req->fmt); -if (err <0 && conf->verbose) { +if (err <0 ) {alsa_logerr2 (err, typ,"Failed to set format %d\n" , req->fmt); }
@@ -685,10 +676,9 @@ static int alsa_open (int in, struct alsa_params_req *req, *handlep = handle; -if (conf->verbose && - (obtfmt != req->fmt || +if (obtfmt != req->fmt || obt->nchannels != req->nchannels || - obt->freq != req->freq)) { + obt->freq != req->freq) {dolog ("Audio parameters for %s\n" , typ);alsa_dump_info (req, obt, obtfmt); }
@@ -728,7 +718,6 @@ static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle)static void alsa_write_pending (ALSAVoiceOut *alsa) {HWVoiceOut *hw = &alsa->hw; -ALSAConf *conf = alsa->pollhlp.conf;while (alsa->pending) {int left_till_end_samples = hw->samples - alsa->wpos;
@@ -743,9 +732,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa)if (written <=0 ) {switch (written) {case 0 : -if (conf->verbose) { -dolog ("Failed to write %d frames (wrote zero)\n" , len); - } +trace_alsa_wrote_zero (len);return ;case -EPIPE :
@@ -754,9 +741,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa) len);return ; } -if (conf->verbose) { -dolog ("Recovering from playback xrun\n" ); - } +trace_alsa_xrun_out ();continue ;case -ESTRPIPE :
@@ -767,9 +752,7 @@ static void alsa_write_pending (ALSAVoiceOut *alsa) len);return ; } -if (conf->verbose) { -dolog ("Resuming suspended output stream\n" ); - } +trace_alsa_resume_out ();continue ;case -EAGAIN :
@@ -1002,7 +985,6 @@ static int alsa_run_in (HWVoiceIn *hw) };snd_pcm_sframes_t avail;snd_pcm_uframes_t read_samples =0 ; -ALSAConf *conf = alsa->pollhlp.conf;if (!dead) {return 0 ;
@@ -1028,14 +1010,10 @@ static int alsa_run_in (HWVoiceIn *hw)dolog ("Failed to resume suspended input stream\n" );return 0 ; } -if (conf->verbose) { -dolog ("Resuming suspended input stream\n" ); - } +trace_alsa_resume_in ();break ;default : -if (conf->verbose) { -dolog ("No frames available and ALSA state is %d\n" , state); - } +trace_alsa_no_frames (state);return 0 ; } }
@@ -1070,9 +1048,7 @@ static int alsa_run_in (HWVoiceIn *hw)if (nread <=0 ) {switch (nread) {case 0 : -if (conf->verbose) { -dolog ("Failed to read %ld frames (read zero)\n" , len); - } +trace_alsa_read_zero (len); goto exit;case -EPIPE :
@@ -1080,9 +1056,7 @@ static int alsa_run_in (HWVoiceIn *hw)alsa_logerr (nread,"Failed to read %ld frames\n" , len); goto exit; } -if (conf->verbose) { -dolog ("Recovering from capture xrun\n" ); - } +trace_alsa_xrun_in ();continue ;case -EAGAIN :
@@ -1233,12 +1207,6 @@ static struct audio_option alsa_options[] = { .valp = &glob_conf.pcm_name_in, .descr = "ADC device name" }, - { - .name = "VERBOSE", - .tag = AUD_OPT_BOOL, - .valp = &glob_conf.verbose, - .descr = "Behave in a more verbose way" - }, {/* End of list */ } };
trace-events +12 -0
@@ -1626,3 +1626,15 @@ cpu_unhalt(int cpu_index) "unhalting cpu %d" # hw/arm/virt-acpi-build.c virt_acpi_setup(void) "No fw cfg or ACPI disabled. Bailing out." + +# audio/alsaaudio.c +alsa_revents(int revents) "revents = %d" +alsa_pollout(int i, int fd) "i = %d fd = %d" +alsa_set_handler(int events, int index, int fd, int err) "events=%#x index=%d fd=%d err=%d" +alsa_wrote_zero(int len) "Failed to write %d frames (wrote zero)" +alsa_read_zero(long len) "Failed to read %ld frames (read zero)" +alsa_xrun_out(void) "Recovering from playback xrun" +alsa_xrun_in(void) "Recovering from capture xrun" +alsa_resume_out(void) "Resuming suspended output stream" +alsa_resume_in(void) "Resuming suspended input stream" +alsa_no_frames(int state) "No frames available and ALSA state is %d"
Signature · 1 line
2.4.2
PATCH 6/12 ossaudio: use trace events instead of debug config flag
In reply to Kővágó, Zoltán--- audio/ossaudio.c | 25 ++++--------------------- trace-events | 4 ++++ 2 files changed, 8 insertions(+), 21 deletions(-)
audio/ossaudio.c +4 -21
@@ -30,6 +30,7 @@#include "qemu/main-loop.h" #include "qemu/host-utils.h" #include "audio.h" +#include "trace.h" #define AUDIO_CAP "oss"#include "audio_int.h"
@@ -44,7 +45,6 @@ typedef struct OSSConf {int fragsize;const char *devpath_out;const char *devpath_in; -int debug;int exclusive;int policy; } OSSConf;
@@ -314,9 +314,7 @@ static int oss_open (int in, struct oss_params *req,int version;if (!oss_get_version (fd, &version, typ)) { -if (conf->debug) { -dolog ("OSS version = %#x\n" , version); - } +trace_oss_version (version);if (version >=0x040000 ) {int policy = conf->policy;
@@ -427,7 +425,6 @@ static int oss_run_out (HWVoiceOut *hw, int live)struct audio_buf_info abinfo;struct count_info cntinfo;int bufsize; -OSSConf *conf = oss->conf; bufsize = hw->samples << hw->info.shift;
@@ -452,19 +449,12 @@ static int oss_run_out (HWVoiceOut *hw, int live) }if (abinfo.bytes > bufsize) { -if (conf->debug) { -dolog ("warning: Invalid available size, size=%d bufsize=%d\n" -"please report your OS/audio hw to [email protected]\n" , - abinfo.bytes, bufsize); - } +trace_oss_invalid_available_size (abinfo.bytes, bufsize); abinfo.bytes = bufsize; }if (abinfo.bytes <0 ) { -if (conf->debug) { -dolog ("warning: Invalid available size, size=%d bufsize=%d\n" , - abinfo.bytes, bufsize); - } +trace_oss_invalid_available_size (abinfo.bytes, bufsize);return 0 ; }
@@ -850,7 +840,6 @@ static OSSConf glob_conf = { .fragsize = 4096, .devpath_out = "/dev/dsp", .devpath_in = "/dev/dsp", - .debug = 0, .exclusive = 0, .policy = 5 };
@@ -917,12 +906,6 @@ static struct audio_option oss_options[] = { .descr = "Set the timing policy of the device, -1 to use fragment mode", },#endif - { - .name = "DEBUG", - .tag = AUD_OPT_BOOL, - .valp = &glob_conf.debug, - .descr = "Turn on some debugging messages" - }, {/* End of list */ } };
trace-events +4 -0
@@ -1638,3 +1638,7 @@ alsa_xrun_in(void) "Recovering from capture xrun" alsa_resume_out(void) "Resuming suspended output stream" alsa_resume_in(void) "Resuming suspended input stream" alsa_no_frames(int state) "No frames available and ALSA state is %d" + +# audio/ossaudio.c +oss_version(int version) "OSS version = %#x" +oss_invalid_available_size(int size, int bufsize) "Invalid available size, size=%d bufsize=%d"
Signature · 1 line
2.4.2
PATCH 7/12 qapi: qapi for audio backends
In reply to Kővágó, ZoltánThis patch adds structures into qapi to replace the existing configuration structures used by audio backends currently. This qapi will be the base of the -audiodev command line parameter (that replaces the old environment variables based config).
This is not a 1:1 translation of the old options, I've tried to make them much more consistent (e.g. almost every backend had an option to specify buffer size, but the name was different for every backend, and some backends required usecs, while some other required frames, samples or bytes). Also tried to reduce the number of abbreviations used by the config keys.
Some of the more important changes:
* use in and out instead of ADC and DAC, as the former is more user friendly imho
* moved buffer settings into the global setting area (so it's the same for all backends that support it. Backends that can't change buffer size will simply ignore them). Also using usecs, as it's probably more user friendly than samples or bytes.
* try-poll is now an alsa and oss backend specific option (as all other backends currently ignore it)
---
Changes from v2 RFC patch:
* in, out are no longer optional
* try-poll: moved to alsa and oss (as no other backend used them)
* voices: added (env variables had this option)
* dsound: removed primary buffer related fields
Changes from v1 RFC patch:
* fixed style issues
* moved definitions into a separate file
* documented undocumented options (hopefully)
* removed plive option. It was useless even years ago so it can probably safely go away: https://lists.nongnu.org/archive/html/qemu-devel/2012-03/msg02427.html
* removed verbose, debug options. Backends should use trace events instead.
* removed *_retries options from dsound. It's a kludge.
* moved buffer_usecs and buffer_count to the global config options. Some driver might ignore it (as they do not expose API to change them).
* wav backend: removed frequecy, format, channels as AudiodevPerDirectionOptions already have them.
Makefile | 4 +- qapi-schema.json | 3 + qapi/audio.json | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 222 insertions(+), 2 deletions(-) create mode 100644 qapi/audio.json
Makefile +2 -2
@@ -257,8 +257,8 @@ $(SRC_PATH)/qga/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py $(qapi-py) " GEN $@") qapi-modules = $(SRC_PATH)/qapi-schema.json $(SRC_PATH)/qapi/common.json \ - $(SRC_PATH)/qapi/block.json $(SRC_PATH)/qapi/block-core.json \ - $(SRC_PATH)/qapi/event.json + $(SRC_PATH)/qapi/audio.json $(SRC_PATH)/qapi/block.json \ + $(SRC_PATH)/qapi/block-core.json $(SRC_PATH)/qapi/event.json qapi-types.c qapi-types.h :\ $(qapi-modules) $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
qapi-schema.json +3 -0
@@ -5,6 +5,9 @@ # QAPI common definitions { 'include': 'qapi/common.json' } +# QAPI audio definitions +{ 'include': 'qapi/audio.json' } + # QAPI block definitions { 'include': 'qapi/block.json' }
qapi/audio.json new file +217 -0
217 lines not on this page · raw message
Signature · 1 line
2.4.2
Re: [Qemu-devel] [PATCH 07/12] qapi: qapi for audio backends
Quoted 27 lines · Zoltán
This patch adds structures into qapi to replace the existing configuration structures used by audio backends currently. This qapi will be the base of the -audiodev command line parameter (that replaces the old environment variables based config).
This is not a 1:1 translation of the old options, I've tried to make them much more consistent (e.g. almost every backend had an option to specify buffer size, but the name was different for every backend, and some backends required usecs, while some other required frames, samples or bytes). Also tried to reduce the number of abbreviations used by the config keys.
Some of the more important changes:
* useinandoutinstead ofADCandDAC, as the former is more user friendly imho
* moved buffer settings into the global setting area (so it's the same for all backends that support it. Backends that can't change buffer size will simply ignore them). Also using usecs, as it's probably more user friendly than samples or bytes.
* try-poll is now an alsa and oss backend specific option (as all other backends currently ignore it)Signed-off-by Kővágó, Zoltán <[email protected]>---
+++
b/qapi/audio.json
qapi/audio.json line 4
Quoted 4 lines
qapi/audio.json new file +4
-0@@ -0,0 +1,217 @@ +# -*- mode: python -*- + +## +# @AudiodevNoneOptions
Might be nice to include copyright/license, but this is not the first .json file missing it.
qapi/audio.json line 6
Quoted 2 lines
qapi/audio.json new file +2
-0+# +# The none, coreaudio, sdl and spice audio backend has no options.
s/has/have/
qapi/audio.json line 11
Quoted 5 lines
qapi/audio.json new file +5
-0+# +# Since: 2.4 +## +{ 'struct': 'AudiodevNoneOptions', + 'data': { } }
Maybe s/None/No/ (since it is shared by backends that have no options), but I can live with it as-is (since it is used by the 'none' backend).
qapi/audio.json line 36
Quoted 8 lines
qapi/audio.json new file +8
-0+## +# @AudiodevAlsaOptions +# +# Options of the alsa audio backend. +# +# @in: #optional options of the capture stream +# +# @out: #optional options of the playback stream
Marked optional here...
qapi/audio.json line 45
Quoted 9 lines
qapi/audio.json new file +9
-0+# +# @threshold: #optional set the threshold (in frames) when playback starts +# +# Since: 2.4 +## +{ 'struct': 'AudiodevAlsaOptions', + 'data': { + 'in': 'AudiodevAlsaPerDirectionOptions', + 'out': 'AudiodevAlsaPerDirectionOptions',
...but not here.
Quoted 4 lines
qapi/audio.json new file +4
-0+ '*threshold': 'int' } } + +## +# @AudiodevDsoundOptions
qapi/audio.json line 59
Quoted 10 lines
qapi/audio.json new file +10
-0+# +# Options of the dsound audio backend. +# +# @latency-millis: #optional add extra latency to playback +# +# Since: 2.4 +## +{ 'struct': 'AudiodevDsoundOptions', + 'data': { + '*latency-millis': 'int' } }
Style question - should we just call this 'latency', and document the milliseconds unit in the description? But having the name latency_millis in C code might not be all that bad, so you may not want to change this one.
qapi/audio.json line 88
Quoted 12 lines
qapi/audio.json new file +12
-0+## +# @AudiodevOssOptions +# +# Options of the oss audio backend. +# +# @in: #optional options of the capture stream +# +# @out: #optional options of the playback stream +# +# @mmap: #optional try using memory mapped access +# +# @exclusive: #optional open device in exclusive mode (vmix wont work)
s/wont/won't/
qapi/audio.json line 98
Quoted 10 lines
qapi/audio.json new file +10
-0+# +# @dsp-policy: #optional set the timing policy of the device, -1 to use fragment +# mode (option ignored on some platforms) +# +# Since: 2.4 +## +{ 'struct': 'AudiodevOssOptions', + 'data': { + 'in': 'AudiodevOssPerDirectionOptions', + 'out': 'AudiodevOssPerDirectionOptions',
Again, inconsistent on the optional marking.
qapi/audio.json line 176
Quoted 12 lines
qapi/audio.json new file +12
-0+## +# @AudiodevPerDirectionOptions +# +# General audio backend options that are used for both playback and recording. +# +# @fixed-settings: #optional use fixed settings for host DAC/ADC +# +# @frequency: #optional frequency to use when using fixed settings +# +# @channels: #optional number of channels when using fixed settings +# +# @format: #optional sample fortmat to use when using fixed settings
s/fortmat/format/
qapi/audio.json line 181
Quoted 5 lines
qapi/audio.json new file +5
-0+# +# @buffer-usecs: #optional the buffer size in microseconds +# +# @buffer-count: #optional nuber of buffers +#
s/nuber/number/
Quoted 24 lines
qapi/audio.json new file +24
-0+# Since: 2.4 +## +{ 'struct': 'AudiodevPerDirectionOptions', + 'data': { + '*fixed-settings': 'bool', + '*frequency': 'int', + '*channels': 'int', + '*voices': 'int', + '*format': 'AudioFormat', + '*buffer-usecs': 'int', + '*buffer-count': 'int' } } + +## +# @Audiodev +# +# Captures the configuration of an audio backend. +# +# @id: identifier of the backend +# +# @in: #optional options of the capture stream +# +# @out: #optional options of the playback stream +# +# @timer-period: #optional timer period in HZ (0 - use lowest possible)
qapi/audio.json line 215
Quoted 10 lines
qapi/audio.json new file +10
-0+# +# @opts: audio backend specific options +# +# Since: 2.4 +## +{ 'struct': 'Audiodev', + 'data': { + '*id': 'str', + 'in': 'AudiodevPerDirectionOptions', + 'out': 'AudiodevPerDirectionOptions',
Another mismatch in optional marking.
Quoted 3 lines
qapi/audio.json new file +2
-0+ '*timer-period': 'int', + 'opts': 'AudiodevBackendOptions' } }
Signature · 2 lines
Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
Re: [Qemu-devel] [PATCH 07/12] qapi: qapi for audio backends
2015-06-13 00:11 keltezéssel, Eric Blake írta:
Quoted 11 lines
qapi/audio.json line 36
Quoted 8 lines
qapi/audio.json new file +8
-0+## +# @AudiodevAlsaOptions +# +# Options of the alsa audio backend. +# +# @in: #optional options of the capture stream +# +# @out: #optional options of the playback streamMarked optional here...
Quoted 11 lines
qapi/audio.json line 45
Quoted 9 lines
qapi/audio.json new file +9
-0+# +# @threshold: #optional set the threshold (in frames) when playback starts +# +# Since: 2.4 +## +{ 'struct': 'AudiodevAlsaOptions', + 'data': { + 'in': 'AudiodevAlsaPerDirectionOptions', + 'out': 'AudiodevAlsaPerDirectionOptions',...but not here.
Oups. The code is the correct (they are not optional), I forgot updating the documentation. (Same goes for the other mismatches).
Quoted 11 lines
Quoted 11 lines
qapi/audio.json new file +10
-0+ '*threshold': 'int' } } + +## +# @AudiodevDsoundOptions +# +# Options of the dsound audio backend. +# +# @latency-millis: #optional add extra latency to playback +# +# Since: 2.4
Quoted 8 lines
qapi/audio.json line 59
Quoted 4 lines
qapi/audio.json new file +4
-0+## +{ 'struct': 'AudiodevDsoundOptions', + 'data': { + '*latency-millis': 'int' } }Style question - should we just call this 'latency', and document the milliseconds unit in the description? But having the name
latency_millisin C code might not be all that bad, so you may not want to change this one.
There is also a buffer-usecs, so I vote for keeping latency-millis. Also there is timer-period in Audiodev. Maybe it should be renamed to timer-period-hz, to keep consistency. Or maybe change all of them to usecs.
Other issues acked.
Thanks,
Zoltan
PATCH 8/12 qapi: support nested structs in OptsVisitor
In reply to Kővágó, ZoltánThe current OptsVisitor flattens the whole structure, if there are same named fields under different paths (like in' and out' in Audiodev'), the current visitor can't cope with them (for example setting frequency=44100' will set the in's frequency to 44100 and leave out's frequency unspecified).
This patch fixes it, by the following changes:
1) Specifying just the field name will apply to all fields that has the specified name (this means it would set both in's and out's frequency to 44100 in the above example).
2) Optionally user can specify the path in the hierarchy. Names are separated by a dot (e.g. in.frequency', foo.bar.something', etc). The user need not specify the whole path, only the last few components (i.e. bar.something' is equivalent to foo.bar.something' if only foo' has a bar' field). This way
1) is just a special case of this when only the last component is specified.
3) In case of an ambiguity (e.g frequency=44100,in.frequency=8000') the longest matching (the most specific) path wins (so in this example, in's frequency would become 8000, because in.frequency' is more specific that frequency', and out's frequency would become 44100, because only frequency' matches it).
--- qapi/opts-visitor.c | 144 +++++++++++++++++++++++++------- tests/qapi-schema/qapi-schema-test.json | 9 +- tests/test-opts-visitor.c | 34 ++++++++ 3 files changed, 157 insertions(+), 30 deletions(-)
qapi/opts-visitor.c +115 -29
@@ -64,13 +64,14 @@ struct OptsVisitor/* Non-null iff depth is positive. Each key is a QemuOpt name. Each value * is a non-empty GQueue, enumerating all QemuOpt occurrences with that * name. */ -GHashTable *unprocessed_opts; +GHashTable *unprocessed_opts, *opts;/* The list currently being traversed with opts_start_list() / * opts_next_list(). The list must have a struct element type in the * schema, with a single mandatory scalar member. */ ListMode list_mode;GQueue *repeated_opts; +char *repeated_name;/* When parsing a list of repeating options as integers, values of the form * "a-b", representing a closed interval, are allowed. Elements in the
@@ -86,6 +87,9 @@ struct OptsVisitor* not survive or escape the OptsVisitor object. */ QemuOpt *fake_id_opt; + +/* List of field names leading to the current structure. */ +GQueue *nested_names; };
@@ -97,11 +101,12 @@ destroy_list(gpointer list)static void -opts_visitor_insert (GHashTable *unprocessed_opts,const QemuOpt *opt) +opts_visitor_insert (OptsVisitor *ov,const QemuOpt *opt) {GQueue *list; +assert (opt); - list =g_hash_table_lookup (unprocessed_opts, opt->name); + list =g_hash_table_lookup (ov->opts, opt->name);if (list ==NULL ) { list =g_queue_new ();
@@ -109,7 +114,8 @@ opts_visitor_insert(GHashTable *unprocessed_opts, const QemuOpt *opt)* "key_destroy_func" in opts_start_struct(). Thus cast away key * const-ness in order to suppress gcc's warning. */ -g_hash_table_insert (unprocessed_opts, (gpointer )opt->name, list); +g_hash_table_insert (ov->opts, (gpointer )opt->name, list); +g_hash_table_insert (ov->unprocessed_opts, (gpointer )opt->name, list); }/* Similarly, destroy_list() doesn't call g_queue_free_full(). */
@@ -127,17 +133,27 @@ opts_start_struct(Visitor *v, void **obj, const char *kind,if (obj) { *obj =g_malloc0 (size >0 ? size :1 ); } + +/* assuming name is a statically allocated string (or at least it's lifetime +* is longer than the visitor's) */ +if (!name) { + name ="" ; + } +g_queue_push_tail (ov->nested_names, (gpointer ) name); +if (ov->depth++ >0 ) {return ; } - ov->unprocessed_opts =g_hash_table_new_full (&g_str_hash, &g_str_equal, -NULL , &destroy_list); + ov->opts =g_hash_table_new_full (&g_str_hash, &g_str_equal, +NULL , &destroy_list); + ov->unprocessed_opts =g_hash_table_new (&g_str_hash, &g_str_equal); + QTAILQ_FOREACH(opt, &ov->opts_root->head, next) {/* ensured by qemu-option.c::opts_do_parse() */ assert (strcmp (opt->name,"id" ) !=0 ); -opts_visitor_insert (ov->unprocessed_opts, opt); +opts_visitor_insert (ov, opt); }if (ov->opts_root->id !=NULL ) {
@@ -145,7 +161,7 @@ opts_start_struct(Visitor *v, void **obj, const char *kind, ov->fake_id_opt->name =g_strdup ("id" ); ov->fake_id_opt->str =g_strdup (ov->opts_root->id); -opts_visitor_insert (ov->unprocessed_opts, ov->fake_id_opt); +opts_visitor_insert (ov, ov->fake_id_opt); } }
@@ -163,6 +179,8 @@ opts_end_struct(Visitor *v, Error **errp)OptsVisitor *ov =DO_UPCAST (OptsVisitor, visitor, v);GQueue *any; +g_queue_pop_tail (ov->nested_names); +if (--ov->depth >0 ) {return ; }
@@ -177,6 +195,8 @@ opts_end_struct(Visitor *v, Error **errp) }g_hash_table_destroy (ov->unprocessed_opts); ov->unprocessed_opts =NULL ; +g_hash_table_destroy (ov->opts); + ov->opts =NULL ;if (ov->fake_id_opt) {g_free (ov->fake_id_opt->name);g_free (ov->fake_id_opt->str);
@@ -185,16 +205,56 @@ opts_end_struct(Visitor *v, Error **errp) ov->fake_id_opt =NULL ; } +static void +sum_strlen (gpointer data,gpointer user_data) +{ +const char *str = data; +size_t *sum_len = user_data; + *sum_len +=strlen (str) +1 ; +} + +static void +append_str (gpointer data,gpointer user_data) +{ +strcat (user_data, data); +strcat (user_data,"." ); +} + +/* lookup a name, trying from the most qualified version (e.g. foo.bar.asd) to +* least qualified ones (i.e. foo.bar.asd overrides bar.asd or asd) */ static GQueue * -lookup_distinct (const OptsVisitor *ov,const char *name,Error **errp) +lookup_distinct (const OptsVisitor *ov,const char *name,char **out_key, +Error **errp) { -GQueue *list; +GQueue *list =NULL ; +char *key, *key2; +size_t sum_len =strlen (name); - list =g_hash_table_lookup (ov->unprocessed_opts, name); +g_queue_foreach (ov->nested_names, sum_strlen, &sum_len); + key =g_malloc (sum_len+1 ); + key[0 ] =0 ; +g_queue_foreach (ov->nested_names, append_str, key); +strcat (key, name); + + key2 = key; +while (*key2) { + list =g_hash_table_lookup (ov->opts, key2); +if (list) { +if (out_key) { + *out_key =g_strdup (key2); + } +break ; + } + +while (*key2 && *key2++ !='.' ) { + } + }if (!list) {error_set (errp,QERR_MISSING_PARAMETER , name); } + +g_free (key);return list; }
@@ -206,7 +266,7 @@ opts_start_list(Visitor *v, const char *name, Error **errp)/* we can't traverse a list in a list */ assert (ov->list_mode ==LM_NONE ); - ov->repeated_opts =lookup_distinct (ov, name, errp); + ov->repeated_opts =lookup_distinct (ov, name, &ov->repeated_name, errp);if (ov->repeated_opts !=NULL ) { ov->list_mode =LM_STARTED ; }
@@ -242,11 +302,9 @@ opts_next_list(Visitor *v, GenericList **list, Error **errp)/* range has been completed, fall through in order to pop option */ case LM_IN_PROGRESS : { -const QemuOpt *opt; - - opt =g_queue_pop_head (ov->repeated_opts); +g_queue_pop_head (ov->repeated_opts);if (g_queue_is_empty (ov->repeated_opts)) { -g_hash_table_remove (ov->unprocessed_opts, opt->name); +g_hash_table_remove (ov->unprocessed_opts, ov->repeated_name);return NULL ; } link = &(*list)->next;
@@ -272,22 +330,28 @@ opts_end_list(Visitor *v, Error **errp) ov->list_mode ==LM_SIGNED_INTERVAL || ov->list_mode == LM_UNSIGNED_INTERVAL); ov->repeated_opts =NULL ; + +g_free (ov->repeated_name); + ov->repeated_name =NULL ; + ov->list_mode =LM_NONE ; }static const QemuOpt * -lookup_scalar (const OptsVisitor *ov,const char *name,Error **errp) +lookup_scalar (const OptsVisitor *ov,const char *name,char ** out_key, +Error **errp) {if (ov->list_mode ==LM_NONE ) {GQueue *list;/* the last occurrence of any QemuOpt takes effect when queried by name */ - list =lookup_distinct (ov, name, errp); + list =lookup_distinct (ov, name, out_key, errp);return list ?g_queue_peek_tail (list) :NULL ; }assert (ov->list_mode ==LM_IN_PROGRESS ); +assert (out_key ==NULL || *out_key ==NULL );return g_queue_peek_head (ov->repeated_opts); }
@@ -309,13 +373,15 @@ opts_type_str(Visitor *v, char **obj, const char *name, Error **errp) {OptsVisitor *ov =DO_UPCAST (OptsVisitor, visitor, v);const QemuOpt *opt; +char *key =NULL ; - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; } *obj =g_strdup (opt->str ? opt->str :"" ); -processed (ov, name); +processed (ov, key); +g_free (key); }
@@ -325,8 +391,9 @@ opts_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) {OptsVisitor *ov =DO_UPCAST (OptsVisitor, visitor, v);const QemuOpt *opt; +char *key =NULL ; - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; }
@@ -343,13 +410,15 @@ opts_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) }else {error_set (errp,QERR_INVALID_PARAMETER_VALUE , opt->name,"on|yes|y|off|no|n" ); +g_free (key);return ; } }else { *obj = true; } -processed (ov, name); +processed (ov, key); +g_free (key); }
@@ -361,13 +430,14 @@ opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)const char *str;long long val;char *endptr; +char *key =NULL ;if (ov->list_mode ==LM_SIGNED_INTERVAL ) { *obj = ov->range_next.s;return ; } - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; }
@@ -381,11 +451,13 @@ opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)if (errno ==0 && endptr > str &&INT64_MIN <= val && val <=INT64_MAX ) {if (*endptr =='\0' ) { *obj = val; -processed (ov, name); +processed (ov, key); +g_free (key);return ; }if (*endptr =='-' && ov->list_mode ==LM_IN_PROGRESS ) {long long val2; +assert (key ==NULL ); str = endptr +1 ; val2 =strtoll (str, &endptr,0 );
@@ -406,6 +478,7 @@ opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)error_set (errp,QERR_INVALID_PARAMETER_VALUE , opt->name, (ov->list_mode ==LM_NONE ) ?"an int64 value" :"an int64 value or range" ); +g_free (key); }
@@ -417,13 +490,14 @@ opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp)const char *str;unsigned long long val;char *endptr; +char *key =NULL ;if (ov->list_mode ==LM_UNSIGNED_INTERVAL ) { *obj = ov->range_next.u;return ; } - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; }
@@ -435,11 +509,13 @@ opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp)if (parse_uint (str, &val, &endptr,0 ) ==0 && val <=UINT64_MAX ) {if (*endptr =='\0' ) { *obj = val; -processed (ov, name); +processed (ov, key); +g_free (key);return ; }if (*endptr =='-' && ov->list_mode ==LM_IN_PROGRESS ) {unsigned long long val2; +assert (key ==NULL ); str = endptr +1 ; if (parse_uint_full(str, &val2, 0) == 0 &&
@@ -458,6 +534,7 @@ opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp)error_set (errp,QERR_INVALID_PARAMETER_VALUE , opt->name, (ov->list_mode ==LM_NONE ) ?"a uint64 value" :"a uint64 value or range" ); +g_free (key); }
@@ -468,8 +545,9 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)const QemuOpt *opt;int64_t val;char *endptr; +char *key =NULL ; - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; }
@@ -479,11 +557,13 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)if (val <0 || *endptr) {error_set (errp,QERR_INVALID_PARAMETER_VALUE , opt->name,"a size value representible as a non-negative int64" ); +g_free (key);return ; } *obj = val; -processed (ov, name); +processed (ov, key); +g_free (key); }
@@ -494,7 +574,7 @@ opts_optional(Visitor *v, bool *present, const char *name, Error **errp)/* we only support a single mandatory scalar field in a list node */ assert (ov->list_mode ==LM_NONE ); - *present = (lookup_distinct (ov, name,NULL ) !=NULL ); + *present = (lookup_distinct (ov, name,NULL ,NULL ) !=NULL ); }
@@ -505,6 +585,8 @@ opts_visitor_new(const QemuOpts *opts) ov =g_malloc0 (sizeof *ov); + ov->nested_names =g_queue_new (); + ov->visitor.start_struct = &opts_start_struct; ov->visitor.end_struct = &opts_end_struct;
@@ -545,6 +627,10 @@ opts_visitor_cleanup(OptsVisitor *ov)if (ov->unprocessed_opts !=NULL ) {g_hash_table_destroy (ov->unprocessed_opts); } +if (ov->opts !=NULL ) { +g_hash_table_destroy (ov->opts); + } +g_queue_free (ov->nested_names);g_free (ov->fake_id_opt);g_free (ov); }
tests/qapi-schema/qapi-schema-test.json +8 -1
@@ -81,6 +81,11 @@ { 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' }, 'returns': 'int' } +# For testing hierarchy support in opts-visitor +{ 'struct': 'UserDefOptionsSub', + 'data': { + '*nint': 'int' } } + # For testing integer range flattening in opts-visitor. The following schema # corresponds to the option format: #
@@ -94,7 +99,9 @@ '*u64' : [ 'uint64' ], '*u16' : [ 'uint16' ], '*i64x': 'int' , - '*u64x': 'uint64' } } + '*u64x': 'uint64' , + 'sub0': 'UserDefOptionsSub', + 'sub1': 'UserDefOptionsSub' } } # testing event { 'struct': 'EventStructOne',
tests/test-opts-visitor.c +34 -0
@@ -177,6 +177,34 @@ expect_u64_max(OptsVisitorFixture *f, gconstpointer test_data)g_assert (f->userdef->u64->value ==UINT64_MAX ); } +static void +expect_both (OptsVisitorFixture *f,gconstpointer test_data) +{ +expect_ok (f, test_data); +g_assert (f->userdef->sub0->has_nint); +g_assert (f->userdef->sub0->nint ==13 ); +g_assert (f->userdef->sub1->has_nint); +g_assert (f->userdef->sub1->nint ==13 ); +} + +static void +expect_sub0 (OptsVisitorFixture *f,gconstpointer test_data) +{ +expect_ok (f, test_data); +g_assert (f->userdef->sub0->has_nint); +g_assert (f->userdef->sub0->nint ==13 ); +g_assert (!f->userdef->sub1->has_nint); +} + +static void +expect_sub1 (OptsVisitorFixture *f,gconstpointer test_data) +{ +expect_ok (f, test_data); +g_assert (!f->userdef->sub0->has_nint); +g_assert (f->userdef->sub1->has_nint); +g_assert (f->userdef->sub1->nint ==13 ); +} +/* test cases */ int
@@ -270,6 +298,12 @@ main(int argc, char **argv)add_test ("/visitor/opts/i64/range/2big/full" , &expect_fail,"i64=-0x8000000000000000-0x7fffffffffffffff" ); +/* Test nested structs support */ +add_test ("/visitor/opts/nested/unqualified" , &expect_both,"nint=13" ); +add_test ("/visitor/opts/nested/both" , &expect_both, +"sub0.nint=13,sub1.nint=13" ); +add_test ("/visitor/opts/nested/sub0" , &expect_sub0,"sub0.nint=13" ); +add_test ("/visitor/opts/nested/sub1" , &expect_sub1,"sub1.nint=13" );g_test_run ();return 0 ; }
Signature · 1 line
2.4.2
Re: [Qemu-devel] [PATCH 08/12] qapi: support nested structs in OptsVisitor
Hi,
Adding qapi maintainers to Cc, full for them quote below, please review.
For your next patch submission:
There is a "MAINTAINERS" file with the people listed.
There is a scripts/get_maintainer.pl scripts which will do the lookup for you (accepts patch as input, prints maintainers).
You can hook this into your .git/config this way ...
[sendemail]
to = [email protected]
cccmd = scripts/get_maintainer.pl --nogit-fallback... and have 'git send-email' Cc the relevant maintainers automatically.
cheers,
Gerd
Quoted 511 lines · Zoltán
The current OptsVisitor flattens the whole structure, if there are same named fields under different paths (like
in' andout' inAudiodev'), the current visitor can't cope with them (for example settingfrequency=44100' will set the in's frequency to 44100 and leave out's frequency unspecified).This patch fixes it, by the following changes:
1) Specifying just the field name will apply to all fields that has the specified name (this means it would set both in's and out's frequency to 44100 in the above example).
2) Optionally user can specify the path in the hierarchy. Names are separated by a dot (e.g.in.frequency',foo.bar.something', etc). The user need not specify the whole path, only the last few components (i.e.bar.something' is equivalent tofoo.bar.something' if onlyfoo' has abar' field). This way
1) is just a special case of this when only the last component is specified.
3) In case of an ambiguity (e.gfrequency=44100,in.frequency=8000') the longest matching (the most specific) path wins (so in this example, in's frequency would become 8000, becausein.frequency' is more specific thatfrequency', and out's frequency would become 44100, because onlyfrequency' matches it).Signed-off-by Kővágó, Zoltán <[email protected]>--- qapi/opts-visitor.c | 144 +++++++++++++++++++++++++------- tests/qapi-schema/qapi-schema-test.json | 9 +- tests/test-opts-visitor.c | 34 ++++++++ 3 files changed, 157 insertions(+), 30 deletions(-)qapi/opts-visitor.c +115
-29@@ -64,13 +64,14 @@ struct OptsVisitor/* Non-null iff depth is positive. Each key is a QemuOpt name. Each value * is a non-empty GQueue, enumerating all QemuOpt occurrences with that * name. */ -GHashTable *unprocessed_opts; +GHashTable *unprocessed_opts, *opts;/* The list currently being traversed with opts_start_list() / * opts_next_list(). The list must have a struct element type in the * schema, with a single mandatory scalar member. */ ListMode list_mode;GQueue *repeated_opts; +char *repeated_name;/* When parsing a list of repeating options as integers, values of the form * "a-b", representing a closed interval, are allowed. Elements in the @@ -86,6 +87,9 @@ struct OptsVisitor* not survive or escape the OptsVisitor object. */ QemuOpt *fake_id_opt; + +/* List of field names leading to the current structure. */ +GQueue *nested_names; };@@ -97,11 +101,12 @@ destroy_list(gpointer list)static void -opts_visitor_insert (GHashTable *unprocessed_opts,const QemuOpt *opt) +opts_visitor_insert (OptsVisitor *ov,const QemuOpt *opt) {GQueue *list; +assert (opt); - list =g_hash_table_lookup (unprocessed_opts, opt->name); + list =g_hash_table_lookup (ov->opts, opt->name);if (list ==NULL ) { list =g_queue_new ();@@ -109,7 +114,8 @@ opts_visitor_insert(GHashTable *unprocessed_opts, const QemuOpt *opt)* "key_destroy_func" in opts_start_struct(). Thus cast away key * const-ness in order to suppress gcc's warning. */ -g_hash_table_insert (unprocessed_opts, (gpointer )opt->name, list); +g_hash_table_insert (ov->opts, (gpointer )opt->name, list); +g_hash_table_insert (ov->unprocessed_opts, (gpointer )opt->name, list); }/* Similarly, destroy_list() doesn't call g_queue_free_full(). */ @@ -127,17 +133,27 @@ opts_start_struct(Visitor *v, void **obj, const char *kind,if (obj) { *obj =g_malloc0 (size >0 ? size :1 ); } + +/* assuming name is a statically allocated string (or at least it's lifetime +* is longer than the visitor's) */ +if (!name) { + name ="" ; + } +g_queue_push_tail (ov->nested_names, (gpointer ) name); +if (ov->depth++ >0 ) {return ; } - ov->unprocessed_opts =g_hash_table_new_full (&g_str_hash, &g_str_equal, -NULL , &destroy_list); + ov->opts =g_hash_table_new_full (&g_str_hash, &g_str_equal, +NULL , &destroy_list); + ov->unprocessed_opts =g_hash_table_new (&g_str_hash, &g_str_equal); + QTAILQ_FOREACH(opt, &ov->opts_root->head, next) {/* ensured by qemu-option.c::opts_do_parse() */ assert (strcmp (opt->name,"id" ) !=0 ); -opts_visitor_insert (ov->unprocessed_opts, opt); +opts_visitor_insert (ov, opt); }if (ov->opts_root->id !=NULL ) {@@ -145,7 +161,7 @@ opts_start_struct(Visitor *v, void **obj, const char *kind, ov->fake_id_opt->name =g_strdup ("id" ); ov->fake_id_opt->str =g_strdup (ov->opts_root->id); -opts_visitor_insert (ov->unprocessed_opts, ov->fake_id_opt); +opts_visitor_insert (ov, ov->fake_id_opt); } }@@ -163,6 +179,8 @@ opts_end_struct(Visitor *v, Error **errp)OptsVisitor *ov =DO_UPCAST (OptsVisitor, visitor, v);GQueue *any; +g_queue_pop_tail (ov->nested_names); +if (--ov->depth >0 ) {return ; }@@ -177,6 +195,8 @@ opts_end_struct(Visitor *v, Error **errp) }g_hash_table_destroy (ov->unprocessed_opts); ov->unprocessed_opts =NULL ; +g_hash_table_destroy (ov->opts); + ov->opts =NULL ;if (ov->fake_id_opt) {g_free (ov->fake_id_opt->name);g_free (ov->fake_id_opt->str);@@ -185,16 +205,56 @@ opts_end_struct(Visitor *v, Error **errp) ov->fake_id_opt =NULL ; } +static void +sum_strlen (gpointer data,gpointer user_data) +{ +const char *str = data; +size_t *sum_len = user_data; + *sum_len +=strlen (str) +1 ; +} + +static void +append_str (gpointer data,gpointer user_data) +{ +strcat (user_data, data); +strcat (user_data,"." ); +} + +/* lookup a name, trying from the most qualified version (e.g. foo.bar.asd) to +* least qualified ones (i.e. foo.bar.asd overrides bar.asd or asd) */ static GQueue * -lookup_distinct (const OptsVisitor *ov,const char *name,Error **errp) +lookup_distinct (const OptsVisitor *ov,const char *name,char **out_key, +Error **errp) { -GQueue *list; +GQueue *list =NULL ; +char *key, *key2; +size_t sum_len =strlen (name); - list =g_hash_table_lookup (ov->unprocessed_opts, name); +g_queue_foreach (ov->nested_names, sum_strlen, &sum_len); + key =g_malloc (sum_len+1 ); + key[0 ] =0 ; +g_queue_foreach (ov->nested_names, append_str, key); +strcat (key, name); + + key2 = key; +while (*key2) { + list =g_hash_table_lookup (ov->opts, key2); +if (list) { +if (out_key) { + *out_key =g_strdup (key2); + } +break ; + } + +while (*key2 && *key2++ !='.' ) { + } + }if (!list) {error_set (errp,QERR_MISSING_PARAMETER , name); } + +g_free (key);return list; }@@ -206,7 +266,7 @@ opts_start_list(Visitor *v, const char *name, Error **errp)/* we can't traverse a list in a list */ assert (ov->list_mode ==LM_NONE ); - ov->repeated_opts =lookup_distinct (ov, name, errp); + ov->repeated_opts =lookup_distinct (ov, name, &ov->repeated_name, errp);if (ov->repeated_opts !=NULL ) { ov->list_mode =LM_STARTED ; }@@ -242,11 +302,9 @@ opts_next_list(Visitor *v, GenericList **list, Error **errp)/* range has been completed, fall through in order to pop option */ case LM_IN_PROGRESS : { -const QemuOpt *opt; - - opt =g_queue_pop_head (ov->repeated_opts); +g_queue_pop_head (ov->repeated_opts);if (g_queue_is_empty (ov->repeated_opts)) { -g_hash_table_remove (ov->unprocessed_opts, opt->name); +g_hash_table_remove (ov->unprocessed_opts, ov->repeated_name);return NULL ; } link = &(*list)->next;@@ -272,22 +330,28 @@ opts_end_list(Visitor *v, Error **errp) ov->list_mode ==LM_SIGNED_INTERVAL || ov->list_mode == LM_UNSIGNED_INTERVAL); ov->repeated_opts =NULL ; + +g_free (ov->repeated_name); + ov->repeated_name =NULL ; + ov->list_mode =LM_NONE ; }static const QemuOpt * -lookup_scalar (const OptsVisitor *ov,const char *name,Error **errp) +lookup_scalar (const OptsVisitor *ov,const char *name,char ** out_key, +Error **errp) {if (ov->list_mode ==LM_NONE ) {GQueue *list;/* the last occurrence of any QemuOpt takes effect when queried by name */ - list =lookup_distinct (ov, name, errp); + list =lookup_distinct (ov, name, out_key, errp);return list ?g_queue_peek_tail (list) :NULL ; }assert (ov->list_mode ==LM_IN_PROGRESS ); +assert (out_key ==NULL || *out_key ==NULL );return g_queue_peek_head (ov->repeated_opts); }@@ -309,13 +373,15 @@ opts_type_str(Visitor *v, char **obj, const char *name, Error **errp) {OptsVisitor *ov =DO_UPCAST (OptsVisitor, visitor, v);const QemuOpt *opt; +char *key =NULL ; - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; } *obj =g_strdup (opt->str ? opt->str :"" ); -processed (ov, name); +processed (ov, key); +g_free (key); }@@ -325,8 +391,9 @@ opts_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) {OptsVisitor *ov =DO_UPCAST (OptsVisitor, visitor, v);const QemuOpt *opt; +char *key =NULL ; - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; }@@ -343,13 +410,15 @@ opts_type_bool(Visitor *v, bool *obj, const char *name, Error **errp) }else {error_set (errp,QERR_INVALID_PARAMETER_VALUE , opt->name,"on|yes|y|off|no|n" ); +g_free (key);return ; } }else { *obj = true; } -processed (ov, name); +processed (ov, key); +g_free (key); }@@ -361,13 +430,14 @@ opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)const char *str;long long val;char *endptr; +char *key =NULL ;if (ov->list_mode ==LM_SIGNED_INTERVAL ) { *obj = ov->range_next.s;return ; } - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; }@@ -381,11 +451,13 @@ opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)if (errno ==0 && endptr > str &&INT64_MIN <= val && val <=INT64_MAX ) {if (*endptr =='\0' ) { *obj = val; -processed (ov, name); +processed (ov, key); +g_free (key);return ; }if (*endptr =='-' && ov->list_mode ==LM_IN_PROGRESS ) {long long val2; +assert (key ==NULL ); str = endptr +1 ; val2 =strtoll (str, &endptr,0 );@@ -406,6 +478,7 @@ opts_type_int(Visitor *v, int64_t *obj, const char *name, Error **errp)error_set (errp,QERR_INVALID_PARAMETER_VALUE , opt->name, (ov->list_mode ==LM_NONE ) ?"an int64 value" :"an int64 value or range" ); +g_free (key); }@@ -417,13 +490,14 @@ opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp)const char *str;unsigned long long val;char *endptr; +char *key =NULL ;if (ov->list_mode ==LM_UNSIGNED_INTERVAL ) { *obj = ov->range_next.u;return ; } - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; }@@ -435,11 +509,13 @@ opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp)if (parse_uint (str, &val, &endptr,0 ) ==0 && val <=UINT64_MAX ) {if (*endptr =='\0' ) { *obj = val; -processed (ov, name); +processed (ov, key); +g_free (key);return ; }if (*endptr =='-' && ov->list_mode ==LM_IN_PROGRESS ) {unsigned long long val2; +assert (key ==NULL ); str = endptr +1 ; if (parse_uint_full(str, &val2, 0) == 0 &&@@ -458,6 +534,7 @@ opts_type_uint64(Visitor *v, uint64_t *obj, const char *name, Error **errp)error_set (errp,QERR_INVALID_PARAMETER_VALUE , opt->name, (ov->list_mode ==LM_NONE ) ?"a uint64 value" :"a uint64 value or range" ); +g_free (key); }@@ -468,8 +545,9 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)const QemuOpt *opt;int64_t val;char *endptr; +char *key =NULL ; - opt =lookup_scalar (ov, name, errp); + opt =lookup_scalar (ov, name, &key, errp);if (!opt) {return ; }@@ -479,11 +557,13 @@ opts_type_size(Visitor *v, uint64_t *obj, const char *name, Error **errp)if (val <0 || *endptr) {error_set (errp,QERR_INVALID_PARAMETER_VALUE , opt->name,"a size value representible as a non-negative int64" ); +g_free (key);return ; } *obj = val; -processed (ov, name); +processed (ov, key); +g_free (key); }@@ -494,7 +574,7 @@ opts_optional(Visitor *v, bool *present, const char *name, Error **errp)/* we only support a single mandatory scalar field in a list node */ assert (ov->list_mode ==LM_NONE ); - *present = (lookup_distinct (ov, name,NULL ) !=NULL ); + *present = (lookup_distinct (ov, name,NULL ,NULL ) !=NULL ); }@@ -505,6 +585,8 @@ opts_visitor_new(const QemuOpts *opts) ov =g_malloc0 (sizeof *ov); + ov->nested_names =g_queue_new (); + ov->visitor.start_struct = &opts_start_struct; ov->visitor.end_struct = &opts_end_struct;@@ -545,6 +627,10 @@ opts_visitor_cleanup(OptsVisitor *ov)if (ov->unprocessed_opts !=NULL ) {g_hash_table_destroy (ov->unprocessed_opts); } +if (ov->opts !=NULL ) { +g_hash_table_destroy (ov->opts); + } +g_queue_free (ov->nested_names);g_free (ov->fake_id_opt);g_free (ov); }tests/qapi-schema/qapi-schema-test.json +8
-1@@ -81,6 +81,11 @@ { 'command': 'user_def_cmd3', 'data': {'a': 'int', '*b': 'int' }, 'returns': 'int' } +# For testing hierarchy support in opts-visitor +{ 'struct': 'UserDefOptionsSub', + 'data': { + '*nint': 'int' } } + # For testing integer range flattening in opts-visitor. The following schema # corresponds to the option format: #@@ -94,7 +99,9 @@ '*u64' : [ 'uint64' ], '*u16' : [ 'uint16' ], '*i64x': 'int' , - '*u64x': 'uint64' } } + '*u64x': 'uint64' , + 'sub0': 'UserDefOptionsSub', + 'sub1': 'UserDefOptionsSub' } } # testing event { 'struct': 'EventStructOne',tests/test-opts-visitor.c +34
-0@@ -177,6 +177,34 @@ expect_u64_max(OptsVisitorFixture *f, gconstpointer test_data)g_assert (f->userdef->u64->value ==UINT64_MAX ); } +static void +expect_both (OptsVisitorFixture *f,gconstpointer test_data) +{ +expect_ok (f, test_data); +g_assert (f->userdef->sub0->has_nint); +g_assert (f->userdef->sub0->nint ==13 ); +g_assert (f->userdef->sub1->has_nint); +g_assert (f->userdef->sub1->nint ==13 ); +} + +static void +expect_sub0 (OptsVisitorFixture *f,gconstpointer test_data) +{ +expect_ok (f, test_data); +g_assert (f->userdef->sub0->has_nint); +g_assert (f->userdef->sub0->nint ==13 ); +g_assert (!f->userdef->sub1->has_nint); +} + +static void +expect_sub1 (OptsVisitorFixture *f,gconstpointer test_data) +{ +expect_ok (f, test_data); +g_assert (!f->userdef->sub0->has_nint); +g_assert (f->userdef->sub1->has_nint); +g_assert (f->userdef->sub1->nint ==13 ); +} +/* test cases */ int @@ -270,6 +298,12 @@ main(int argc, char **argv)add_test ("/visitor/opts/i64/range/2big/full" , &expect_fail,"i64=-0x8000000000000000-0x7fffffffffffffff" ); +/* Test nested structs support */ +add_test ("/visitor/opts/nested/unqualified" , &expect_both,"nint=13" ); +add_test ("/visitor/opts/nested/both" , &expect_both, +"sub0.nint=13,sub1.nint=13" ); +add_test ("/visitor/opts/nested/sub0" , &expect_sub0,"sub0.nint=13" ); +add_test ("/visitor/opts/nested/sub1" , &expect_sub1,"sub1.nint=13" );g_test_run ();return 0 ; }
PATCH 9/12 opts: do not print separator before first item in qemu_opts_print
In reply to Kővágó, ZoltánThis allows to print options in a format that the user would actually write it on the command line (foo=bar,baz=asd,etc=def), without prepending a spurious comma at the beginning of the list.
Only block.c depended on the old behavior, but it was also updated.
--- block.c | 2 +- util/qemu-option.c | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-)
block.c +1 -1
@@ -3644,7 +3644,7 @@ void bdrv_img_create(const char *filename, const char *fmt, }if (!quiet) { -printf ("Formatting '%s', fmt=%s" , filename, fmt); +printf ("Formatting '%s', fmt=%s " , filename, fmt);qemu_opts_print (opts," " );puts ("" ); }
util/qemu-option.c +4 -1
@@ -728,14 +728,16 @@ void qemu_opts_del(QemuOpts *opts)g_free (opts); } -void qemu_opts_print (QemuOpts *opts,const char *sep) +void qemu_opts_print (QemuOpts *opts,const char *d_sep) {QemuOpt *opt;QemuOptDesc *desc = opts->list->desc; +const char *sep ="" ;if (desc[0 ].name ==NULL ) { QTAILQ_FOREACH(opt, &opts->head, next) {printf ("%s%s=\"%s\"" , sep, opt->name, opt->str); + sep = d_sep; }return ; }
@@ -755,6 +757,7 @@ void qemu_opts_print(QemuOpts *opts, const char *sep) }else {printf ("%s%s=%s" , sep, desc->name, value); } + sep = d_sep; } }
Signature · 1 line
2.4.2
PATCH 10/12 qapi: AllocVisitor
In reply to Kővágó, ZoltánSimple visitor that recursively allocates structures with only optional variables. Unions are initialized to the first type specified. Other non optional types are not supported.
--- include/qapi/alloc-visitor.h | 18 +++++++++++++ qapi/Makefile.objs | 1 + qapi/alloc-visitor.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 include/qapi/alloc-visitor.h create mode 100644 qapi/alloc-visitor.c
include/qapi/alloc-visitor.h new file +18 -0
@@ -0,0 +1,18 @@ +/* +* Alloc Visitor. +* Recursively allocates structs, leaving all optional fields unset. In case of +* a non-optional field it fails. +*/ + +#ifndef ALLOC_VISITOR_H +#define ALLOC_VISITOR_H + +#include "qapi/visitor.h" + +typedef struct AllocVisitor AllocVisitor ; + +AllocVisitor *alloc_visitor_new (void ); +void alloc_visitor_cleanup (AllocVisitor *v); +Visitor *alloc_visitor_get_visitor (AllocVisitor *v); + +#endif
qapi/Makefile.objs +1 -0
@@ -4,3 +4,4 @@ util-obj-y += string-input-visitor.o string-output-visitor.o util-obj-y += opts-visitor.o util-obj-y += qmp-event.o util-obj-y += qapi-util.o +util-obj-y += alloc-visitor.o
qapi/alloc-visitor.c new file +62 -0
62 lines not on this page · raw message
Signature · 1 line
2.4.2
PATCH 11/12 audio: use qapi AudioFormat instead of audfmt_e
In reply to Kővágó, ZoltánI had to include an enum for audio sampling formats into qapi, but that meant duplicating the audfmt_e enum. This patch replaces audfmt_e and associated values with the qapi generated AudioFormat enum.
This patch is mostly a search-and-replace, except for switches where the qapi generated AUDIO_FORMAT_MAX caused problems.
--- audio/alsaaudio.c | 53 ++++++++++++++------------ audio/audio.c | 97 ++++++++++++++++++++++++++--------------------- audio/audio.h | 11 +----- audio/audio_win_int.c | 18 ++++----- audio/ossaudio.c | 30 +++++++-------- audio/paaudio.c | 28 +++++++------- audio/sdlaudio.c | 26 ++++++------- audio/spiceaudio.c | 4 +- audio/wavaudio.c | 17 +++++---- audio/wavcapture.c | 2 +- hw/arm/omap2.c | 2 +- hw/audio/ac97.c | 2 +- hw/audio/adlib.c | 2 +- hw/audio/cs4231a.c | 6 +-- hw/audio/es1370.c | 4 +- hw/audio/gus.c | 2 +- hw/audio/hda-codec.c | 18 ++++----- hw/audio/lm4549.c | 6 +-- hw/audio/milkymist-ac97.c | 2 +- hw/audio/pcspk.c | 2 +- hw/audio/sb16.c | 14 +++---- hw/audio/wm8750.c | 4 +- hw/input/tsc210x.c | 2 +- hw/usb/dev-audio.c | 2 +- ui/vnc.c | 14 +++---- 25 files changed, 187 insertions(+), 181 deletions(-)
audio/alsaaudio.c +28 -25
@@ -88,7 +88,7 @@ struct alsa_params_req {struct alsa_params_obt {int freq; -audfmt_e fmt; +AudioFormat fmt;int endianness;int nchannels;snd_pcm_uframes_t samples;
@@ -307,16 +307,16 @@ static int alsa_write (SWVoiceOut *sw, void *buf, int len)return audio_pcm_sw_write (sw, buf, len); } -static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt,int endianness) +static snd_pcm_format_t aud_to_alsafmt (AudioFormat fmt,int endianness) {switch (fmt) { -case AUD_FMT_S8 : +case AUDIO_FORMAT_S8 :return SND_PCM_FORMAT_S8 ; -case AUD_FMT_U8 : +case AUDIO_FORMAT_U8 :return SND_PCM_FORMAT_U8 ; -case AUD_FMT_S16 : +case AUDIO_FORMAT_S16 :if (endianness) {return SND_PCM_FORMAT_S16_BE ; }
@@ -324,7 +324,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)return SND_PCM_FORMAT_S16_LE ; } -case AUD_FMT_U16 : +case AUDIO_FORMAT_U16 :if (endianness) {return SND_PCM_FORMAT_U16_BE ; }
@@ -332,7 +332,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)return SND_PCM_FORMAT_U16_LE ; } -case AUD_FMT_S32 : +case AUDIO_FORMAT_S32 :if (endianness) {return SND_PCM_FORMAT_S32_BE ; }
@@ -340,7 +340,7 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness)return SND_PCM_FORMAT_S32_LE ; } -case AUD_FMT_U32 : +case AUDIO_FORMAT_U32 :if (endianness) {return SND_PCM_FORMAT_U32_BE ; }
@@ -357,58 +357,58 @@ static snd_pcm_format_t aud_to_alsafmt (audfmt_e fmt, int endianness) } } -static int alsa_to_audfmt (snd_pcm_format_t alsafmt,audfmt_e *fmt, +static int alsa_to_audfmt (snd_pcm_format_t alsafmt,AudioFormat *fmt,int *endianness) {switch (alsafmt) {case SND_PCM_FORMAT_S8 : *endianness =0 ; - *fmt =AUD_FMT_S8 ; + *fmt =AUDIO_FORMAT_S8 ;break ;case SND_PCM_FORMAT_U8 : *endianness =0 ; - *fmt =AUD_FMT_U8 ; + *fmt =AUDIO_FORMAT_U8 ;break ;case SND_PCM_FORMAT_S16_LE : *endianness =0 ; - *fmt =AUD_FMT_S16 ; + *fmt =AUDIO_FORMAT_S16 ;break ;case SND_PCM_FORMAT_U16_LE : *endianness =0 ; - *fmt =AUD_FMT_U16 ; + *fmt =AUDIO_FORMAT_U16 ;break ;case SND_PCM_FORMAT_S16_BE : *endianness =1 ; - *fmt =AUD_FMT_S16 ; + *fmt =AUDIO_FORMAT_S16 ;break ;case SND_PCM_FORMAT_U16_BE : *endianness =1 ; - *fmt =AUD_FMT_U16 ; + *fmt =AUDIO_FORMAT_U16 ;break ;case SND_PCM_FORMAT_S32_LE : *endianness =0 ; - *fmt =AUD_FMT_S32 ; + *fmt =AUDIO_FORMAT_S32 ;break ;case SND_PCM_FORMAT_U32_LE : *endianness =0 ; - *fmt =AUD_FMT_U32 ; + *fmt =AUDIO_FORMAT_U32 ;break ;case SND_PCM_FORMAT_S32_BE : *endianness =1 ; - *fmt =AUD_FMT_S32 ; + *fmt =AUDIO_FORMAT_S32 ;break ;case SND_PCM_FORMAT_U32_BE : *endianness =1 ; - *fmt =AUD_FMT_U32 ; + *fmt =AUDIO_FORMAT_U32 ;break ;default :
@@ -651,19 +651,22 @@ static int alsa_open (int in, struct alsa_params_req *req, bytes_per_sec = freq << (nchannels ==2 );switch (obt->fmt) { -case AUD_FMT_S8 : -case AUD_FMT_U8 : +case AUDIO_FORMAT_S8 : +case AUDIO_FORMAT_U8 :break ; -case AUD_FMT_S16 : -case AUD_FMT_U16 : +case AUDIO_FORMAT_S16 : +case AUDIO_FORMAT_U16 : bytes_per_sec <<=1 ;break ; -case AUD_FMT_S32 : -case AUD_FMT_U32 : +case AUDIO_FORMAT_S32 : +case AUDIO_FORMAT_U32 : bytes_per_sec <<=2 ;break ; + +case AUDIO_FORMAT_MAX : +break ; } threshold = (conf->threshold * bytes_per_sec) /1000 ;
audio/audio.c +53 -44
230 lines not on this page · raw message
audio/audio.h +1 -10
@@ -29,15 +29,6 @@typedef void (*audio_callback_fn ) (void *opaque,int avail); -typedef enum { -AUD_FMT_U8 , -AUD_FMT_S8 , -AUD_FMT_U16 , -AUD_FMT_S16 , -AUD_FMT_U32 , -AUD_FMT_S32 -}audfmt_e ; -#ifdef HOST_WORDS_BIGENDIAN #define AUDIO_HOST_ENDIANNESS 1#else
@@ -47,7 +38,7 @@ typedef enum {struct audsettings {int freq;int nchannels; -audfmt_e fmt; +AudioFormat fmt;int endianness; };
audio/audio_win_int.c +9 -9
@@ -23,20 +23,20 @@ int waveformat_from_audio_settings (WAVEFORMATEX *wfx, wfx->cbSize =0 ;switch (as->fmt) { -case AUD_FMT_S8 : -case AUD_FMT_U8 : +case AUDIO_FORMAT_S8 : +case AUDIO_FORMAT_U8 : wfx->wBitsPerSample =8 ;break ; -case AUD_FMT_S16 : -case AUD_FMT_U16 : +case AUDIO_FORMAT_S16 : +case AUDIO_FORMAT_U16 : wfx->wBitsPerSample =16 ; wfx->nAvgBytesPerSec <<=1 ; wfx->nBlockAlign <<=1 ;break ; -case AUD_FMT_S32 : -case AUD_FMT_U32 : +case AUDIO_FORMAT_S32 : +case AUDIO_FORMAT_U32 : wfx->wBitsPerSample =32 ; wfx->nAvgBytesPerSec <<=2 ; wfx->nBlockAlign <<=2 ;
@@ -84,15 +84,15 @@ int waveformat_to_audio_settings (WAVEFORMATEX *wfx,switch (wfx->wBitsPerSample) {case 8 : - as->fmt =AUD_FMT_U8 ; + as->fmt =AUDIO_FORMAT_U8 ;break ;case 16 : - as->fmt =AUD_FMT_S16 ; + as->fmt =AUDIO_FORMAT_S16 ;break ;case 32 : - as->fmt =AUD_FMT_S32 ; + as->fmt =AUDIO_FORMAT_S32 ;break ;default :
audio/ossaudio.c +15 -15
@@ -72,7 +72,7 @@ typedef struct OSSVoiceIn {struct oss_params {int freq; -audfmt_e fmt; +AudioFormat fmt;int nchannels;int nfrags;int fragsize;
@@ -150,16 +150,16 @@ static int oss_write (SWVoiceOut *sw, void *buf, int len)return audio_pcm_sw_write (sw, buf, len); } -static int aud_to_ossfmt (audfmt_e fmt,int endianness) +static int aud_to_ossfmt (AudioFormat fmt,int endianness) {switch (fmt) { -case AUD_FMT_S8 : +case AUDIO_FORMAT_S8 :return AFMT_S8 ; -case AUD_FMT_U8 : +case AUDIO_FORMAT_U8 :return AFMT_U8 ; -case AUD_FMT_S16 : +case AUDIO_FORMAT_S16 :if (endianness) {return AFMT_S16_BE ; }
@@ -167,7 +167,7 @@ static int aud_to_ossfmt (audfmt_e fmt, int endianness)return AFMT_S16_LE ; } -case AUD_FMT_U16 : +case AUDIO_FORMAT_U16 :if (endianness) {return AFMT_U16_BE ; }
@@ -184,37 +184,37 @@ static int aud_to_ossfmt (audfmt_e fmt, int endianness) } } -static int oss_to_audfmt (int ossfmt,audfmt_e *fmt,int *endianness) +static int oss_to_audfmt (int ossfmt,AudioFormat *fmt,int *endianness) {switch (ossfmt) {case AFMT_S8 : *endianness =0 ; - *fmt =AUD_FMT_S8 ; + *fmt =AUDIO_FORMAT_S8 ;break ;case AFMT_U8 : *endianness =0 ; - *fmt =AUD_FMT_U8 ; + *fmt =AUDIO_FORMAT_U8 ;break ;case AFMT_S16_LE : *endianness =0 ; - *fmt =AUD_FMT_S16 ; + *fmt =AUDIO_FORMAT_S16 ;break ;case AFMT_U16_LE : *endianness =0 ; - *fmt =AUD_FMT_U16 ; + *fmt =AUDIO_FORMAT_U16 ;break ;case AFMT_S16_BE : *endianness =1 ; - *fmt =AUD_FMT_S16 ; + *fmt =AUDIO_FORMAT_S16 ;break ;case AFMT_U16_BE : *endianness =1 ; - *fmt =AUD_FMT_U16 ; + *fmt =AUDIO_FORMAT_U16 ;break ;default :
@@ -502,7 +502,7 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,int endianness;int err;int fd; -audfmt_e effective_fmt; +AudioFormat effective_fmt;struct audsettings obt_as;OSSConf *conf = drv_opaque;
@@ -670,7 +670,7 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)int endianness;int err;int fd; -audfmt_e effective_fmt; +AudioFormat effective_fmt;struct audsettings obt_as;OSSConf *conf = drv_opaque;
audio/paaudio.c +14 -14
@@ -384,21 +384,21 @@ static int qpa_read (SWVoiceIn *sw, void *buf, int len)return audio_pcm_sw_read (sw, buf, len); } -static pa_sample_format_t audfmt_to_pa (audfmt_e afmt,int endianness) +static pa_sample_format_t audfmt_to_pa (AudioFormat afmt,int endianness) {int format;switch (afmt) { -case AUD_FMT_S8 : -case AUD_FMT_U8 : +case AUDIO_FORMAT_S8 : +case AUDIO_FORMAT_U8 : format =PA_SAMPLE_U8 ;break ; -case AUD_FMT_S16 : -case AUD_FMT_U16 : +case AUDIO_FORMAT_S16 : +case AUDIO_FORMAT_U16 : format = endianness ?PA_SAMPLE_S16BE :PA_SAMPLE_S16LE ;break ; -case AUD_FMT_S32 : -case AUD_FMT_U32 : +case AUDIO_FORMAT_S32 : +case AUDIO_FORMAT_U32 : format = endianness ?PA_SAMPLE_S32BE :PA_SAMPLE_S32LE ;break ;default :
@@ -409,26 +409,26 @@ static pa_sample_format_t audfmt_to_pa (audfmt_e afmt, int endianness)return format; } -static audfmt_e pa_to_audfmt (pa_sample_format_t fmt,int *endianness) +static AudioFormat pa_to_audfmt (pa_sample_format_t fmt,int *endianness) {switch (fmt) {case PA_SAMPLE_U8 : -return AUD_FMT_U8 ; +return AUDIO_FORMAT_U8 ;case PA_SAMPLE_S16BE : *endianness =1 ; -return AUD_FMT_S16 ; +return AUDIO_FORMAT_S16 ;case PA_SAMPLE_S16LE : *endianness =0 ; -return AUD_FMT_S16 ; +return AUDIO_FORMAT_S16 ;case PA_SAMPLE_S32BE : *endianness =1 ; -return AUD_FMT_S32 ; +return AUDIO_FORMAT_S32 ;case PA_SAMPLE_S32LE : *endianness =0 ; -return AUD_FMT_S32 ; +return AUDIO_FORMAT_S32 ;default :dolog ("Internal logic error: Bad pa_sample_format %d\n" , fmt); -return AUD_FMT_U8 ; +return AUDIO_FORMAT_U8 ; } }
audio/sdlaudio.c +13 -13
@@ -115,19 +115,19 @@ static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn)return sdl_post (s, forfn); } -static int aud_to_sdlfmt (audfmt_e fmt) +static int aud_to_sdlfmt (AudioFormat fmt) {switch (fmt) { -case AUD_FMT_S8 : +case AUDIO_FORMAT_S8 :return AUDIO_S8 ; -case AUD_FMT_U8 : +case AUDIO_FORMAT_U8 :return AUDIO_U8 ; -case AUD_FMT_S16 : +case AUDIO_FORMAT_S16 :return AUDIO_S16LSB ; -case AUD_FMT_U16 : +case AUDIO_FORMAT_U16 :return AUDIO_U16LSB ;default :
@@ -139,37 +139,37 @@ static int aud_to_sdlfmt (audfmt_e fmt) } } -static int sdl_to_audfmt (int sdlfmt,audfmt_e *fmt,int *endianness) +static int sdl_to_audfmt (int sdlfmt,AudioFormat *fmt,int *endianness) {switch (sdlfmt) {case AUDIO_S8 : *endianness =0 ; - *fmt =AUD_FMT_S8 ; + *fmt =AUDIO_FORMAT_S8 ;break ;case AUDIO_U8 : *endianness =0 ; - *fmt =AUD_FMT_U8 ; + *fmt =AUDIO_FORMAT_U8 ;break ;case AUDIO_S16LSB : *endianness =0 ; - *fmt =AUD_FMT_S16 ; + *fmt =AUDIO_FORMAT_S16 ;break ;case AUDIO_U16LSB : *endianness =0 ; - *fmt =AUD_FMT_U16 ; + *fmt =AUDIO_FORMAT_U16 ;break ;case AUDIO_S16MSB : *endianness =1 ; - *fmt =AUD_FMT_S16 ; + *fmt =AUDIO_FORMAT_S16 ;break ;case AUDIO_U16MSB : *endianness =1 ; - *fmt =AUD_FMT_U16 ; + *fmt =AUDIO_FORMAT_U16 ;break ;default :
@@ -341,7 +341,7 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as,SDL_AudioSpec req, obt;int endianness;int err; -audfmt_e effective_fmt; +AudioFormat effective_fmt;struct audsettings obt_as; req.freq = as->freq;
audio/spiceaudio.c +2 -2
@@ -127,7 +127,7 @@ static int line_out_init(HWVoiceOut *hw, struct audsettings *as, settings.freq =SPICE_INTERFACE_PLAYBACK_FREQ ;#endif settings.nchannels =SPICE_INTERFACE_PLAYBACK_CHAN ; - settings.fmt =AUD_FMT_S16 ; + settings.fmt =AUDIO_FORMAT_S16 ; settings.endianness =AUDIO_HOST_ENDIANNESS ;audio_pcm_init_info (&hw->info, &settings);
@@ -255,7 +255,7 @@ static int line_in_init(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) settings.freq =SPICE_INTERFACE_RECORD_FREQ ;#endif settings.nchannels =SPICE_INTERFACE_RECORD_CHAN ; - settings.fmt =AUD_FMT_S16 ; + settings.fmt =AUDIO_FORMAT_S16 ; settings.endianness =AUDIO_HOST_ENDIANNESS ;audio_pcm_init_info (&hw->info, &settings);
audio/wavaudio.c +10 -7
@@ -116,20 +116,23 @@ static int wav_init_out(HWVoiceOut *hw, struct audsettings *as, stereo = wav_as.nchannels ==2 ;switch (wav_as.fmt) { -case AUD_FMT_S8 : -case AUD_FMT_U8 : +case AUDIO_FORMAT_S8 : +case AUDIO_FORMAT_U8 : bits16 =0 ;break ; -case AUD_FMT_S16 : -case AUD_FMT_U16 : +case AUDIO_FORMAT_S16 : +case AUDIO_FORMAT_U16 : bits16 =1 ;break ; -case AUD_FMT_S32 : -case AUD_FMT_U32 : +case AUDIO_FORMAT_S32 : +case AUDIO_FORMAT_U32 :dolog ("WAVE files can not handle 32bit formats\n" );return -1 ; + +case AUDIO_FORMAT_MAX : +abort (); } hdr[34 ] = bits16 ?0x10 :0x08 ;
@@ -224,7 +227,7 @@ static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...)static WAVConf glob_conf = { .settings.freq =44100 , .settings.nchannels =2 , - .settings.fmt =AUD_FMT_S16 , + .settings.fmt =AUDIO_FORMAT_S16 , .wav_path ="qemu.wav" };
audio/wavcapture.c +1 -1
@@ -135,7 +135,7 @@ int wav_start_capture (CaptureState *s, const char *path, int freq, as.freq = freq; as.nchannels =1 << stereo; - as.fmt = bits16 ?AUD_FMT_S16 :AUD_FMT_U8 ; + as.fmt = bits16 ?AUDIO_FORMAT_S16 :AUDIO_FORMAT_U8 ; as.endianness =0 ; ops.notify = wav_notify;
hw/arm/omap2.c +1 -1
@@ -269,7 +269,7 @@ static void omap_eac_format_update(struct omap_eac_s *s)* does I2S specify it? */ /* All register writes are 16 bits so we we store 16-bit samples * in the buffers regardless of AGCFR[B8_16] value. */ - fmt.fmt =AUD_FMT_U16 ; + fmt.fmt =AUDIO_FORMAT_U16 ; s->codec.in_voice =AUD_open_in (&s->codec.card, s->codec.in_voice,"eac.codec.in" , s, omap_eac_in_cb, &fmt);
hw/audio/ac97.c +1 -1
@@ -360,7 +360,7 @@ static void open_voice (AC97LinkState *s, int index, int freq) as.freq = freq; as.nchannels =2 ; - as.fmt =AUD_FMT_S16 ; + as.fmt =AUDIO_FORMAT_S16 ; as.endianness =0 ;if (freq >0 ) {
hw/audio/adlib.c +1 -1
@@ -323,7 +323,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp) as.freq = s->freq; as.nchannels =SHIFT ; - as.fmt =AUD_FMT_S16 ; + as.fmt =AUDIO_FORMAT_S16 ; as.endianness =AUDIO_HOST_ENDIANNESS ;AUD_register_card ("adlib" , &s->card);
hw/audio/cs4231a.c +3 -3
@@ -284,7 +284,7 @@ static void cs_reset_voices (CSState *s, uint32_t val)switch ((val >>5 ) & ((s->dregs[MODE_And_ID] &MODE2 ) ?7 :3 )) {case 0 : - as.fmt =AUD_FMT_U8 ; + as.fmt =AUDIO_FORMAT_U8 ; s->shift = as.nchannels ==2 ;break ;
@@ -294,7 +294,7 @@ static void cs_reset_voices (CSState *s, uint32_t val)case 3 : s->tab = ALawDecompressTable; x_law: - as.fmt =AUD_FMT_S16 ; + as.fmt =AUDIO_FORMAT_S16 ; as.endianness =AUDIO_HOST_ENDIANNESS ; s->shift = as.nchannels ==2 ;break ;
@@ -302,7 +302,7 @@ static void cs_reset_voices (CSState *s, uint32_t val)case 6 : as.endianness =1 ;case 2 : - as.fmt =AUD_FMT_S16 ; + as.fmt =AUDIO_FORMAT_S16 ; s->shift = as.nchannels;break ;
hw/audio/es1370.c +2 -2
@@ -414,14 +414,14 @@ static void es1370_update_voices (ES1370State *s, uint32_t ctl, uint32_t sctl) i, new_freq,1 << (new_fmt &1 ), - (new_fmt &2 ) ?AUD_FMT_S16 :AUD_FMT_U8 , + (new_fmt &2 ) ?AUDIO_FORMAT_S16 :AUDIO_FORMAT_U8 , d->shift);if (new_freq) {struct audsettings as; as.freq = new_freq; as.nchannels =1 << (new_fmt &1 ); - as.fmt = (new_fmt &2 ) ?AUD_FMT_S16 :AUD_FMT_U8 ; + as.fmt = (new_fmt &2 ) ?AUDIO_FORMAT_S16 :AUDIO_FORMAT_U8 ; as.endianness =0 ;if (i ==ADC_CHANNEL ) {
hw/audio/gus.c +1 -1
@@ -242,7 +242,7 @@ static void gus_realizefn (DeviceState *dev, Error **errp) as.freq = s->freq; as.nchannels =2 ; - as.fmt =AUD_FMT_S16 ; + as.fmt =AUDIO_FORMAT_S16 ; as.endianness =GUS_ENDIANNESS ; s->voice = AUD_open_out (
hw/audio/hda-codec.c +9 -9
@@ -97,9 +97,9 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) }switch (format &AC_FMT_BITS_MASK ) { -case AC_FMT_BITS_8 : as->fmt =AUD_FMT_S8 ;break ; -case AC_FMT_BITS_16 : as->fmt =AUD_FMT_S16 ;break ; -case AC_FMT_BITS_32 : as->fmt =AUD_FMT_S32 ;break ; +case AC_FMT_BITS_8 : as->fmt =AUDIO_FORMAT_S8 ;break ; +case AC_FMT_BITS_16 : as->fmt =AUDIO_FORMAT_S16 ;break ; +case AC_FMT_BITS_32 : as->fmt =AUDIO_FORMAT_S32 ;break ; } as->nchannels = ((format &AC_FMT_CHAN_MASK ) >>AC_FMT_CHAN_SHIFT ) +1 ;
@@ -128,12 +128,12 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as)/* -------------------------------------------------------------------------- */ static const char *fmt2name[] = { - [AUD_FMT_U8 ] ="PCM-U8" , - [AUD_FMT_S8 ] ="PCM-S8" , - [AUD_FMT_U16 ] ="PCM-U16" , - [AUD_FMT_S16 ] ="PCM-S16" , - [AUD_FMT_U32 ] ="PCM-U32" , - [AUD_FMT_S32 ] ="PCM-S32" , + [AUDIO_FORMAT_U8 ] ="PCM-U8" , + [AUDIO_FORMAT_S8 ] ="PCM-S8" , + [AUDIO_FORMAT_U16 ] ="PCM-U16" , + [AUDIO_FORMAT_S16 ] ="PCM-S16" , + [AUDIO_FORMAT_U32 ] ="PCM-U32" , + [AUDIO_FORMAT_S32 ] ="PCM-S32" , };typedef struct HDAAudioState HDAAudioState ;
hw/audio/lm4549.c +3 -3
@@ -185,7 +185,7 @@ void lm4549_write(lm4549_state *s,struct audsettings as; as.freq = value; as.nchannels =2 ; - as.fmt =AUD_FMT_S16 ; + as.fmt =AUDIO_FORMAT_S16 ; as.endianness =0 ; s->voice = AUD_open_out(
@@ -255,7 +255,7 @@ static int lm4549_post_load(void *opaque, int version_id)struct audsettings as; as.freq = freq; as.nchannels =2 ; - as.fmt =AUD_FMT_S16 ; + as.fmt =AUDIO_FORMAT_S16 ; as.endianness =0 ; s->voice = AUD_open_out(
@@ -292,7 +292,7 @@ void lm4549_init(lm4549_state *s, lm4549_callback data_req_cb, void* opaque)/* Open a default voice */ as.freq =48000 ; as.nchannels =2 ; - as.fmt =AUD_FMT_S16 ; + as.fmt =AUDIO_FORMAT_S16 ; as.endianness =0 ; s->voice = AUD_open_out(
hw/audio/milkymist-ac97.c +1 -1
@@ -297,7 +297,7 @@ static int milkymist_ac97_init(SysBusDevice *dev) as.freq =48000 ; as.nchannels =2 ; - as.fmt =AUD_FMT_S16 ; + as.fmt =AUDIO_FORMAT_S16 ; as.endianness =1 ; s->voice_in = AUD_open_in(&s->card, s->voice_in,
hw/audio/pcspk.c +1 -1
@@ -112,7 +112,7 @@ static void pcspk_callback(void *opaque, int free)static int pcspk_audio_init (ISABus *bus) {PCSpkState *s = pcspk_state; -struct audsettings as = {PCSPK_SAMPLE_RATE ,1 ,AUD_FMT_U8 ,0 }; +struct audsettings as = {PCSPK_SAMPLE_RATE ,1 ,AUDIO_FORMAT_U8 ,0 };AUD_register_card (s_spk, &s->card);
hw/audio/sb16.c +7 -7
@@ -66,7 +66,7 @@ typedef struct SB16State {int fmt_stereo;int fmt_signed;int fmt_bits; -audfmt_e fmt; +AudioFormat fmt;int dma_auto;int block_size;int fifo;
@@ -221,7 +221,7 @@ static void continue_dma8 (SB16State *s)static void dma_cmd8 (SB16State *s,int mask,int dma_len) { - s->fmt =AUD_FMT_U8 ; + s->fmt =AUDIO_FORMAT_U8 ; s->use_hdma =0 ; s->fmt_bits =8 ; s->fmt_signed =0 ;
@@ -316,18 +316,18 @@ static void dma_cmd (SB16State *s, uint8_t cmd, uint8_t d0, int dma_len)if (16 == s->fmt_bits) {if (s->fmt_signed) { - s->fmt =AUD_FMT_S16 ; + s->fmt =AUDIO_FORMAT_S16 ; }else { - s->fmt =AUD_FMT_U16 ; + s->fmt =AUDIO_FORMAT_U16 ; } }else {if (s->fmt_signed) { - s->fmt =AUD_FMT_S8 ; + s->fmt =AUDIO_FORMAT_S8 ; }else { - s->fmt =AUD_FMT_U8 ; + s->fmt =AUDIO_FORMAT_U8 ; } }
@@ -839,7 +839,7 @@ static void legacy_reset (SB16State *s) as.freq = s->freq; as.nchannels =1 ; - as.fmt =AUD_FMT_U8 ; + as.fmt =AUDIO_FORMAT_U8 ; as.endianness =0 ; s->voice = AUD_open_out (
hw/audio/wm8750.c +2 -2
@@ -201,7 +201,7 @@ static void wm8750_set_format(WM8750State *s) in_fmt.endianness =0 ; in_fmt.nchannels =2 ; in_fmt.freq = s->adc_hz; - in_fmt.fmt =AUD_FMT_S16 ; + in_fmt.fmt =AUDIO_FORMAT_S16 ; s->adc_voice[0 ] =AUD_open_in (&s->card, s->adc_voice[0 ],CODEC ".input1" , s, wm8750_audio_in_cb, &in_fmt);
@@ -214,7 +214,7 @@ static void wm8750_set_format(WM8750State *s) out_fmt.endianness =0 ; out_fmt.nchannels =2 ; out_fmt.freq = s->dac_hz; - out_fmt.fmt =AUD_FMT_S16 ; + out_fmt.fmt =AUDIO_FORMAT_S16 ; s->dac_voice[0 ] =AUD_open_out (&s->card, s->dac_voice[0 ],CODEC ".speaker" , s, wm8750_audio_out_cb, &out_fmt);
hw/input/tsc210x.c +1 -1
@@ -315,7 +315,7 @@ static void tsc2102_audio_output_update(TSC210xState *s) fmt.endianness =0 ; fmt.nchannels =2 ; fmt.freq = s->codec.tx_rate; - fmt.fmt =AUD_FMT_S16 ; + fmt.fmt =AUDIO_FORMAT_S16 ; s->dac_voice[0 ] =AUD_open_out (&s->card, s->dac_voice[0 ],"tsc2102.sink" , s, (void *) tsc210x_audio_out_cb, &fmt);
hw/usb/dev-audio.c +1 -1
@@ -646,7 +646,7 @@ static void usb_audio_realize(USBDevice *dev, Error **errp) s->out.vol[1 ] =240 ;/* 0 dB */ s->out.as.freq =USBAUDIO_SAMPLE_RATE ; s->out.as.nchannels =2 ; - s->out.as.fmt =AUD_FMT_S16 ; + s->out.as.fmt =AUDIO_FORMAT_S16 ; s->out.as.endianness =0 ;streambuf_init (&s->out.buf, s->buffer);
ui/vnc.c +7 -7
@@ -2379,12 +2379,12 @@ static int protocol_client_msg(VncState *vs, uint8_t *data, size_t len)if (len ==4 )return 10 ;switch (read_u8 (data,4 )) { -case 0 : vs->as.fmt =AUD_FMT_U8 ;break ; -case 1 : vs->as.fmt =AUD_FMT_S8 ;break ; -case 2 : vs->as.fmt =AUD_FMT_U16 ;break ; -case 3 : vs->as.fmt =AUD_FMT_S16 ;break ; -case 4 : vs->as.fmt =AUD_FMT_U32 ;break ; -case 5 : vs->as.fmt =AUD_FMT_S32 ;break ; +case 0 : vs->as.fmt =AUDIO_FORMAT_U8 ;break ; +case 1 : vs->as.fmt =AUDIO_FORMAT_S8 ;break ; +case 2 : vs->as.fmt =AUDIO_FORMAT_U16 ;break ; +case 3 : vs->as.fmt =AUDIO_FORMAT_S16 ;break ; +case 4 : vs->as.fmt =AUDIO_FORMAT_U32 ;break ; +case 5 : vs->as.fmt =AUDIO_FORMAT_S32 ;break ;default :VNC_DEBUG ("Invalid audio format %d\n" ,read_u8 (data,4 ));vnc_client_error (vs);
@@ -3067,7 +3067,7 @@ void vnc_init_state(VncState *vs) vs->as.freq =44100 ; vs->as.nchannels =2 ; - vs->as.fmt =AUD_FMT_S16 ; + vs->as.fmt =AUDIO_FORMAT_S16 ; vs->as.endianness =0 ;qemu_mutex_init (&vs->output_mutex);
Signature · 1 line
2.4.2
PATCH 12/12 audio: -audiodev command line option
In reply to Kővágó, ZoltánThis patch adds an -audiodev command line option, and deprecates the QEMU_* environment variables for audio backend configuration. It's syntax is similar to existing options (-netdev, -device, etc):
-audiodev driver_name,property=value,...
Audio drivers now get an Audiodev * as config paramters, instead of the global audio_option structs. There is some code in audio/audio_legacy.c that converts the old environment variables to audiodev options (this way backends do not have to worry about legacy options, also print out them with -audio-help, to ease migrating to -audiodev).
Although now it's possible to specify multiple -audiodev options on command line, multiple audio backends are not supported yet.
--- audio/Makefile.objs | 2 +- audio/alsaaudio.c | 284 ++++++------------ audio/audio.c | 745 +++++++++++++----------------------------------- audio/audio.h | 21 +- audio/audio_int.h | 7 +- audio/audio_legacy.c | 319 +++++++++++++++++++++ audio/audio_template.h | 13 +- audio/coreaudio.c | 49 +--- audio/dsound_template.h | 6 +- audio/dsoundaudio.c | 56 +--- audio/noaudio.c | 3 +- audio/ossaudio.c | 155 +++------- audio/paaudio.c | 81 ++---- audio/sdlaudio.c | 24 +- audio/spiceaudio.c | 7 +- audio/wavaudio.c | 61 +--- qemu-options.hx | 218 +++++++++++++- vl.c | 9 +- 18 files changed, 979 insertions(+), 1081 deletions(-) create mode 100644 audio/audio_legacy.c
audio/Makefile.objs +1 -1
@@ -1,4 +1,4 @@ -common-obj-y = audio.o noaudio.o wavaudio.o mixeng.o +common-obj-y = audio.o audio_legacy.o noaudio.o wavaudio.o mixeng.o common-obj-$(CONFIG_SDL) += sdlaudio.o common-obj-$(CONFIG_OSS) += ossaudio.o common-obj-$(CONFIG_SPICE) += spiceaudio.o
audio/alsaaudio.c +82 -202
459 lines not on this page · raw message
audio/audio.c +202 -543
894 lines not on this page · raw message
audio/audio.h +18 -3
@@ -25,6 +25,7 @@#define QEMU_AUDIO_H #include "config-host.h" +#include "qemu-common.h" #include "qemu/queue.h" typedef void (*audio_callback_fn ) (void *opaque,int avail);
@@ -35,12 +36,21 @@ typedef void (*audio_callback_fn) (void *opaque, int avail);#define AUDIO_HOST_ENDIANNESS 0#endif -struct audsettings { +typedef struct audsettings {int freq;int nchannels;AudioFormat fmt;int endianness; -}; +}audsettings ; + +audsettings audiodev_to_audsettings (AudiodevPerDirectionOptions *pdo); +int audioformat_bytes_per_sample (AudioFormat fmt); +int audio_buffer_frames (AudiodevPerDirectionOptions *pdo, +audsettings *as,int def_usecs); +int audio_buffer_samples (AudiodevPerDirectionOptions *pdo, +audsettings *as,int def_usecs); +int audio_buffer_bytes (AudiodevPerDirectionOptions *pdo, +audsettings *as,int def_usecs); typedef enum { AUD_CNOTIFY_ENABLE,
@@ -77,10 +87,11 @@ typedef struct QEMUAudioTimeStamp {uint64_t old_ts; } QEMUAudioTimeStamp; +extern QemuOptsList qemu_audiodev_opts; + void AUD_vlog (const char *cap, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0); void AUD_log (const char *cap, const char *fmt, ...) GCC_FMT_ATTR(2, 3); -void AUD_help (void );void AUD_register_card (const char *name,QEMUSoundCard *card);void AUD_remove_card (QEMUSoundCard *card); CaptureVoiceOut *AUD_add_capture (
@@ -154,4 +165,8 @@ static inline void *advance (void *p, int incr)int wav_start_capture (CaptureState *s,const char *path,int freq,int bits,int nchannels); +void audio_set_options (void ); +void audio_handle_legacy_opts (void ); +void audio_legacy_help (void ); +#endif /* audio.h */
audio/audio_int.h +5 -2
@@ -143,8 +143,7 @@ struct SWVoiceIn {struct audio_driver {const char *name;const char *descr; -struct audio_option *options; -void *(*init) (void ); +void *(*init) (Audiodev *);void (*fini) (void *);struct audio_pcm_ops *pcm_ops;int can_be_default;
@@ -190,6 +189,7 @@ struct SWVoiceCap {struct AudioState {struct audio_driver *drv; +Audiodev *dev;void *drv_opaque;QEMUTimer *ts;
@@ -200,6 +200,7 @@ struct AudioState {int nb_hw_voices_out;int nb_hw_voices_in;int vm_running; +int64_t period_ticks; };extern struct audio_driver no_audio_driver;
@@ -213,6 +214,8 @@ extern struct audio_driver pa_audio_driver;extern struct audio_driver spice_audio_driver;extern const struct mixeng_volume nominal_volume; +extern struct audio_driver *drvtab[]; +void audio_pcm_init_info (struct audio_pcm_info *info,struct audsettings *as);void audio_pcm_info_clear_buf (struct audio_pcm_info *info,void *buf,int len);
audio/audio_legacy.c new file +319 -0
319 lines not on this page · raw message
audio/audio_template.h +9 -4
@@ -302,8 +302,10 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as)static HW *glue (audio_pcm_hw_add_ ,TYPE ) (struct audsettings *as) {HW *hw; +AudioState *s = &glob_audio_state; +AudiodevPerDirectionOptions *pdo = s->dev->TYPE; -if (glue (conf.fixed_,TYPE ).enabled &&glue (conf.fixed_,TYPE ).greedy) { +if (pdo->fixed_settings) { hw =glue (audio_pcm_hw_add_new_,TYPE ) (as);if (hw) {return hw;
@@ -331,9 +333,11 @@ static SW *glue (audio_pcm_create_voice_pair_, TYPE) (SW *sw;HW *hw;struct audsettings hw_as; +AudioState *s = &glob_audio_state; +AudiodevPerDirectionOptions *pdo = s->dev->TYPE; -if (glue (conf.fixed_,TYPE ).enabled) { - hw_as =glue (conf.fixed_,TYPE ).settings; +if (pdo->fixed_settings) { + hw_as =audiodev_to_audsettings (pdo); }else { hw_as = *as;
@@ -398,6 +402,7 @@ SW *glue (AUD_open_, TYPE) ( ) {AudioState *s = &glob_audio_state; +AudiodevPerDirectionOptions *pdo = s->dev->TYPE;if (audio_bug (AUDIO_FUNC , !card || !name || !callback_fn || !as)) { dolog ("card=%p name=%p callback_fn=%p as=%p\n",
@@ -422,7 +427,7 @@ SW *glue (AUD_open_, TYPE) (return sw; } -if (!glue (conf.fixed_,TYPE ).enabled && sw) { +if (!pdo->fixed_settings && sw) {glue (AUD_close_,TYPE ) (card, sw); sw =NULL ; }
audio/coreaudio.c +11 -38
100 lines not on this page · raw message
audio/dsound_template.h +3 -3
@@ -167,17 +167,18 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,dsound *s = drv_opaque;WAVEFORMATEX wfx;struct audsettings obt_as; -DSoundConf *conf = &s->conf;#ifdef DSBTYPE_IN const char *typ ="ADC" ;DSoundVoiceIn *ds = (DSoundVoiceIn *) hw;DSCBUFFERDESC bd;DSCBCAPS bc; +AudiodevPerDirectionOptions *pdo = s->dev->in;#else const char *typ ="DAC" ;DSoundVoiceOut *ds = (DSoundVoiceOut *) hw;DSBUFFERDESC bd;DSBCAPS bc; +AudiodevPerDirectionOptions *pdo = s->dev->out;#endif if (!s->FIELD2) {
@@ -193,8 +194,8 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,memset (&bd,0 ,sizeof (bd)); bd.dwSize =sizeof (bd); bd.lpwfxFormat = &wfx; + bd.dwBufferBytes =audio_buffer_bytes (pdo, as,92880 );#ifdef DSBTYPE_IN - bd.dwBufferBytes = conf->bufsize_in; hr = IDirectSoundCapture_CreateCaptureBuffer ( s->dsound_capture, &bd,
@@ -203,7 +204,6 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as, );#else bd.dwFlags =DSBCAPS_STICKYFOCUS |DSBCAPS_GETCURRENTPOSITION2 ; - bd.dwBufferBytes = conf->bufsize_out; hr = IDirectSound_CreateSoundBuffer ( s->dsound, &bd,
audio/dsoundaudio.c +15 -41
112 lines not on this page · raw message
audio/noaudio.c +1 -2
@@ -134,7 +134,7 @@ static int no_ctl_in (HWVoiceIn *hw, int cmd, ...)return 0 ; } -static void *no_audio_init (void ) +static void *no_audio_init (Audiodev *dev) {return &no_audio_init; }
@@ -161,7 +161,6 @@ static struct audio_pcm_ops no_pcm_ops = {struct audio_driver no_audio_driver = { .name ="none" , .descr ="Timer based audio emulation" , - .options =NULL , .init = no_audio_init, .fini = no_audio_fini, .pcm_ops = &no_pcm_ops,
audio/ossaudio.c +44 -111
302 lines not on this page · raw message
audio/paaudio.c +29 -52
184 lines not on this page · raw message
audio/sdlaudio.c +5 -19
@@ -44,18 +44,13 @@ typedef struct SDLVoiceOut {int decr; } SDLVoiceOut; -static struct { -int nb_samples; -} conf = { - .nb_samples =1024 -}; -static struct SDLAudioState {int exit;SDL_mutex *mutex;SDL_sem *sem;int initialized;bool driver_created; +Audiodev *dev; } glob_sdl;typedef struct SDLAudioState SDLAudioState ;
@@ -347,7 +342,7 @@ static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as, req.freq = as->freq; req.format =aud_to_sdlfmt (as->fmt); req.channels = as->nchannels; - req.samples = conf.nb_samples; + req.samples =audio_buffer_samples (s->dev->out, as,11610 ); req.callback = sdl_callback; req.userdata = sdl;
@@ -391,7 +386,7 @@ static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...)return 0 ; } -static void *sdl_audio_init (void ) +static void *sdl_audio_init (Audiodev *dev) {SDLAudioState *s = &glob_sdl;if (s->driver_created) {
@@ -420,6 +415,7 @@ static void *sdl_audio_init (void) } s->driver_created = true; + s->dev = dev;return s; }
@@ -431,18 +427,9 @@ static void sdl_audio_fini (void *opaque)SDL_DestroyMutex (s->mutex);SDL_QuitSubSystem (SDL_INIT_AUDIO ); s->driver_created = false; + s->dev =NULL ; } -static struct audio_option sdl_options[] = { - { - .name ="SAMPLES" , - .tag =AUD_OPT_INT , - .valp = &conf.nb_samples, - .descr ="Size of SDL buffer in samples" - }, - {/* End of list */ } -}; -static struct audio_pcm_ops sdl_pcm_ops = { .init_out = sdl_init_out, .fini_out = sdl_fini_out,
@@ -454,7 +441,6 @@ static struct audio_pcm_ops sdl_pcm_ops = {struct audio_driver sdl_audio_driver = { .name ="sdl" , .descr ="SDL http://www.libsdl.org" , - .options = sdl_options, .init = sdl_audio_init, .fini = sdl_audio_fini, .pcm_ops = &sdl_pcm_ops,
audio/spiceaudio.c +1 -6
@@ -74,7 +74,7 @@ static const SpiceRecordInterface record_sif = { .base.minor_version = SPICE_INTERFACE_RECORD_MINOR, }; -static void *spice_audio_init (void ) +static void *spice_audio_init (Audiodev *dev) {if (!using_spice) {return NULL ;
@@ -370,10 +370,6 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...)return 0 ; } -static struct audio_option audio_options[] = { - {/* end of list */ }, -}; -static struct audio_pcm_ops audio_callbacks = { .init_out = line_out_init, .fini_out = line_out_fini,
@@ -391,7 +387,6 @@ static struct audio_pcm_ops audio_callbacks = {struct audio_driver spice_audio_driver = { .name ="spice" , .descr ="spice audio driver" , - .options = audio_options, .init = spice_audio_init, .fini = spice_audio_fini, .pcm_ops = &audio_callbacks,
audio/wavaudio.c +11 -50
107 lines not on this page · raw message
qemu-options.hx +215 -3
229 lines not on this page · raw message
vl.c +8 -1
@@ -2860,6 +2860,7 @@ int main(int argc, char **argv, char **envp)qemu_add_opts (&qemu_trace_opts);qemu_add_opts (&qemu_option_rom_opts);qemu_add_opts (&qemu_machine_opts); +qemu_add_opts (&qemu_audiodev_opts);qemu_add_opts (&qemu_mem_opts);qemu_add_opts (&qemu_smp_opts);qemu_add_opts (&qemu_boot_opts);
@@ -3157,9 +3158,14 @@ int main(int argc, char **argv, char **envp)add_device_config (DEV_BT , optarg);break ;case QEMU_OPTION_audio_help: -AUD_help (); +audio_legacy_help ();exit (0 );break ; +case QEMU_OPTION_audiodev: +if (!qemu_opts_parse (qemu_find_opts ("audiodev" ), optarg,1 )) { +exit (1 ); + } +break ;case QEMU_OPTION_soundhw:select_soundhw (optarg);break ;
@@ -4326,6 +4332,7 @@ int main(int argc, char **argv, char **envp)realtime_init (); +audio_set_options ();
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.4.2
Part of the diff is not shown here. View the raw message.
Hi,
Quoted 11 lines
This series of patches adds a new -audiodev command line option to specify audio subsytem parameters instead of environment variables. This will later allow us to specify multiple audio backends. The syntax is something like this:
-audiodev driver_name,property=value,...
like:
-audiodev alsa,frequency=8000,channels=1The first 6 commits are cleanup commits of the audio backends. The next commit adds a qapi Audiodev struct that describes the audio backend options. The next 4 commits are some miscellaneous additions that are needed by the last commit which finally adds the -audiodev option.
Fails to apply to latest & build on latest git master, due to some error handling changes by markus.
You can use 'git rebase' to rebase the patches to latest master, resolve conflicts and also edit patches to adapt them to the qemu_opts_foreach changes so they build again.
cheers,
Gerd