diff options
Diffstat (limited to 'qemu/audio')
-rw-r--r-- | qemu/audio/Makefile.objs | 13 | ||||
-rw-r--r-- | qemu/audio/alsaaudio.c | 1228 | ||||
-rw-r--r-- | qemu/audio/audio.c | 2057 | ||||
-rw-r--r-- | qemu/audio/audio.h | 165 | ||||
-rw-r--r-- | qemu/audio/audio_int.h | 260 | ||||
-rw-r--r-- | qemu/audio/audio_pt_int.c | 174 | ||||
-rw-r--r-- | qemu/audio/audio_pt_int.h | 22 | ||||
-rw-r--r-- | qemu/audio/audio_template.h | 514 | ||||
-rw-r--r-- | qemu/audio/audio_win_int.c | 108 | ||||
-rw-r--r-- | qemu/audio/audio_win_int.h | 10 | ||||
-rw-r--r-- | qemu/audio/coreaudio.c | 745 | ||||
-rw-r--r-- | qemu/audio/dsound_template.h | 278 | ||||
-rw-r--r-- | qemu/audio/dsoundaudio.c | 905 | ||||
-rw-r--r-- | qemu/audio/mixeng.c | 367 | ||||
-rw-r--r-- | qemu/audio/mixeng.h | 51 | ||||
-rw-r--r-- | qemu/audio/mixeng_template.h | 154 | ||||
-rw-r--r-- | qemu/audio/noaudio.c | 174 | ||||
-rw-r--r-- | qemu/audio/ossaudio.c | 940 | ||||
-rw-r--r-- | qemu/audio/paaudio.c | 954 | ||||
-rw-r--r-- | qemu/audio/rate_template.h | 111 | ||||
-rw-r--r-- | qemu/audio/sdlaudio.c | 467 | ||||
-rw-r--r-- | qemu/audio/spiceaudio.c | 412 | ||||
-rw-r--r-- | qemu/audio/wavaudio.c | 293 | ||||
-rw-r--r-- | qemu/audio/wavcapture.c | 195 |
24 files changed, 0 insertions, 10597 deletions
diff --git a/qemu/audio/Makefile.objs b/qemu/audio/Makefile.objs deleted file mode 100644 index 481d1aa30..000000000 --- a/qemu/audio/Makefile.objs +++ /dev/null @@ -1,13 +0,0 @@ -common-obj-y = audio.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 -common-obj-$(CONFIG_COREAUDIO) += coreaudio.o -common-obj-$(CONFIG_ALSA) += alsaaudio.o -common-obj-$(CONFIG_DSOUND) += dsoundaudio.o -common-obj-$(CONFIG_PA) += paaudio.o -common-obj-$(CONFIG_AUDIO_PT_INT) += audio_pt_int.o -common-obj-$(CONFIG_AUDIO_WIN_INT) += audio_win_int.o -common-obj-y += wavcapture.o - -sdlaudio.o-cflags := $(SDL_CFLAGS) diff --git a/qemu/audio/alsaaudio.c b/qemu/audio/alsaaudio.c deleted file mode 100644 index 3652a7b5f..000000000 --- a/qemu/audio/alsaaudio.c +++ /dev/null @@ -1,1228 +0,0 @@ -/* - * QEMU ALSA audio driver - * - * Copyright (c) 2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include <alsa/asoundlib.h> -#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" -#endif - -#define AUDIO_CAP "alsa" -#include "audio_int.h" - -typedef struct ALSAConf { - int size_in_usec_in; - int size_in_usec_out; - const char *pcm_name_in; - const char *pcm_name_out; - unsigned int buffer_size_in; - unsigned int period_size_in; - unsigned int buffer_size_out; - unsigned int period_size_out; - unsigned int threshold; - - int buffer_size_in_overridden; - int period_size_in_overridden; - - int buffer_size_out_overridden; - int period_size_out_overridden; -} ALSAConf; - -struct pollhlp { - snd_pcm_t *handle; - struct pollfd *pfds; - ALSAConf *conf; - int count; - int mask; -}; - -typedef struct ALSAVoiceOut { - HWVoiceOut hw; - int wpos; - int pending; - void *pcm_buf; - snd_pcm_t *handle; - struct pollhlp pollhlp; -} ALSAVoiceOut; - -typedef struct ALSAVoiceIn { - HWVoiceIn hw; - snd_pcm_t *handle; - void *pcm_buf; - struct pollhlp pollhlp; -} ALSAVoiceIn; - -struct alsa_params_req { - int freq; - snd_pcm_format_t fmt; - int nchannels; - int size_in_usec; - int override_mask; - unsigned int buffer_size; - unsigned int period_size; -}; - -struct alsa_params_obt { - int freq; - audfmt_e fmt; - int endianness; - int nchannels; - snd_pcm_uframes_t samples; -}; - -static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err)); -} - -static void GCC_FMT_ATTR (3, 4) alsa_logerr2 ( - int err, - const char *typ, - const char *fmt, - ... - ) -{ - va_list ap; - - AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - AUD_log (AUDIO_CAP, "Reason: %s\n", snd_strerror (err)); -} - -static void alsa_fini_poll (struct pollhlp *hlp) -{ - int i; - struct pollfd *pfds = hlp->pfds; - - if (pfds) { - for (i = 0; i < hlp->count; ++i) { - qemu_set_fd_handler (pfds[i].fd, NULL, NULL, NULL); - } - g_free (pfds); - } - hlp->pfds = NULL; - hlp->count = 0; - hlp->handle = NULL; -} - -static void alsa_anal_close1 (snd_pcm_t **handlep) -{ - int err = snd_pcm_close (*handlep); - if (err) { - alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep); - } - *handlep = NULL; -} - -static void alsa_anal_close (snd_pcm_t **handlep, struct pollhlp *hlp) -{ - alsa_fini_poll (hlp); - alsa_anal_close1 (handlep); -} - -static int alsa_recover (snd_pcm_t *handle) -{ - int err = snd_pcm_prepare (handle); - if (err < 0) { - alsa_logerr (err, "Failed to prepare handle %p\n", handle); - return -1; - } - return 0; -} - -static int alsa_resume (snd_pcm_t *handle) -{ - int err = snd_pcm_resume (handle); - if (err < 0) { - alsa_logerr (err, "Failed to resume handle %p\n", handle); - return -1; - } - return 0; -} - -static void alsa_poll_handler (void *opaque) -{ - int err, count; - snd_pcm_state_t state; - struct pollhlp *hlp = opaque; - unsigned short revents; - - count = poll (hlp->pfds, hlp->count, 0); - if (count < 0) { - dolog ("alsa_poll_handler: poll %s\n", strerror (errno)); - return; - } - - if (!count) { - return; - } - - /* XXX: ALSA example uses initial count, not the one returned by - poll, correct? */ - err = snd_pcm_poll_descriptors_revents (hlp->handle, hlp->pfds, - hlp->count, &revents); - if (err < 0) { - alsa_logerr (err, "snd_pcm_poll_descriptors_revents"); - return; - } - - if (!(revents & hlp->mask)) { - trace_alsa_revents(revents); - return; - } - - state = snd_pcm_state (hlp->handle); - switch (state) { - case SND_PCM_STATE_SETUP: - alsa_recover (hlp->handle); - break; - - case SND_PCM_STATE_XRUN: - alsa_recover (hlp->handle); - break; - - case SND_PCM_STATE_SUSPENDED: - alsa_resume (hlp->handle); - break; - - case SND_PCM_STATE_PREPARED: - audio_run ("alsa run (prepared)"); - break; - - case SND_PCM_STATE_RUNNING: - audio_run ("alsa run (running)"); - break; - - default: - dolog ("Unexpected state %d\n", state); - } -} - -static int alsa_poll_helper (snd_pcm_t *handle, struct pollhlp *hlp, int mask) -{ - int i, count, err; - struct pollfd *pfds; - - count = snd_pcm_poll_descriptors_count (handle); - if (count <= 0) { - dolog ("Could not initialize poll mode\n" - "Invalid number of poll descriptors %d\n", count); - return -1; - } - - pfds = audio_calloc ("alsa_poll_helper", count, sizeof (*pfds)); - if (!pfds) { - dolog ("Could not initialize poll mode\n"); - return -1; - } - - err = snd_pcm_poll_descriptors (handle, pfds, count); - if (err < 0) { - alsa_logerr (err, "Could not initialize poll mode\n" - "Could not obtain poll descriptors\n"); - g_free (pfds); - return -1; - } - - for (i = 0; i < count; ++i) { - if (pfds[i].events & POLLIN) { - qemu_set_fd_handler (pfds[i].fd, alsa_poll_handler, NULL, hlp); - } - if (pfds[i].events & POLLOUT) { - trace_alsa_pollout(i, pfds[i].fd); - qemu_set_fd_handler (pfds[i].fd, NULL, alsa_poll_handler, hlp); - } - trace_alsa_set_handler(pfds[i].events, i, pfds[i].fd, err); - - } - hlp->pfds = pfds; - hlp->count = count; - hlp->handle = handle; - hlp->mask = mask; - return 0; -} - -static int alsa_poll_out (HWVoiceOut *hw) -{ - ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; - - return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLOUT); -} - -static int alsa_poll_in (HWVoiceIn *hw) -{ - ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; - - return alsa_poll_helper (alsa->handle, &alsa->pollhlp, POLLIN); -} - -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) -{ - switch (fmt) { - case AUD_FMT_S8: - return SND_PCM_FORMAT_S8; - - case AUD_FMT_U8: - return SND_PCM_FORMAT_U8; - - case AUD_FMT_S16: - if (endianness) { - return SND_PCM_FORMAT_S16_BE; - } - else { - return SND_PCM_FORMAT_S16_LE; - } - - case AUD_FMT_U16: - if (endianness) { - return SND_PCM_FORMAT_U16_BE; - } - else { - return SND_PCM_FORMAT_U16_LE; - } - - case AUD_FMT_S32: - if (endianness) { - return SND_PCM_FORMAT_S32_BE; - } - else { - return SND_PCM_FORMAT_S32_LE; - } - - case AUD_FMT_U32: - if (endianness) { - return SND_PCM_FORMAT_U32_BE; - } - else { - return SND_PCM_FORMAT_U32_LE; - } - - default: - dolog ("Internal logic error: Bad audio format %d\n", fmt); -#ifdef DEBUG_AUDIO - abort (); -#endif - return SND_PCM_FORMAT_U8; - } -} - -static int alsa_to_audfmt (snd_pcm_format_t alsafmt, audfmt_e *fmt, - int *endianness) -{ - switch (alsafmt) { - case SND_PCM_FORMAT_S8: - *endianness = 0; - *fmt = AUD_FMT_S8; - break; - - case SND_PCM_FORMAT_U8: - *endianness = 0; - *fmt = AUD_FMT_U8; - break; - - case SND_PCM_FORMAT_S16_LE: - *endianness = 0; - *fmt = AUD_FMT_S16; - break; - - case SND_PCM_FORMAT_U16_LE: - *endianness = 0; - *fmt = AUD_FMT_U16; - break; - - case SND_PCM_FORMAT_S16_BE: - *endianness = 1; - *fmt = AUD_FMT_S16; - break; - - case SND_PCM_FORMAT_U16_BE: - *endianness = 1; - *fmt = AUD_FMT_U16; - break; - - case SND_PCM_FORMAT_S32_LE: - *endianness = 0; - *fmt = AUD_FMT_S32; - break; - - case SND_PCM_FORMAT_U32_LE: - *endianness = 0; - *fmt = AUD_FMT_U32; - break; - - case SND_PCM_FORMAT_S32_BE: - *endianness = 1; - *fmt = AUD_FMT_S32; - break; - - case SND_PCM_FORMAT_U32_BE: - *endianness = 1; - *fmt = AUD_FMT_U32; - break; - - default: - dolog ("Unrecognized audio format %d\n", alsafmt); - return -1; - } - - return 0; -} - -static void alsa_dump_info (struct alsa_params_req *req, - struct alsa_params_obt *obt, - snd_pcm_format_t obtfmt) -{ - dolog ("parameter | requested value | obtained value\n"); - dolog ("format | %10d | %10d\n", req->fmt, obtfmt); - dolog ("channels | %10d | %10d\n", - req->nchannels, obt->nchannels); - dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); - dolog ("============================================\n"); - dolog ("requested: buffer size %d period size %d\n", - req->buffer_size, req->period_size); - dolog ("obtained: samples %ld\n", obt->samples); -} - -static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold) -{ - int err; - snd_pcm_sw_params_t *sw_params; - - snd_pcm_sw_params_alloca (&sw_params); - - err = snd_pcm_sw_params_current (handle, sw_params); - if (err < 0) { - dolog ("Could not fully initialize DAC\n"); - alsa_logerr (err, "Failed to get current software parameters\n"); - return; - } - - err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold); - if (err < 0) { - dolog ("Could not fully initialize DAC\n"); - alsa_logerr (err, "Failed to set software threshold to %ld\n", - threshold); - return; - } - - err = snd_pcm_sw_params (handle, sw_params); - if (err < 0) { - dolog ("Could not fully initialize DAC\n"); - alsa_logerr (err, "Failed to set software parameters\n"); - return; - } -} - -static int alsa_open (int in, struct alsa_params_req *req, - struct alsa_params_obt *obt, snd_pcm_t **handlep, - ALSAConf *conf) -{ - snd_pcm_t *handle; - snd_pcm_hw_params_t *hw_params; - int err; - int size_in_usec; - unsigned int freq, nchannels; - const char *pcm_name = in ? conf->pcm_name_in : conf->pcm_name_out; - snd_pcm_uframes_t obt_buffer_size; - const char *typ = in ? "ADC" : "DAC"; - snd_pcm_format_t obtfmt; - - freq = req->freq; - nchannels = req->nchannels; - size_in_usec = req->size_in_usec; - - snd_pcm_hw_params_alloca (&hw_params); - - err = snd_pcm_open ( - &handle, - pcm_name, - in ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, - SND_PCM_NONBLOCK - ); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to open `%s':\n", pcm_name); - return -1; - } - - err = snd_pcm_hw_params_any (handle, hw_params); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n"); - goto err; - } - - err = snd_pcm_hw_params_set_access ( - handle, - hw_params, - SND_PCM_ACCESS_RW_INTERLEAVED - ); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to set access type\n"); - goto err; - } - - err = snd_pcm_hw_params_set_format (handle, hw_params, req->fmt); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt); - } - - err = snd_pcm_hw_params_set_rate_near (handle, hw_params, &freq, 0); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to set frequency %d\n", req->freq); - goto err; - } - - err = snd_pcm_hw_params_set_channels_near ( - handle, - hw_params, - &nchannels - ); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to set number of channels %d\n", - req->nchannels); - goto err; - } - - if (nchannels != 1 && nchannels != 2) { - alsa_logerr2 (err, typ, - "Can not handle obtained number of channels %d\n", - nchannels); - goto err; - } - - if (req->buffer_size) { - unsigned long obt; - - if (size_in_usec) { - int dir = 0; - unsigned int btime = req->buffer_size; - - err = snd_pcm_hw_params_set_buffer_time_near ( - handle, - hw_params, - &btime, - &dir - ); - obt = btime; - } - else { - snd_pcm_uframes_t bsize = req->buffer_size; - - err = snd_pcm_hw_params_set_buffer_size_near ( - handle, - hw_params, - &bsize - ); - obt = bsize; - } - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to set buffer %s to %d\n", - size_in_usec ? "time" : "size", req->buffer_size); - goto err; - } - - if ((req->override_mask & 2) && (obt - req->buffer_size)) - dolog ("Requested buffer %s %u was rejected, using %lu\n", - size_in_usec ? "time" : "size", req->buffer_size, obt); - } - - if (req->period_size) { - unsigned long obt; - - if (size_in_usec) { - int dir = 0; - unsigned int ptime = req->period_size; - - err = snd_pcm_hw_params_set_period_time_near ( - handle, - hw_params, - &ptime, - &dir - ); - obt = ptime; - } - else { - int dir = 0; - snd_pcm_uframes_t psize = req->period_size; - - err = snd_pcm_hw_params_set_period_size_near ( - handle, - hw_params, - &psize, - &dir - ); - obt = psize; - } - - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to set period %s to %d\n", - size_in_usec ? "time" : "size", req->period_size); - goto err; - } - - if (((req->override_mask & 1) && (obt - req->period_size))) - dolog ("Requested period %s %u was rejected, using %lu\n", - size_in_usec ? "time" : "size", req->period_size, obt); - } - - err = snd_pcm_hw_params (handle, hw_params); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to apply audio parameters\n"); - goto err; - } - - err = snd_pcm_hw_params_get_buffer_size (hw_params, &obt_buffer_size); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to get buffer size\n"); - goto err; - } - - err = snd_pcm_hw_params_get_format (hw_params, &obtfmt); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to get format\n"); - goto err; - } - - if (alsa_to_audfmt (obtfmt, &obt->fmt, &obt->endianness)) { - dolog ("Invalid format was returned %d\n", obtfmt); - goto err; - } - - err = snd_pcm_prepare (handle); - if (err < 0) { - alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle); - goto err; - } - - if (!in && conf->threshold) { - snd_pcm_uframes_t threshold; - int bytes_per_sec; - - bytes_per_sec = freq << (nchannels == 2); - - switch (obt->fmt) { - case AUD_FMT_S8: - case AUD_FMT_U8: - break; - - case AUD_FMT_S16: - case AUD_FMT_U16: - bytes_per_sec <<= 1; - break; - - case AUD_FMT_S32: - case AUD_FMT_U32: - bytes_per_sec <<= 2; - break; - } - - threshold = (conf->threshold * bytes_per_sec) / 1000; - alsa_set_threshold (handle, threshold); - } - - obt->nchannels = nchannels; - obt->freq = freq; - obt->samples = obt_buffer_size; - - *handlep = handle; - - if (obtfmt != req->fmt || - obt->nchannels != req->nchannels || - obt->freq != req->freq) { - dolog ("Audio parameters for %s\n", typ); - alsa_dump_info (req, obt, obtfmt); - } - -#ifdef DEBUG - alsa_dump_info (req, obt, obtfmt); -#endif - return 0; - - err: - alsa_anal_close1 (&handle); - return -1; -} - -static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle) -{ - snd_pcm_sframes_t avail; - - avail = snd_pcm_avail_update (handle); - if (avail < 0) { - if (avail == -EPIPE) { - if (!alsa_recover (handle)) { - avail = snd_pcm_avail_update (handle); - } - } - - if (avail < 0) { - alsa_logerr (avail, - "Could not obtain number of available frames\n"); - return -1; - } - } - - return avail; -} - -static void alsa_write_pending (ALSAVoiceOut *alsa) -{ - HWVoiceOut *hw = &alsa->hw; - - while (alsa->pending) { - int left_till_end_samples = hw->samples - alsa->wpos; - int len = audio_MIN (alsa->pending, left_till_end_samples); - char *src = advance (alsa->pcm_buf, alsa->wpos << hw->info.shift); - - while (len) { - snd_pcm_sframes_t written; - - written = snd_pcm_writei (alsa->handle, src, len); - - if (written <= 0) { - switch (written) { - case 0: - trace_alsa_wrote_zero(len); - return; - - case -EPIPE: - if (alsa_recover (alsa->handle)) { - alsa_logerr (written, "Failed to write %d frames\n", - len); - return; - } - trace_alsa_xrun_out(); - continue; - - case -ESTRPIPE: - /* stream is suspended and waiting for an - application recovery */ - if (alsa_resume (alsa->handle)) { - alsa_logerr (written, "Failed to write %d frames\n", - len); - return; - } - trace_alsa_resume_out(); - continue; - - case -EAGAIN: - return; - - default: - alsa_logerr (written, "Failed to write %d frames from %p\n", - len, src); - return; - } - } - - alsa->wpos = (alsa->wpos + written) % hw->samples; - alsa->pending -= written; - len -= written; - } - } -} - -static int alsa_run_out (HWVoiceOut *hw, int live) -{ - ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; - int decr; - snd_pcm_sframes_t avail; - - avail = alsa_get_avail (alsa->handle); - if (avail < 0) { - dolog ("Could not get number of available playback frames\n"); - return 0; - } - - decr = audio_MIN (live, avail); - decr = audio_pcm_hw_clip_out (hw, alsa->pcm_buf, decr, alsa->pending); - alsa->pending += decr; - alsa_write_pending (alsa); - return decr; -} - -static void alsa_fini_out (HWVoiceOut *hw) -{ - ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; - - ldebug ("alsa_fini\n"); - alsa_anal_close (&alsa->handle, &alsa->pollhlp); - - g_free(alsa->pcm_buf); - alsa->pcm_buf = NULL; -} - -static int alsa_init_out(HWVoiceOut *hw, struct audsettings *as, - void *drv_opaque) -{ - ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; - struct alsa_params_req req; - struct alsa_params_obt obt; - snd_pcm_t *handle; - struct audsettings obt_as; - ALSAConf *conf = drv_opaque; - - req.fmt = aud_to_alsafmt (as->fmt, as->endianness); - req.freq = as->freq; - req.nchannels = as->nchannels; - req.period_size = conf->period_size_out; - req.buffer_size = conf->buffer_size_out; - req.size_in_usec = conf->size_in_usec_out; - req.override_mask = - (conf->period_size_out_overridden ? 1 : 0) | - (conf->buffer_size_out_overridden ? 2 : 0); - - if (alsa_open (0, &req, &obt, &handle, conf)) { - return -1; - } - - obt_as.freq = obt.freq; - obt_as.nchannels = obt.nchannels; - obt_as.fmt = obt.fmt; - obt_as.endianness = obt.endianness; - - audio_pcm_init_info (&hw->info, &obt_as); - hw->samples = obt.samples; - - alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift); - if (!alsa->pcm_buf) { - dolog ("Could not allocate DAC buffer (%d samples, each %d bytes)\n", - hw->samples, 1 << hw->info.shift); - alsa_anal_close1 (&handle); - return -1; - } - - alsa->handle = handle; - alsa->pollhlp.conf = conf; - return 0; -} - -#define VOICE_CTL_PAUSE 0 -#define VOICE_CTL_PREPARE 1 -#define VOICE_CTL_START 2 - -static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int ctl) -{ - int err; - - if (ctl == VOICE_CTL_PAUSE) { - err = snd_pcm_drop (handle); - if (err < 0) { - alsa_logerr (err, "Could not stop %s\n", typ); - return -1; - } - } - else { - err = snd_pcm_prepare (handle); - if (err < 0) { - alsa_logerr (err, "Could not prepare handle for %s\n", typ); - return -1; - } - if (ctl == VOICE_CTL_START) { - err = snd_pcm_start(handle); - if (err < 0) { - alsa_logerr (err, "Could not start handle for %s\n", typ); - return -1; - } - } - } - - return 0; -} - -static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; - - switch (cmd) { - case VOICE_ENABLE: - { - va_list ap; - int poll_mode; - - va_start (ap, cmd); - poll_mode = va_arg (ap, int); - va_end (ap); - - ldebug ("enabling voice\n"); - if (poll_mode && alsa_poll_out (hw)) { - poll_mode = 0; - } - hw->poll_mode = poll_mode; - return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PREPARE); - } - - case VOICE_DISABLE: - ldebug ("disabling voice\n"); - if (hw->poll_mode) { - hw->poll_mode = 0; - alsa_fini_poll (&alsa->pollhlp); - } - return alsa_voice_ctl (alsa->handle, "playback", VOICE_CTL_PAUSE); - } - - return -1; -} - -static int alsa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) -{ - ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; - struct alsa_params_req req; - struct alsa_params_obt obt; - snd_pcm_t *handle; - struct audsettings obt_as; - ALSAConf *conf = drv_opaque; - - req.fmt = aud_to_alsafmt (as->fmt, as->endianness); - req.freq = as->freq; - req.nchannels = as->nchannels; - req.period_size = conf->period_size_in; - req.buffer_size = conf->buffer_size_in; - req.size_in_usec = conf->size_in_usec_in; - req.override_mask = - (conf->period_size_in_overridden ? 1 : 0) | - (conf->buffer_size_in_overridden ? 2 : 0); - - if (alsa_open (1, &req, &obt, &handle, conf)) { - return -1; - } - - obt_as.freq = obt.freq; - obt_as.nchannels = obt.nchannels; - obt_as.fmt = obt.fmt; - obt_as.endianness = obt.endianness; - - audio_pcm_init_info (&hw->info, &obt_as); - hw->samples = obt.samples; - - alsa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - if (!alsa->pcm_buf) { - dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", - hw->samples, 1 << hw->info.shift); - alsa_anal_close1 (&handle); - return -1; - } - - alsa->handle = handle; - alsa->pollhlp.conf = conf; - return 0; -} - -static void alsa_fini_in (HWVoiceIn *hw) -{ - ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; - - alsa_anal_close (&alsa->handle, &alsa->pollhlp); - - g_free(alsa->pcm_buf); - alsa->pcm_buf = NULL; -} - -static int alsa_run_in (HWVoiceIn *hw) -{ - ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; - int hwshift = hw->info.shift; - int i; - int live = audio_pcm_hw_get_live_in (hw); - int dead = hw->samples - live; - int decr; - struct { - int add; - int len; - } bufs[2] = { - { .add = hw->wpos, .len = 0 }, - { .add = 0, .len = 0 } - }; - snd_pcm_sframes_t avail; - snd_pcm_uframes_t read_samples = 0; - - if (!dead) { - return 0; - } - - avail = alsa_get_avail (alsa->handle); - if (avail < 0) { - dolog ("Could not get number of captured frames\n"); - return 0; - } - - if (!avail) { - snd_pcm_state_t state; - - state = snd_pcm_state (alsa->handle); - switch (state) { - case SND_PCM_STATE_PREPARED: - avail = hw->samples; - break; - case SND_PCM_STATE_SUSPENDED: - /* stream is suspended and waiting for an application recovery */ - if (alsa_resume (alsa->handle)) { - dolog ("Failed to resume suspended input stream\n"); - return 0; - } - trace_alsa_resume_in(); - break; - default: - trace_alsa_no_frames(state); - return 0; - } - } - - decr = audio_MIN (dead, avail); - if (!decr) { - return 0; - } - - if (hw->wpos + decr > hw->samples) { - bufs[0].len = (hw->samples - hw->wpos); - bufs[1].len = (decr - (hw->samples - hw->wpos)); - } - else { - bufs[0].len = decr; - } - - for (i = 0; i < 2; ++i) { - void *src; - struct st_sample *dst; - snd_pcm_sframes_t nread; - snd_pcm_uframes_t len; - - len = bufs[i].len; - - src = advance (alsa->pcm_buf, bufs[i].add << hwshift); - dst = hw->conv_buf + bufs[i].add; - - while (len) { - nread = snd_pcm_readi (alsa->handle, src, len); - - if (nread <= 0) { - switch (nread) { - case 0: - trace_alsa_read_zero(len); - goto exit; - - case -EPIPE: - if (alsa_recover (alsa->handle)) { - alsa_logerr (nread, "Failed to read %ld frames\n", len); - goto exit; - } - trace_alsa_xrun_in(); - continue; - - case -EAGAIN: - goto exit; - - default: - alsa_logerr ( - nread, - "Failed to read %ld frames from %p\n", - len, - src - ); - goto exit; - } - } - - hw->conv (dst, src, nread); - - src = advance (src, nread << hwshift); - dst += nread; - - read_samples += nread; - len -= nread; - } - } - - exit: - hw->wpos = (hw->wpos + read_samples) % hw->samples; - return read_samples; -} - -static int alsa_read (SWVoiceIn *sw, void *buf, int size) -{ - return audio_pcm_sw_read (sw, buf, size); -} - -static int alsa_ctl_in (HWVoiceIn *hw, int cmd, ...) -{ - ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; - - switch (cmd) { - case VOICE_ENABLE: - { - va_list ap; - int poll_mode; - - va_start (ap, cmd); - poll_mode = va_arg (ap, int); - va_end (ap); - - ldebug ("enabling voice\n"); - if (poll_mode && alsa_poll_in (hw)) { - poll_mode = 0; - } - hw->poll_mode = poll_mode; - - return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_START); - } - - case VOICE_DISABLE: - ldebug ("disabling voice\n"); - if (hw->poll_mode) { - hw->poll_mode = 0; - alsa_fini_poll (&alsa->pollhlp); - } - return alsa_voice_ctl (alsa->handle, "capture", VOICE_CTL_PAUSE); - } - - return -1; -} - -static ALSAConf glob_conf = { - .buffer_size_out = 4096, - .period_size_out = 1024, - .pcm_name_out = "default", - .pcm_name_in = "default", -}; - -static void *alsa_audio_init (void) -{ - ALSAConf *conf = g_malloc(sizeof(ALSAConf)); - *conf = glob_conf; - return conf; -} - -static void alsa_audio_fini (void *opaque) -{ - g_free(opaque); -} - -static struct audio_option alsa_options[] = { - { - .name = "DAC_SIZE_IN_USEC", - .tag = AUD_OPT_BOOL, - .valp = &glob_conf.size_in_usec_out, - .descr = "DAC period/buffer size in microseconds (otherwise in frames)" - }, - { - .name = "DAC_PERIOD_SIZE", - .tag = AUD_OPT_INT, - .valp = &glob_conf.period_size_out, - .descr = "DAC period size (0 to go with system default)", - .overriddenp = &glob_conf.period_size_out_overridden - }, - { - .name = "DAC_BUFFER_SIZE", - .tag = AUD_OPT_INT, - .valp = &glob_conf.buffer_size_out, - .descr = "DAC buffer size (0 to go with system default)", - .overriddenp = &glob_conf.buffer_size_out_overridden - }, - { - .name = "ADC_SIZE_IN_USEC", - .tag = AUD_OPT_BOOL, - .valp = &glob_conf.size_in_usec_in, - .descr = - "ADC period/buffer size in microseconds (otherwise in frames)" - }, - { - .name = "ADC_PERIOD_SIZE", - .tag = AUD_OPT_INT, - .valp = &glob_conf.period_size_in, - .descr = "ADC period size (0 to go with system default)", - .overriddenp = &glob_conf.period_size_in_overridden - }, - { - .name = "ADC_BUFFER_SIZE", - .tag = AUD_OPT_INT, - .valp = &glob_conf.buffer_size_in, - .descr = "ADC buffer size (0 to go with system default)", - .overriddenp = &glob_conf.buffer_size_in_overridden - }, - { - .name = "THRESHOLD", - .tag = AUD_OPT_INT, - .valp = &glob_conf.threshold, - .descr = "(undocumented)" - }, - { - .name = "DAC_DEV", - .tag = AUD_OPT_STR, - .valp = &glob_conf.pcm_name_out, - .descr = "DAC device name (for instance dmix)" - }, - { - .name = "ADC_DEV", - .tag = AUD_OPT_STR, - .valp = &glob_conf.pcm_name_in, - .descr = "ADC device name" - }, - { /* End of list */ } -}; - -static struct audio_pcm_ops alsa_pcm_ops = { - .init_out = alsa_init_out, - .fini_out = alsa_fini_out, - .run_out = alsa_run_out, - .write = alsa_write, - .ctl_out = alsa_ctl_out, - - .init_in = alsa_init_in, - .fini_in = alsa_fini_in, - .run_in = alsa_run_in, - .read = alsa_read, - .ctl_in = alsa_ctl_in, -}; - -struct audio_driver alsa_audio_driver = { - .name = "alsa", - .descr = "ALSA http://www.alsa-project.org", - .options = alsa_options, - .init = alsa_audio_init, - .fini = alsa_audio_fini, - .pcm_ops = &alsa_pcm_ops, - .can_be_default = 1, - .max_voices_out = INT_MAX, - .max_voices_in = INT_MAX, - .voice_size_out = sizeof (ALSAVoiceOut), - .voice_size_in = sizeof (ALSAVoiceIn) -}; diff --git a/qemu/audio/audio.c b/qemu/audio/audio.c deleted file mode 100644 index e60c124de..000000000 --- a/qemu/audio/audio.c +++ /dev/null @@ -1,2057 +0,0 @@ -/* - * QEMU Audio subsystem - * - * Copyright (c) 2003-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "audio.h" -#include "monitor/monitor.h" -#include "qemu/timer.h" -#include "sysemu/sysemu.h" -#include "qemu/cutils.h" - -#define AUDIO_CAP "audio" -#include "audio_int.h" - -/* #define DEBUG_LIVE */ -/* #define DEBUG_OUT */ -/* #define DEBUG_CAPTURE */ -/* #define DEBUG_POLL */ - -#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown" - - -/* Order of CONFIG_AUDIO_DRIVERS is import. - The 1st one is the one used by default, that is the reason - that we generate the list. -*/ -static struct audio_driver *drvtab[] = { -#ifdef CONFIG_SPICE - &spice_audio_driver, -#endif - CONFIG_AUDIO_DRIVERS - &no_audio_driver, - &wav_audio_driver -}; - -struct fixed_settings { - int enabled; - int nb_voices; - int greedy; - struct audsettings settings; -}; - -static struct { - struct fixed_settings fixed_out; - struct fixed_settings fixed_in; - union { - int hertz; - int64_t ticks; - } period; - int try_poll_in; - int try_poll_out; -} conf = { - .fixed_out = { /* DAC fixed settings */ - .enabled = 1, - .nb_voices = 1, - .greedy = 1, - .settings = { - .freq = 44100, - .nchannels = 2, - .fmt = AUD_FMT_S16, - .endianness = AUDIO_HOST_ENDIANNESS, - } - }, - - .fixed_in = { /* ADC fixed settings */ - .enabled = 1, - .nb_voices = 1, - .greedy = 1, - .settings = { - .freq = 44100, - .nchannels = 2, - .fmt = AUD_FMT_S16, - .endianness = AUDIO_HOST_ENDIANNESS, - } - }, - - .period = { .hertz = 100 }, - .try_poll_in = 1, - .try_poll_out = 1, -}; - -static AudioState glob_audio_state; - -const struct mixeng_volume nominal_volume = { - .mute = 0, -#ifdef FLOAT_MIXENG - .r = 1.0, - .l = 1.0, -#else - .r = 1ULL << 32, - .l = 1ULL << 32, -#endif -}; - -#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED -#error No its not -#else -static void audio_print_options (const char *prefix, - struct audio_option *opt); - -int audio_bug (const char *funcname, int cond) -{ - if (cond) { - static int shown; - - AUD_log (NULL, "A bug was just triggered in %s\n", funcname); - if (!shown) { - struct audio_driver *d; - - shown = 1; - AUD_log (NULL, "Save all your work and restart without audio\n"); - AUD_log (NULL, "Please send bug report to av1474@comtv.ru\n"); - AUD_log (NULL, "I am sorry\n"); - d = glob_audio_state.drv; - if (d) { - audio_print_options (d->name, d->options); - } - } - AUD_log (NULL, "Context:\n"); - -#if defined AUDIO_BREAKPOINT_ON_BUG -# if defined HOST_I386 -# if defined __GNUC__ - __asm__ ("int3"); -# elif defined _MSC_VER - _asm _emit 0xcc; -# else - abort (); -# endif -# else - abort (); -# endif -#endif - } - - return cond; -} -#endif - -static inline int audio_bits_to_index (int bits) -{ - switch (bits) { - case 8: - return 0; - - case 16: - return 1; - - case 32: - return 2; - - default: - audio_bug ("bits_to_index", 1); - AUD_log (NULL, "invalid bits %d\n", bits); - return 0; - } -} - -void *audio_calloc (const char *funcname, int nmemb, size_t size) -{ - int cond; - size_t len; - - len = nmemb * size; - cond = !nmemb || !size; - cond |= nmemb < 0; - cond |= len < size; - - if (audio_bug ("audio_calloc", cond)) { - AUD_log (NULL, "%s passed invalid arguments to audio_calloc\n", - funcname); - AUD_log (NULL, "nmemb=%d size=%zu (len=%zu)\n", nmemb, size, len); - return NULL; - } - - return g_malloc0 (len); -} - -static char *audio_alloc_prefix (const char *s) -{ - const char qemu_prefix[] = "QEMU_"; - size_t len, i; - char *r, *u; - - if (!s) { - return NULL; - } - - len = strlen (s); - r = g_malloc (len + sizeof (qemu_prefix)); - - u = r + sizeof (qemu_prefix) - 1; - - pstrcpy (r, len + sizeof (qemu_prefix), qemu_prefix); - pstrcat (r, len + sizeof (qemu_prefix), s); - - for (i = 0; i < len; ++i) { - u[i] = qemu_toupper(u[i]); - } - - return r; -} - -static const char *audio_audfmt_to_string (audfmt_e fmt) -{ - switch (fmt) { - case AUD_FMT_U8: - return "U8"; - - case AUD_FMT_U16: - return "U16"; - - case AUD_FMT_S8: - return "S8"; - - case AUD_FMT_S16: - return "S16"; - - case AUD_FMT_U32: - return "U32"; - - case AUD_FMT_S32: - return "S32"; - } - - dolog ("Bogus audfmt %d returning S16\n", fmt); - return "S16"; -} - -static audfmt_e audio_string_to_audfmt (const char *s, audfmt_e defval, - int *defaultp) -{ - if (!strcasecmp (s, "u8")) { - *defaultp = 0; - return AUD_FMT_U8; - } - else if (!strcasecmp (s, "u16")) { - *defaultp = 0; - return AUD_FMT_U16; - } - else if (!strcasecmp (s, "u32")) { - *defaultp = 0; - return AUD_FMT_U32; - } - else if (!strcasecmp (s, "s8")) { - *defaultp = 0; - return AUD_FMT_S8; - } - else if (!strcasecmp (s, "s16")) { - *defaultp = 0; - return AUD_FMT_S16; - } - else if (!strcasecmp (s, "s32")) { - *defaultp = 0; - return AUD_FMT_S32; - } - else { - dolog ("Bogus audio format `%s' using %s\n", - s, audio_audfmt_to_string (defval)); - *defaultp = 1; - return defval; - } -} - -static audfmt_e audio_get_conf_fmt (const char *envname, - audfmt_e defval, - int *defaultp) -{ - const char *var = getenv (envname); - if (!var) { - *defaultp = 1; - return defval; - } - return audio_string_to_audfmt (var, defval, defaultp); -} - -static int audio_get_conf_int (const char *key, int defval, int *defaultp) -{ - int val; - char *strval; - - strval = getenv (key); - if (strval) { - *defaultp = 0; - val = atoi (strval); - return val; - } - else { - *defaultp = 1; - return defval; - } -} - -static const char *audio_get_conf_str (const char *key, - const char *defval, - int *defaultp) -{ - const char *val = getenv (key); - if (!val) { - *defaultp = 1; - return defval; - } - else { - *defaultp = 0; - return val; - } -} - -void AUD_vlog (const char *cap, const char *fmt, va_list ap) -{ - if (cap) { - fprintf(stderr, "%s: ", cap); - } - - vfprintf(stderr, fmt, ap); -} - -void AUD_log (const char *cap, const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (cap, fmt, ap); - va_end (ap); -} - -static void audio_print_options (const char *prefix, - struct audio_option *opt) -{ - char *uprefix; - - if (!prefix) { - dolog ("No prefix specified\n"); - return; - } - - if (!opt) { - dolog ("No options\n"); - return; - } - - uprefix = audio_alloc_prefix (prefix); - - for (; opt->name; opt++) { - const char *state = "default"; - printf (" %s_%s: ", uprefix, opt->name); - - if (opt->overriddenp && *opt->overriddenp) { - state = "current"; - } - - switch (opt->tag) { - case AUD_OPT_BOOL: - { - int *intp = opt->valp; - printf ("boolean, %s = %d\n", state, *intp ? 1 : 0); - } - break; - - case AUD_OPT_INT: - { - int *intp = opt->valp; - printf ("integer, %s = %d\n", state, *intp); - } - break; - - case AUD_OPT_FMT: - { - audfmt_e *fmtp = opt->valp; - printf ( - "format, %s = %s, (one of: U8 S8 U16 S16 U32 S32)\n", - state, - audio_audfmt_to_string (*fmtp) - ); - } - break; - - case AUD_OPT_STR: - { - const char **strp = opt->valp; - printf ("string, %s = %s\n", - state, - *strp ? *strp : "(not set)"); - } - break; - - default: - printf ("???\n"); - dolog ("Bad value tag for option %s_%s %d\n", - uprefix, opt->name, opt->tag); - break; - } - printf (" %s\n", opt->descr); - } - - g_free (uprefix); -} - -static void audio_process_options (const char *prefix, - struct audio_option *opt) -{ - char *optname; - const char qemu_prefix[] = "QEMU_"; - size_t preflen, optlen; - - if (audio_bug (AUDIO_FUNC, !prefix)) { - dolog ("prefix = NULL\n"); - return; - } - - if (audio_bug (AUDIO_FUNC, !opt)) { - dolog ("opt = NULL\n"); - return; - } - - preflen = strlen (prefix); - - for (; opt->name; opt++) { - size_t len, i; - int def; - - if (!opt->valp) { - dolog ("Option value pointer for `%s' is not set\n", - opt->name); - continue; - } - - len = strlen (opt->name); - /* len of opt->name + len of prefix + size of qemu_prefix - * (includes trailing zero) + zero + underscore (on behalf of - * sizeof) */ - optlen = len + preflen + sizeof (qemu_prefix) + 1; - optname = g_malloc (optlen); - - pstrcpy (optname, optlen, qemu_prefix); - - /* copy while upper-casing, including trailing zero */ - for (i = 0; i <= preflen; ++i) { - optname[i + sizeof (qemu_prefix) - 1] = qemu_toupper(prefix[i]); - } - pstrcat (optname, optlen, "_"); - pstrcat (optname, optlen, opt->name); - - def = 1; - switch (opt->tag) { - case AUD_OPT_BOOL: - case AUD_OPT_INT: - { - int *intp = opt->valp; - *intp = audio_get_conf_int (optname, *intp, &def); - } - break; - - case AUD_OPT_FMT: - { - audfmt_e *fmtp = opt->valp; - *fmtp = audio_get_conf_fmt (optname, *fmtp, &def); - } - break; - - case AUD_OPT_STR: - { - const char **strp = opt->valp; - *strp = audio_get_conf_str (optname, *strp, &def); - } - break; - - default: - dolog ("Bad value tag for option `%s' - %d\n", - optname, opt->tag); - break; - } - - if (!opt->overriddenp) { - opt->overriddenp = &opt->overridden; - } - *opt->overriddenp = !def; - g_free (optname); - } -} - -static void audio_print_settings (struct audsettings *as) -{ - dolog ("frequency=%d nchannels=%d fmt=", as->freq, as->nchannels); - - switch (as->fmt) { - case AUD_FMT_S8: - AUD_log (NULL, "S8"); - break; - case AUD_FMT_U8: - AUD_log (NULL, "U8"); - break; - case AUD_FMT_S16: - AUD_log (NULL, "S16"); - break; - case AUD_FMT_U16: - AUD_log (NULL, "U16"); - break; - case AUD_FMT_S32: - AUD_log (NULL, "S32"); - break; - case AUD_FMT_U32: - AUD_log (NULL, "U32"); - break; - default: - AUD_log (NULL, "invalid(%d)", as->fmt); - break; - } - - AUD_log (NULL, " endianness="); - switch (as->endianness) { - case 0: - AUD_log (NULL, "little"); - break; - case 1: - AUD_log (NULL, "big"); - break; - default: - AUD_log (NULL, "invalid"); - break; - } - AUD_log (NULL, "\n"); -} - -static int audio_validate_settings (struct audsettings *as) -{ - int invalid; - - invalid = as->nchannels != 1 && as->nchannels != 2; - invalid |= as->endianness != 0 && as->endianness != 1; - - switch (as->fmt) { - case AUD_FMT_S8: - case AUD_FMT_U8: - case AUD_FMT_S16: - case AUD_FMT_U16: - case AUD_FMT_S32: - case AUD_FMT_U32: - break; - default: - invalid = 1; - break; - } - - invalid |= as->freq <= 0; - return invalid ? -1 : 0; -} - -static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *as) -{ - int bits = 8, sign = 0; - - switch (as->fmt) { - case AUD_FMT_S8: - sign = 1; - /* fall through */ - case AUD_FMT_U8: - break; - - case AUD_FMT_S16: - sign = 1; - /* fall through */ - case AUD_FMT_U16: - bits = 16; - break; - - case AUD_FMT_S32: - sign = 1; - /* fall through */ - case AUD_FMT_U32: - bits = 32; - break; - } - return info->freq == as->freq - && info->nchannels == as->nchannels - && info->sign == sign - && info->bits == bits - && info->swap_endianness == (as->endianness != AUDIO_HOST_ENDIANNESS); -} - -void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as) -{ - int bits = 8, sign = 0, shift = 0; - - switch (as->fmt) { - case AUD_FMT_S8: - sign = 1; - case AUD_FMT_U8: - break; - - case AUD_FMT_S16: - sign = 1; - case AUD_FMT_U16: - bits = 16; - shift = 1; - break; - - case AUD_FMT_S32: - sign = 1; - case AUD_FMT_U32: - bits = 32; - shift = 2; - break; - } - - info->freq = as->freq; - info->bits = bits; - info->sign = sign; - info->nchannels = as->nchannels; - info->shift = (as->nchannels == 2) + shift; - info->align = (1 << info->shift) - 1; - info->bytes_per_second = info->freq << info->shift; - info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); -} - -void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len) -{ - if (!len) { - return; - } - - if (info->sign) { - memset (buf, 0x00, len << info->shift); - } - else { - switch (info->bits) { - case 8: - memset (buf, 0x80, len << info->shift); - break; - - case 16: - { - int i; - uint16_t *p = buf; - int shift = info->nchannels - 1; - short s = INT16_MAX; - - if (info->swap_endianness) { - s = bswap16 (s); - } - - for (i = 0; i < len << shift; i++) { - p[i] = s; - } - } - break; - - case 32: - { - int i; - uint32_t *p = buf; - int shift = info->nchannels - 1; - int32_t s = INT32_MAX; - - if (info->swap_endianness) { - s = bswap32 (s); - } - - for (i = 0; i < len << shift; i++) { - p[i] = s; - } - } - break; - - default: - AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n", - info->bits); - break; - } - } -} - -/* - * Capture - */ -static void noop_conv (struct st_sample *dst, const void *src, int samples) -{ - (void) src; - (void) dst; - (void) samples; -} - -static CaptureVoiceOut *audio_pcm_capture_find_specific ( - struct audsettings *as - ) -{ - CaptureVoiceOut *cap; - AudioState *s = &glob_audio_state; - - for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { - if (audio_pcm_info_eq (&cap->hw.info, as)) { - return cap; - } - } - return NULL; -} - -static void audio_notify_capture (CaptureVoiceOut *cap, audcnotification_e cmd) -{ - struct capture_callback *cb; - -#ifdef DEBUG_CAPTURE - dolog ("notification %d sent\n", cmd); -#endif - for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { - cb->ops.notify (cb->opaque, cmd); - } -} - -static void audio_capture_maybe_changed (CaptureVoiceOut *cap, int enabled) -{ - if (cap->hw.enabled != enabled) { - audcnotification_e cmd; - cap->hw.enabled = enabled; - cmd = enabled ? AUD_CNOTIFY_ENABLE : AUD_CNOTIFY_DISABLE; - audio_notify_capture (cap, cmd); - } -} - -static void audio_recalc_and_notify_capture (CaptureVoiceOut *cap) -{ - HWVoiceOut *hw = &cap->hw; - SWVoiceOut *sw; - int enabled = 0; - - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - if (sw->active) { - enabled = 1; - break; - } - } - audio_capture_maybe_changed (cap, enabled); -} - -static void audio_detach_capture (HWVoiceOut *hw) -{ - SWVoiceCap *sc = hw->cap_head.lh_first; - - while (sc) { - SWVoiceCap *sc1 = sc->entries.le_next; - SWVoiceOut *sw = &sc->sw; - CaptureVoiceOut *cap = sc->cap; - int was_active = sw->active; - - if (sw->rate) { - st_rate_stop (sw->rate); - sw->rate = NULL; - } - - QLIST_REMOVE (sw, entries); - QLIST_REMOVE (sc, entries); - g_free (sc); - if (was_active) { - /* We have removed soft voice from the capture: - this might have changed the overall status of the capture - since this might have been the only active voice */ - audio_recalc_and_notify_capture (cap); - } - sc = sc1; - } -} - -static int audio_attach_capture (HWVoiceOut *hw) -{ - AudioState *s = &glob_audio_state; - CaptureVoiceOut *cap; - - audio_detach_capture (hw); - for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { - SWVoiceCap *sc; - SWVoiceOut *sw; - HWVoiceOut *hw_cap = &cap->hw; - - sc = audio_calloc (AUDIO_FUNC, 1, sizeof (*sc)); - if (!sc) { - dolog ("Could not allocate soft capture voice (%zu bytes)\n", - sizeof (*sc)); - return -1; - } - - sc->cap = cap; - sw = &sc->sw; - sw->hw = hw_cap; - sw->info = hw->info; - sw->empty = 1; - sw->active = hw->enabled; - sw->conv = noop_conv; - sw->ratio = ((int64_t) hw_cap->info.freq << 32) / sw->info.freq; - sw->vol = nominal_volume; - sw->rate = st_rate_start (sw->info.freq, hw_cap->info.freq); - if (!sw->rate) { - dolog ("Could not start rate conversion for `%s'\n", SW_NAME (sw)); - g_free (sw); - return -1; - } - QLIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries); - QLIST_INSERT_HEAD (&hw->cap_head, sc, entries); -#ifdef DEBUG_CAPTURE - sw->name = g_strdup_printf ("for %p %d,%d,%d", - hw, sw->info.freq, sw->info.bits, - sw->info.nchannels); - dolog ("Added %s active = %d\n", sw->name, sw->active); -#endif - if (sw->active) { - audio_capture_maybe_changed (cap, 1); - } - } - return 0; -} - -/* - * Hard voice (capture) - */ -static int audio_pcm_hw_find_min_in (HWVoiceIn *hw) -{ - SWVoiceIn *sw; - int m = hw->total_samples_captured; - - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - if (sw->active) { - m = audio_MIN (m, sw->total_hw_samples_acquired); - } - } - return m; -} - -int audio_pcm_hw_get_live_in (HWVoiceIn *hw) -{ - int live = hw->total_samples_captured - audio_pcm_hw_find_min_in (hw); - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { - dolog ("live=%d hw->samples=%d\n", live, hw->samples); - return 0; - } - return live; -} - -int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf, - int live, int pending) -{ - int left = hw->samples - pending; - int len = audio_MIN (left, live); - int clipped = 0; - - while (len) { - struct st_sample *src = hw->mix_buf + hw->rpos; - uint8_t *dst = advance (pcm_buf, hw->rpos << hw->info.shift); - int samples_till_end_of_buf = hw->samples - hw->rpos; - int samples_to_clip = audio_MIN (len, samples_till_end_of_buf); - - hw->clip (dst, src, samples_to_clip); - - hw->rpos = (hw->rpos + samples_to_clip) % hw->samples; - len -= samples_to_clip; - clipped += samples_to_clip; - } - return clipped; -} - -/* - * Soft voice (capture) - */ -static int audio_pcm_sw_get_rpos_in (SWVoiceIn *sw) -{ - HWVoiceIn *hw = sw->hw; - int live = hw->total_samples_captured - sw->total_hw_samples_acquired; - int rpos; - - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { - dolog ("live=%d hw->samples=%d\n", live, hw->samples); - return 0; - } - - rpos = hw->wpos - live; - if (rpos >= 0) { - return rpos; - } - else { - return hw->samples + rpos; - } -} - -int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) -{ - HWVoiceIn *hw = sw->hw; - int samples, live, ret = 0, swlim, isamp, osamp, rpos, total = 0; - struct st_sample *src, *dst = sw->buf; - - rpos = audio_pcm_sw_get_rpos_in (sw) % hw->samples; - - live = hw->total_samples_captured - sw->total_hw_samples_acquired; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { - dolog ("live_in=%d hw->samples=%d\n", live, hw->samples); - return 0; - } - - samples = size >> sw->info.shift; - if (!live) { - return 0; - } - - swlim = (live * sw->ratio) >> 32; - swlim = audio_MIN (swlim, samples); - - while (swlim) { - src = hw->conv_buf + rpos; - isamp = hw->wpos - rpos; - /* XXX: <= ? */ - if (isamp <= 0) { - isamp = hw->samples - rpos; - } - - if (!isamp) { - break; - } - osamp = swlim; - - if (audio_bug (AUDIO_FUNC, osamp < 0)) { - dolog ("osamp=%d\n", osamp); - return 0; - } - - st_rate_flow (sw->rate, src, dst, &isamp, &osamp); - swlim -= osamp; - rpos = (rpos + isamp) % hw->samples; - dst += osamp; - ret += osamp; - total += isamp; - } - - if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) { - mixeng_volume (sw->buf, ret, &sw->vol); - } - - sw->clip (buf, sw->buf, ret); - sw->total_hw_samples_acquired += total; - return ret << sw->info.shift; -} - -/* - * Hard voice (playback) - */ -static int audio_pcm_hw_find_min_out (HWVoiceOut *hw, int *nb_livep) -{ - SWVoiceOut *sw; - int m = INT_MAX; - int nb_live = 0; - - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - if (sw->active || !sw->empty) { - m = audio_MIN (m, sw->total_hw_samples_mixed); - nb_live += 1; - } - } - - *nb_livep = nb_live; - return m; -} - -static int audio_pcm_hw_get_live_out (HWVoiceOut *hw, int *nb_live) -{ - int smin; - int nb_live1; - - smin = audio_pcm_hw_find_min_out (hw, &nb_live1); - if (nb_live) { - *nb_live = nb_live1; - } - - if (nb_live1) { - int live = smin; - - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { - dolog ("live=%d hw->samples=%d\n", live, hw->samples); - return 0; - } - return live; - } - return 0; -} - -/* - * Soft voice (playback) - */ -int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) -{ - int hwsamples, samples, isamp, osamp, wpos, live, dead, left, swlim, blck; - int ret = 0, pos = 0, total = 0; - - if (!sw) { - return size; - } - - hwsamples = sw->hw->samples; - - live = sw->total_hw_samples_mixed; - if (audio_bug (AUDIO_FUNC, live < 0 || live > hwsamples)){ - dolog ("live=%d hw->samples=%d\n", live, hwsamples); - return 0; - } - - if (live == hwsamples) { -#ifdef DEBUG_OUT - dolog ("%s is full %d\n", sw->name, live); -#endif - return 0; - } - - wpos = (sw->hw->rpos + live) % hwsamples; - samples = size >> sw->info.shift; - - dead = hwsamples - live; - swlim = ((int64_t) dead << 32) / sw->ratio; - swlim = audio_MIN (swlim, samples); - if (swlim) { - sw->conv (sw->buf, buf, swlim); - - if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { - mixeng_volume (sw->buf, swlim, &sw->vol); - } - } - - while (swlim) { - dead = hwsamples - live; - left = hwsamples - wpos; - blck = audio_MIN (dead, left); - if (!blck) { - break; - } - isamp = swlim; - osamp = blck; - st_rate_flow_mix ( - sw->rate, - sw->buf + pos, - sw->hw->mix_buf + wpos, - &isamp, - &osamp - ); - ret += isamp; - swlim -= isamp; - pos += isamp; - live += osamp; - wpos = (wpos + osamp) % hwsamples; - total += osamp; - } - - sw->total_hw_samples_mixed += total; - sw->empty = sw->total_hw_samples_mixed == 0; - -#ifdef DEBUG_OUT - dolog ( - "%s: write size %d ret %d total sw %d\n", - SW_NAME (sw), - size >> sw->info.shift, - ret, - sw->total_hw_samples_mixed - ); -#endif - - return ret << sw->info.shift; -} - -#ifdef DEBUG_AUDIO -static void audio_pcm_print_info (const char *cap, struct audio_pcm_info *info) -{ - dolog ("%s: bits %d, sign %d, freq %d, nchan %d\n", - cap, info->bits, info->sign, info->freq, info->nchannels); -} -#endif - -#define DAC -#include "audio_template.h" -#undef DAC -#include "audio_template.h" - -/* - * Timer - */ -static int audio_is_timer_needed (void) -{ - HWVoiceIn *hwi = NULL; - HWVoiceOut *hwo = NULL; - - while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) { - if (!hwo->poll_mode) return 1; - } - while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) { - if (!hwi->poll_mode) return 1; - } - return 0; -} - -static void audio_reset_timer (AudioState *s) -{ - if (audio_is_timer_needed ()) { - timer_mod (s->ts, - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + conf.period.ticks); - } - else { - timer_del (s->ts); - } -} - -static void audio_timer (void *opaque) -{ - audio_run ("timer"); - audio_reset_timer (opaque); -} - -/* - * Public API - */ -int AUD_write (SWVoiceOut *sw, void *buf, int size) -{ - int bytes; - - if (!sw) { - /* XXX: Consider options */ - return size; - } - - if (!sw->hw->enabled) { - dolog ("Writing to disabled voice %s\n", SW_NAME (sw)); - return 0; - } - - bytes = sw->hw->pcm_ops->write (sw, buf, size); - return bytes; -} - -int AUD_read (SWVoiceIn *sw, void *buf, int size) -{ - int bytes; - - if (!sw) { - /* XXX: Consider options */ - return size; - } - - if (!sw->hw->enabled) { - dolog ("Reading from disabled voice %s\n", SW_NAME (sw)); - return 0; - } - - bytes = sw->hw->pcm_ops->read (sw, buf, size); - return bytes; -} - -int AUD_get_buffer_size_out (SWVoiceOut *sw) -{ - return sw->hw->samples << sw->hw->info.shift; -} - -void AUD_set_active_out (SWVoiceOut *sw, int on) -{ - HWVoiceOut *hw; - - if (!sw) { - return; - } - - hw = sw->hw; - if (sw->active != on) { - AudioState *s = &glob_audio_state; - SWVoiceOut *temp_sw; - SWVoiceCap *sc; - - if (on) { - hw->pending_disable = 0; - if (!hw->enabled) { - hw->enabled = 1; - if (s->vm_running) { - hw->pcm_ops->ctl_out (hw, VOICE_ENABLE, conf.try_poll_out); - audio_reset_timer (s); - } - } - } - else { - if (hw->enabled) { - int nb_active = 0; - - for (temp_sw = hw->sw_head.lh_first; temp_sw; - temp_sw = temp_sw->entries.le_next) { - nb_active += temp_sw->active != 0; - } - - hw->pending_disable = nb_active == 1; - } - } - - for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { - sc->sw.active = hw->enabled; - if (hw->enabled) { - audio_capture_maybe_changed (sc->cap, 1); - } - } - sw->active = on; - } -} - -void AUD_set_active_in (SWVoiceIn *sw, int on) -{ - HWVoiceIn *hw; - - if (!sw) { - return; - } - - hw = sw->hw; - if (sw->active != on) { - AudioState *s = &glob_audio_state; - SWVoiceIn *temp_sw; - - if (on) { - if (!hw->enabled) { - hw->enabled = 1; - if (s->vm_running) { - hw->pcm_ops->ctl_in (hw, VOICE_ENABLE, conf.try_poll_in); - audio_reset_timer (s); - } - } - sw->total_hw_samples_acquired = hw->total_samples_captured; - } - else { - if (hw->enabled) { - int nb_active = 0; - - for (temp_sw = hw->sw_head.lh_first; temp_sw; - temp_sw = temp_sw->entries.le_next) { - nb_active += temp_sw->active != 0; - } - - if (nb_active == 1) { - hw->enabled = 0; - hw->pcm_ops->ctl_in (hw, VOICE_DISABLE); - } - } - } - sw->active = on; - } -} - -static int audio_get_avail (SWVoiceIn *sw) -{ - int live; - - if (!sw) { - return 0; - } - - live = sw->hw->total_samples_captured - sw->total_hw_samples_acquired; - if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { - dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); - return 0; - } - - ldebug ( - "%s: get_avail live %d ret %" PRId64 "\n", - SW_NAME (sw), - live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift - ); - - return (((int64_t) live << 32) / sw->ratio) << sw->info.shift; -} - -static int audio_get_free (SWVoiceOut *sw) -{ - int live, dead; - - if (!sw) { - return 0; - } - - live = sw->total_hw_samples_mixed; - - if (audio_bug (AUDIO_FUNC, live < 0 || live > sw->hw->samples)) { - dolog ("live=%d sw->hw->samples=%d\n", live, sw->hw->samples); - return 0; - } - - dead = sw->hw->samples - live; - -#ifdef DEBUG_OUT - dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n", - SW_NAME (sw), - live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); -#endif - - return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; -} - -static void audio_capture_mix_and_clear (HWVoiceOut *hw, int rpos, int samples) -{ - int n; - - if (hw->enabled) { - SWVoiceCap *sc; - - for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { - SWVoiceOut *sw = &sc->sw; - int rpos2 = rpos; - - n = samples; - while (n) { - int till_end_of_hw = hw->samples - rpos2; - int to_write = audio_MIN (till_end_of_hw, n); - int bytes = to_write << hw->info.shift; - int written; - - sw->buf = hw->mix_buf + rpos2; - written = audio_pcm_sw_write (sw, NULL, bytes); - if (written - bytes) { - dolog ("Could not mix %d bytes into a capture " - "buffer, mixed %d\n", - bytes, written); - break; - } - n -= to_write; - rpos2 = (rpos2 + to_write) % hw->samples; - } - } - } - - n = audio_MIN (samples, hw->samples - rpos); - mixeng_clear (hw->mix_buf + rpos, n); - mixeng_clear (hw->mix_buf, samples - n); -} - -static void audio_run_out (AudioState *s) -{ - HWVoiceOut *hw = NULL; - SWVoiceOut *sw; - - while ((hw = audio_pcm_hw_find_any_enabled_out (hw))) { - int played; - int live, free, nb_live, cleanup_required, prev_rpos; - - live = audio_pcm_hw_get_live_out (hw, &nb_live); - if (!nb_live) { - live = 0; - } - - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { - dolog ("live=%d hw->samples=%d\n", live, hw->samples); - continue; - } - - if (hw->pending_disable && !nb_live) { - SWVoiceCap *sc; -#ifdef DEBUG_OUT - dolog ("Disabling voice\n"); -#endif - hw->enabled = 0; - hw->pending_disable = 0; - hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); - for (sc = hw->cap_head.lh_first; sc; sc = sc->entries.le_next) { - sc->sw.active = 0; - audio_recalc_and_notify_capture (sc->cap); - } - continue; - } - - if (!live) { - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - if (sw->active) { - free = audio_get_free (sw); - if (free > 0) { - sw->callback.fn (sw->callback.opaque, free); - } - } - } - continue; - } - - prev_rpos = hw->rpos; - played = hw->pcm_ops->run_out (hw, live); - if (audio_bug (AUDIO_FUNC, hw->rpos >= hw->samples)) { - dolog ("hw->rpos=%d hw->samples=%d played=%d\n", - hw->rpos, hw->samples, played); - hw->rpos = 0; - } - -#ifdef DEBUG_OUT - dolog ("played=%d\n", played); -#endif - - if (played) { - hw->ts_helper += played; - audio_capture_mix_and_clear (hw, prev_rpos, played); - } - - cleanup_required = 0; - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - if (!sw->active && sw->empty) { - continue; - } - - if (audio_bug (AUDIO_FUNC, played > sw->total_hw_samples_mixed)) { - dolog ("played=%d sw->total_hw_samples_mixed=%d\n", - played, sw->total_hw_samples_mixed); - played = sw->total_hw_samples_mixed; - } - - sw->total_hw_samples_mixed -= played; - - if (!sw->total_hw_samples_mixed) { - sw->empty = 1; - cleanup_required |= !sw->active && !sw->callback.fn; - } - - if (sw->active) { - free = audio_get_free (sw); - if (free > 0) { - sw->callback.fn (sw->callback.opaque, free); - } - } - } - - if (cleanup_required) { - SWVoiceOut *sw1; - - sw = hw->sw_head.lh_first; - while (sw) { - sw1 = sw->entries.le_next; - if (!sw->active && !sw->callback.fn) { - audio_close_out (sw); - } - sw = sw1; - } - } - } -} - -static void audio_run_in (AudioState *s) -{ - HWVoiceIn *hw = NULL; - - while ((hw = audio_pcm_hw_find_any_enabled_in (hw))) { - SWVoiceIn *sw; - int captured, min; - - captured = hw->pcm_ops->run_in (hw); - - min = audio_pcm_hw_find_min_in (hw); - hw->total_samples_captured += captured - min; - hw->ts_helper += captured; - - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - sw->total_hw_samples_acquired -= min; - - if (sw->active) { - int avail; - - avail = audio_get_avail (sw); - if (avail > 0) { - sw->callback.fn (sw->callback.opaque, avail); - } - } - } - } -} - -static void audio_run_capture (AudioState *s) -{ - CaptureVoiceOut *cap; - - for (cap = s->cap_head.lh_first; cap; cap = cap->entries.le_next) { - int live, rpos, captured; - HWVoiceOut *hw = &cap->hw; - SWVoiceOut *sw; - - captured = live = audio_pcm_hw_get_live_out (hw, NULL); - rpos = hw->rpos; - while (live) { - int left = hw->samples - rpos; - int to_capture = audio_MIN (live, left); - struct st_sample *src; - struct capture_callback *cb; - - src = hw->mix_buf + rpos; - hw->clip (cap->buf, src, to_capture); - mixeng_clear (src, to_capture); - - for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { - cb->ops.capture (cb->opaque, cap->buf, - to_capture << hw->info.shift); - } - rpos = (rpos + to_capture) % hw->samples; - live -= to_capture; - } - hw->rpos = rpos; - - for (sw = hw->sw_head.lh_first; sw; sw = sw->entries.le_next) { - if (!sw->active && sw->empty) { - continue; - } - - if (audio_bug (AUDIO_FUNC, captured > sw->total_hw_samples_mixed)) { - dolog ("captured=%d sw->total_hw_samples_mixed=%d\n", - captured, sw->total_hw_samples_mixed); - captured = sw->total_hw_samples_mixed; - } - - sw->total_hw_samples_mixed -= captured; - sw->empty = sw->total_hw_samples_mixed == 0; - } - } -} - -void audio_run (const char *msg) -{ - AudioState *s = &glob_audio_state; - - audio_run_out (s); - audio_run_in (s); - audio_run_capture (s); -#ifdef DEBUG_POLL - { - static double prevtime; - double currtime; - struct timeval tv; - - if (gettimeofday (&tv, NULL)) { - perror ("audio_run: gettimeofday"); - return; - } - - currtime = tv.tv_sec + tv.tv_usec * 1e-6; - dolog ("Elapsed since last %s: %f\n", msg, currtime - prevtime); - prevtime = currtime; - } -#endif -} - -static struct audio_option audio_options[] = { - /* DAC */ - { - .name = "DAC_FIXED_SETTINGS", - .tag = AUD_OPT_BOOL, - .valp = &conf.fixed_out.enabled, - .descr = "Use fixed settings for host DAC" - }, - { - .name = "DAC_FIXED_FREQ", - .tag = AUD_OPT_INT, - .valp = &conf.fixed_out.settings.freq, - .descr = "Frequency for fixed host DAC" - }, - { - .name = "DAC_FIXED_FMT", - .tag = AUD_OPT_FMT, - .valp = &conf.fixed_out.settings.fmt, - .descr = "Format for fixed host DAC" - }, - { - .name = "DAC_FIXED_CHANNELS", - .tag = AUD_OPT_INT, - .valp = &conf.fixed_out.settings.nchannels, - .descr = "Number of channels for fixed DAC (1 - mono, 2 - stereo)" - }, - { - .name = "DAC_VOICES", - .tag = AUD_OPT_INT, - .valp = &conf.fixed_out.nb_voices, - .descr = "Number of voices for DAC" - }, - { - .name = "DAC_TRY_POLL", - .tag = AUD_OPT_BOOL, - .valp = &conf.try_poll_out, - .descr = "Attempt using poll mode for DAC" - }, - /* ADC */ - { - .name = "ADC_FIXED_SETTINGS", - .tag = AUD_OPT_BOOL, - .valp = &conf.fixed_in.enabled, - .descr = "Use fixed settings for host ADC" - }, - { - .name = "ADC_FIXED_FREQ", - .tag = AUD_OPT_INT, - .valp = &conf.fixed_in.settings.freq, - .descr = "Frequency for fixed host ADC" - }, - { - .name = "ADC_FIXED_FMT", - .tag = AUD_OPT_FMT, - .valp = &conf.fixed_in.settings.fmt, - .descr = "Format for fixed host ADC" - }, - { - .name = "ADC_FIXED_CHANNELS", - .tag = AUD_OPT_INT, - .valp = &conf.fixed_in.settings.nchannels, - .descr = "Number of channels for fixed ADC (1 - mono, 2 - stereo)" - }, - { - .name = "ADC_VOICES", - .tag = AUD_OPT_INT, - .valp = &conf.fixed_in.nb_voices, - .descr = "Number of voices for ADC" - }, - { - .name = "ADC_TRY_POLL", - .tag = AUD_OPT_BOOL, - .valp = &conf.try_poll_in, - .descr = "Attempt using poll mode for ADC" - }, - /* Misc */ - { - .name = "TIMER_PERIOD", - .tag = AUD_OPT_INT, - .valp = &conf.period.hertz, - .descr = "Timer period in HZ (0 - use lowest possible)" - }, - { /* End of list */ } -}; - -static void audio_pp_nb_voices (const char *typ, int nb) -{ - switch (nb) { - case 0: - printf ("Does not support %s\n", typ); - break; - case 1: - printf ("One %s voice\n", typ); - break; - case INT_MAX: - printf ("Theoretically supports many %s voices\n", typ); - break; - default: - printf ("Theoretically supports up to %d %s voices\n", nb, typ); - break; - } - -} - -void AUD_help (void) -{ - size_t i; - - audio_process_options ("AUDIO", audio_options); - for (i = 0; i < ARRAY_SIZE (drvtab); i++) { - struct audio_driver *d = drvtab[i]; - if (d->options) { - audio_process_options (d->name, d->options); - } - } - - printf ("Audio options:\n"); - audio_print_options ("AUDIO", audio_options); - printf ("\n"); - - printf ("Available drivers:\n"); - - for (i = 0; i < ARRAY_SIZE (drvtab); i++) { - struct audio_driver *d = drvtab[i]; - - printf ("Name: %s\n", d->name); - printf ("Description: %s\n", d->descr); - - audio_pp_nb_voices ("playback", d->max_voices_out); - audio_pp_nb_voices ("capture", d->max_voices_in); - - if (d->options) { - printf ("Options:\n"); - audio_print_options (d->name, d->options); - } - else { - printf ("No options\n"); - } - printf ("\n"); - } - - printf ( - "Options are settable through environment variables.\n" - "Example:\n" -#ifdef _WIN32 - " set QEMU_AUDIO_DRV=wav\n" - " set QEMU_WAV_PATH=c:\\tune.wav\n" -#else - " export QEMU_AUDIO_DRV=wav\n" - " export QEMU_WAV_PATH=$HOME/tune.wav\n" - "(for csh replace export with setenv in the above)\n" -#endif - " qemu ...\n\n" - ); -} - -static int audio_driver_init (AudioState *s, struct audio_driver *drv) -{ - if (drv->options) { - audio_process_options (drv->name, drv->options); - } - s->drv_opaque = drv->init (); - - if (s->drv_opaque) { - audio_init_nb_voices_out (drv); - audio_init_nb_voices_in (drv); - s->drv = drv; - return 0; - } - else { - dolog ("Could not init `%s' audio driver\n", drv->name); - return -1; - } -} - -static void audio_vm_change_state_handler (void *opaque, int running, - RunState state) -{ - AudioState *s = opaque; - HWVoiceOut *hwo = NULL; - HWVoiceIn *hwi = NULL; - int op = running ? VOICE_ENABLE : VOICE_DISABLE; - - s->vm_running = running; - while ((hwo = audio_pcm_hw_find_any_enabled_out (hwo))) { - hwo->pcm_ops->ctl_out (hwo, op, conf.try_poll_out); - } - - while ((hwi = audio_pcm_hw_find_any_enabled_in (hwi))) { - hwi->pcm_ops->ctl_in (hwi, op, conf.try_poll_in); - } - audio_reset_timer (s); -} - -static void audio_atexit (void) -{ - AudioState *s = &glob_audio_state; - HWVoiceOut *hwo = NULL; - HWVoiceIn *hwi = NULL; - - while ((hwo = audio_pcm_hw_find_any_out (hwo))) { - SWVoiceCap *sc; - - if (hwo->enabled) { - hwo->pcm_ops->ctl_out (hwo, VOICE_DISABLE); - } - hwo->pcm_ops->fini_out (hwo); - - for (sc = hwo->cap_head.lh_first; sc; sc = sc->entries.le_next) { - CaptureVoiceOut *cap = sc->cap; - struct capture_callback *cb; - - for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { - cb->ops.destroy (cb->opaque); - } - } - } - - while ((hwi = audio_pcm_hw_find_any_in (hwi))) { - if (hwi->enabled) { - hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE); - } - hwi->pcm_ops->fini_in (hwi); - } - - if (s->drv) { - s->drv->fini (s->drv_opaque); - } -} - -static const VMStateDescription vmstate_audio = { - .name = "audio", - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_END_OF_LIST() - } -}; - -static void audio_init (void) -{ - size_t i; - int done = 0; - const char *drvname; - VMChangeStateEntry *e; - AudioState *s = &glob_audio_state; - - if (s->drv) { - return; - } - - QLIST_INIT (&s->hw_head_out); - QLIST_INIT (&s->hw_head_in); - QLIST_INIT (&s->cap_head); - atexit (audio_atexit); - - s->ts = timer_new_ns(QEMU_CLOCK_VIRTUAL, audio_timer, s); - - audio_process_options ("AUDIO", audio_options); - - s->nb_hw_voices_out = conf.fixed_out.nb_voices; - s->nb_hw_voices_in = conf.fixed_in.nb_voices; - - if (s->nb_hw_voices_out <= 0) { - dolog ("Bogus number of playback voices %d, setting to 1\n", - s->nb_hw_voices_out); - s->nb_hw_voices_out = 1; - } - - if (s->nb_hw_voices_in <= 0) { - dolog ("Bogus number of capture voices %d, setting to 0\n", - s->nb_hw_voices_in); - s->nb_hw_voices_in = 0; - } - - { - int def; - drvname = audio_get_conf_str ("QEMU_AUDIO_DRV", NULL, &def); - } - - if (drvname) { - int found = 0; - - for (i = 0; i < ARRAY_SIZE (drvtab); i++) { - if (!strcmp (drvname, drvtab[i]->name)) { - done = !audio_driver_init (s, drvtab[i]); - found = 1; - break; - } - } - - if (!found) { - dolog ("Unknown audio driver `%s'\n", drvname); - dolog ("Run with -audio-help to list available drivers\n"); - } - } - - if (!done) { - for (i = 0; !done && i < ARRAY_SIZE (drvtab); i++) { - if (drvtab[i]->can_be_default) { - done = !audio_driver_init (s, drvtab[i]); - } - } - } - - if (!done) { - done = !audio_driver_init (s, &no_audio_driver); - assert(done); - dolog("warning: Using timer based audio emulation\n"); - } - - if (conf.period.hertz <= 0) { - if (conf.period.hertz < 0) { - dolog ("warning: Timer period is negative - %d " - "treating as zero\n", - conf.period.hertz); - } - conf.period.ticks = 1; - } else { - conf.period.ticks = NANOSECONDS_PER_SECOND / conf.period.hertz; - } - - e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s); - if (!e) { - dolog ("warning: Could not register change state handler\n" - "(Audio can continue looping even after stopping the VM)\n"); - } - - QLIST_INIT (&s->card_head); - vmstate_register (NULL, 0, &vmstate_audio, s); -} - -void AUD_register_card (const char *name, QEMUSoundCard *card) -{ - audio_init (); - card->name = g_strdup (name); - memset (&card->entries, 0, sizeof (card->entries)); - QLIST_INSERT_HEAD (&glob_audio_state.card_head, card, entries); -} - -void AUD_remove_card (QEMUSoundCard *card) -{ - QLIST_REMOVE (card, entries); - g_free (card->name); -} - - -CaptureVoiceOut *AUD_add_capture ( - struct audsettings *as, - struct audio_capture_ops *ops, - void *cb_opaque - ) -{ - AudioState *s = &glob_audio_state; - CaptureVoiceOut *cap; - struct capture_callback *cb; - - if (audio_validate_settings (as)) { - dolog ("Invalid settings were passed when trying to add capture\n"); - audio_print_settings (as); - goto err0; - } - - cb = audio_calloc (AUDIO_FUNC, 1, sizeof (*cb)); - if (!cb) { - dolog ("Could not allocate capture callback information, size %zu\n", - sizeof (*cb)); - goto err0; - } - cb->ops = *ops; - cb->opaque = cb_opaque; - - cap = audio_pcm_capture_find_specific (as); - if (cap) { - QLIST_INSERT_HEAD (&cap->cb_head, cb, entries); - return cap; - } - else { - HWVoiceOut *hw; - CaptureVoiceOut *cap; - - cap = audio_calloc (AUDIO_FUNC, 1, sizeof (*cap)); - if (!cap) { - dolog ("Could not allocate capture voice, size %zu\n", - sizeof (*cap)); - goto err1; - } - - hw = &cap->hw; - QLIST_INIT (&hw->sw_head); - QLIST_INIT (&cap->cb_head); - - /* XXX find a more elegant way */ - hw->samples = 4096 * 4; - hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, - sizeof (struct st_sample)); - if (!hw->mix_buf) { - dolog ("Could not allocate capture mix buffer (%d samples)\n", - hw->samples); - goto err2; - } - - audio_pcm_init_info (&hw->info, as); - - cap->buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - if (!cap->buf) { - dolog ("Could not allocate capture buffer " - "(%d samples, each %d bytes)\n", - hw->samples, 1 << hw->info.shift); - goto err3; - } - - hw->clip = mixeng_clip - [hw->info.nchannels == 2] - [hw->info.sign] - [hw->info.swap_endianness] - [audio_bits_to_index (hw->info.bits)]; - - QLIST_INSERT_HEAD (&s->cap_head, cap, entries); - QLIST_INSERT_HEAD (&cap->cb_head, cb, entries); - - hw = NULL; - while ((hw = audio_pcm_hw_find_any_out (hw))) { - audio_attach_capture (hw); - } - return cap; - - err3: - g_free (cap->hw.mix_buf); - err2: - g_free (cap); - err1: - g_free (cb); - err0: - return NULL; - } -} - -void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) -{ - struct capture_callback *cb; - - for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { - if (cb->opaque == cb_opaque) { - cb->ops.destroy (cb_opaque); - QLIST_REMOVE (cb, entries); - g_free (cb); - - if (!cap->cb_head.lh_first) { - SWVoiceOut *sw = cap->hw.sw_head.lh_first, *sw1; - - while (sw) { - SWVoiceCap *sc = (SWVoiceCap *) sw; -#ifdef DEBUG_CAPTURE - dolog ("freeing %s\n", sw->name); -#endif - - sw1 = sw->entries.le_next; - if (sw->rate) { - st_rate_stop (sw->rate); - sw->rate = NULL; - } - QLIST_REMOVE (sw, entries); - QLIST_REMOVE (sc, entries); - g_free (sc); - sw = sw1; - } - QLIST_REMOVE (cap, entries); - g_free (cap); - } - return; - } - } -} - -void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) -{ - if (sw) { - HWVoiceOut *hw = sw->hw; - - sw->vol.mute = mute; - sw->vol.l = nominal_volume.l * lvol / 255; - sw->vol.r = nominal_volume.r * rvol / 255; - - if (hw->pcm_ops->ctl_out) { - hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw); - } - } -} - -void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) -{ - if (sw) { - HWVoiceIn *hw = sw->hw; - - sw->vol.mute = mute; - sw->vol.l = nominal_volume.l * lvol / 255; - sw->vol.r = nominal_volume.r * rvol / 255; - - if (hw->pcm_ops->ctl_in) { - hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw); - } - } -} diff --git a/qemu/audio/audio.h b/qemu/audio/audio.h deleted file mode 100644 index b41a97053..000000000 --- a/qemu/audio/audio.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * QEMU Audio subsystem header - * - * Copyright (c) 2003-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_AUDIO_H -#define QEMU_AUDIO_H - -#include "qemu/queue.h" - -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 -#define AUDIO_HOST_ENDIANNESS 0 -#endif - -struct audsettings { - int freq; - int nchannels; - audfmt_e fmt; - int endianness; -}; - -typedef enum { - AUD_CNOTIFY_ENABLE, - AUD_CNOTIFY_DISABLE -} audcnotification_e; - -struct audio_capture_ops { - void (*notify) (void *opaque, audcnotification_e cmd); - void (*capture) (void *opaque, void *buf, int size); - void (*destroy) (void *opaque); -}; - -struct capture_ops { - void (*info) (void *opaque); - void (*destroy) (void *opaque); -}; - -typedef struct CaptureState { - void *opaque; - struct capture_ops ops; - QLIST_ENTRY (CaptureState) entries; -} CaptureState; - -typedef struct SWVoiceOut SWVoiceOut; -typedef struct CaptureVoiceOut CaptureVoiceOut; -typedef struct SWVoiceIn SWVoiceIn; - -typedef struct QEMUSoundCard { - char *name; - QLIST_ENTRY (QEMUSoundCard) entries; -} QEMUSoundCard; - -typedef struct QEMUAudioTimeStamp { - uint64_t old_ts; -} QEMUAudioTimeStamp; - -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 ( - struct audsettings *as, - struct audio_capture_ops *ops, - void *opaque - ); -void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque); - -SWVoiceOut *AUD_open_out ( - QEMUSoundCard *card, - SWVoiceOut *sw, - const char *name, - void *callback_opaque, - audio_callback_fn callback_fn, - struct audsettings *settings - ); - -void AUD_close_out (QEMUSoundCard *card, SWVoiceOut *sw); -int AUD_write (SWVoiceOut *sw, void *pcm_buf, int size); -int AUD_get_buffer_size_out (SWVoiceOut *sw); -void AUD_set_active_out (SWVoiceOut *sw, int on); -int AUD_is_active_out (SWVoiceOut *sw); - -void AUD_init_time_stamp_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); -uint64_t AUD_get_elapsed_usec_out (SWVoiceOut *sw, QEMUAudioTimeStamp *ts); - -void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol); -void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol); - -SWVoiceIn *AUD_open_in ( - QEMUSoundCard *card, - SWVoiceIn *sw, - const char *name, - void *callback_opaque, - audio_callback_fn callback_fn, - struct audsettings *settings - ); - -void AUD_close_in (QEMUSoundCard *card, SWVoiceIn *sw); -int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size); -void AUD_set_active_in (SWVoiceIn *sw, int on); -int AUD_is_active_in (SWVoiceIn *sw); - -void AUD_init_time_stamp_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts); -uint64_t AUD_get_elapsed_usec_in (SWVoiceIn *sw, QEMUAudioTimeStamp *ts); - -static inline void *advance (void *p, int incr) -{ - uint8_t *d = p; - return (d + incr); -} - -#ifdef __GNUC__ -#define audio_MIN(a, b) ( __extension__ ({ \ - __typeof (a) ta = a; \ - __typeof (b) tb = b; \ - ((ta)>(tb)?(tb):(ta)); \ -})) - -#define audio_MAX(a, b) ( __extension__ ({ \ - __typeof (a) ta = a; \ - __typeof (b) tb = b; \ - ((ta)<(tb)?(tb):(ta)); \ -})) -#else -#define audio_MIN(a, b) ((a)>(b)?(b):(a)) -#define audio_MAX(a, b) ((a)<(b)?(b):(a)) -#endif - -int wav_start_capture (CaptureState *s, const char *path, int freq, - int bits, int nchannels); - -#endif /* audio.h */ diff --git a/qemu/audio/audio_int.h b/qemu/audio/audio_int.h deleted file mode 100644 index 566df5edf..000000000 --- a/qemu/audio/audio_int.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - * QEMU Audio subsystem header - * - * Copyright (c) 2003-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_AUDIO_INT_H -#define QEMU_AUDIO_INT_H - -#ifdef CONFIG_COREAUDIO -#define FLOAT_MIXENG -/* #define RECIPROCAL */ -#endif -#include "mixeng.h" - -struct audio_pcm_ops; - -typedef enum { - AUD_OPT_INT, - AUD_OPT_FMT, - AUD_OPT_STR, - AUD_OPT_BOOL -} audio_option_tag_e; - -struct audio_option { - const char *name; - audio_option_tag_e tag; - void *valp; - const char *descr; - int *overriddenp; - int overridden; -}; - -struct audio_callback { - void *opaque; - audio_callback_fn fn; -}; - -struct audio_pcm_info { - int bits; - int sign; - int freq; - int nchannels; - int align; - int shift; - int bytes_per_second; - int swap_endianness; -}; - -typedef struct SWVoiceCap SWVoiceCap; - -typedef struct HWVoiceOut { - int enabled; - int poll_mode; - int pending_disable; - struct audio_pcm_info info; - - f_sample *clip; - - int rpos; - uint64_t ts_helper; - - struct st_sample *mix_buf; - - int samples; - QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; - QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; - int ctl_caps; - struct audio_pcm_ops *pcm_ops; - QLIST_ENTRY (HWVoiceOut) entries; -} HWVoiceOut; - -typedef struct HWVoiceIn { - int enabled; - int poll_mode; - struct audio_pcm_info info; - - t_sample *conv; - - int wpos; - int total_samples_captured; - uint64_t ts_helper; - - struct st_sample *conv_buf; - - int samples; - QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; - int ctl_caps; - struct audio_pcm_ops *pcm_ops; - QLIST_ENTRY (HWVoiceIn) entries; -} HWVoiceIn; - -struct SWVoiceOut { - QEMUSoundCard *card; - struct audio_pcm_info info; - t_sample *conv; - int64_t ratio; - struct st_sample *buf; - void *rate; - int total_hw_samples_mixed; - int active; - int empty; - HWVoiceOut *hw; - char *name; - struct mixeng_volume vol; - struct audio_callback callback; - QLIST_ENTRY (SWVoiceOut) entries; -}; - -struct SWVoiceIn { - QEMUSoundCard *card; - int active; - struct audio_pcm_info info; - int64_t ratio; - void *rate; - int total_hw_samples_acquired; - struct st_sample *buf; - f_sample *clip; - HWVoiceIn *hw; - char *name; - struct mixeng_volume vol; - struct audio_callback callback; - QLIST_ENTRY (SWVoiceIn) entries; -}; - -struct audio_driver { - const char *name; - const char *descr; - struct audio_option *options; - void *(*init) (void); - void (*fini) (void *); - struct audio_pcm_ops *pcm_ops; - int can_be_default; - int max_voices_out; - int max_voices_in; - int voice_size_out; - int voice_size_in; - int ctl_caps; -}; - -struct audio_pcm_ops { - int (*init_out)(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque); - void (*fini_out)(HWVoiceOut *hw); - int (*run_out) (HWVoiceOut *hw, int live); - int (*write) (SWVoiceOut *sw, void *buf, int size); - int (*ctl_out) (HWVoiceOut *hw, int cmd, ...); - - int (*init_in) (HWVoiceIn *hw, struct audsettings *as, void *drv_opaque); - void (*fini_in) (HWVoiceIn *hw); - int (*run_in) (HWVoiceIn *hw); - int (*read) (SWVoiceIn *sw, void *buf, int size); - int (*ctl_in) (HWVoiceIn *hw, int cmd, ...); -}; - -struct capture_callback { - struct audio_capture_ops ops; - void *opaque; - QLIST_ENTRY (capture_callback) entries; -}; - -struct CaptureVoiceOut { - HWVoiceOut hw; - void *buf; - QLIST_HEAD (cb_listhead, capture_callback) cb_head; - QLIST_ENTRY (CaptureVoiceOut) entries; -}; - -struct SWVoiceCap { - SWVoiceOut sw; - CaptureVoiceOut *cap; - QLIST_ENTRY (SWVoiceCap) entries; -}; - -struct AudioState { - struct audio_driver *drv; - void *drv_opaque; - - QEMUTimer *ts; - QLIST_HEAD (card_listhead, QEMUSoundCard) card_head; - QLIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; - QLIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; - QLIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head; - int nb_hw_voices_out; - int nb_hw_voices_in; - int vm_running; -}; - -extern struct audio_driver no_audio_driver; -extern struct audio_driver oss_audio_driver; -extern struct audio_driver sdl_audio_driver; -extern struct audio_driver wav_audio_driver; -extern struct audio_driver alsa_audio_driver; -extern struct audio_driver coreaudio_audio_driver; -extern struct audio_driver dsound_audio_driver; -extern struct audio_driver pa_audio_driver; -extern struct audio_driver spice_audio_driver; -extern const struct mixeng_volume nominal_volume; - -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); - -int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int len); -int audio_pcm_hw_get_live_in (HWVoiceIn *hw); - -int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int len); - -int audio_pcm_hw_clip_out (HWVoiceOut *hw, void *pcm_buf, - int live, int pending); - -int audio_bug (const char *funcname, int cond); -void *audio_calloc (const char *funcname, int nmemb, size_t size); - -void audio_run (const char *msg); - -#define VOICE_ENABLE 1 -#define VOICE_DISABLE 2 -#define VOICE_VOLUME 3 - -#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME) - -static inline int audio_ring_dist (int dst, int src, int len) -{ - return (dst >= src) ? (dst - src) : (len - src + dst); -} - -#define dolog(fmt, ...) AUD_log(AUDIO_CAP, fmt, ## __VA_ARGS__) - -#ifdef DEBUG -#define ldebug(fmt, ...) AUD_log(AUDIO_CAP, fmt, ## __VA_ARGS__) -#else -#define ldebug(fmt, ...) (void)0 -#endif - -#define AUDIO_STRINGIFY_(n) #n -#define AUDIO_STRINGIFY(n) AUDIO_STRINGIFY_(n) - -#if defined _MSC_VER || defined __GNUC__ -#define AUDIO_FUNC __FUNCTION__ -#else -#define AUDIO_FUNC __FILE__ ":" AUDIO_STRINGIFY (__LINE__) -#endif - -#endif /* audio_int.h */ diff --git a/qemu/audio/audio_pt_int.c b/qemu/audio/audio_pt_int.c deleted file mode 100644 index 21ff9c580..000000000 --- a/qemu/audio/audio_pt_int.c +++ /dev/null @@ -1,174 +0,0 @@ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "audio.h" - -#define AUDIO_CAP "audio-pt" - -#include "audio_int.h" -#include "audio_pt_int.h" - -static void GCC_FMT_ATTR(3, 4) logerr (struct audio_pt *pt, int err, - const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (pt->drv, fmt, ap); - va_end (ap); - - AUD_log (NULL, "\n"); - AUD_log (pt->drv, "Reason: %s\n", strerror (err)); -} - -int audio_pt_init (struct audio_pt *p, void *(*func) (void *), - void *opaque, const char *drv, const char *cap) -{ - int err, err2; - const char *efunc; - sigset_t set, old_set; - - p->drv = drv; - - err = sigfillset (&set); - if (err) { - logerr (p, errno, "%s(%s): sigfillset failed", cap, AUDIO_FUNC); - return -1; - } - - err = pthread_mutex_init (&p->mutex, NULL); - if (err) { - efunc = "pthread_mutex_init"; - goto err0; - } - - err = pthread_cond_init (&p->cond, NULL); - if (err) { - efunc = "pthread_cond_init"; - goto err1; - } - - err = pthread_sigmask (SIG_BLOCK, &set, &old_set); - if (err) { - efunc = "pthread_sigmask"; - goto err2; - } - - err = pthread_create (&p->thread, NULL, func, opaque); - - err2 = pthread_sigmask (SIG_SETMASK, &old_set, NULL); - if (err2) { - logerr (p, err2, "%s(%s): pthread_sigmask (restore) failed", - cap, AUDIO_FUNC); - /* We have failed to restore original signal mask, all bets are off, - so terminate the process */ - exit (EXIT_FAILURE); - } - - if (err) { - efunc = "pthread_create"; - goto err2; - } - - return 0; - - err2: - err2 = pthread_cond_destroy (&p->cond); - if (err2) { - logerr (p, err2, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC); - } - - err1: - err2 = pthread_mutex_destroy (&p->mutex); - if (err2) { - logerr (p, err2, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC); - } - - err0: - logerr (p, err, "%s(%s): %s failed", cap, AUDIO_FUNC, efunc); - return -1; -} - -int audio_pt_fini (struct audio_pt *p, const char *cap) -{ - int err, ret = 0; - - err = pthread_cond_destroy (&p->cond); - if (err) { - logerr (p, err, "%s(%s): pthread_cond_destroy failed", cap, AUDIO_FUNC); - ret = -1; - } - - err = pthread_mutex_destroy (&p->mutex); - if (err) { - logerr (p, err, "%s(%s): pthread_mutex_destroy failed", cap, AUDIO_FUNC); - ret = -1; - } - return ret; -} - -int audio_pt_lock (struct audio_pt *p, const char *cap) -{ - int err; - - err = pthread_mutex_lock (&p->mutex); - if (err) { - logerr (p, err, "%s(%s): pthread_mutex_lock failed", cap, AUDIO_FUNC); - return -1; - } - return 0; -} - -int audio_pt_unlock (struct audio_pt *p, const char *cap) -{ - int err; - - err = pthread_mutex_unlock (&p->mutex); - if (err) { - logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC); - return -1; - } - return 0; -} - -int audio_pt_wait (struct audio_pt *p, const char *cap) -{ - int err; - - err = pthread_cond_wait (&p->cond, &p->mutex); - if (err) { - logerr (p, err, "%s(%s): pthread_cond_wait failed", cap, AUDIO_FUNC); - return -1; - } - return 0; -} - -int audio_pt_unlock_and_signal (struct audio_pt *p, const char *cap) -{ - int err; - - err = pthread_mutex_unlock (&p->mutex); - if (err) { - logerr (p, err, "%s(%s): pthread_mutex_unlock failed", cap, AUDIO_FUNC); - return -1; - } - err = pthread_cond_signal (&p->cond); - if (err) { - logerr (p, err, "%s(%s): pthread_cond_signal failed", cap, AUDIO_FUNC); - return -1; - } - return 0; -} - -int audio_pt_join (struct audio_pt *p, void **arg, const char *cap) -{ - int err; - void *ret; - - err = pthread_join (p->thread, &ret); - if (err) { - logerr (p, err, "%s(%s): pthread_join failed", cap, AUDIO_FUNC); - return -1; - } - *arg = ret; - return 0; -} diff --git a/qemu/audio/audio_pt_int.h b/qemu/audio/audio_pt_int.h deleted file mode 100644 index 0dfff76aa..000000000 --- a/qemu/audio/audio_pt_int.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef QEMU_AUDIO_PT_INT_H -#define QEMU_AUDIO_PT_INT_H - -#include <pthread.h> - -struct audio_pt { - const char *drv; - pthread_t thread; - pthread_cond_t cond; - pthread_mutex_t mutex; -}; - -int audio_pt_init (struct audio_pt *, void *(*) (void *), void *, - const char *, const char *); -int audio_pt_fini (struct audio_pt *, const char *); -int audio_pt_lock (struct audio_pt *, const char *); -int audio_pt_unlock (struct audio_pt *, const char *); -int audio_pt_wait (struct audio_pt *, const char *); -int audio_pt_unlock_and_signal (struct audio_pt *, const char *); -int audio_pt_join (struct audio_pt *, void **, const char *); - -#endif /* audio_pt_int.h */ diff --git a/qemu/audio/audio_template.h b/qemu/audio/audio_template.h deleted file mode 100644 index 99b27b285..000000000 --- a/qemu/audio/audio_template.h +++ /dev/null @@ -1,514 +0,0 @@ -/* - * QEMU Audio subsystem header - * - * Copyright (c) 2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifdef DAC -#define NAME "playback" -#define HWBUF hw->mix_buf -#define TYPE out -#define HW HWVoiceOut -#define SW SWVoiceOut -#else -#define NAME "capture" -#define TYPE in -#define HW HWVoiceIn -#define SW SWVoiceIn -#define HWBUF hw->conv_buf -#endif - -static void glue (audio_init_nb_voices_, TYPE) (struct audio_driver *drv) -{ - AudioState *s = &glob_audio_state; - int max_voices = glue (drv->max_voices_, TYPE); - int voice_size = glue (drv->voice_size_, TYPE); - - if (glue (s->nb_hw_voices_, TYPE) > max_voices) { - if (!max_voices) { -#ifdef DAC - dolog ("Driver `%s' does not support " NAME "\n", drv->name); -#endif - } - else { - dolog ("Driver `%s' does not support %d " NAME " voices, max %d\n", - drv->name, - glue (s->nb_hw_voices_, TYPE), - max_voices); - } - glue (s->nb_hw_voices_, TYPE) = max_voices; - } - - if (audio_bug (AUDIO_FUNC, !voice_size && max_voices)) { - dolog ("drv=`%s' voice_size=0 max_voices=%d\n", - drv->name, max_voices); - glue (s->nb_hw_voices_, TYPE) = 0; - } - - if (audio_bug (AUDIO_FUNC, voice_size && !max_voices)) { - dolog ("drv=`%s' voice_size=%d max_voices=0\n", - drv->name, voice_size); - } -} - -static void glue (audio_pcm_hw_free_resources_, TYPE) (HW *hw) -{ - g_free (HWBUF); - HWBUF = NULL; -} - -static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw) -{ - HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (struct st_sample)); - if (!HWBUF) { - dolog ("Could not allocate " NAME " buffer (%d samples)\n", - hw->samples); - return -1; - } - - return 0; -} - -static void glue (audio_pcm_sw_free_resources_, TYPE) (SW *sw) -{ - g_free (sw->buf); - - if (sw->rate) { - st_rate_stop (sw->rate); - } - - sw->buf = NULL; - sw->rate = NULL; -} - -static int glue (audio_pcm_sw_alloc_resources_, TYPE) (SW *sw) -{ - int samples; - - samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; - - sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (struct st_sample)); - if (!sw->buf) { - dolog ("Could not allocate buffer for `%s' (%d samples)\n", - SW_NAME (sw), samples); - return -1; - } - -#ifdef DAC - sw->rate = st_rate_start (sw->info.freq, sw->hw->info.freq); -#else - sw->rate = st_rate_start (sw->hw->info.freq, sw->info.freq); -#endif - if (!sw->rate) { - g_free (sw->buf); - sw->buf = NULL; - return -1; - } - return 0; -} - -static int glue (audio_pcm_sw_init_, TYPE) ( - SW *sw, - HW *hw, - const char *name, - struct audsettings *as - ) -{ - int err; - - audio_pcm_init_info (&sw->info, as); - sw->hw = hw; - sw->active = 0; -#ifdef DAC - sw->ratio = ((int64_t) sw->hw->info.freq << 32) / sw->info.freq; - sw->total_hw_samples_mixed = 0; - sw->empty = 1; -#else - sw->ratio = ((int64_t) sw->info.freq << 32) / sw->hw->info.freq; -#endif - -#ifdef DAC - sw->conv = mixeng_conv -#else - sw->clip = mixeng_clip -#endif - [sw->info.nchannels == 2] - [sw->info.sign] - [sw->info.swap_endianness] - [audio_bits_to_index (sw->info.bits)]; - - sw->name = g_strdup (name); - err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); - if (err) { - g_free (sw->name); - sw->name = NULL; - } - return err; -} - -static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw) -{ - glue (audio_pcm_sw_free_resources_, TYPE) (sw); - g_free (sw->name); - sw->name = NULL; -} - -static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw) -{ - QLIST_INSERT_HEAD (&hw->sw_head, sw, entries); -} - -static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) -{ - QLIST_REMOVE (sw, entries); -} - -static void glue (audio_pcm_hw_gc_, TYPE) (HW **hwp) -{ - AudioState *s = &glob_audio_state; - HW *hw = *hwp; - - if (!hw->sw_head.lh_first) { -#ifdef DAC - audio_detach_capture (hw); -#endif - QLIST_REMOVE (hw, entries); - glue (hw->pcm_ops->fini_, TYPE) (hw); - glue (s->nb_hw_voices_, TYPE) += 1; - glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); - g_free (hw); - *hwp = NULL; - } -} - -static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw) -{ - AudioState *s = &glob_audio_state; - return hw ? hw->entries.le_next : glue (s->hw_head_, TYPE).lh_first; -} - -static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (HW *hw) -{ - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { - if (hw->enabled) { - return hw; - } - } - return NULL; -} - -static HW *glue (audio_pcm_hw_find_specific_, TYPE) ( - HW *hw, - struct audsettings *as - ) -{ - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (hw))) { - if (audio_pcm_info_eq (&hw->info, as)) { - return hw; - } - } - return NULL; -} - -static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) -{ - HW *hw; - AudioState *s = &glob_audio_state; - struct audio_driver *drv = s->drv; - - if (!glue (s->nb_hw_voices_, TYPE)) { - return NULL; - } - - if (audio_bug (AUDIO_FUNC, !drv)) { - dolog ("No host audio driver\n"); - return NULL; - } - - if (audio_bug (AUDIO_FUNC, !drv->pcm_ops)) { - dolog ("Host audio driver without pcm_ops\n"); - return NULL; - } - - hw = audio_calloc (AUDIO_FUNC, 1, glue (drv->voice_size_, TYPE)); - if (!hw) { - dolog ("Can not allocate voice `%s' size %d\n", - drv->name, glue (drv->voice_size_, TYPE)); - return NULL; - } - - hw->pcm_ops = drv->pcm_ops; - hw->ctl_caps = drv->ctl_caps; - - QLIST_INIT (&hw->sw_head); -#ifdef DAC - QLIST_INIT (&hw->cap_head); -#endif - if (glue (hw->pcm_ops->init_, TYPE) (hw, as, s->drv_opaque)) { - goto err0; - } - - if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) { - dolog ("hw->samples=%d\n", hw->samples); - goto err1; - } - -#ifdef DAC - hw->clip = mixeng_clip -#else - hw->conv = mixeng_conv -#endif - [hw->info.nchannels == 2] - [hw->info.sign] - [hw->info.swap_endianness] - [audio_bits_to_index (hw->info.bits)]; - - if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) { - goto err1; - } - - QLIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); - glue (s->nb_hw_voices_, TYPE) -= 1; -#ifdef DAC - audio_attach_capture (hw); -#endif - return hw; - - err1: - glue (hw->pcm_ops->fini_, TYPE) (hw); - err0: - g_free (hw); - return NULL; -} - -static HW *glue (audio_pcm_hw_add_, TYPE) (struct audsettings *as) -{ - HW *hw; - - if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) { - hw = glue (audio_pcm_hw_add_new_, TYPE) (as); - if (hw) { - return hw; - } - } - - hw = glue (audio_pcm_hw_find_specific_, TYPE) (NULL, as); - if (hw) { - return hw; - } - - hw = glue (audio_pcm_hw_add_new_, TYPE) (as); - if (hw) { - return hw; - } - - return glue (audio_pcm_hw_find_any_, TYPE) (NULL); -} - -static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( - const char *sw_name, - struct audsettings *as - ) -{ - SW *sw; - HW *hw; - struct audsettings hw_as; - - if (glue (conf.fixed_, TYPE).enabled) { - hw_as = glue (conf.fixed_, TYPE).settings; - } - else { - hw_as = *as; - } - - sw = audio_calloc (AUDIO_FUNC, 1, sizeof (*sw)); - if (!sw) { - dolog ("Could not allocate soft voice `%s' (%zu bytes)\n", - sw_name ? sw_name : "unknown", sizeof (*sw)); - goto err1; - } - - hw = glue (audio_pcm_hw_add_, TYPE) (&hw_as); - if (!hw) { - goto err2; - } - - glue (audio_pcm_hw_add_sw_, TYPE) (hw, sw); - - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, sw_name, as)) { - goto err3; - } - - return sw; - -err3: - glue (audio_pcm_hw_del_sw_, TYPE) (sw); - glue (audio_pcm_hw_gc_, TYPE) (&hw); -err2: - g_free (sw); -err1: - return NULL; -} - -static void glue (audio_close_, TYPE) (SW *sw) -{ - glue (audio_pcm_sw_fini_, TYPE) (sw); - glue (audio_pcm_hw_del_sw_, TYPE) (sw); - glue (audio_pcm_hw_gc_, TYPE) (&sw->hw); - g_free (sw); -} - -void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw) -{ - if (sw) { - if (audio_bug (AUDIO_FUNC, !card)) { - dolog ("card=%p\n", card); - return; - } - - glue (audio_close_, TYPE) (sw); - } -} - -SW *glue (AUD_open_, TYPE) ( - QEMUSoundCard *card, - SW *sw, - const char *name, - void *callback_opaque , - audio_callback_fn callback_fn, - struct audsettings *as - ) -{ - AudioState *s = &glob_audio_state; - - if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) { - dolog ("card=%p name=%p callback_fn=%p as=%p\n", - card, name, callback_fn, as); - goto fail; - } - - ldebug ("open %s, freq %d, nchannels %d, fmt %d\n", - name, as->freq, as->nchannels, as->fmt); - - if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) { - audio_print_settings (as); - goto fail; - } - - if (audio_bug (AUDIO_FUNC, !s->drv)) { - dolog ("Can not open `%s' (no host audio driver)\n", name); - goto fail; - } - - if (sw && audio_pcm_info_eq (&sw->info, as)) { - return sw; - } - - if (!glue (conf.fixed_, TYPE).enabled && sw) { - glue (AUD_close_, TYPE) (card, sw); - sw = NULL; - } - - if (sw) { - HW *hw = sw->hw; - - if (!hw) { - dolog ("Internal logic error voice `%s' has no hardware store\n", - SW_NAME (sw)); - goto fail; - } - - glue (audio_pcm_sw_fini_, TYPE) (sw); - if (glue (audio_pcm_sw_init_, TYPE) (sw, hw, name, as)) { - goto fail; - } - } - else { - sw = glue (audio_pcm_create_voice_pair_, TYPE) (name, as); - if (!sw) { - dolog ("Failed to create voice `%s'\n", name); - return NULL; - } - } - - sw->card = card; - sw->vol = nominal_volume; - sw->callback.fn = callback_fn; - sw->callback.opaque = callback_opaque; - -#ifdef DEBUG_AUDIO - dolog ("%s\n", name); - audio_pcm_print_info ("hw", &sw->hw->info); - audio_pcm_print_info ("sw", &sw->info); -#endif - - return sw; - - fail: - glue (AUD_close_, TYPE) (card, sw); - return NULL; -} - -int glue (AUD_is_active_, TYPE) (SW *sw) -{ - return sw ? sw->active : 0; -} - -void glue (AUD_init_time_stamp_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) -{ - if (!sw) { - return; - } - - ts->old_ts = sw->hw->ts_helper; -} - -uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts) -{ - uint64_t delta, cur_ts, old_ts; - - if (!sw) { - return 0; - } - - cur_ts = sw->hw->ts_helper; - old_ts = ts->old_ts; - /* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */ - - if (cur_ts >= old_ts) { - delta = cur_ts - old_ts; - } - else { - delta = UINT64_MAX - old_ts + cur_ts; - } - - if (!delta) { - return 0; - } - - return muldiv64 (delta, sw->hw->info.freq, 1000000); -} - -#undef TYPE -#undef HW -#undef SW -#undef HWBUF -#undef NAME diff --git a/qemu/audio/audio_win_int.c b/qemu/audio/audio_win_int.c deleted file mode 100644 index 6900008d0..000000000 --- a/qemu/audio/audio_win_int.c +++ /dev/null @@ -1,108 +0,0 @@ -/* public domain */ - -#include "qemu/osdep.h" -#include "qemu-common.h" - -#define AUDIO_CAP "win-int" -#include <windows.h> -#include <mmsystem.h> - -#include "audio.h" -#include "audio_int.h" -#include "audio_win_int.h" - -int waveformat_from_audio_settings (WAVEFORMATEX *wfx, - struct audsettings *as) -{ - memset (wfx, 0, sizeof (*wfx)); - - wfx->wFormatTag = WAVE_FORMAT_PCM; - wfx->nChannels = as->nchannels; - wfx->nSamplesPerSec = as->freq; - wfx->nAvgBytesPerSec = as->freq << (as->nchannels == 2); - wfx->nBlockAlign = 1 << (as->nchannels == 2); - wfx->cbSize = 0; - - switch (as->fmt) { - case AUD_FMT_S8: - case AUD_FMT_U8: - wfx->wBitsPerSample = 8; - break; - - case AUD_FMT_S16: - case AUD_FMT_U16: - wfx->wBitsPerSample = 16; - wfx->nAvgBytesPerSec <<= 1; - wfx->nBlockAlign <<= 1; - break; - - case AUD_FMT_S32: - case AUD_FMT_U32: - wfx->wBitsPerSample = 32; - wfx->nAvgBytesPerSec <<= 2; - wfx->nBlockAlign <<= 2; - break; - - default: - dolog ("Internal logic error: Bad audio format %d\n", as->freq); - return -1; - } - - return 0; -} - -int waveformat_to_audio_settings (WAVEFORMATEX *wfx, - struct audsettings *as) -{ - if (wfx->wFormatTag != WAVE_FORMAT_PCM) { - dolog ("Invalid wave format, tag is not PCM, but %d\n", - wfx->wFormatTag); - return -1; - } - - if (!wfx->nSamplesPerSec) { - dolog ("Invalid wave format, frequency is zero\n"); - return -1; - } - as->freq = wfx->nSamplesPerSec; - - switch (wfx->nChannels) { - case 1: - as->nchannels = 1; - break; - - case 2: - as->nchannels = 2; - break; - - default: - dolog ( - "Invalid wave format, number of channels is not 1 or 2, but %d\n", - wfx->nChannels - ); - return -1; - } - - switch (wfx->wBitsPerSample) { - case 8: - as->fmt = AUD_FMT_U8; - break; - - case 16: - as->fmt = AUD_FMT_S16; - break; - - case 32: - as->fmt = AUD_FMT_S32; - break; - - default: - dolog ("Invalid wave format, bits per sample is not " - "8, 16 or 32, but %d\n", - wfx->wBitsPerSample); - return -1; - } - - return 0; -} - diff --git a/qemu/audio/audio_win_int.h b/qemu/audio/audio_win_int.h deleted file mode 100644 index fa5b3cb80..000000000 --- a/qemu/audio/audio_win_int.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef AUDIO_WIN_INT_H -#define AUDIO_WIN_INT_H - -int waveformat_from_audio_settings (WAVEFORMATEX *wfx, - struct audsettings *as); - -int waveformat_to_audio_settings (WAVEFORMATEX *wfx, - struct audsettings *as); - -#endif /* AUDIO_WIN_INT_H */ diff --git a/qemu/audio/coreaudio.c b/qemu/audio/coreaudio.c deleted file mode 100644 index d4ad22459..000000000 --- a/qemu/audio/coreaudio.c +++ /dev/null @@ -1,745 +0,0 @@ -/* - * QEMU OS X CoreAudio audio driver - * - * Copyright (c) 2005 Mike Kronenberg - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "qemu/osdep.h" -#include <CoreAudio/CoreAudio.h> -#include <pthread.h> /* pthread_X */ - -#include "qemu-common.h" -#include "audio.h" - -#define AUDIO_CAP "coreaudio" -#include "audio_int.h" - -#ifndef MAC_OS_X_VERSION_10_6 -#define MAC_OS_X_VERSION_10_6 1060 -#endif - -static int isAtexit; - -typedef struct { - int buffer_frames; - int nbuffers; -} CoreaudioConf; - -typedef struct coreaudioVoiceOut { - HWVoiceOut hw; - pthread_mutex_t mutex; - AudioDeviceID outputDeviceID; - UInt32 audioDevicePropertyBufferFrameSize; - AudioStreamBasicDescription outputStreamBasicDescription; - AudioDeviceIOProcID ioprocid; - int live; - int decr; - int rpos; -} coreaudioVoiceOut; - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 -/* The APIs used here only become available from 10.6 */ - -static OSStatus coreaudio_get_voice(AudioDeviceID *id) -{ - UInt32 size = sizeof(*id); - AudioObjectPropertyAddress addr = { - kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster - }; - - return AudioObjectGetPropertyData(kAudioObjectSystemObject, - &addr, - 0, - NULL, - &size, - id); -} - -static OSStatus coreaudio_get_framesizerange(AudioDeviceID id, - AudioValueRange *framerange) -{ - UInt32 size = sizeof(*framerange); - AudioObjectPropertyAddress addr = { - kAudioDevicePropertyBufferFrameSizeRange, - kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster - }; - - return AudioObjectGetPropertyData(id, - &addr, - 0, - NULL, - &size, - framerange); -} - -static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize) -{ - UInt32 size = sizeof(*framesize); - AudioObjectPropertyAddress addr = { - kAudioDevicePropertyBufferFrameSize, - kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster - }; - - return AudioObjectGetPropertyData(id, - &addr, - 0, - NULL, - &size, - framesize); -} - -static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize) -{ - UInt32 size = sizeof(*framesize); - AudioObjectPropertyAddress addr = { - kAudioDevicePropertyBufferFrameSize, - kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster - }; - - return AudioObjectSetPropertyData(id, - &addr, - 0, - NULL, - size, - framesize); -} - -static OSStatus coreaudio_get_streamformat(AudioDeviceID id, - AudioStreamBasicDescription *d) -{ - UInt32 size = sizeof(*d); - AudioObjectPropertyAddress addr = { - kAudioDevicePropertyStreamFormat, - kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster - }; - - return AudioObjectGetPropertyData(id, - &addr, - 0, - NULL, - &size, - d); -} - -static OSStatus coreaudio_set_streamformat(AudioDeviceID id, - AudioStreamBasicDescription *d) -{ - UInt32 size = sizeof(*d); - AudioObjectPropertyAddress addr = { - kAudioDevicePropertyStreamFormat, - kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster - }; - - return AudioObjectSetPropertyData(id, - &addr, - 0, - NULL, - size, - d); -} - -static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result) -{ - UInt32 size = sizeof(*result); - AudioObjectPropertyAddress addr = { - kAudioDevicePropertyDeviceIsRunning, - kAudioDevicePropertyScopeOutput, - kAudioObjectPropertyElementMaster - }; - - return AudioObjectGetPropertyData(id, - &addr, - 0, - NULL, - &size, - result); -} -#else -/* Legacy versions of functions using deprecated APIs */ - -static OSStatus coreaudio_get_voice(AudioDeviceID *id) -{ - UInt32 size = sizeof(*id); - - return AudioHardwareGetProperty( - kAudioHardwarePropertyDefaultOutputDevice, - &size, - id); -} - -static OSStatus coreaudio_get_framesizerange(AudioDeviceID id, - AudioValueRange *framerange) -{ - UInt32 size = sizeof(*framerange); - - return AudioDeviceGetProperty( - id, - 0, - 0, - kAudioDevicePropertyBufferFrameSizeRange, - &size, - framerange); -} - -static OSStatus coreaudio_get_framesize(AudioDeviceID id, UInt32 *framesize) -{ - UInt32 size = sizeof(*framesize); - - return AudioDeviceGetProperty( - id, - 0, - false, - kAudioDevicePropertyBufferFrameSize, - &size, - framesize); -} - -static OSStatus coreaudio_set_framesize(AudioDeviceID id, UInt32 *framesize) -{ - UInt32 size = sizeof(*framesize); - - return AudioDeviceSetProperty( - id, - NULL, - 0, - false, - kAudioDevicePropertyBufferFrameSize, - size, - framesize); -} - -static OSStatus coreaudio_get_streamformat(AudioDeviceID id, - AudioStreamBasicDescription *d) -{ - UInt32 size = sizeof(*d); - - return AudioDeviceGetProperty( - id, - 0, - false, - kAudioDevicePropertyStreamFormat, - &size, - d); -} - -static OSStatus coreaudio_set_streamformat(AudioDeviceID id, - AudioStreamBasicDescription *d) -{ - UInt32 size = sizeof(*d); - - return AudioDeviceSetProperty( - id, - 0, - 0, - 0, - kAudioDevicePropertyStreamFormat, - size, - d); -} - -static OSStatus coreaudio_get_isrunning(AudioDeviceID id, UInt32 *result) -{ - UInt32 size = sizeof(*result); - - return AudioDeviceGetProperty( - id, - 0, - 0, - kAudioDevicePropertyDeviceIsRunning, - &size, - result); -} -#endif - -static void coreaudio_logstatus (OSStatus status) -{ - const char *str = "BUG"; - - switch(status) { - case kAudioHardwareNoError: - str = "kAudioHardwareNoError"; - break; - - case kAudioHardwareNotRunningError: - str = "kAudioHardwareNotRunningError"; - break; - - case kAudioHardwareUnspecifiedError: - str = "kAudioHardwareUnspecifiedError"; - break; - - case kAudioHardwareUnknownPropertyError: - str = "kAudioHardwareUnknownPropertyError"; - break; - - case kAudioHardwareBadPropertySizeError: - str = "kAudioHardwareBadPropertySizeError"; - break; - - case kAudioHardwareIllegalOperationError: - str = "kAudioHardwareIllegalOperationError"; - break; - - case kAudioHardwareBadDeviceError: - str = "kAudioHardwareBadDeviceError"; - break; - - case kAudioHardwareBadStreamError: - str = "kAudioHardwareBadStreamError"; - break; - - case kAudioHardwareUnsupportedOperationError: - str = "kAudioHardwareUnsupportedOperationError"; - break; - - case kAudioDeviceUnsupportedFormatError: - str = "kAudioDeviceUnsupportedFormatError"; - break; - - case kAudioDevicePermissionsError: - str = "kAudioDevicePermissionsError"; - break; - - default: - AUD_log (AUDIO_CAP, "Reason: status code %" PRId32 "\n", (int32_t)status); - return; - } - - AUD_log (AUDIO_CAP, "Reason: %s\n", str); -} - -static void GCC_FMT_ATTR (2, 3) coreaudio_logerr ( - OSStatus status, - const char *fmt, - ... - ) -{ - va_list ap; - - va_start (ap, fmt); - AUD_log (AUDIO_CAP, fmt, ap); - va_end (ap); - - coreaudio_logstatus (status); -} - -static void GCC_FMT_ATTR (3, 4) coreaudio_logerr2 ( - OSStatus status, - const char *typ, - const char *fmt, - ... - ) -{ - va_list ap; - - AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - coreaudio_logstatus (status); -} - -static inline UInt32 isPlaying (AudioDeviceID outputDeviceID) -{ - OSStatus status; - UInt32 result = 0; - status = coreaudio_get_isrunning(outputDeviceID, &result); - if (status != kAudioHardwareNoError) { - coreaudio_logerr(status, - "Could not determine whether Device is playing\n"); - } - return result; -} - -static void coreaudio_atexit (void) -{ - isAtexit = 1; -} - -static int coreaudio_lock (coreaudioVoiceOut *core, const char *fn_name) -{ - int err; - - err = pthread_mutex_lock (&core->mutex); - if (err) { - dolog ("Could not lock voice for %s\nReason: %s\n", - fn_name, strerror (err)); - return -1; - } - return 0; -} - -static int coreaudio_unlock (coreaudioVoiceOut *core, const char *fn_name) -{ - int err; - - err = pthread_mutex_unlock (&core->mutex); - if (err) { - dolog ("Could not unlock voice for %s\nReason: %s\n", - fn_name, strerror (err)); - return -1; - } - return 0; -} - -static int coreaudio_run_out (HWVoiceOut *hw, int live) -{ - int decr; - coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; - - if (coreaudio_lock (core, "coreaudio_run_out")) { - return 0; - } - - if (core->decr > live) { - ldebug ("core->decr %d live %d core->live %d\n", - core->decr, - live, - core->live); - } - - decr = audio_MIN (core->decr, live); - core->decr -= decr; - - core->live = live - decr; - hw->rpos = core->rpos; - - coreaudio_unlock (core, "coreaudio_run_out"); - return decr; -} - -/* callback to feed audiooutput buffer */ -static OSStatus audioDeviceIOProc( - AudioDeviceID inDevice, - const AudioTimeStamp* inNow, - const AudioBufferList* inInputData, - const AudioTimeStamp* inInputTime, - AudioBufferList* outOutputData, - const AudioTimeStamp* inOutputTime, - void* hwptr) -{ - UInt32 frame, frameCount; - float *out = outOutputData->mBuffers[0].mData; - HWVoiceOut *hw = hwptr; - coreaudioVoiceOut *core = (coreaudioVoiceOut *) hwptr; - int rpos, live; - struct st_sample *src; -#ifndef FLOAT_MIXENG -#ifdef RECIPROCAL - const float scale = 1.f / UINT_MAX; -#else - const float scale = UINT_MAX; -#endif -#endif - - if (coreaudio_lock (core, "audioDeviceIOProc")) { - inInputTime = 0; - return 0; - } - - frameCount = core->audioDevicePropertyBufferFrameSize; - live = core->live; - - /* if there are not enough samples, set signal and return */ - if (live < frameCount) { - inInputTime = 0; - coreaudio_unlock (core, "audioDeviceIOProc(empty)"); - return 0; - } - - rpos = core->rpos; - src = hw->mix_buf + rpos; - - /* fill buffer */ - for (frame = 0; frame < frameCount; frame++) { -#ifdef FLOAT_MIXENG - *out++ = src[frame].l; /* left channel */ - *out++ = src[frame].r; /* right channel */ -#else -#ifdef RECIPROCAL - *out++ = src[frame].l * scale; /* left channel */ - *out++ = src[frame].r * scale; /* right channel */ -#else - *out++ = src[frame].l / scale; /* left channel */ - *out++ = src[frame].r / scale; /* right channel */ -#endif -#endif - } - - rpos = (rpos + frameCount) % hw->samples; - core->decr += frameCount; - core->rpos = rpos; - - coreaudio_unlock (core, "audioDeviceIOProc"); - return 0; -} - -static int coreaudio_write (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -static int coreaudio_init_out(HWVoiceOut *hw, struct audsettings *as, - void *drv_opaque) -{ - OSStatus status; - coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; - int err; - const char *typ = "playback"; - AudioValueRange frameRange; - CoreaudioConf *conf = drv_opaque; - - /* create mutex */ - err = pthread_mutex_init(&core->mutex, NULL); - if (err) { - dolog("Could not create mutex\nReason: %s\n", strerror (err)); - return -1; - } - - audio_pcm_init_info (&hw->info, as); - - status = coreaudio_get_voice(&core->outputDeviceID); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not get default output Device\n"); - return -1; - } - if (core->outputDeviceID == kAudioDeviceUnknown) { - dolog ("Could not initialize %s - Unknown Audiodevice\n", typ); - return -1; - } - - /* get minimum and maximum buffer frame sizes */ - status = coreaudio_get_framesizerange(core->outputDeviceID, - &frameRange); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not get device buffer frame range\n"); - return -1; - } - - if (frameRange.mMinimum > conf->buffer_frames) { - core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMinimum; - dolog ("warning: Upsizing Buffer Frames to %f\n", frameRange.mMinimum); - } - else if (frameRange.mMaximum < conf->buffer_frames) { - core->audioDevicePropertyBufferFrameSize = (UInt32) frameRange.mMaximum; - dolog ("warning: Downsizing Buffer Frames to %f\n", frameRange.mMaximum); - } - else { - core->audioDevicePropertyBufferFrameSize = conf->buffer_frames; - } - - /* set Buffer Frame Size */ - status = coreaudio_set_framesize(core->outputDeviceID, - &core->audioDevicePropertyBufferFrameSize); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not set device buffer frame size %" PRIu32 "\n", - (uint32_t)core->audioDevicePropertyBufferFrameSize); - return -1; - } - - /* get Buffer Frame Size */ - status = coreaudio_get_framesize(core->outputDeviceID, - &core->audioDevicePropertyBufferFrameSize); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not get device buffer frame size\n"); - return -1; - } - hw->samples = conf->nbuffers * core->audioDevicePropertyBufferFrameSize; - - /* get StreamFormat */ - status = coreaudio_get_streamformat(core->outputDeviceID, - &core->outputStreamBasicDescription); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not get Device Stream properties\n"); - core->outputDeviceID = kAudioDeviceUnknown; - return -1; - } - - /* set Samplerate */ - core->outputStreamBasicDescription.mSampleRate = (Float64) as->freq; - status = coreaudio_set_streamformat(core->outputDeviceID, - &core->outputStreamBasicDescription); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", - as->freq); - core->outputDeviceID = kAudioDeviceUnknown; - return -1; - } - - /* set Callback */ - core->ioprocid = NULL; - status = AudioDeviceCreateIOProcID(core->outputDeviceID, - audioDeviceIOProc, - hw, - &core->ioprocid); - if (status != kAudioHardwareNoError || core->ioprocid == NULL) { - coreaudio_logerr2 (status, typ, "Could not set IOProc\n"); - core->outputDeviceID = kAudioDeviceUnknown; - return -1; - } - - /* start Playback */ - if (!isPlaying(core->outputDeviceID)) { - status = AudioDeviceStart(core->outputDeviceID, core->ioprocid); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Could not start playback\n"); - AudioDeviceDestroyIOProcID(core->outputDeviceID, core->ioprocid); - core->outputDeviceID = kAudioDeviceUnknown; - return -1; - } - } - - return 0; -} - -static void coreaudio_fini_out (HWVoiceOut *hw) -{ - OSStatus status; - int err; - coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; - - if (!isAtexit) { - /* stop playback */ - if (isPlaying(core->outputDeviceID)) { - status = AudioDeviceStop(core->outputDeviceID, core->ioprocid); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not stop playback\n"); - } - } - - /* remove callback */ - status = AudioDeviceDestroyIOProcID(core->outputDeviceID, - core->ioprocid); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not remove IOProc\n"); - } - } - core->outputDeviceID = kAudioDeviceUnknown; - - /* destroy mutex */ - err = pthread_mutex_destroy(&core->mutex); - if (err) { - dolog("Could not destroy mutex\nReason: %s\n", strerror (err)); - } -} - -static int coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - OSStatus status; - coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw; - - switch (cmd) { - case VOICE_ENABLE: - /* start playback */ - if (!isPlaying(core->outputDeviceID)) { - status = AudioDeviceStart(core->outputDeviceID, core->ioprocid); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not resume playback\n"); - } - } - break; - - case VOICE_DISABLE: - /* stop playback */ - if (!isAtexit) { - if (isPlaying(core->outputDeviceID)) { - status = AudioDeviceStop(core->outputDeviceID, - core->ioprocid); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not pause playback\n"); - } - } - } - break; - } - return 0; -} - -static CoreaudioConf glob_conf = { - .buffer_frames = 512, - .nbuffers = 4, -}; - -static void *coreaudio_audio_init (void) -{ - CoreaudioConf *conf = g_malloc(sizeof(CoreaudioConf)); - *conf = glob_conf; - - atexit(coreaudio_atexit); - return conf; -} - -static void coreaudio_audio_fini (void *opaque) -{ - g_free(opaque); -} - -static struct audio_option coreaudio_options[] = { - { - .name = "BUFFER_SIZE", - .tag = AUD_OPT_INT, - .valp = &glob_conf.buffer_frames, - .descr = "Size of the buffer in frames" - }, - { - .name = "BUFFER_COUNT", - .tag = AUD_OPT_INT, - .valp = &glob_conf.nbuffers, - .descr = "Number of buffers" - }, - { /* End of list */ } -}; - -static struct audio_pcm_ops coreaudio_pcm_ops = { - .init_out = coreaudio_init_out, - .fini_out = coreaudio_fini_out, - .run_out = coreaudio_run_out, - .write = coreaudio_write, - .ctl_out = coreaudio_ctl_out -}; - -struct audio_driver coreaudio_audio_driver = { - .name = "coreaudio", - .descr = "CoreAudio http://developer.apple.com/audio/coreaudio.html", - .options = coreaudio_options, - .init = coreaudio_audio_init, - .fini = coreaudio_audio_fini, - .pcm_ops = &coreaudio_pcm_ops, - .can_be_default = 1, - .max_voices_out = 1, - .max_voices_in = 0, - .voice_size_out = sizeof (coreaudioVoiceOut), - .voice_size_in = 0 -}; diff --git a/qemu/audio/dsound_template.h b/qemu/audio/dsound_template.h deleted file mode 100644 index b439f33f5..000000000 --- a/qemu/audio/dsound_template.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * QEMU DirectSound audio driver header - * - * Copyright (c) 2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifdef DSBTYPE_IN -#define NAME "capture buffer" -#define NAME2 "DirectSoundCapture" -#define TYPE in -#define IFACE IDirectSoundCaptureBuffer -#define BUFPTR LPDIRECTSOUNDCAPTUREBUFFER -#define FIELD dsound_capture_buffer -#define FIELD2 dsound_capture -#else -#define NAME "playback buffer" -#define NAME2 "DirectSound" -#define TYPE out -#define IFACE IDirectSoundBuffer -#define BUFPTR LPDIRECTSOUNDBUFFER -#define FIELD dsound_buffer -#define FIELD2 dsound -#endif - -static int glue (dsound_unlock_, TYPE) ( - BUFPTR buf, - LPVOID p1, - LPVOID p2, - DWORD blen1, - DWORD blen2 - ) -{ - HRESULT hr; - - hr = glue (IFACE, _Unlock) (buf, p1, blen1, p2, blen2); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not unlock " NAME "\n"); - return -1; - } - - return 0; -} - -static int glue (dsound_lock_, TYPE) ( - BUFPTR buf, - struct audio_pcm_info *info, - DWORD pos, - DWORD len, - LPVOID *p1p, - LPVOID *p2p, - DWORD *blen1p, - DWORD *blen2p, - int entire, - dsound *s - ) -{ - HRESULT hr; - LPVOID p1 = NULL, p2 = NULL; - DWORD blen1 = 0, blen2 = 0; - DWORD flag; - -#ifdef DSBTYPE_IN - flag = entire ? DSCBLOCK_ENTIREBUFFER : 0; -#else - flag = entire ? DSBLOCK_ENTIREBUFFER : 0; -#endif - hr = glue(IFACE, _Lock)(buf, pos, len, &p1, &blen1, &p2, &blen2, flag); - - 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; - } -#endif - dsound_logerr (hr, "Could not lock " NAME "\n"); - goto fail; - } - - if ((p1 && (blen1 & info->align)) || (p2 && (blen2 & info->align))) { - dolog ("DirectSound returned misaligned buffer %ld %ld\n", - blen1, blen2); - glue (dsound_unlock_, TYPE) (buf, p1, p2, blen1, blen2); - goto fail; - } - - if (!p1 && blen1) { - dolog ("warning: !p1 && blen1=%ld\n", blen1); - blen1 = 0; - } - - if (!p2 && blen2) { - dolog ("warning: !p2 && blen2=%ld\n", blen2); - blen2 = 0; - } - - *p1p = p1; - *p2p = p2; - *blen1p = blen1; - *blen2p = blen2; - return 0; - - fail: - *p1p = NULL - 1; - *p2p = NULL - 1; - *blen1p = -1; - *blen2p = -1; - return -1; -} - -#ifdef DSBTYPE_IN -static void dsound_fini_in (HWVoiceIn *hw) -#else -static void dsound_fini_out (HWVoiceOut *hw) -#endif -{ - HRESULT hr; -#ifdef DSBTYPE_IN - DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; -#else - DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; -#endif - - if (ds->FIELD) { - hr = glue (IFACE, _Stop) (ds->FIELD); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not stop " NAME "\n"); - } - - hr = glue (IFACE, _Release) (ds->FIELD); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not release " NAME "\n"); - } - ds->FIELD = NULL; - } -} - -#ifdef DSBTYPE_IN -static int dsound_init_in(HWVoiceIn *hw, struct audsettings *as, - void *drv_opaque) -#else -static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as, - void *drv_opaque) -#endif -{ - int err; - HRESULT hr; - 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; -#else - const char *typ = "DAC"; - DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; - DSBUFFERDESC bd; - DSBCAPS bc; -#endif - - if (!s->FIELD2) { - dolog ("Attempt to initialize voice without " NAME2 " object\n"); - return -1; - } - - err = waveformat_from_audio_settings (&wfx, as); - if (err) { - return -1; - } - - memset (&bd, 0, sizeof (bd)); - bd.dwSize = sizeof (bd); - bd.lpwfxFormat = &wfx; -#ifdef DSBTYPE_IN - bd.dwBufferBytes = conf->bufsize_in; - hr = IDirectSoundCapture_CreateCaptureBuffer ( - s->dsound_capture, - &bd, - &ds->dsound_capture_buffer, - NULL - ); -#else - bd.dwFlags = DSBCAPS_STICKYFOCUS | DSBCAPS_GETCURRENTPOSITION2; - bd.dwBufferBytes = conf->bufsize_out; - hr = IDirectSound_CreateSoundBuffer ( - s->dsound, - &bd, - &ds->dsound_buffer, - NULL - ); -#endif - - if (FAILED (hr)) { - dsound_logerr2 (hr, typ, "Could not create " NAME "\n"); - return -1; - } - - hr = glue (IFACE, _GetFormat) (ds->FIELD, &wfx, sizeof (wfx), NULL); - if (FAILED (hr)) { - dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); - goto fail0; - } - -#ifdef DEBUG_DSOUND - dolog (NAME "\n"); - print_wave_format (&wfx); -#endif - - memset (&bc, 0, sizeof (bc)); - bc.dwSize = sizeof (bc); - - hr = glue (IFACE, _GetCaps) (ds->FIELD, &bc); - if (FAILED (hr)) { - dsound_logerr2 (hr, typ, "Could not get " NAME " format\n"); - goto fail0; - } - - err = waveformat_to_audio_settings (&wfx, &obt_as); - if (err) { - goto fail0; - } - - ds->first_time = 1; - obt_as.endianness = 0; - audio_pcm_init_info (&hw->info, &obt_as); - - if (bc.dwBufferBytes & hw->info.align) { - dolog ( - "GetCaps returned misaligned buffer size %ld, alignment %d\n", - bc.dwBufferBytes, hw->info.align + 1 - ); - } - hw->samples = bc.dwBufferBytes >> hw->info.shift; - ds->s = s; - -#ifdef DEBUG_DSOUND - dolog ("caps %ld, desc %ld\n", - bc.dwBufferBytes, bd.dwBufferBytes); - - dolog ("bufsize %d, freq %d, chan %d, fmt %d\n", - hw->bufsize, settings.freq, settings.nchannels, settings.fmt); -#endif - return 0; - - fail0: - glue (dsound_fini_, TYPE) (hw); - return -1; -} - -#undef NAME -#undef NAME2 -#undef TYPE -#undef IFACE -#undef BUFPTR -#undef FIELD -#undef FIELD2 diff --git a/qemu/audio/dsoundaudio.c b/qemu/audio/dsoundaudio.c deleted file mode 100644 index 516846eb8..000000000 --- a/qemu/audio/dsoundaudio.c +++ /dev/null @@ -1,905 +0,0 @@ -/* - * QEMU DirectSound audio driver - * - * Copyright (c) 2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* - * SEAL 1.07 by Carlos 'pel' Hasan was used as documentation - */ - -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "audio.h" - -#define AUDIO_CAP "dsound" -#include "audio_int.h" - -#include <windows.h> -#include <mmsystem.h> -#include <objbase.h> -#include <dsound.h> - -#include "audio_win_int.h" - -/* #define DEBUG_DSOUND */ - -typedef struct { - int bufsize_in; - int bufsize_out; - int latency_millis; -} DSoundConf; - -typedef struct { - LPDIRECTSOUND dsound; - LPDIRECTSOUNDCAPTURE dsound_capture; - struct audsettings settings; - DSoundConf conf; -} dsound; - -typedef struct { - HWVoiceOut hw; - LPDIRECTSOUNDBUFFER dsound_buffer; - DWORD old_pos; - int first_time; - dsound *s; -#ifdef DEBUG_DSOUND - DWORD old_ppos; - DWORD played; - DWORD mixed; -#endif -} DSoundVoiceOut; - -typedef struct { - HWVoiceIn hw; - int first_time; - LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer; - dsound *s; -} DSoundVoiceIn; - -static void dsound_log_hresult (HRESULT hr) -{ - const char *str = "BUG"; - - switch (hr) { - case DS_OK: - str = "The method succeeded"; - break; -#ifdef DS_NO_VIRTUALIZATION - case DS_NO_VIRTUALIZATION: - str = "The buffer was created, but another 3D algorithm was substituted"; - break; -#endif -#ifdef DS_INCOMPLETE - case DS_INCOMPLETE: - str = "The method succeeded, but not all the optional effects were obtained"; - break; -#endif -#ifdef DSERR_ACCESSDENIED - case DSERR_ACCESSDENIED: - str = "The request failed because access was denied"; - break; -#endif -#ifdef DSERR_ALLOCATED - case DSERR_ALLOCATED: - str = "The request failed because resources, such as a priority level, were already in use by another caller"; - break; -#endif -#ifdef DSERR_ALREADYINITIALIZED - case DSERR_ALREADYINITIALIZED: - str = "The object is already initialized"; - break; -#endif -#ifdef DSERR_BADFORMAT - case DSERR_BADFORMAT: - str = "The specified wave format is not supported"; - break; -#endif -#ifdef DSERR_BADSENDBUFFERGUID - case DSERR_BADSENDBUFFERGUID: - str = "The GUID specified in an audiopath file does not match a valid mix-in buffer"; - break; -#endif -#ifdef DSERR_BUFFERLOST - case DSERR_BUFFERLOST: - str = "The buffer memory has been lost and must be restored"; - break; -#endif -#ifdef DSERR_BUFFERTOOSMALL - case DSERR_BUFFERTOOSMALL: - str = "The buffer size is not great enough to enable effects processing"; - break; -#endif -#ifdef DSERR_CONTROLUNAVAIL - case DSERR_CONTROLUNAVAIL: - str = "The buffer control (volume, pan, and so on) requested by the caller is not available. Controls must be specified when the buffer is created, using the dwFlags member of DSBUFFERDESC"; - break; -#endif -#ifdef DSERR_DS8_REQUIRED - case DSERR_DS8_REQUIRED: - str = "A DirectSound object of class CLSID_DirectSound8 or later is required for the requested functionality. For more information, see IDirectSound8 Interface"; - break; -#endif -#ifdef DSERR_FXUNAVAILABLE - case DSERR_FXUNAVAILABLE: - str = "The effects requested could not be found on the system, or they are in the wrong order or in the wrong location; for example, an effect expected in hardware was found in software"; - break; -#endif -#ifdef DSERR_GENERIC - case DSERR_GENERIC : - str = "An undetermined error occurred inside the DirectSound subsystem"; - break; -#endif -#ifdef DSERR_INVALIDCALL - case DSERR_INVALIDCALL: - str = "This function is not valid for the current state of this object"; - break; -#endif -#ifdef DSERR_INVALIDPARAM - case DSERR_INVALIDPARAM: - str = "An invalid parameter was passed to the returning function"; - break; -#endif -#ifdef DSERR_NOAGGREGATION - case DSERR_NOAGGREGATION: - str = "The object does not support aggregation"; - break; -#endif -#ifdef DSERR_NODRIVER - case DSERR_NODRIVER: - str = "No sound driver is available for use, or the given GUID is not a valid DirectSound device ID"; - break; -#endif -#ifdef DSERR_NOINTERFACE - case DSERR_NOINTERFACE: - str = "The requested COM interface is not available"; - break; -#endif -#ifdef DSERR_OBJECTNOTFOUND - case DSERR_OBJECTNOTFOUND: - str = "The requested object was not found"; - break; -#endif -#ifdef DSERR_OTHERAPPHASPRIO - case DSERR_OTHERAPPHASPRIO: - str = "Another application has a higher priority level, preventing this call from succeeding"; - break; -#endif -#ifdef DSERR_OUTOFMEMORY - case DSERR_OUTOFMEMORY: - str = "The DirectSound subsystem could not allocate sufficient memory to complete the caller's request"; - break; -#endif -#ifdef DSERR_PRIOLEVELNEEDED - case DSERR_PRIOLEVELNEEDED: - str = "A cooperative level of DSSCL_PRIORITY or higher is required"; - break; -#endif -#ifdef DSERR_SENDLOOP - case DSERR_SENDLOOP: - str = "A circular loop of send effects was detected"; - break; -#endif -#ifdef DSERR_UNINITIALIZED - case DSERR_UNINITIALIZED: - str = "The Initialize method has not been called or has not been called successfully before other methods were called"; - break; -#endif -#ifdef DSERR_UNSUPPORTED - case DSERR_UNSUPPORTED: - str = "The function called is not supported at this time"; - break; -#endif - default: - AUD_log (AUDIO_CAP, "Reason: Unknown (HRESULT %#lx)\n", hr); - return; - } - - AUD_log (AUDIO_CAP, "Reason: %s\n", str); -} - -static void GCC_FMT_ATTR (2, 3) dsound_logerr ( - HRESULT hr, - const char *fmt, - ... - ) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - dsound_log_hresult (hr); -} - -static void GCC_FMT_ATTR (3, 4) dsound_logerr2 ( - HRESULT hr, - const char *typ, - const char *fmt, - ... - ) -{ - va_list ap; - - AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - dsound_log_hresult (hr); -} - -static DWORD millis_to_bytes (struct audio_pcm_info *info, DWORD millis) -{ - return (millis * info->bytes_per_second) / 1000; -} - -#ifdef DEBUG_DSOUND -static void print_wave_format (WAVEFORMATEX *wfx) -{ - dolog ("tag = %d\n", wfx->wFormatTag); - dolog ("nChannels = %d\n", wfx->nChannels); - dolog ("nSamplesPerSec = %ld\n", wfx->nSamplesPerSec); - dolog ("nAvgBytesPerSec = %ld\n", wfx->nAvgBytesPerSec); - dolog ("nBlockAlign = %d\n", wfx->nBlockAlign); - dolog ("wBitsPerSample = %d\n", wfx->wBitsPerSample); - dolog ("cbSize = %d\n", wfx->cbSize); -} -#endif - -static int dsound_restore_out (LPDIRECTSOUNDBUFFER dsb, dsound *s) -{ - HRESULT hr; - - hr = IDirectSoundBuffer_Restore (dsb); - - if (hr != DS_OK) { - dsound_logerr (hr, "Could not restore playback buffer\n"); - return -1; - } - return 0; -} - -#include "dsound_template.h" -#define DSBTYPE_IN -#include "dsound_template.h" -#undef DSBTYPE_IN - -static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp, - dsound *s) -{ - HRESULT hr; - - hr = IDirectSoundBuffer_GetStatus (dsb, statusp); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not get playback buffer status\n"); - return -1; - } - - if (*statusp & DSERR_BUFFERLOST) { - dsound_restore_out(dsb, s); - return -1; - } - - return 0; -} - -static int dsound_get_status_in (LPDIRECTSOUNDCAPTUREBUFFER dscb, - DWORD *statusp) -{ - HRESULT hr; - - hr = IDirectSoundCaptureBuffer_GetStatus (dscb, statusp); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not get capture buffer status\n"); - return -1; - } - - return 0; -} - -static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len) -{ - int src_len1 = dst_len; - int src_len2 = 0; - int pos = hw->rpos + dst_len; - struct st_sample *src1 = hw->mix_buf + hw->rpos; - struct st_sample *src2 = NULL; - - if (pos > hw->samples) { - src_len1 = hw->samples - hw->rpos; - src2 = hw->mix_buf; - src_len2 = dst_len - src_len1; - pos = src_len2; - } - - if (src_len1) { - hw->clip (dst, src1, src_len1); - } - - if (src_len2) { - dst = advance (dst, src_len1 << hw->info.shift); - hw->clip (dst, src2, src_len2); - } - - hw->rpos = pos % hw->samples; -} - -static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb, - dsound *s) -{ - int err; - LPVOID p1, p2; - DWORD blen1, blen2, len1, len2; - - err = dsound_lock_out ( - dsb, - &hw->info, - 0, - hw->samples << hw->info.shift, - &p1, &p2, - &blen1, &blen2, - 1, - s - ); - if (err) { - return; - } - - len1 = blen1 >> hw->info.shift; - len2 = blen2 >> hw->info.shift; - -#ifdef DEBUG_DSOUND - dolog ("clear %p,%ld,%ld %p,%ld,%ld\n", - p1, blen1, len1, - p2, blen2, len2); -#endif - - if (p1 && len1) { - audio_pcm_info_clear_buf (&hw->info, p1, len1); - } - - if (p2 && len2) { - audio_pcm_info_clear_buf (&hw->info, p2, len2); - } - - dsound_unlock_out (dsb, p1, p2, blen1, blen2); -} - -static int dsound_open (dsound *s) -{ - HRESULT hr; - HWND hwnd; - - hwnd = GetForegroundWindow (); - hr = IDirectSound_SetCooperativeLevel ( - s->dsound, - hwnd, - DSSCL_PRIORITY - ); - - if (FAILED (hr)) { - dsound_logerr (hr, "Could not set cooperative level for window %p\n", - hwnd); - return -1; - } - - return 0; -} - -static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - HRESULT hr; - DWORD status; - DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; - LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer; - dsound *s = ds->s; - - if (!dsb) { - dolog ("Attempt to control voice without a buffer\n"); - return 0; - } - - switch (cmd) { - case VOICE_ENABLE: - if (dsound_get_status_out (dsb, &status, s)) { - return -1; - } - - if (status & DSBSTATUS_PLAYING) { - dolog ("warning: Voice is already playing\n"); - return 0; - } - - dsound_clear_sample (hw, dsb, s); - - hr = IDirectSoundBuffer_Play (dsb, 0, 0, DSBPLAY_LOOPING); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not start playing buffer\n"); - return -1; - } - break; - - case VOICE_DISABLE: - if (dsound_get_status_out (dsb, &status, s)) { - return -1; - } - - if (status & DSBSTATUS_PLAYING) { - hr = IDirectSoundBuffer_Stop (dsb); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not stop playing buffer\n"); - return -1; - } - } - else { - dolog ("warning: Voice is not playing\n"); - } - break; - } - return 0; -} - -static int dsound_write (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -static int dsound_run_out (HWVoiceOut *hw, int live) -{ - int err; - HRESULT hr; - DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; - LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer; - int len, hwshift; - DWORD blen1, blen2; - DWORD len1, len2; - DWORD decr; - DWORD wpos, ppos, old_pos; - LPVOID p1, p2; - int bufsize; - dsound *s = ds->s; - DSoundConf *conf = &s->conf; - - if (!dsb) { - dolog ("Attempt to run empty with playback buffer\n"); - return 0; - } - - hwshift = hw->info.shift; - bufsize = hw->samples << hwshift; - - hr = IDirectSoundBuffer_GetCurrentPosition ( - dsb, - &ppos, - ds->first_time ? &wpos : NULL - ); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not get playback buffer position\n"); - return 0; - } - - len = live << hwshift; - - if (ds->first_time) { - if (conf->latency_millis) { - DWORD cur_blat; - - cur_blat = audio_ring_dist (wpos, ppos, bufsize); - ds->first_time = 0; - old_pos = wpos; - old_pos += - millis_to_bytes (&hw->info, conf->latency_millis) - cur_blat; - old_pos %= bufsize; - old_pos &= ~hw->info.align; - } - else { - old_pos = wpos; - } -#ifdef DEBUG_DSOUND - ds->played = 0; - ds->mixed = 0; -#endif - } - else { - if (ds->old_pos == ppos) { -#ifdef DEBUG_DSOUND - dolog ("old_pos == ppos\n"); -#endif - return 0; - } - -#ifdef DEBUG_DSOUND - ds->played += audio_ring_dist (ds->old_pos, ppos, hw->bufsize); -#endif - old_pos = ds->old_pos; - } - - if ((old_pos < ppos) && ((old_pos + len) > ppos)) { - len = ppos - old_pos; - } - else { - if ((old_pos > ppos) && ((old_pos + len) > (ppos + bufsize))) { - len = bufsize - old_pos + ppos; - } - } - - if (audio_bug (AUDIO_FUNC, len < 0 || len > bufsize)) { - dolog ("len=%d bufsize=%d old_pos=%ld ppos=%ld\n", - len, bufsize, old_pos, ppos); - return 0; - } - - len &= ~hw->info.align; - if (!len) { - return 0; - } - -#ifdef DEBUG_DSOUND - ds->old_ppos = ppos; -#endif - err = dsound_lock_out ( - dsb, - &hw->info, - old_pos, - len, - &p1, &p2, - &blen1, &blen2, - 0, - s - ); - if (err) { - return 0; - } - - len1 = blen1 >> hwshift; - len2 = blen2 >> hwshift; - decr = len1 + len2; - - if (p1 && len1) { - dsound_write_sample (hw, p1, len1); - } - - if (p2 && len2) { - dsound_write_sample (hw, p2, len2); - } - - dsound_unlock_out (dsb, p1, p2, blen1, blen2); - ds->old_pos = (old_pos + (decr << hwshift)) % bufsize; - -#ifdef DEBUG_DSOUND - ds->mixed += decr << hwshift; - - dolog ("played %lu mixed %lu diff %ld sec %f\n", - ds->played, - ds->mixed, - ds->mixed - ds->played, - abs (ds->mixed - ds->played) / (double) hw->info.bytes_per_second); -#endif - return decr; -} - -static int dsound_ctl_in (HWVoiceIn *hw, int cmd, ...) -{ - HRESULT hr; - DWORD status; - DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; - LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer; - - if (!dscb) { - dolog ("Attempt to control capture voice without a buffer\n"); - return -1; - } - - switch (cmd) { - case VOICE_ENABLE: - if (dsound_get_status_in (dscb, &status)) { - return -1; - } - - if (status & DSCBSTATUS_CAPTURING) { - dolog ("warning: Voice is already capturing\n"); - return 0; - } - - /* clear ?? */ - - hr = IDirectSoundCaptureBuffer_Start (dscb, DSCBSTART_LOOPING); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not start capturing\n"); - return -1; - } - break; - - case VOICE_DISABLE: - if (dsound_get_status_in (dscb, &status)) { - return -1; - } - - if (status & DSCBSTATUS_CAPTURING) { - hr = IDirectSoundCaptureBuffer_Stop (dscb); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not stop capturing\n"); - return -1; - } - } - else { - dolog ("warning: Voice is not capturing\n"); - } - break; - } - return 0; -} - -static int dsound_read (SWVoiceIn *sw, void *buf, int len) -{ - return audio_pcm_sw_read (sw, buf, len); -} - -static int dsound_run_in (HWVoiceIn *hw) -{ - int err; - HRESULT hr; - DSoundVoiceIn *ds = (DSoundVoiceIn *) hw; - LPDIRECTSOUNDCAPTUREBUFFER dscb = ds->dsound_capture_buffer; - int live, len, dead; - DWORD blen1, blen2; - DWORD len1, len2; - DWORD decr; - DWORD cpos, rpos; - LPVOID p1, p2; - int hwshift; - dsound *s = ds->s; - - if (!dscb) { - dolog ("Attempt to run without capture buffer\n"); - return 0; - } - - hwshift = hw->info.shift; - - live = audio_pcm_hw_get_live_in (hw); - dead = hw->samples - live; - if (!dead) { - return 0; - } - - hr = IDirectSoundCaptureBuffer_GetCurrentPosition ( - dscb, - &cpos, - ds->first_time ? &rpos : NULL - ); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not get capture buffer position\n"); - return 0; - } - - if (ds->first_time) { - ds->first_time = 0; - if (rpos & hw->info.align) { - ldebug ("warning: Misaligned capture read position %ld(%d)\n", - rpos, hw->info.align); - } - hw->wpos = rpos >> hwshift; - } - - if (cpos & hw->info.align) { - ldebug ("warning: Misaligned capture position %ld(%d)\n", - cpos, hw->info.align); - } - cpos >>= hwshift; - - len = audio_ring_dist (cpos, hw->wpos, hw->samples); - if (!len) { - return 0; - } - len = audio_MIN (len, dead); - - err = dsound_lock_in ( - dscb, - &hw->info, - hw->wpos << hwshift, - len << hwshift, - &p1, - &p2, - &blen1, - &blen2, - 0, - s - ); - if (err) { - return 0; - } - - len1 = blen1 >> hwshift; - len2 = blen2 >> hwshift; - decr = len1 + len2; - - if (p1 && len1) { - hw->conv (hw->conv_buf + hw->wpos, p1, len1); - } - - if (p2 && len2) { - hw->conv (hw->conv_buf, p2, len2); - } - - dsound_unlock_in (dscb, p1, p2, blen1, blen2); - hw->wpos = (hw->wpos + decr) % hw->samples; - return decr; -} - -static DSoundConf glob_conf = { - .bufsize_in = 16384, - .bufsize_out = 16384, - .latency_millis = 10 -}; - -static void dsound_audio_fini (void *opaque) -{ - HRESULT hr; - dsound *s = opaque; - - if (!s->dsound) { - g_free(s); - return; - } - - hr = IDirectSound_Release (s->dsound); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not release DirectSound\n"); - } - s->dsound = NULL; - - if (!s->dsound_capture) { - g_free(s); - return; - } - - hr = IDirectSoundCapture_Release (s->dsound_capture); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not release DirectSoundCapture\n"); - } - s->dsound_capture = NULL; - - g_free(s); -} - -static void *dsound_audio_init (void) -{ - int err; - HRESULT hr; - dsound *s = g_malloc0(sizeof(dsound)); - - s->conf = glob_conf; - hr = CoInitialize (NULL); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not initialize COM\n"); - g_free(s); - return NULL; - } - - hr = CoCreateInstance ( - &CLSID_DirectSound, - NULL, - CLSCTX_ALL, - &IID_IDirectSound, - (void **) &s->dsound - ); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not create DirectSound instance\n"); - g_free(s); - return NULL; - } - - hr = IDirectSound_Initialize (s->dsound, NULL); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not initialize DirectSound\n"); - - hr = IDirectSound_Release (s->dsound); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not release DirectSound\n"); - } - g_free(s); - return NULL; - } - - hr = CoCreateInstance ( - &CLSID_DirectSoundCapture, - NULL, - CLSCTX_ALL, - &IID_IDirectSoundCapture, - (void **) &s->dsound_capture - ); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not create DirectSoundCapture instance\n"); - } - else { - hr = IDirectSoundCapture_Initialize (s->dsound_capture, NULL); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not initialize DirectSoundCapture\n"); - - hr = IDirectSoundCapture_Release (s->dsound_capture); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not release DirectSoundCapture\n"); - } - s->dsound_capture = NULL; - } - } - - err = dsound_open (s); - if (err) { - dsound_audio_fini (s); - return NULL; - } - - return s; -} - -static struct audio_option dsound_options[] = { - { - .name = "LATENCY_MILLIS", - .tag = AUD_OPT_INT, - .valp = &glob_conf.latency_millis, - .descr = "(undocumented)" - }, - { - .name = "BUFSIZE_OUT", - .tag = AUD_OPT_INT, - .valp = &glob_conf.bufsize_out, - .descr = "(undocumented)" - }, - { - .name = "BUFSIZE_IN", - .tag = AUD_OPT_INT, - .valp = &glob_conf.bufsize_in, - .descr = "(undocumented)" - }, - { /* End of list */ } -}; - -static struct audio_pcm_ops dsound_pcm_ops = { - .init_out = dsound_init_out, - .fini_out = dsound_fini_out, - .run_out = dsound_run_out, - .write = dsound_write, - .ctl_out = dsound_ctl_out, - - .init_in = dsound_init_in, - .fini_in = dsound_fini_in, - .run_in = dsound_run_in, - .read = dsound_read, - .ctl_in = dsound_ctl_in -}; - -struct audio_driver dsound_audio_driver = { - .name = "dsound", - .descr = "DirectSound http://wikipedia.org/wiki/DirectSound", - .options = dsound_options, - .init = dsound_audio_init, - .fini = dsound_audio_fini, - .pcm_ops = &dsound_pcm_ops, - .can_be_default = 1, - .max_voices_out = INT_MAX, - .max_voices_in = 1, - .voice_size_out = sizeof (DSoundVoiceOut), - .voice_size_in = sizeof (DSoundVoiceIn) -}; diff --git a/qemu/audio/mixeng.c b/qemu/audio/mixeng.c deleted file mode 100644 index 981b97a96..000000000 --- a/qemu/audio/mixeng.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * QEMU Mixing engine - * - * Copyright (c) 2004-2005 Vassili Karpov (malc) - * Copyright (c) 1998 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "audio.h" - -#define AUDIO_CAP "mixeng" -#include "audio_int.h" - -/* 8 bit */ -#define ENDIAN_CONVERSION natural -#define ENDIAN_CONVERT(v) (v) - -/* Signed 8 bit */ -#define BSIZE 8 -#define ITYPE int -#define IN_MIN SCHAR_MIN -#define IN_MAX SCHAR_MAX -#define SIGNED -#define SHIFT 8 -#include "mixeng_template.h" -#undef SIGNED -#undef IN_MAX -#undef IN_MIN -#undef BSIZE -#undef ITYPE -#undef SHIFT - -/* Unsigned 8 bit */ -#define BSIZE 8 -#define ITYPE uint -#define IN_MIN 0 -#define IN_MAX UCHAR_MAX -#define SHIFT 8 -#include "mixeng_template.h" -#undef IN_MAX -#undef IN_MIN -#undef BSIZE -#undef ITYPE -#undef SHIFT - -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION - -/* Signed 16 bit */ -#define BSIZE 16 -#define ITYPE int -#define IN_MIN SHRT_MIN -#define IN_MAX SHRT_MAX -#define SIGNED -#define SHIFT 16 -#define ENDIAN_CONVERSION natural -#define ENDIAN_CONVERT(v) (v) -#include "mixeng_template.h" -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION -#define ENDIAN_CONVERSION swap -#define ENDIAN_CONVERT(v) bswap16 (v) -#include "mixeng_template.h" -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION -#undef SIGNED -#undef IN_MAX -#undef IN_MIN -#undef BSIZE -#undef ITYPE -#undef SHIFT - -/* Unsigned 16 bit */ -#define BSIZE 16 -#define ITYPE uint -#define IN_MIN 0 -#define IN_MAX USHRT_MAX -#define SHIFT 16 -#define ENDIAN_CONVERSION natural -#define ENDIAN_CONVERT(v) (v) -#include "mixeng_template.h" -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION -#define ENDIAN_CONVERSION swap -#define ENDIAN_CONVERT(v) bswap16 (v) -#include "mixeng_template.h" -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION -#undef IN_MAX -#undef IN_MIN -#undef BSIZE -#undef ITYPE -#undef SHIFT - -/* Signed 32 bit */ -#define BSIZE 32 -#define ITYPE int -#define IN_MIN INT32_MIN -#define IN_MAX INT32_MAX -#define SIGNED -#define SHIFT 32 -#define ENDIAN_CONVERSION natural -#define ENDIAN_CONVERT(v) (v) -#include "mixeng_template.h" -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION -#define ENDIAN_CONVERSION swap -#define ENDIAN_CONVERT(v) bswap32 (v) -#include "mixeng_template.h" -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION -#undef SIGNED -#undef IN_MAX -#undef IN_MIN -#undef BSIZE -#undef ITYPE -#undef SHIFT - -/* Unsigned 32 bit */ -#define BSIZE 32 -#define ITYPE uint -#define IN_MIN 0 -#define IN_MAX UINT32_MAX -#define SHIFT 32 -#define ENDIAN_CONVERSION natural -#define ENDIAN_CONVERT(v) (v) -#include "mixeng_template.h" -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION -#define ENDIAN_CONVERSION swap -#define ENDIAN_CONVERT(v) bswap32 (v) -#include "mixeng_template.h" -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION -#undef IN_MAX -#undef IN_MIN -#undef BSIZE -#undef ITYPE -#undef SHIFT - -t_sample *mixeng_conv[2][2][2][3] = { - { - { - { - conv_natural_uint8_t_to_mono, - conv_natural_uint16_t_to_mono, - conv_natural_uint32_t_to_mono - }, - { - conv_natural_uint8_t_to_mono, - conv_swap_uint16_t_to_mono, - conv_swap_uint32_t_to_mono, - } - }, - { - { - conv_natural_int8_t_to_mono, - conv_natural_int16_t_to_mono, - conv_natural_int32_t_to_mono - }, - { - conv_natural_int8_t_to_mono, - conv_swap_int16_t_to_mono, - conv_swap_int32_t_to_mono - } - } - }, - { - { - { - conv_natural_uint8_t_to_stereo, - conv_natural_uint16_t_to_stereo, - conv_natural_uint32_t_to_stereo - }, - { - conv_natural_uint8_t_to_stereo, - conv_swap_uint16_t_to_stereo, - conv_swap_uint32_t_to_stereo - } - }, - { - { - conv_natural_int8_t_to_stereo, - conv_natural_int16_t_to_stereo, - conv_natural_int32_t_to_stereo - }, - { - conv_natural_int8_t_to_stereo, - conv_swap_int16_t_to_stereo, - conv_swap_int32_t_to_stereo, - } - } - } -}; - -f_sample *mixeng_clip[2][2][2][3] = { - { - { - { - clip_natural_uint8_t_from_mono, - clip_natural_uint16_t_from_mono, - clip_natural_uint32_t_from_mono - }, - { - clip_natural_uint8_t_from_mono, - clip_swap_uint16_t_from_mono, - clip_swap_uint32_t_from_mono - } - }, - { - { - clip_natural_int8_t_from_mono, - clip_natural_int16_t_from_mono, - clip_natural_int32_t_from_mono - }, - { - clip_natural_int8_t_from_mono, - clip_swap_int16_t_from_mono, - clip_swap_int32_t_from_mono - } - } - }, - { - { - { - clip_natural_uint8_t_from_stereo, - clip_natural_uint16_t_from_stereo, - clip_natural_uint32_t_from_stereo - }, - { - clip_natural_uint8_t_from_stereo, - clip_swap_uint16_t_from_stereo, - clip_swap_uint32_t_from_stereo - } - }, - { - { - clip_natural_int8_t_from_stereo, - clip_natural_int16_t_from_stereo, - clip_natural_int32_t_from_stereo - }, - { - clip_natural_int8_t_from_stereo, - clip_swap_int16_t_from_stereo, - clip_swap_int32_t_from_stereo - } - } - } -}; - -/* - * August 21, 1998 - * Copyright 1998 Fabrice Bellard. - * - * [Rewrote completly the code of Lance Norskog And Sundry - * Contributors with a more efficient algorithm.] - * - * This source code is freely redistributable and may be used for - * any purpose. This copyright notice must be maintained. - * Lance Norskog And Sundry Contributors are not responsible for - * the consequences of using this software. - */ - -/* - * Sound Tools rate change effect file. - */ -/* - * Linear Interpolation. - * - * The use of fractional increment allows us to use no buffer. It - * avoid the problems at the end of the buffer we had with the old - * method which stored a possibly big buffer of size - * lcm(in_rate,out_rate). - * - * Limited to 16 bit samples and sampling frequency <= 65535 Hz. If - * the input & output frequencies are equal, a delay of one sample is - * introduced. Limited to processing 32-bit count worth of samples. - * - * 1 << FRAC_BITS evaluating to zero in several places. Changed with - * an (unsigned long) cast to make it safe. MarkMLl 2/1/99 - */ - -/* Private data */ -struct rate { - uint64_t opos; - uint64_t opos_inc; - uint32_t ipos; /* position in the input stream (integer) */ - struct st_sample ilast; /* last sample in the input stream */ -}; - -/* - * Prepare processing. - */ -void *st_rate_start (int inrate, int outrate) -{ - struct rate *rate = audio_calloc (AUDIO_FUNC, 1, sizeof (*rate)); - - if (!rate) { - dolog ("Could not allocate resampler (%zu bytes)\n", sizeof (*rate)); - return NULL; - } - - rate->opos = 0; - - /* increment */ - rate->opos_inc = ((uint64_t) inrate << 32) / outrate; - - rate->ipos = 0; - rate->ilast.l = 0; - rate->ilast.r = 0; - return rate; -} - -#define NAME st_rate_flow_mix -#define OP(a, b) a += b -#include "rate_template.h" - -#define NAME st_rate_flow -#define OP(a, b) a = b -#include "rate_template.h" - -void st_rate_stop (void *opaque) -{ - g_free (opaque); -} - -void mixeng_clear (struct st_sample *buf, int len) -{ - memset (buf, 0, len * sizeof (struct st_sample)); -} - -void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol) -{ - if (vol->mute) { - mixeng_clear (buf, len); - return; - } - - while (len--) { -#ifdef FLOAT_MIXENG - buf->l = buf->l * vol->l; - buf->r = buf->r * vol->r; -#else - buf->l = (buf->l * vol->l) >> 32; - buf->r = (buf->r * vol->r) >> 32; -#endif - buf += 1; - } -} diff --git a/qemu/audio/mixeng.h b/qemu/audio/mixeng.h deleted file mode 100644 index 9de443b01..000000000 --- a/qemu/audio/mixeng.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * QEMU Mixing engine header - * - * Copyright (c) 2004-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef QEMU_MIXENG_H -#define QEMU_MIXENG_H - -#ifdef FLOAT_MIXENG -typedef float mixeng_real; -struct mixeng_volume { int mute; mixeng_real r; mixeng_real l; }; -struct st_sample { mixeng_real l; mixeng_real r; }; -#else -struct mixeng_volume { int mute; int64_t r; int64_t l; }; -struct st_sample { int64_t l; int64_t r; }; -#endif - -typedef void (t_sample) (struct st_sample *dst, const void *src, int samples); -typedef void (f_sample) (void *dst, const struct st_sample *src, int samples); - -extern t_sample *mixeng_conv[2][2][2][3]; -extern f_sample *mixeng_clip[2][2][2][3]; - -void *st_rate_start (int inrate, int outrate); -void st_rate_flow (void *opaque, struct st_sample *ibuf, struct st_sample *obuf, - int *isamp, int *osamp); -void st_rate_flow_mix (void *opaque, struct st_sample *ibuf, struct st_sample *obuf, - int *isamp, int *osamp); -void st_rate_stop (void *opaque); -void mixeng_clear (struct st_sample *buf, int len); -void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol); - -#endif /* mixeng.h */ diff --git a/qemu/audio/mixeng_template.h b/qemu/audio/mixeng_template.h deleted file mode 100644 index 77cc89b9e..000000000 --- a/qemu/audio/mixeng_template.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * QEMU Mixing engine - * - * Copyright (c) 2004-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* - * Tusen tack till Mike Nordell - * dec++'ified by Dscho - */ - -#ifndef SIGNED -#define HALF (IN_MAX >> 1) -#endif - -#define ET glue (ENDIAN_CONVERSION, glue (glue (glue (_, ITYPE), BSIZE), _t)) -#define IN_T glue (glue (ITYPE, BSIZE), _t) - -#ifdef FLOAT_MIXENG -static inline mixeng_real glue (conv_, ET) (IN_T v) -{ - IN_T nv = ENDIAN_CONVERT (v); - -#ifdef RECIPROCAL -#ifdef SIGNED - return nv * (1.f / (mixeng_real) (IN_MAX - IN_MIN)); -#else - return (nv - HALF) * (1.f / (mixeng_real) IN_MAX); -#endif -#else /* !RECIPROCAL */ -#ifdef SIGNED - return nv / (mixeng_real) ((mixeng_real) IN_MAX - IN_MIN); -#else - return (nv - HALF) / (mixeng_real) IN_MAX; -#endif -#endif -} - -static inline IN_T glue (clip_, ET) (mixeng_real v) -{ - if (v >= 0.5) { - return IN_MAX; - } - else if (v < -0.5) { - return IN_MIN; - } - -#ifdef SIGNED - return ENDIAN_CONVERT ((IN_T) (v * ((mixeng_real) IN_MAX - IN_MIN))); -#else - return ENDIAN_CONVERT ((IN_T) ((v * IN_MAX) + HALF)); -#endif -} - -#else /* !FLOAT_MIXENG */ - -static inline int64_t glue (conv_, ET) (IN_T v) -{ - IN_T nv = ENDIAN_CONVERT (v); -#ifdef SIGNED - return ((int64_t) nv) << (32 - SHIFT); -#else - return ((int64_t) nv - HALF) << (32 - SHIFT); -#endif -} - -static inline IN_T glue (clip_, ET) (int64_t v) -{ - if (v >= 0x7f000000) { - return IN_MAX; - } - else if (v < -2147483648LL) { - return IN_MIN; - } - -#ifdef SIGNED - return ENDIAN_CONVERT ((IN_T) (v >> (32 - SHIFT))); -#else - return ENDIAN_CONVERT ((IN_T) ((v >> (32 - SHIFT)) + HALF)); -#endif -} -#endif - -static void glue (glue (conv_, ET), _to_stereo) - (struct st_sample *dst, const void *src, int samples) -{ - struct st_sample *out = dst; - IN_T *in = (IN_T *) src; - - while (samples--) { - out->l = glue (conv_, ET) (*in++); - out->r = glue (conv_, ET) (*in++); - out += 1; - } -} - -static void glue (glue (conv_, ET), _to_mono) - (struct st_sample *dst, const void *src, int samples) -{ - struct st_sample *out = dst; - IN_T *in = (IN_T *) src; - - while (samples--) { - out->l = glue (conv_, ET) (in[0]); - out->r = out->l; - out += 1; - in += 1; - } -} - -static void glue (glue (clip_, ET), _from_stereo) - (void *dst, const struct st_sample *src, int samples) -{ - const struct st_sample *in = src; - IN_T *out = (IN_T *) dst; - while (samples--) { - *out++ = glue (clip_, ET) (in->l); - *out++ = glue (clip_, ET) (in->r); - in += 1; - } -} - -static void glue (glue (clip_, ET), _from_mono) - (void *dst, const struct st_sample *src, int samples) -{ - const struct st_sample *in = src; - IN_T *out = (IN_T *) dst; - while (samples--) { - *out++ = glue (clip_, ET) (in->l + in->r); - in += 1; - } -} - -#undef ET -#undef HALF -#undef IN_T diff --git a/qemu/audio/noaudio.c b/qemu/audio/noaudio.c deleted file mode 100644 index b360c199a..000000000 --- a/qemu/audio/noaudio.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * QEMU Timer based audio emulation - * - * Copyright (c) 2004-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "audio.h" -#include "qemu/timer.h" - -#define AUDIO_CAP "noaudio" -#include "audio_int.h" - -typedef struct NoVoiceOut { - HWVoiceOut hw; - int64_t old_ticks; -} NoVoiceOut; - -typedef struct NoVoiceIn { - HWVoiceIn hw; - int64_t old_ticks; -} NoVoiceIn; - -static int no_run_out (HWVoiceOut *hw, int live) -{ - NoVoiceOut *no = (NoVoiceOut *) hw; - int decr, samples; - int64_t now; - int64_t ticks; - int64_t bytes; - - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ticks = now - no->old_ticks; - bytes = muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND); - bytes = audio_MIN(bytes, INT_MAX); - samples = bytes >> hw->info.shift; - - no->old_ticks = now; - decr = audio_MIN (live, samples); - hw->rpos = (hw->rpos + decr) % hw->samples; - return decr; -} - -static int no_write (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write(sw, buf, len); -} - -static int no_init_out(HWVoiceOut *hw, struct audsettings *as, void *drv_opaque) -{ - audio_pcm_init_info (&hw->info, as); - hw->samples = 1024; - return 0; -} - -static void no_fini_out (HWVoiceOut *hw) -{ - (void) hw; -} - -static int no_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - -static int no_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) -{ - audio_pcm_init_info (&hw->info, as); - hw->samples = 1024; - return 0; -} - -static void no_fini_in (HWVoiceIn *hw) -{ - (void) hw; -} - -static int no_run_in (HWVoiceIn *hw) -{ - NoVoiceIn *no = (NoVoiceIn *) hw; - int live = audio_pcm_hw_get_live_in (hw); - int dead = hw->samples - live; - int samples = 0; - - if (dead) { - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int64_t ticks = now - no->old_ticks; - int64_t bytes = - muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND); - - no->old_ticks = now; - bytes = audio_MIN (bytes, INT_MAX); - samples = bytes >> hw->info.shift; - samples = audio_MIN (samples, dead); - } - return samples; -} - -static int no_read (SWVoiceIn *sw, void *buf, int size) -{ - /* use custom code here instead of audio_pcm_sw_read() to avoid - * useless resampling/mixing */ - int samples = size >> sw->info.shift; - int total = sw->hw->total_samples_captured - sw->total_hw_samples_acquired; - int to_clear = audio_MIN (samples, total); - sw->total_hw_samples_acquired += total; - audio_pcm_info_clear_buf (&sw->info, buf, to_clear); - return to_clear << sw->info.shift; -} - -static int no_ctl_in (HWVoiceIn *hw, int cmd, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - -static void *no_audio_init (void) -{ - return &no_audio_init; -} - -static void no_audio_fini (void *opaque) -{ - (void) opaque; -} - -static struct audio_pcm_ops no_pcm_ops = { - .init_out = no_init_out, - .fini_out = no_fini_out, - .run_out = no_run_out, - .write = no_write, - .ctl_out = no_ctl_out, - - .init_in = no_init_in, - .fini_in = no_fini_in, - .run_in = no_run_in, - .read = no_read, - .ctl_in = no_ctl_in -}; - -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, - .can_be_default = 1, - .max_voices_out = INT_MAX, - .max_voices_in = INT_MAX, - .voice_size_out = sizeof (NoVoiceOut), - .voice_size_in = sizeof (NoVoiceIn) -}; diff --git a/qemu/audio/ossaudio.c b/qemu/audio/ossaudio.c deleted file mode 100644 index 349e9dd53..000000000 --- a/qemu/audio/ossaudio.c +++ /dev/null @@ -1,940 +0,0 @@ -/* - * QEMU OSS audio driver - * - * Copyright (c) 2003-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include <sys/mman.h> -#include <sys/ioctl.h> -#include <sys/soundcard.h> -#include "qemu-common.h" -#include "qemu/main-loop.h" -#include "qemu/host-utils.h" -#include "audio.h" -#include "trace.h" - -#define AUDIO_CAP "oss" -#include "audio_int.h" - -#if defined OSS_GETVERSION && defined SNDCTL_DSP_POLICY -#define USE_DSP_POLICY -#endif - -typedef struct OSSConf { - int try_mmap; - int nfrags; - int fragsize; - const char *devpath_out; - const char *devpath_in; - int exclusive; - int policy; -} OSSConf; - -typedef struct OSSVoiceOut { - HWVoiceOut hw; - void *pcm_buf; - int fd; - int wpos; - int nfrags; - int fragsize; - int mmapped; - int pending; - OSSConf *conf; -} OSSVoiceOut; - -typedef struct OSSVoiceIn { - HWVoiceIn hw; - void *pcm_buf; - int fd; - int nfrags; - int fragsize; - OSSConf *conf; -} OSSVoiceIn; - -struct oss_params { - int freq; - audfmt_e fmt; - int nchannels; - int nfrags; - int fragsize; -}; - -static void GCC_FMT_ATTR (2, 3) oss_logerr (int err, const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); -} - -static void GCC_FMT_ATTR (3, 4) oss_logerr2 ( - int err, - const char *typ, - const char *fmt, - ... - ) -{ - va_list ap; - - AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ); - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - AUD_log (AUDIO_CAP, "Reason: %s\n", strerror (err)); -} - -static void oss_anal_close (int *fdp) -{ - int err; - - qemu_set_fd_handler (*fdp, NULL, NULL, NULL); - err = close (*fdp); - if (err) { - oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp); - } - *fdp = -1; -} - -static void oss_helper_poll_out (void *opaque) -{ - (void) opaque; - audio_run ("oss_poll_out"); -} - -static void oss_helper_poll_in (void *opaque) -{ - (void) opaque; - audio_run ("oss_poll_in"); -} - -static void oss_poll_out (HWVoiceOut *hw) -{ - OSSVoiceOut *oss = (OSSVoiceOut *) hw; - - qemu_set_fd_handler (oss->fd, NULL, oss_helper_poll_out, NULL); -} - -static void oss_poll_in (HWVoiceIn *hw) -{ - OSSVoiceIn *oss = (OSSVoiceIn *) hw; - - qemu_set_fd_handler (oss->fd, oss_helper_poll_in, NULL, NULL); -} - -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) -{ - switch (fmt) { - case AUD_FMT_S8: - return AFMT_S8; - - case AUD_FMT_U8: - return AFMT_U8; - - case AUD_FMT_S16: - if (endianness) { - return AFMT_S16_BE; - } - else { - return AFMT_S16_LE; - } - - case AUD_FMT_U16: - if (endianness) { - return AFMT_U16_BE; - } - else { - return AFMT_U16_LE; - } - - default: - dolog ("Internal logic error: Bad audio format %d\n", fmt); -#ifdef DEBUG_AUDIO - abort (); -#endif - return AFMT_U8; - } -} - -static int oss_to_audfmt (int ossfmt, audfmt_e *fmt, int *endianness) -{ - switch (ossfmt) { - case AFMT_S8: - *endianness = 0; - *fmt = AUD_FMT_S8; - break; - - case AFMT_U8: - *endianness = 0; - *fmt = AUD_FMT_U8; - break; - - case AFMT_S16_LE: - *endianness = 0; - *fmt = AUD_FMT_S16; - break; - - case AFMT_U16_LE: - *endianness = 0; - *fmt = AUD_FMT_U16; - break; - - case AFMT_S16_BE: - *endianness = 1; - *fmt = AUD_FMT_S16; - break; - - case AFMT_U16_BE: - *endianness = 1; - *fmt = AUD_FMT_U16; - break; - - default: - dolog ("Unrecognized audio format %d\n", ossfmt); - return -1; - } - - return 0; -} - -#if defined DEBUG_MISMATCHES || defined DEBUG -static void oss_dump_info (struct oss_params *req, struct oss_params *obt) -{ - dolog ("parameter | requested value | obtained value\n"); - dolog ("format | %10d | %10d\n", req->fmt, obt->fmt); - dolog ("channels | %10d | %10d\n", - req->nchannels, obt->nchannels); - dolog ("frequency | %10d | %10d\n", req->freq, obt->freq); - dolog ("nfrags | %10d | %10d\n", req->nfrags, obt->nfrags); - dolog ("fragsize | %10d | %10d\n", - req->fragsize, obt->fragsize); -} -#endif - -#ifdef USE_DSP_POLICY -static int oss_get_version (int fd, int *version, const char *typ) -{ - if (ioctl (fd, OSS_GETVERSION, &version)) { -#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) - /* - * Looks like atm (20100109) FreeBSD knows OSS_GETVERSION - * since 7.x, but currently only on the mixer device (or in - * the Linuxolator), and in the native version that part of - * the code is in fact never reached so the ioctl fails anyway. - * Until this is fixed, just check the errno and if its what - * FreeBSD's sound drivers return atm assume they are new enough. - */ - if (errno == EINVAL) { - *version = 0x040000; - return 0; - } -#endif - oss_logerr2 (errno, typ, "Failed to get OSS version\n"); - return -1; - } - return 0; -} -#endif - -static int oss_open (int in, struct oss_params *req, - struct oss_params *obt, int *pfd, OSSConf* conf) -{ - int fd; - int oflags = conf->exclusive ? O_EXCL : 0; - audio_buf_info abinfo; - int fmt, freq, nchannels; - int setfragment = 1; - const char *dspname = in ? conf->devpath_in : conf->devpath_out; - const char *typ = in ? "ADC" : "DAC"; - - /* Kludge needed to have working mmap on Linux */ - oflags |= conf->try_mmap ? O_RDWR : (in ? O_RDONLY : O_WRONLY); - - fd = open (dspname, oflags | O_NONBLOCK); - if (-1 == fd) { - oss_logerr2 (errno, typ, "Failed to open `%s'\n", dspname); - return -1; - } - - freq = req->freq; - nchannels = req->nchannels; - fmt = req->fmt; - - if (ioctl (fd, SNDCTL_DSP_SAMPLESIZE, &fmt)) { - oss_logerr2 (errno, typ, "Failed to set sample size %d\n", req->fmt); - goto err; - } - - if (ioctl (fd, SNDCTL_DSP_CHANNELS, &nchannels)) { - oss_logerr2 (errno, typ, "Failed to set number of channels %d\n", - req->nchannels); - goto err; - } - - if (ioctl (fd, SNDCTL_DSP_SPEED, &freq)) { - oss_logerr2 (errno, typ, "Failed to set frequency %d\n", req->freq); - goto err; - } - - if (ioctl (fd, SNDCTL_DSP_NONBLOCK, NULL)) { - oss_logerr2 (errno, typ, "Failed to set non-blocking mode\n"); - goto err; - } - -#ifdef USE_DSP_POLICY - if (conf->policy >= 0) { - int version; - - if (!oss_get_version (fd, &version, typ)) { - trace_oss_version(version); - - if (version >= 0x040000) { - int policy = conf->policy; - if (ioctl (fd, SNDCTL_DSP_POLICY, &policy)) { - oss_logerr2 (errno, typ, - "Failed to set timing policy to %d\n", - conf->policy); - goto err; - } - setfragment = 0; - } - } - } -#endif - - if (setfragment) { - int mmmmssss = (req->nfrags << 16) | ctz32 (req->fragsize); - if (ioctl (fd, SNDCTL_DSP_SETFRAGMENT, &mmmmssss)) { - oss_logerr2 (errno, typ, "Failed to set buffer length (%d, %d)\n", - req->nfrags, req->fragsize); - goto err; - } - } - - if (ioctl (fd, in ? SNDCTL_DSP_GETISPACE : SNDCTL_DSP_GETOSPACE, &abinfo)) { - oss_logerr2 (errno, typ, "Failed to get buffer length\n"); - goto err; - } - - if (!abinfo.fragstotal || !abinfo.fragsize) { - AUD_log (AUDIO_CAP, "Returned bogus buffer information(%d, %d) for %s\n", - abinfo.fragstotal, abinfo.fragsize, typ); - goto err; - } - - obt->fmt = fmt; - obt->nchannels = nchannels; - obt->freq = freq; - obt->nfrags = abinfo.fragstotal; - obt->fragsize = abinfo.fragsize; - *pfd = fd; - -#ifdef DEBUG_MISMATCHES - if ((req->fmt != obt->fmt) || - (req->nchannels != obt->nchannels) || - (req->freq != obt->freq) || - (req->fragsize != obt->fragsize) || - (req->nfrags != obt->nfrags)) { - dolog ("Audio parameters mismatch\n"); - oss_dump_info (req, obt); - } -#endif - -#ifdef DEBUG - oss_dump_info (req, obt); -#endif - return 0; - - err: - oss_anal_close (&fd); - return -1; -} - -static void oss_write_pending (OSSVoiceOut *oss) -{ - HWVoiceOut *hw = &oss->hw; - - if (oss->mmapped) { - return; - } - - while (oss->pending) { - int samples_written; - ssize_t bytes_written; - int samples_till_end = hw->samples - oss->wpos; - int samples_to_write = audio_MIN (oss->pending, samples_till_end); - int bytes_to_write = samples_to_write << hw->info.shift; - void *pcm = advance (oss->pcm_buf, oss->wpos << hw->info.shift); - - bytes_written = write (oss->fd, pcm, bytes_to_write); - if (bytes_written < 0) { - if (errno != EAGAIN) { - oss_logerr (errno, "failed to write %d bytes\n", - bytes_to_write); - } - break; - } - - if (bytes_written & hw->info.align) { - dolog ("misaligned write asked for %d, but got %zd\n", - bytes_to_write, bytes_written); - return; - } - - samples_written = bytes_written >> hw->info.shift; - oss->pending -= samples_written; - oss->wpos = (oss->wpos + samples_written) % hw->samples; - if (bytes_written - bytes_to_write) { - break; - } - } -} - -static int oss_run_out (HWVoiceOut *hw, int live) -{ - OSSVoiceOut *oss = (OSSVoiceOut *) hw; - int err, decr; - struct audio_buf_info abinfo; - struct count_info cntinfo; - int bufsize; - - bufsize = hw->samples << hw->info.shift; - - if (oss->mmapped) { - int bytes, pos; - - err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo); - if (err < 0) { - oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); - return 0; - } - - pos = hw->rpos << hw->info.shift; - bytes = audio_ring_dist (cntinfo.ptr, pos, bufsize); - decr = audio_MIN (bytes >> hw->info.shift, live); - } - else { - err = ioctl (oss->fd, SNDCTL_DSP_GETOSPACE, &abinfo); - if (err < 0) { - oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); - return 0; - } - - if (abinfo.bytes > bufsize) { - trace_oss_invalid_available_size(abinfo.bytes, bufsize); - abinfo.bytes = bufsize; - } - - if (abinfo.bytes < 0) { - trace_oss_invalid_available_size(abinfo.bytes, bufsize); - return 0; - } - - decr = audio_MIN (abinfo.bytes >> hw->info.shift, live); - if (!decr) { - return 0; - } - } - - decr = audio_pcm_hw_clip_out (hw, oss->pcm_buf, decr, oss->pending); - oss->pending += decr; - oss_write_pending (oss); - - return decr; -} - -static void oss_fini_out (HWVoiceOut *hw) -{ - int err; - OSSVoiceOut *oss = (OSSVoiceOut *) hw; - - ldebug ("oss_fini\n"); - oss_anal_close (&oss->fd); - - if (oss->pcm_buf) { - if (oss->mmapped) { - err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); - if (err) { - oss_logerr (errno, "Failed to unmap buffer %p, size %d\n", - oss->pcm_buf, hw->samples << hw->info.shift); - } - } - else { - g_free (oss->pcm_buf); - } - oss->pcm_buf = NULL; - } -} - -static int oss_init_out(HWVoiceOut *hw, struct audsettings *as, - void *drv_opaque) -{ - OSSVoiceOut *oss = (OSSVoiceOut *) hw; - struct oss_params req, obt; - int endianness; - int err; - int fd; - audfmt_e effective_fmt; - struct audsettings obt_as; - OSSConf *conf = drv_opaque; - - oss->fd = -1; - - req.fmt = aud_to_ossfmt (as->fmt, as->endianness); - req.freq = as->freq; - req.nchannels = as->nchannels; - req.fragsize = conf->fragsize; - req.nfrags = conf->nfrags; - - if (oss_open (0, &req, &obt, &fd, conf)) { - return -1; - } - - err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); - if (err) { - oss_anal_close (&fd); - return -1; - } - - obt_as.freq = obt.freq; - obt_as.nchannels = obt.nchannels; - obt_as.fmt = effective_fmt; - obt_as.endianness = endianness; - - audio_pcm_init_info (&hw->info, &obt_as); - oss->nfrags = obt.nfrags; - oss->fragsize = obt.fragsize; - - if (obt.nfrags * obt.fragsize & hw->info.align) { - dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", - obt.nfrags * obt.fragsize, hw->info.align + 1); - } - - hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; - - oss->mmapped = 0; - if (conf->try_mmap) { - oss->pcm_buf = mmap ( - NULL, - hw->samples << hw->info.shift, - PROT_READ | PROT_WRITE, - MAP_SHARED, - fd, - 0 - ); - if (oss->pcm_buf == MAP_FAILED) { - oss_logerr (errno, "Failed to map %d bytes of DAC\n", - hw->samples << hw->info.shift); - } - else { - int err; - int trig = 0; - if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { - oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); - } - else { - trig = PCM_ENABLE_OUTPUT; - if (ioctl (fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { - oss_logerr ( - errno, - "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" - ); - } - else { - oss->mmapped = 1; - } - } - - if (!oss->mmapped) { - err = munmap (oss->pcm_buf, hw->samples << hw->info.shift); - if (err) { - oss_logerr (errno, "Failed to unmap buffer %p size %d\n", - oss->pcm_buf, hw->samples << hw->info.shift); - } - } - } - } - - if (!oss->mmapped) { - oss->pcm_buf = audio_calloc ( - AUDIO_FUNC, - hw->samples, - 1 << hw->info.shift - ); - if (!oss->pcm_buf) { - dolog ( - "Could not allocate DAC buffer (%d samples, each %d bytes)\n", - hw->samples, - 1 << hw->info.shift - ); - oss_anal_close (&fd); - return -1; - } - } - - oss->fd = fd; - oss->conf = conf; - return 0; -} - -static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - int trig; - OSSVoiceOut *oss = (OSSVoiceOut *) hw; - - switch (cmd) { - case VOICE_ENABLE: - { - va_list ap; - int poll_mode; - - va_start (ap, cmd); - poll_mode = va_arg (ap, int); - va_end (ap); - - ldebug ("enabling voice\n"); - if (poll_mode) { - oss_poll_out (hw); - poll_mode = 0; - } - hw->poll_mode = poll_mode; - - if (!oss->mmapped) { - return 0; - } - - audio_pcm_info_clear_buf (&hw->info, oss->pcm_buf, hw->samples); - trig = PCM_ENABLE_OUTPUT; - if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { - oss_logerr ( - errno, - "SNDCTL_DSP_SETTRIGGER PCM_ENABLE_OUTPUT failed\n" - ); - return -1; - } - } - break; - - case VOICE_DISABLE: - if (hw->poll_mode) { - qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); - hw->poll_mode = 0; - } - - if (!oss->mmapped) { - return 0; - } - - ldebug ("disabling voice\n"); - trig = 0; - if (ioctl (oss->fd, SNDCTL_DSP_SETTRIGGER, &trig) < 0) { - oss_logerr (errno, "SNDCTL_DSP_SETTRIGGER 0 failed\n"); - return -1; - } - break; - } - return 0; -} - -static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) -{ - OSSVoiceIn *oss = (OSSVoiceIn *) hw; - struct oss_params req, obt; - int endianness; - int err; - int fd; - audfmt_e effective_fmt; - struct audsettings obt_as; - OSSConf *conf = drv_opaque; - - oss->fd = -1; - - req.fmt = aud_to_ossfmt (as->fmt, as->endianness); - req.freq = as->freq; - req.nchannels = as->nchannels; - req.fragsize = conf->fragsize; - req.nfrags = conf->nfrags; - if (oss_open (1, &req, &obt, &fd, conf)) { - return -1; - } - - err = oss_to_audfmt (obt.fmt, &effective_fmt, &endianness); - if (err) { - oss_anal_close (&fd); - return -1; - } - - obt_as.freq = obt.freq; - obt_as.nchannels = obt.nchannels; - obt_as.fmt = effective_fmt; - obt_as.endianness = endianness; - - audio_pcm_init_info (&hw->info, &obt_as); - oss->nfrags = obt.nfrags; - oss->fragsize = obt.fragsize; - - if (obt.nfrags * obt.fragsize & hw->info.align) { - dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", - obt.nfrags * obt.fragsize, hw->info.align + 1); - } - - hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; - oss->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - if (!oss->pcm_buf) { - dolog ("Could not allocate ADC buffer (%d samples, each %d bytes)\n", - hw->samples, 1 << hw->info.shift); - oss_anal_close (&fd); - return -1; - } - - oss->fd = fd; - oss->conf = conf; - return 0; -} - -static void oss_fini_in (HWVoiceIn *hw) -{ - OSSVoiceIn *oss = (OSSVoiceIn *) hw; - - oss_anal_close (&oss->fd); - - g_free(oss->pcm_buf); - oss->pcm_buf = NULL; -} - -static int oss_run_in (HWVoiceIn *hw) -{ - OSSVoiceIn *oss = (OSSVoiceIn *) hw; - int hwshift = hw->info.shift; - int i; - int live = audio_pcm_hw_get_live_in (hw); - int dead = hw->samples - live; - size_t read_samples = 0; - struct { - int add; - int len; - } bufs[2] = { - { .add = hw->wpos, .len = 0 }, - { .add = 0, .len = 0 } - }; - - if (!dead) { - return 0; - } - - if (hw->wpos + dead > hw->samples) { - bufs[0].len = (hw->samples - hw->wpos) << hwshift; - bufs[1].len = (dead - (hw->samples - hw->wpos)) << hwshift; - } - else { - bufs[0].len = dead << hwshift; - } - - for (i = 0; i < 2; ++i) { - ssize_t nread; - - if (bufs[i].len) { - void *p = advance (oss->pcm_buf, bufs[i].add << hwshift); - nread = read (oss->fd, p, bufs[i].len); - - if (nread > 0) { - if (nread & hw->info.align) { - dolog ("warning: Misaligned read %zd (requested %d), " - "alignment %d\n", nread, bufs[i].add << hwshift, - hw->info.align + 1); - } - read_samples += nread >> hwshift; - hw->conv (hw->conv_buf + bufs[i].add, p, nread >> hwshift); - } - - if (bufs[i].len - nread) { - if (nread == -1) { - switch (errno) { - case EINTR: - case EAGAIN: - break; - default: - oss_logerr ( - errno, - "Failed to read %d bytes of audio (to %p)\n", - bufs[i].len, p - ); - break; - } - } - break; - } - } - } - - hw->wpos = (hw->wpos + read_samples) % hw->samples; - return read_samples; -} - -static int oss_read (SWVoiceIn *sw, void *buf, int size) -{ - return audio_pcm_sw_read (sw, buf, size); -} - -static int oss_ctl_in (HWVoiceIn *hw, int cmd, ...) -{ - OSSVoiceIn *oss = (OSSVoiceIn *) hw; - - switch (cmd) { - case VOICE_ENABLE: - { - va_list ap; - int poll_mode; - - va_start (ap, cmd); - poll_mode = va_arg (ap, int); - va_end (ap); - - if (poll_mode) { - oss_poll_in (hw); - poll_mode = 0; - } - hw->poll_mode = poll_mode; - } - break; - - case VOICE_DISABLE: - if (hw->poll_mode) { - hw->poll_mode = 0; - qemu_set_fd_handler (oss->fd, NULL, NULL, NULL); - } - break; - } - return 0; -} - -static OSSConf glob_conf = { - .try_mmap = 0, - .nfrags = 4, - .fragsize = 4096, - .devpath_out = "/dev/dsp", - .devpath_in = "/dev/dsp", - .exclusive = 0, - .policy = 5 -}; - -static void *oss_audio_init (void) -{ - OSSConf *conf = g_malloc(sizeof(OSSConf)); - *conf = glob_conf; - - if (access(conf->devpath_in, R_OK | W_OK) < 0 || - access(conf->devpath_out, R_OK | W_OK) < 0) { - g_free(conf); - return NULL; - } - return conf; -} - -static void oss_audio_fini (void *opaque) -{ - g_free(opaque); -} - -static struct audio_option oss_options[] = { - { - .name = "FRAGSIZE", - .tag = AUD_OPT_INT, - .valp = &glob_conf.fragsize, - .descr = "Fragment size in bytes" - }, - { - .name = "NFRAGS", - .tag = AUD_OPT_INT, - .valp = &glob_conf.nfrags, - .descr = "Number of fragments" - }, - { - .name = "MMAP", - .tag = AUD_OPT_BOOL, - .valp = &glob_conf.try_mmap, - .descr = "Try using memory mapped access" - }, - { - .name = "DAC_DEV", - .tag = AUD_OPT_STR, - .valp = &glob_conf.devpath_out, - .descr = "Path to DAC device" - }, - { - .name = "ADC_DEV", - .tag = AUD_OPT_STR, - .valp = &glob_conf.devpath_in, - .descr = "Path to ADC device" - }, - { - .name = "EXCLUSIVE", - .tag = AUD_OPT_BOOL, - .valp = &glob_conf.exclusive, - .descr = "Open device in exclusive mode (vmix wont work)" - }, -#ifdef USE_DSP_POLICY - { - .name = "POLICY", - .tag = AUD_OPT_INT, - .valp = &glob_conf.policy, - .descr = "Set the timing policy of the device, -1 to use fragment mode", - }, -#endif - { /* End of list */ } -}; - -static struct audio_pcm_ops oss_pcm_ops = { - .init_out = oss_init_out, - .fini_out = oss_fini_out, - .run_out = oss_run_out, - .write = oss_write, - .ctl_out = oss_ctl_out, - - .init_in = oss_init_in, - .fini_in = oss_fini_in, - .run_in = oss_run_in, - .read = oss_read, - .ctl_in = oss_ctl_in -}; - -struct audio_driver oss_audio_driver = { - .name = "oss", - .descr = "OSS http://www.opensound.com", - .options = oss_options, - .init = oss_audio_init, - .fini = oss_audio_fini, - .pcm_ops = &oss_pcm_ops, - .can_be_default = 1, - .max_voices_out = INT_MAX, - .max_voices_in = INT_MAX, - .voice_size_out = sizeof (OSSVoiceOut), - .voice_size_in = sizeof (OSSVoiceIn) -}; diff --git a/qemu/audio/paaudio.c b/qemu/audio/paaudio.c deleted file mode 100644 index 57678e72e..000000000 --- a/qemu/audio/paaudio.c +++ /dev/null @@ -1,954 +0,0 @@ -/* public domain */ -#include "qemu/osdep.h" -#include "qemu-common.h" -#include "audio.h" - -#include <pulse/pulseaudio.h> - -#define AUDIO_CAP "pulseaudio" -#include "audio_int.h" -#include "audio_pt_int.h" - -typedef struct { - int samples; - char *server; - char *sink; - char *source; -} PAConf; - -typedef struct { - PAConf conf; - pa_threaded_mainloop *mainloop; - pa_context *context; -} paaudio; - -typedef struct { - HWVoiceOut hw; - int done; - int live; - int decr; - int rpos; - pa_stream *stream; - void *pcm_buf; - struct audio_pt pt; - paaudio *g; -} PAVoiceOut; - -typedef struct { - HWVoiceIn hw; - int done; - int dead; - int incr; - int wpos; - pa_stream *stream; - void *pcm_buf; - struct audio_pt pt; - const void *read_data; - size_t read_index, read_length; - paaudio *g; -} PAVoiceIn; - -static void qpa_audio_fini(void *opaque); - -static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); -} - -#ifndef PA_CONTEXT_IS_GOOD -static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x) -{ - return - x == PA_CONTEXT_CONNECTING || - x == PA_CONTEXT_AUTHORIZING || - x == PA_CONTEXT_SETTING_NAME || - x == PA_CONTEXT_READY; -} -#endif - -#ifndef PA_STREAM_IS_GOOD -static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) -{ - return - x == PA_STREAM_CREATING || - x == PA_STREAM_READY; -} -#endif - -#define CHECK_SUCCESS_GOTO(c, rerror, expression, label) \ - do { \ - if (!(expression)) { \ - if (rerror) { \ - *(rerror) = pa_context_errno ((c)->context); \ - } \ - goto label; \ - } \ - } while (0); - -#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ - do { \ - if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ - !(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream)))) { \ - if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ - ((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ - if (rerror) { \ - *(rerror) = pa_context_errno ((c)->context); \ - } \ - } else { \ - if (rerror) { \ - *(rerror) = PA_ERR_BADSTATE; \ - } \ - } \ - goto label; \ - } \ - } while (0); - -static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror) -{ - paaudio *g = p->g; - - pa_threaded_mainloop_lock (g->mainloop); - - CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); - - while (length > 0) { - size_t l; - - while (!p->read_data) { - int r; - - r = pa_stream_peek (p->stream, &p->read_data, &p->read_length); - CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); - - if (!p->read_data) { - pa_threaded_mainloop_wait (g->mainloop); - CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); - } else { - p->read_index = 0; - } - } - - l = p->read_length < length ? p->read_length : length; - memcpy (data, (const uint8_t *) p->read_data+p->read_index, l); - - data = (uint8_t *) data + l; - length -= l; - - p->read_index += l; - p->read_length -= l; - - if (!p->read_length) { - int r; - - r = pa_stream_drop (p->stream); - p->read_data = NULL; - p->read_length = 0; - p->read_index = 0; - - CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); - } - } - - pa_threaded_mainloop_unlock (g->mainloop); - return 0; - -unlock_and_fail: - pa_threaded_mainloop_unlock (g->mainloop); - return -1; -} - -static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror) -{ - paaudio *g = p->g; - - pa_threaded_mainloop_lock (g->mainloop); - - CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); - - while (length > 0) { - size_t l; - int r; - - while (!(l = pa_stream_writable_size (p->stream))) { - pa_threaded_mainloop_wait (g->mainloop); - CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); - } - - CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail); - - if (l > length) { - l = length; - } - - r = pa_stream_write (p->stream, data, l, NULL, 0LL, PA_SEEK_RELATIVE); - CHECK_SUCCESS_GOTO (g, rerror, r >= 0, unlock_and_fail); - - data = (const uint8_t *) data + l; - length -= l; - } - - pa_threaded_mainloop_unlock (g->mainloop); - return 0; - -unlock_and_fail: - pa_threaded_mainloop_unlock (g->mainloop); - return -1; -} - -static void *qpa_thread_out (void *arg) -{ - PAVoiceOut *pa = arg; - HWVoiceOut *hw = &pa->hw; - - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { - return NULL; - } - - for (;;) { - int decr, to_mix, rpos; - - for (;;) { - if (pa->done) { - goto exit; - } - - if (pa->live > 0) { - break; - } - - if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) { - goto exit; - } - } - - decr = to_mix = audio_MIN (pa->live, pa->g->conf.samples >> 2); - rpos = pa->rpos; - - if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { - return NULL; - } - - while (to_mix) { - int error; - int chunk = audio_MIN (to_mix, hw->samples - rpos); - struct st_sample *src = hw->mix_buf + rpos; - - hw->clip (pa->pcm_buf, src, chunk); - - if (qpa_simple_write (pa, pa->pcm_buf, - chunk << hw->info.shift, &error) < 0) { - qpa_logerr (error, "pa_simple_write failed\n"); - return NULL; - } - - rpos = (rpos + chunk) % hw->samples; - to_mix -= chunk; - } - - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { - return NULL; - } - - pa->rpos = rpos; - pa->live -= decr; - pa->decr += decr; - } - - exit: - audio_pt_unlock (&pa->pt, AUDIO_FUNC); - return NULL; -} - -static int qpa_run_out (HWVoiceOut *hw, int live) -{ - int decr; - PAVoiceOut *pa = (PAVoiceOut *) hw; - - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { - return 0; - } - - decr = audio_MIN (live, pa->decr); - pa->decr -= decr; - pa->live = live - decr; - hw->rpos = pa->rpos; - if (pa->live > 0) { - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); - } - else { - audio_pt_unlock (&pa->pt, AUDIO_FUNC); - } - return decr; -} - -static int qpa_write (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -/* capture */ -static void *qpa_thread_in (void *arg) -{ - PAVoiceIn *pa = arg; - HWVoiceIn *hw = &pa->hw; - - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { - return NULL; - } - - for (;;) { - int incr, to_grab, wpos; - - for (;;) { - if (pa->done) { - goto exit; - } - - if (pa->dead > 0) { - break; - } - - if (audio_pt_wait (&pa->pt, AUDIO_FUNC)) { - goto exit; - } - } - - incr = to_grab = audio_MIN (pa->dead, pa->g->conf.samples >> 2); - wpos = pa->wpos; - - if (audio_pt_unlock (&pa->pt, AUDIO_FUNC)) { - return NULL; - } - - while (to_grab) { - int error; - int chunk = audio_MIN (to_grab, hw->samples - wpos); - void *buf = advance (pa->pcm_buf, wpos); - - if (qpa_simple_read (pa, buf, - chunk << hw->info.shift, &error) < 0) { - qpa_logerr (error, "pa_simple_read failed\n"); - return NULL; - } - - hw->conv (hw->conv_buf + wpos, buf, chunk); - wpos = (wpos + chunk) % hw->samples; - to_grab -= chunk; - } - - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { - return NULL; - } - - pa->wpos = wpos; - pa->dead -= incr; - pa->incr += incr; - } - - exit: - audio_pt_unlock (&pa->pt, AUDIO_FUNC); - return NULL; -} - -static int qpa_run_in (HWVoiceIn *hw) -{ - int live, incr, dead; - PAVoiceIn *pa = (PAVoiceIn *) hw; - - if (audio_pt_lock (&pa->pt, AUDIO_FUNC)) { - return 0; - } - - live = audio_pcm_hw_get_live_in (hw); - dead = hw->samples - live; - incr = audio_MIN (dead, pa->incr); - pa->incr -= incr; - pa->dead = dead - incr; - hw->wpos = pa->wpos; - if (pa->dead > 0) { - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); - } - else { - audio_pt_unlock (&pa->pt, AUDIO_FUNC); - } - return incr; -} - -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) -{ - int format; - - switch (afmt) { - case AUD_FMT_S8: - case AUD_FMT_U8: - format = PA_SAMPLE_U8; - break; - case AUD_FMT_S16: - case AUD_FMT_U16: - format = endianness ? PA_SAMPLE_S16BE : PA_SAMPLE_S16LE; - break; - case AUD_FMT_S32: - case AUD_FMT_U32: - format = endianness ? PA_SAMPLE_S32BE : PA_SAMPLE_S32LE; - break; - default: - dolog ("Internal logic error: Bad audio format %d\n", afmt); - format = PA_SAMPLE_U8; - break; - } - return format; -} - -static audfmt_e pa_to_audfmt (pa_sample_format_t fmt, int *endianness) -{ - switch (fmt) { - case PA_SAMPLE_U8: - return AUD_FMT_U8; - case PA_SAMPLE_S16BE: - *endianness = 1; - return AUD_FMT_S16; - case PA_SAMPLE_S16LE: - *endianness = 0; - return AUD_FMT_S16; - case PA_SAMPLE_S32BE: - *endianness = 1; - return AUD_FMT_S32; - case PA_SAMPLE_S32LE: - *endianness = 0; - return AUD_FMT_S32; - default: - dolog ("Internal logic error: Bad pa_sample_format %d\n", fmt); - return AUD_FMT_U8; - } -} - -static void context_state_cb (pa_context *c, void *userdata) -{ - paaudio *g = userdata; - - switch (pa_context_get_state(c)) { - case PA_CONTEXT_READY: - case PA_CONTEXT_TERMINATED: - case PA_CONTEXT_FAILED: - pa_threaded_mainloop_signal (g->mainloop, 0); - break; - - case PA_CONTEXT_UNCONNECTED: - case PA_CONTEXT_CONNECTING: - case PA_CONTEXT_AUTHORIZING: - case PA_CONTEXT_SETTING_NAME: - break; - } -} - -static void stream_state_cb (pa_stream *s, void * userdata) -{ - paaudio *g = userdata; - - switch (pa_stream_get_state (s)) { - - case PA_STREAM_READY: - case PA_STREAM_FAILED: - case PA_STREAM_TERMINATED: - pa_threaded_mainloop_signal (g->mainloop, 0); - break; - - case PA_STREAM_UNCONNECTED: - case PA_STREAM_CREATING: - break; - } -} - -static void stream_request_cb (pa_stream *s, size_t length, void *userdata) -{ - paaudio *g = userdata; - - pa_threaded_mainloop_signal (g->mainloop, 0); -} - -static pa_stream *qpa_simple_new ( - paaudio *g, - const char *name, - pa_stream_direction_t dir, - const char *dev, - const pa_sample_spec *ss, - const pa_channel_map *map, - const pa_buffer_attr *attr, - int *rerror) -{ - int r; - pa_stream *stream; - - pa_threaded_mainloop_lock (g->mainloop); - - stream = pa_stream_new (g->context, name, ss, map); - if (!stream) { - goto fail; - } - - pa_stream_set_state_callback (stream, stream_state_cb, g); - pa_stream_set_read_callback (stream, stream_request_cb, g); - pa_stream_set_write_callback (stream, stream_request_cb, g); - - if (dir == PA_STREAM_PLAYBACK) { - r = pa_stream_connect_playback (stream, dev, attr, - PA_STREAM_INTERPOLATE_TIMING -#ifdef PA_STREAM_ADJUST_LATENCY - |PA_STREAM_ADJUST_LATENCY -#endif - |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); - } else { - r = pa_stream_connect_record (stream, dev, attr, - PA_STREAM_INTERPOLATE_TIMING -#ifdef PA_STREAM_ADJUST_LATENCY - |PA_STREAM_ADJUST_LATENCY -#endif - |PA_STREAM_AUTO_TIMING_UPDATE); - } - - if (r < 0) { - goto fail; - } - - pa_threaded_mainloop_unlock (g->mainloop); - - return stream; - -fail: - pa_threaded_mainloop_unlock (g->mainloop); - - if (stream) { - pa_stream_unref (stream); - } - - *rerror = pa_context_errno (g->context); - - return NULL; -} - -static int qpa_init_out(HWVoiceOut *hw, struct audsettings *as, - void *drv_opaque) -{ - int error; - pa_sample_spec ss; - pa_buffer_attr ba; - struct audsettings obt_as = *as; - PAVoiceOut *pa = (PAVoiceOut *) hw; - paaudio *g = pa->g = drv_opaque; - - ss.format = audfmt_to_pa (as->fmt, as->endianness); - ss.channels = as->nchannels; - ss.rate = as->freq; - - /* - * qemu audio tick runs at 100 Hz (by default), so processing - * data chunks worth 10 ms of sound should be a good fit. - */ - ba.tlength = pa_usec_to_bytes (10 * 1000, &ss); - ba.minreq = pa_usec_to_bytes (5 * 1000, &ss); - ba.maxlength = -1; - ba.prebuf = -1; - - obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); - - pa->stream = qpa_simple_new ( - g, - "qemu", - PA_STREAM_PLAYBACK, - g->conf.sink, - &ss, - NULL, /* channel map */ - &ba, /* buffering attributes */ - &error - ); - if (!pa->stream) { - qpa_logerr (error, "pa_simple_new for playback failed\n"); - goto fail1; - } - - audio_pcm_init_info (&hw->info, &obt_as); - hw->samples = g->conf.samples; - pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - pa->rpos = hw->rpos; - if (!pa->pcm_buf) { - dolog ("Could not allocate buffer (%d bytes)\n", - hw->samples << hw->info.shift); - goto fail2; - } - - if (audio_pt_init (&pa->pt, qpa_thread_out, hw, AUDIO_CAP, AUDIO_FUNC)) { - goto fail3; - } - - return 0; - - fail3: - g_free (pa->pcm_buf); - pa->pcm_buf = NULL; - fail2: - if (pa->stream) { - pa_stream_unref (pa->stream); - pa->stream = NULL; - } - fail1: - return -1; -} - -static int qpa_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) -{ - int error; - pa_sample_spec ss; - struct audsettings obt_as = *as; - PAVoiceIn *pa = (PAVoiceIn *) hw; - paaudio *g = pa->g = drv_opaque; - - ss.format = audfmt_to_pa (as->fmt, as->endianness); - ss.channels = as->nchannels; - ss.rate = as->freq; - - obt_as.fmt = pa_to_audfmt (ss.format, &obt_as.endianness); - - pa->stream = qpa_simple_new ( - g, - "qemu", - PA_STREAM_RECORD, - g->conf.source, - &ss, - NULL, /* channel map */ - NULL, /* buffering attributes */ - &error - ); - if (!pa->stream) { - qpa_logerr (error, "pa_simple_new for capture failed\n"); - goto fail1; - } - - audio_pcm_init_info (&hw->info, &obt_as); - hw->samples = g->conf.samples; - pa->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - pa->wpos = hw->wpos; - if (!pa->pcm_buf) { - dolog ("Could not allocate buffer (%d bytes)\n", - hw->samples << hw->info.shift); - goto fail2; - } - - if (audio_pt_init (&pa->pt, qpa_thread_in, hw, AUDIO_CAP, AUDIO_FUNC)) { - goto fail3; - } - - return 0; - - fail3: - g_free (pa->pcm_buf); - pa->pcm_buf = NULL; - fail2: - if (pa->stream) { - pa_stream_unref (pa->stream); - pa->stream = NULL; - } - fail1: - return -1; -} - -static void qpa_fini_out (HWVoiceOut *hw) -{ - void *ret; - PAVoiceOut *pa = (PAVoiceOut *) hw; - - audio_pt_lock (&pa->pt, AUDIO_FUNC); - pa->done = 1; - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); - audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); - - if (pa->stream) { - pa_stream_unref (pa->stream); - pa->stream = NULL; - } - - audio_pt_fini (&pa->pt, AUDIO_FUNC); - g_free (pa->pcm_buf); - pa->pcm_buf = NULL; -} - -static void qpa_fini_in (HWVoiceIn *hw) -{ - void *ret; - PAVoiceIn *pa = (PAVoiceIn *) hw; - - audio_pt_lock (&pa->pt, AUDIO_FUNC); - pa->done = 1; - audio_pt_unlock_and_signal (&pa->pt, AUDIO_FUNC); - audio_pt_join (&pa->pt, &ret, AUDIO_FUNC); - - if (pa->stream) { - pa_stream_unref (pa->stream); - pa->stream = NULL; - } - - audio_pt_fini (&pa->pt, AUDIO_FUNC); - g_free (pa->pcm_buf); - pa->pcm_buf = NULL; -} - -static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - PAVoiceOut *pa = (PAVoiceOut *) hw; - pa_operation *op; - pa_cvolume v; - paaudio *g = pa->g; - -#ifdef PA_CHECK_VERSION /* macro is present in 0.9.16+ */ - pa_cvolume_init (&v); /* function is present in 0.9.13+ */ -#endif - - switch (cmd) { - case VOICE_VOLUME: - { - SWVoiceOut *sw; - va_list ap; - - va_start (ap, cmd); - sw = va_arg (ap, SWVoiceOut *); - va_end (ap); - - v.channels = 2; - v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; - v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; - - pa_threaded_mainloop_lock (g->mainloop); - - op = pa_context_set_sink_input_volume (g->context, - pa_stream_get_index (pa->stream), - &v, NULL, NULL); - if (!op) - qpa_logerr (pa_context_errno (g->context), - "set_sink_input_volume() failed\n"); - else - pa_operation_unref (op); - - op = pa_context_set_sink_input_mute (g->context, - pa_stream_get_index (pa->stream), - sw->vol.mute, NULL, NULL); - if (!op) { - qpa_logerr (pa_context_errno (g->context), - "set_sink_input_mute() failed\n"); - } else { - pa_operation_unref (op); - } - - pa_threaded_mainloop_unlock (g->mainloop); - } - } - return 0; -} - -static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) -{ - PAVoiceIn *pa = (PAVoiceIn *) hw; - pa_operation *op; - pa_cvolume v; - paaudio *g = pa->g; - -#ifdef PA_CHECK_VERSION - pa_cvolume_init (&v); -#endif - - switch (cmd) { - case VOICE_VOLUME: - { - SWVoiceIn *sw; - va_list ap; - - va_start (ap, cmd); - sw = va_arg (ap, SWVoiceIn *); - va_end (ap); - - v.channels = 2; - v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; - v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; - - pa_threaded_mainloop_lock (g->mainloop); - - /* FIXME: use the upcoming "set_source_output_{volume,mute}" */ - op = pa_context_set_source_volume_by_index (g->context, - pa_stream_get_device_index (pa->stream), - &v, NULL, NULL); - if (!op) { - qpa_logerr (pa_context_errno (g->context), - "set_source_volume() failed\n"); - } else { - pa_operation_unref(op); - } - - op = pa_context_set_source_mute_by_index (g->context, - pa_stream_get_index (pa->stream), - sw->vol.mute, NULL, NULL); - if (!op) { - qpa_logerr (pa_context_errno (g->context), - "set_source_mute() failed\n"); - } else { - pa_operation_unref (op); - } - - pa_threaded_mainloop_unlock (g->mainloop); - } - } - return 0; -} - -/* common */ -static PAConf glob_conf = { - .samples = 4096, -}; - -static void *qpa_audio_init (void) -{ - paaudio *g = g_malloc(sizeof(paaudio)); - g->conf = glob_conf; - g->mainloop = NULL; - g->context = NULL; - - g->mainloop = pa_threaded_mainloop_new (); - if (!g->mainloop) { - goto fail; - } - - g->context = pa_context_new (pa_threaded_mainloop_get_api (g->mainloop), - g->conf.server); - if (!g->context) { - goto fail; - } - - pa_context_set_state_callback (g->context, context_state_cb, g); - - if (pa_context_connect (g->context, g->conf.server, 0, NULL) < 0) { - qpa_logerr (pa_context_errno (g->context), - "pa_context_connect() failed\n"); - goto fail; - } - - pa_threaded_mainloop_lock (g->mainloop); - - if (pa_threaded_mainloop_start (g->mainloop) < 0) { - goto unlock_and_fail; - } - - for (;;) { - pa_context_state_t state; - - state = pa_context_get_state (g->context); - - if (state == PA_CONTEXT_READY) { - break; - } - - if (!PA_CONTEXT_IS_GOOD (state)) { - qpa_logerr (pa_context_errno (g->context), - "Wrong context state\n"); - goto unlock_and_fail; - } - - /* Wait until the context is ready */ - pa_threaded_mainloop_wait (g->mainloop); - } - - pa_threaded_mainloop_unlock (g->mainloop); - - return g; - -unlock_and_fail: - pa_threaded_mainloop_unlock (g->mainloop); -fail: - AUD_log (AUDIO_CAP, "Failed to initialize PA context"); - qpa_audio_fini(g); - return NULL; -} - -static void qpa_audio_fini (void *opaque) -{ - paaudio *g = opaque; - - if (g->mainloop) { - pa_threaded_mainloop_stop (g->mainloop); - } - - if (g->context) { - pa_context_disconnect (g->context); - pa_context_unref (g->context); - } - - if (g->mainloop) { - pa_threaded_mainloop_free (g->mainloop); - } - - g_free(g); -} - -struct audio_option qpa_options[] = { - { - .name = "SAMPLES", - .tag = AUD_OPT_INT, - .valp = &glob_conf.samples, - .descr = "buffer size in samples" - }, - { - .name = "SERVER", - .tag = AUD_OPT_STR, - .valp = &glob_conf.server, - .descr = "server address" - }, - { - .name = "SINK", - .tag = AUD_OPT_STR, - .valp = &glob_conf.sink, - .descr = "sink device name" - }, - { - .name = "SOURCE", - .tag = AUD_OPT_STR, - .valp = &glob_conf.source, - .descr = "source device name" - }, - { /* End of list */ } -}; - -static struct audio_pcm_ops qpa_pcm_ops = { - .init_out = qpa_init_out, - .fini_out = qpa_fini_out, - .run_out = qpa_run_out, - .write = qpa_write, - .ctl_out = qpa_ctl_out, - - .init_in = qpa_init_in, - .fini_in = qpa_fini_in, - .run_in = qpa_run_in, - .read = qpa_read, - .ctl_in = qpa_ctl_in -}; - -struct audio_driver pa_audio_driver = { - .name = "pa", - .descr = "http://www.pulseaudio.org/", - .options = qpa_options, - .init = qpa_audio_init, - .fini = qpa_audio_fini, - .pcm_ops = &qpa_pcm_ops, - .can_be_default = 1, - .max_voices_out = INT_MAX, - .max_voices_in = INT_MAX, - .voice_size_out = sizeof (PAVoiceOut), - .voice_size_in = sizeof (PAVoiceIn), - .ctl_caps = VOICE_VOLUME_CAP -}; diff --git a/qemu/audio/rate_template.h b/qemu/audio/rate_template.h deleted file mode 100644 index bd4b1c768..000000000 --- a/qemu/audio/rate_template.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * QEMU Mixing engine - * - * Copyright (c) 2004-2005 Vassili Karpov (malc) - * Copyright (c) 1998 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* - * Processed signed long samples from ibuf to obuf. - * Return number of samples processed. - */ -void NAME (void *opaque, struct st_sample *ibuf, struct st_sample *obuf, - int *isamp, int *osamp) -{ - struct rate *rate = opaque; - struct st_sample *istart, *iend; - struct st_sample *ostart, *oend; - struct st_sample ilast, icur, out; -#ifdef FLOAT_MIXENG - mixeng_real t; -#else - int64_t t; -#endif - - ilast = rate->ilast; - - istart = ibuf; - iend = ibuf + *isamp; - - ostart = obuf; - oend = obuf + *osamp; - - if (rate->opos_inc == (1ULL + UINT_MAX)) { - int i, n = *isamp > *osamp ? *osamp : *isamp; - for (i = 0; i < n; i++) { - OP (obuf[i].l, ibuf[i].l); - OP (obuf[i].r, ibuf[i].r); - } - *isamp = n; - *osamp = n; - return; - } - - while (obuf < oend) { - - /* Safety catch to make sure we have input samples. */ - if (ibuf >= iend) { - break; - } - - /* read as many input samples so that ipos > opos */ - - while (rate->ipos <= (rate->opos >> 32)) { - ilast = *ibuf++; - rate->ipos++; - /* See if we finished the input buffer yet */ - if (ibuf >= iend) { - goto the_end; - } - } - - icur = *ibuf; - - /* interpolate */ -#ifdef FLOAT_MIXENG -#ifdef RECIPROCAL - t = (rate->opos & UINT_MAX) * (1.f / UINT_MAX); -#else - t = (rate->opos & UINT_MAX) / (mixeng_real) UINT_MAX; -#endif - out.l = (ilast.l * (1.0 - t)) + icur.l * t; - out.r = (ilast.r * (1.0 - t)) + icur.r * t; -#else - t = rate->opos & 0xffffffff; - out.l = (ilast.l * ((int64_t) UINT_MAX - t) + icur.l * t) >> 32; - out.r = (ilast.r * ((int64_t) UINT_MAX - t) + icur.r * t) >> 32; -#endif - - /* output sample & increment position */ - OP (obuf->l, out.l); - OP (obuf->r, out.r); - obuf += 1; - rate->opos += rate->opos_inc; - } - -the_end: - *isamp = ibuf - istart; - *osamp = obuf - ostart; - rate->ilast = ilast; -} - -#undef NAME -#undef OP diff --git a/qemu/audio/sdlaudio.c b/qemu/audio/sdlaudio.c deleted file mode 100644 index db69fe141..000000000 --- a/qemu/audio/sdlaudio.c +++ /dev/null @@ -1,467 +0,0 @@ -/* - * QEMU SDL audio driver - * - * Copyright (c) 2004-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include <SDL.h> -#include <SDL_thread.h> -#include "qemu-common.h" -#include "audio.h" - -#ifndef _WIN32 -#ifdef __sun__ -#define _POSIX_PTHREAD_SEMANTICS 1 -#elif defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) -#include <pthread.h> -#endif -#endif - -#define AUDIO_CAP "sdl" -#include "audio_int.h" - -typedef struct SDLVoiceOut { - HWVoiceOut hw; - int live; - int rpos; - 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; -} glob_sdl; -typedef struct SDLAudioState SDLAudioState; - -static void GCC_FMT_ATTR (1, 2) sdl_logerr (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); - - AUD_log (AUDIO_CAP, "Reason: %s\n", SDL_GetError ()); -} - -static int sdl_lock (SDLAudioState *s, const char *forfn) -{ - if (SDL_LockMutex (s->mutex)) { - sdl_logerr ("SDL_LockMutex for %s failed\n", forfn); - return -1; - } - return 0; -} - -static int sdl_unlock (SDLAudioState *s, const char *forfn) -{ - if (SDL_UnlockMutex (s->mutex)) { - sdl_logerr ("SDL_UnlockMutex for %s failed\n", forfn); - return -1; - } - return 0; -} - -static int sdl_post (SDLAudioState *s, const char *forfn) -{ - if (SDL_SemPost (s->sem)) { - sdl_logerr ("SDL_SemPost for %s failed\n", forfn); - return -1; - } - return 0; -} - -static int sdl_wait (SDLAudioState *s, const char *forfn) -{ - if (SDL_SemWait (s->sem)) { - sdl_logerr ("SDL_SemWait for %s failed\n", forfn); - return -1; - } - return 0; -} - -static int sdl_unlock_and_post (SDLAudioState *s, const char *forfn) -{ - if (sdl_unlock (s, forfn)) { - return -1; - } - - return sdl_post (s, forfn); -} - -static int aud_to_sdlfmt (audfmt_e fmt) -{ - switch (fmt) { - case AUD_FMT_S8: - return AUDIO_S8; - - case AUD_FMT_U8: - return AUDIO_U8; - - case AUD_FMT_S16: - return AUDIO_S16LSB; - - case AUD_FMT_U16: - return AUDIO_U16LSB; - - default: - dolog ("Internal logic error: Bad audio format %d\n", fmt); -#ifdef DEBUG_AUDIO - abort (); -#endif - return AUDIO_U8; - } -} - -static int sdl_to_audfmt(int sdlfmt, audfmt_e *fmt, int *endianness) -{ - switch (sdlfmt) { - case AUDIO_S8: - *endianness = 0; - *fmt = AUD_FMT_S8; - break; - - case AUDIO_U8: - *endianness = 0; - *fmt = AUD_FMT_U8; - break; - - case AUDIO_S16LSB: - *endianness = 0; - *fmt = AUD_FMT_S16; - break; - - case AUDIO_U16LSB: - *endianness = 0; - *fmt = AUD_FMT_U16; - break; - - case AUDIO_S16MSB: - *endianness = 1; - *fmt = AUD_FMT_S16; - break; - - case AUDIO_U16MSB: - *endianness = 1; - *fmt = AUD_FMT_U16; - break; - - default: - dolog ("Unrecognized SDL audio format %d\n", sdlfmt); - return -1; - } - - return 0; -} - -static int sdl_open (SDL_AudioSpec *req, SDL_AudioSpec *obt) -{ - int status; -#ifndef _WIN32 - int err; - sigset_t new, old; - - /* Make sure potential threads created by SDL don't hog signals. */ - err = sigfillset (&new); - if (err) { - dolog ("sdl_open: sigfillset failed: %s\n", strerror (errno)); - return -1; - } - err = pthread_sigmask (SIG_BLOCK, &new, &old); - if (err) { - dolog ("sdl_open: pthread_sigmask failed: %s\n", strerror (err)); - return -1; - } -#endif - - status = SDL_OpenAudio (req, obt); - if (status) { - sdl_logerr ("SDL_OpenAudio failed\n"); - } - -#ifndef _WIN32 - err = pthread_sigmask (SIG_SETMASK, &old, NULL); - if (err) { - dolog ("sdl_open: pthread_sigmask (restore) failed: %s\n", - strerror (errno)); - /* We have failed to restore original signal mask, all bets are off, - so exit the process */ - exit (EXIT_FAILURE); - } -#endif - return status; -} - -static void sdl_close (SDLAudioState *s) -{ - if (s->initialized) { - sdl_lock (s, "sdl_close"); - s->exit = 1; - sdl_unlock_and_post (s, "sdl_close"); - SDL_PauseAudio (1); - SDL_CloseAudio (); - s->initialized = 0; - } -} - -static void sdl_callback (void *opaque, Uint8 *buf, int len) -{ - SDLVoiceOut *sdl = opaque; - SDLAudioState *s = &glob_sdl; - HWVoiceOut *hw = &sdl->hw; - int samples = len >> hw->info.shift; - - if (s->exit) { - return; - } - - while (samples) { - int to_mix, decr; - - /* dolog ("in callback samples=%d\n", samples); */ - sdl_wait (s, "sdl_callback"); - if (s->exit) { - return; - } - - if (sdl_lock (s, "sdl_callback")) { - return; - } - - if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) { - dolog ("sdl->live=%d hw->samples=%d\n", - sdl->live, hw->samples); - return; - } - - if (!sdl->live) { - goto again; - } - - /* dolog ("in callback live=%d\n", live); */ - to_mix = audio_MIN (samples, sdl->live); - decr = to_mix; - while (to_mix) { - int chunk = audio_MIN (to_mix, hw->samples - hw->rpos); - struct st_sample *src = hw->mix_buf + hw->rpos; - - /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ - hw->clip (buf, src, chunk); - sdl->rpos = (sdl->rpos + chunk) % hw->samples; - to_mix -= chunk; - buf += chunk << hw->info.shift; - } - samples -= decr; - sdl->live -= decr; - sdl->decr += decr; - - again: - if (sdl_unlock (s, "sdl_callback")) { - return; - } - } - /* dolog ("done len=%d\n", len); */ -} - -static int sdl_write_out (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -static int sdl_run_out (HWVoiceOut *hw, int live) -{ - int decr; - SDLVoiceOut *sdl = (SDLVoiceOut *) hw; - SDLAudioState *s = &glob_sdl; - - if (sdl_lock (s, "sdl_run_out")) { - return 0; - } - - if (sdl->decr > live) { - ldebug ("sdl->decr %d live %d sdl->live %d\n", - sdl->decr, - live, - sdl->live); - } - - decr = audio_MIN (sdl->decr, live); - sdl->decr -= decr; - - sdl->live = live - decr; - hw->rpos = sdl->rpos; - - if (sdl->live > 0) { - sdl_unlock_and_post (s, "sdl_run_out"); - } - else { - sdl_unlock (s, "sdl_run_out"); - } - return decr; -} - -static void sdl_fini_out (HWVoiceOut *hw) -{ - (void) hw; - - sdl_close (&glob_sdl); -} - -static int sdl_init_out(HWVoiceOut *hw, struct audsettings *as, - void *drv_opaque) -{ - SDLVoiceOut *sdl = (SDLVoiceOut *) hw; - SDLAudioState *s = &glob_sdl; - SDL_AudioSpec req, obt; - int endianness; - int err; - audfmt_e effective_fmt; - struct audsettings obt_as; - - req.freq = as->freq; - req.format = aud_to_sdlfmt (as->fmt); - req.channels = as->nchannels; - req.samples = conf.nb_samples; - req.callback = sdl_callback; - req.userdata = sdl; - - if (sdl_open (&req, &obt)) { - return -1; - } - - err = sdl_to_audfmt(obt.format, &effective_fmt, &endianness); - if (err) { - sdl_close (s); - return -1; - } - - obt_as.freq = obt.freq; - obt_as.nchannels = obt.channels; - obt_as.fmt = effective_fmt; - obt_as.endianness = endianness; - - audio_pcm_init_info (&hw->info, &obt_as); - hw->samples = obt.samples; - - s->initialized = 1; - s->exit = 0; - SDL_PauseAudio (0); - return 0; -} - -static int sdl_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - (void) hw; - - switch (cmd) { - case VOICE_ENABLE: - SDL_PauseAudio (0); - break; - - case VOICE_DISABLE: - SDL_PauseAudio (1); - break; - } - return 0; -} - -static void *sdl_audio_init (void) -{ - SDLAudioState *s = &glob_sdl; - if (s->driver_created) { - sdl_logerr("Can't create multiple sdl backends\n"); - return NULL; - } - - if (SDL_InitSubSystem (SDL_INIT_AUDIO)) { - sdl_logerr ("SDL failed to initialize audio subsystem\n"); - return NULL; - } - - s->mutex = SDL_CreateMutex (); - if (!s->mutex) { - sdl_logerr ("Failed to create SDL mutex\n"); - SDL_QuitSubSystem (SDL_INIT_AUDIO); - return NULL; - } - - s->sem = SDL_CreateSemaphore (0); - if (!s->sem) { - sdl_logerr ("Failed to create SDL semaphore\n"); - SDL_DestroyMutex (s->mutex); - SDL_QuitSubSystem (SDL_INIT_AUDIO); - return NULL; - } - - s->driver_created = true; - return s; -} - -static void sdl_audio_fini (void *opaque) -{ - SDLAudioState *s = opaque; - sdl_close (s); - SDL_DestroySemaphore (s->sem); - SDL_DestroyMutex (s->mutex); - SDL_QuitSubSystem (SDL_INIT_AUDIO); - s->driver_created = false; -} - -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, - .run_out = sdl_run_out, - .write = sdl_write_out, - .ctl_out = sdl_ctl_out, -}; - -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, - .can_be_default = 1, - .max_voices_out = 1, - .max_voices_in = 0, - .voice_size_out = sizeof (SDLVoiceOut), - .voice_size_in = 0 -}; diff --git a/qemu/audio/spiceaudio.c b/qemu/audio/spiceaudio.c deleted file mode 100644 index dea71d37a..000000000 --- a/qemu/audio/spiceaudio.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat, Inc. - * - * maintained by Gerd Hoffmann <kraxel@redhat.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 or - * (at your option) version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "qemu/error-report.h" -#include "qemu/timer.h" -#include "ui/qemu-spice.h" - -#define AUDIO_CAP "spice" -#include "audio.h" -#include "audio_int.h" - -#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3 -#define LINE_OUT_SAMPLES (480 * 4) -#else -#define LINE_OUT_SAMPLES (256 * 4) -#endif - -#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3 -#define LINE_IN_SAMPLES (480 * 4) -#else -#define LINE_IN_SAMPLES (256 * 4) -#endif - -typedef struct SpiceRateCtl { - int64_t start_ticks; - int64_t bytes_sent; -} SpiceRateCtl; - -typedef struct SpiceVoiceOut { - HWVoiceOut hw; - SpicePlaybackInstance sin; - SpiceRateCtl rate; - int active; - uint32_t *frame; - uint32_t *fpos; - uint32_t fsize; -} SpiceVoiceOut; - -typedef struct SpiceVoiceIn { - HWVoiceIn hw; - SpiceRecordInstance sin; - SpiceRateCtl rate; - int active; - uint32_t samples[LINE_IN_SAMPLES]; -} SpiceVoiceIn; - -static const SpicePlaybackInterface playback_sif = { - .base.type = SPICE_INTERFACE_PLAYBACK, - .base.description = "playback", - .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR, - .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR, -}; - -static const SpiceRecordInterface record_sif = { - .base.type = SPICE_INTERFACE_RECORD, - .base.description = "record", - .base.major_version = SPICE_INTERFACE_RECORD_MAJOR, - .base.minor_version = SPICE_INTERFACE_RECORD_MINOR, -}; - -static void *spice_audio_init (void) -{ - if (!using_spice) { - return NULL; - } - return &spice_audio_init; -} - -static void spice_audio_fini (void *opaque) -{ - /* nothing */ -} - -static void rate_start (SpiceRateCtl *rate) -{ - memset (rate, 0, sizeof (*rate)); - rate->start_ticks = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); -} - -static int rate_get_samples (struct audio_pcm_info *info, SpiceRateCtl *rate) -{ - int64_t now; - int64_t ticks; - int64_t bytes; - int64_t samples; - - now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - ticks = now - rate->start_ticks; - bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND); - samples = (bytes - rate->bytes_sent) >> info->shift; - if (samples < 0 || samples > 65536) { - error_report("Resetting rate control (%" PRId64 " samples)", samples); - rate_start(rate); - samples = 0; - } - rate->bytes_sent += samples << info->shift; - return samples; -} - -/* playback */ - -static int line_out_init(HWVoiceOut *hw, struct audsettings *as, - void *drv_opaque) -{ - SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); - struct audsettings settings; - -#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3 - settings.freq = spice_server_get_best_playback_rate(NULL); -#else - settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ; -#endif - settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN; - settings.fmt = AUD_FMT_S16; - settings.endianness = AUDIO_HOST_ENDIANNESS; - - audio_pcm_init_info (&hw->info, &settings); - hw->samples = LINE_OUT_SAMPLES; - out->active = 0; - - out->sin.base.sif = &playback_sif.base; - qemu_spice_add_interface (&out->sin.base); -#if SPICE_INTERFACE_PLAYBACK_MAJOR > 1 || SPICE_INTERFACE_PLAYBACK_MINOR >= 3 - spice_server_set_playback_rate(&out->sin, settings.freq); -#endif - return 0; -} - -static void line_out_fini (HWVoiceOut *hw) -{ - SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); - - spice_server_remove_interface (&out->sin.base); -} - -static int line_out_run (HWVoiceOut *hw, int live) -{ - SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); - int rpos, decr; - int samples; - - if (!live) { - return 0; - } - - decr = rate_get_samples (&hw->info, &out->rate); - decr = audio_MIN (live, decr); - - samples = decr; - rpos = hw->rpos; - while (samples) { - int left_till_end_samples = hw->samples - rpos; - int len = audio_MIN (samples, left_till_end_samples); - - if (!out->frame) { - spice_server_playback_get_buffer (&out->sin, &out->frame, &out->fsize); - out->fpos = out->frame; - } - if (out->frame) { - len = audio_MIN (len, out->fsize); - hw->clip (out->fpos, hw->mix_buf + rpos, len); - out->fsize -= len; - out->fpos += len; - if (out->fsize == 0) { - spice_server_playback_put_samples (&out->sin, out->frame); - out->frame = out->fpos = NULL; - } - } - rpos = (rpos + len) % hw->samples; - samples -= len; - } - hw->rpos = rpos; - return decr; -} - -static int line_out_write (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) -{ - SpiceVoiceOut *out = container_of (hw, SpiceVoiceOut, hw); - - switch (cmd) { - case VOICE_ENABLE: - if (out->active) { - break; - } - out->active = 1; - rate_start (&out->rate); - spice_server_playback_start (&out->sin); - break; - case VOICE_DISABLE: - if (!out->active) { - break; - } - out->active = 0; - if (out->frame) { - memset (out->fpos, 0, out->fsize << 2); - spice_server_playback_put_samples (&out->sin, out->frame); - out->frame = out->fpos = NULL; - } - spice_server_playback_stop (&out->sin); - break; - case VOICE_VOLUME: - { -#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) - SWVoiceOut *sw; - va_list ap; - uint16_t vol[2]; - - va_start (ap, cmd); - sw = va_arg (ap, SWVoiceOut *); - va_end (ap); - - vol[0] = sw->vol.l / ((1ULL << 16) + 1); - vol[1] = sw->vol.r / ((1ULL << 16) + 1); - spice_server_playback_set_volume (&out->sin, 2, vol); - spice_server_playback_set_mute (&out->sin, sw->vol.mute); -#endif - break; - } - } - - return 0; -} - -/* record */ - -static int line_in_init(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque) -{ - SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); - struct audsettings settings; - -#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3 - settings.freq = spice_server_get_best_record_rate(NULL); -#else - settings.freq = SPICE_INTERFACE_RECORD_FREQ; -#endif - settings.nchannels = SPICE_INTERFACE_RECORD_CHAN; - settings.fmt = AUD_FMT_S16; - settings.endianness = AUDIO_HOST_ENDIANNESS; - - audio_pcm_init_info (&hw->info, &settings); - hw->samples = LINE_IN_SAMPLES; - in->active = 0; - - in->sin.base.sif = &record_sif.base; - qemu_spice_add_interface (&in->sin.base); -#if SPICE_INTERFACE_RECORD_MAJOR > 2 || SPICE_INTERFACE_RECORD_MINOR >= 3 - spice_server_set_record_rate(&in->sin, settings.freq); -#endif - return 0; -} - -static void line_in_fini (HWVoiceIn *hw) -{ - SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); - - spice_server_remove_interface (&in->sin.base); -} - -static int line_in_run (HWVoiceIn *hw) -{ - SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); - int num_samples; - int ready; - int len[2]; - uint64_t delta_samp; - const uint32_t *samples; - - if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in (hw))) { - return 0; - } - - delta_samp = rate_get_samples (&hw->info, &in->rate); - num_samples = audio_MIN (num_samples, delta_samp); - - ready = spice_server_record_get_samples (&in->sin, in->samples, num_samples); - samples = in->samples; - if (ready == 0) { - static const uint32_t silence[LINE_IN_SAMPLES]; - samples = silence; - ready = LINE_IN_SAMPLES; - } - - num_samples = audio_MIN (ready, num_samples); - - if (hw->wpos + num_samples > hw->samples) { - len[0] = hw->samples - hw->wpos; - len[1] = num_samples - len[0]; - } else { - len[0] = num_samples; - len[1] = 0; - } - - hw->conv (hw->conv_buf + hw->wpos, samples, len[0]); - - if (len[1]) { - hw->conv (hw->conv_buf, samples + len[0], len[1]); - } - - hw->wpos = (hw->wpos + num_samples) % hw->samples; - - return num_samples; -} - -static int line_in_read (SWVoiceIn *sw, void *buf, int size) -{ - return audio_pcm_sw_read (sw, buf, size); -} - -static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) -{ - SpiceVoiceIn *in = container_of (hw, SpiceVoiceIn, hw); - - switch (cmd) { - case VOICE_ENABLE: - if (in->active) { - break; - } - in->active = 1; - rate_start (&in->rate); - spice_server_record_start (&in->sin); - break; - case VOICE_DISABLE: - if (!in->active) { - break; - } - in->active = 0; - spice_server_record_stop (&in->sin); - break; - case VOICE_VOLUME: - { -#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) - SWVoiceIn *sw; - va_list ap; - uint16_t vol[2]; - - va_start (ap, cmd); - sw = va_arg (ap, SWVoiceIn *); - va_end (ap); - - vol[0] = sw->vol.l / ((1ULL << 16) + 1); - vol[1] = sw->vol.r / ((1ULL << 16) + 1); - spice_server_record_set_volume (&in->sin, 2, vol); - spice_server_record_set_mute (&in->sin, sw->vol.mute); -#endif - break; - } - } - - 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, - .run_out = line_out_run, - .write = line_out_write, - .ctl_out = line_out_ctl, - - .init_in = line_in_init, - .fini_in = line_in_fini, - .run_in = line_in_run, - .read = line_in_read, - .ctl_in = line_in_ctl, -}; - -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, - .max_voices_out = 1, - .max_voices_in = 1, - .voice_size_out = sizeof (SpiceVoiceOut), - .voice_size_in = sizeof (SpiceVoiceIn), -#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) - .ctl_caps = VOICE_VOLUME_CAP -#endif -}; - -void qemu_spice_audio_init (void) -{ - spice_audio_driver.can_be_default = 1; -} diff --git a/qemu/audio/wavaudio.c b/qemu/audio/wavaudio.c deleted file mode 100644 index 345952e51..000000000 --- a/qemu/audio/wavaudio.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * QEMU WAV audio driver - * - * Copyright (c) 2004-2005 Vassili Karpov (malc) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "qemu/timer.h" -#include "audio.h" - -#define AUDIO_CAP "wav" -#include "audio_int.h" - -typedef struct WAVVoiceOut { - HWVoiceOut hw; - FILE *f; - int64_t old_ticks; - void *pcm_buf; - int total_samples; -} WAVVoiceOut; - -typedef struct { - struct audsettings settings; - const char *wav_path; -} WAVConf; - -static int wav_run_out (HWVoiceOut *hw, int live) -{ - WAVVoiceOut *wav = (WAVVoiceOut *) hw; - int rpos, decr, samples; - uint8_t *dst; - struct st_sample *src; - int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); - int64_t ticks = now - wav->old_ticks; - int64_t bytes = - muldiv64(ticks, hw->info.bytes_per_second, NANOSECONDS_PER_SECOND); - - if (bytes > INT_MAX) { - samples = INT_MAX >> hw->info.shift; - } - else { - samples = bytes >> hw->info.shift; - } - - wav->old_ticks = now; - decr = audio_MIN (live, samples); - samples = decr; - rpos = hw->rpos; - while (samples) { - int left_till_end_samples = hw->samples - rpos; - int convert_samples = audio_MIN (samples, left_till_end_samples); - - src = hw->mix_buf + rpos; - dst = advance (wav->pcm_buf, rpos << hw->info.shift); - - hw->clip (dst, src, convert_samples); - if (fwrite (dst, convert_samples << hw->info.shift, 1, wav->f) != 1) { - dolog ("wav_run_out: fwrite of %d bytes failed\nReaons: %s\n", - convert_samples << hw->info.shift, strerror (errno)); - } - - rpos = (rpos + convert_samples) % hw->samples; - samples -= convert_samples; - wav->total_samples += convert_samples; - } - - hw->rpos = rpos; - return decr; -} - -static int wav_write_out (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -/* VICE code: Store number as little endian. */ -static void le_store (uint8_t *buf, uint32_t val, int len) -{ - int i; - for (i = 0; i < len; i++) { - buf[i] = (uint8_t) (val & 0xff); - val >>= 8; - } -} - -static int wav_init_out(HWVoiceOut *hw, struct audsettings *as, - void *drv_opaque) -{ - WAVVoiceOut *wav = (WAVVoiceOut *) hw; - int bits16 = 0, stereo = 0; - uint8_t hdr[] = { - 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, - 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, - 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 - }; - WAVConf *conf = drv_opaque; - struct audsettings wav_as = conf->settings; - - stereo = wav_as.nchannels == 2; - switch (wav_as.fmt) { - case AUD_FMT_S8: - case AUD_FMT_U8: - bits16 = 0; - break; - - case AUD_FMT_S16: - case AUD_FMT_U16: - bits16 = 1; - break; - - case AUD_FMT_S32: - case AUD_FMT_U32: - dolog ("WAVE files can not handle 32bit formats\n"); - return -1; - } - - hdr[34] = bits16 ? 0x10 : 0x08; - - wav_as.endianness = 0; - audio_pcm_init_info (&hw->info, &wav_as); - - hw->samples = 1024; - wav->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - if (!wav->pcm_buf) { - dolog ("Could not allocate buffer (%d bytes)\n", - hw->samples << hw->info.shift); - return -1; - } - - le_store (hdr + 22, hw->info.nchannels, 2); - le_store (hdr + 24, hw->info.freq, 4); - le_store (hdr + 28, hw->info.freq << (bits16 + stereo), 4); - le_store (hdr + 32, 1 << (bits16 + stereo), 2); - - wav->f = fopen (conf->wav_path, "wb"); - if (!wav->f) { - dolog ("Failed to open wave file `%s'\nReason: %s\n", - conf->wav_path, strerror (errno)); - g_free (wav->pcm_buf); - wav->pcm_buf = NULL; - return -1; - } - - if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) { - dolog ("wav_init_out: failed to write header\nReason: %s\n", - strerror(errno)); - return -1; - } - return 0; -} - -static void wav_fini_out (HWVoiceOut *hw) -{ - WAVVoiceOut *wav = (WAVVoiceOut *) hw; - uint8_t rlen[4]; - uint8_t dlen[4]; - uint32_t datalen = wav->total_samples << hw->info.shift; - uint32_t rifflen = datalen + 36; - - if (!wav->f) { - return; - } - - le_store (rlen, rifflen, 4); - le_store (dlen, datalen, 4); - - if (fseek (wav->f, 4, SEEK_SET)) { - dolog ("wav_fini_out: fseek to rlen failed\nReason: %s\n", - strerror(errno)); - goto doclose; - } - if (fwrite (rlen, 4, 1, wav->f) != 1) { - dolog ("wav_fini_out: failed to write rlen\nReason: %s\n", - strerror (errno)); - goto doclose; - } - if (fseek (wav->f, 32, SEEK_CUR)) { - dolog ("wav_fini_out: fseek to dlen failed\nReason: %s\n", - strerror (errno)); - goto doclose; - } - if (fwrite (dlen, 4, 1, wav->f) != 1) { - dolog ("wav_fini_out: failed to write dlen\nReaons: %s\n", - strerror (errno)); - goto doclose; - } - - doclose: - if (fclose (wav->f)) { - dolog ("wav_fini_out: fclose %p failed\nReason: %s\n", - wav->f, strerror (errno)); - } - wav->f = NULL; - - g_free (wav->pcm_buf); - wav->pcm_buf = NULL; -} - -static int wav_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - -static WAVConf glob_conf = { - .settings.freq = 44100, - .settings.nchannels = 2, - .settings.fmt = AUD_FMT_S16, - .wav_path = "qemu.wav" -}; - -static void *wav_audio_init (void) -{ - WAVConf *conf = g_malloc(sizeof(WAVConf)); - *conf = glob_conf; - return conf; -} - -static void wav_audio_fini (void *opaque) -{ - ldebug ("wav_fini"); - g_free(opaque); -} - -static struct audio_option wav_options[] = { - { - .name = "FREQUENCY", - .tag = AUD_OPT_INT, - .valp = &glob_conf.settings.freq, - .descr = "Frequency" - }, - { - .name = "FORMAT", - .tag = AUD_OPT_FMT, - .valp = &glob_conf.settings.fmt, - .descr = "Format" - }, - { - .name = "DAC_FIXED_CHANNELS", - .tag = AUD_OPT_INT, - .valp = &glob_conf.settings.nchannels, - .descr = "Number of channels (1 - mono, 2 - stereo)" - }, - { - .name = "PATH", - .tag = AUD_OPT_STR, - .valp = &glob_conf.wav_path, - .descr = "Path to wave file" - }, - { /* End of list */ } -}; - -static struct audio_pcm_ops wav_pcm_ops = { - .init_out = wav_init_out, - .fini_out = wav_fini_out, - .run_out = wav_run_out, - .write = wav_write_out, - .ctl_out = wav_ctl_out, -}; - -struct audio_driver wav_audio_driver = { - .name = "wav", - .descr = "WAV renderer http://wikipedia.org/wiki/WAV", - .options = wav_options, - .init = wav_audio_init, - .fini = wav_audio_fini, - .pcm_ops = &wav_pcm_ops, - .can_be_default = 0, - .max_voices_out = 1, - .max_voices_in = 0, - .voice_size_out = sizeof (WAVVoiceOut), - .voice_size_in = 0 -}; diff --git a/qemu/audio/wavcapture.c b/qemu/audio/wavcapture.c deleted file mode 100644 index 8bfb9e765..000000000 --- a/qemu/audio/wavcapture.c +++ /dev/null @@ -1,195 +0,0 @@ -#include "qemu/osdep.h" -#include "hw/hw.h" -#include "monitor/monitor.h" -#include "qemu/error-report.h" -#include "audio.h" - -typedef struct { - FILE *f; - int bytes; - char *path; - int freq; - int bits; - int nchannels; - CaptureVoiceOut *cap; -} WAVState; - -/* VICE code: Store number as little endian. */ -static void le_store (uint8_t *buf, uint32_t val, int len) -{ - int i; - for (i = 0; i < len; i++) { - buf[i] = (uint8_t) (val & 0xff); - val >>= 8; - } -} - -static void wav_notify (void *opaque, audcnotification_e cmd) -{ - (void) opaque; - (void) cmd; -} - -static void wav_destroy (void *opaque) -{ - WAVState *wav = opaque; - uint8_t rlen[4]; - uint8_t dlen[4]; - uint32_t datalen = wav->bytes; - uint32_t rifflen = datalen + 36; - Monitor *mon = cur_mon; - - if (wav->f) { - le_store (rlen, rifflen, 4); - le_store (dlen, datalen, 4); - - if (fseek (wav->f, 4, SEEK_SET)) { - monitor_printf (mon, "wav_destroy: rlen fseek failed\nReason: %s\n", - strerror (errno)); - goto doclose; - } - if (fwrite (rlen, 4, 1, wav->f) != 1) { - monitor_printf (mon, "wav_destroy: rlen fwrite failed\nReason %s\n", - strerror (errno)); - goto doclose; - } - if (fseek (wav->f, 32, SEEK_CUR)) { - monitor_printf (mon, "wav_destroy: dlen fseek failed\nReason %s\n", - strerror (errno)); - goto doclose; - } - if (fwrite (dlen, 1, 4, wav->f) != 4) { - monitor_printf (mon, "wav_destroy: dlen fwrite failed\nReason %s\n", - strerror (errno)); - goto doclose; - } - doclose: - if (fclose (wav->f)) { - error_report("wav_destroy: fclose failed: %s", strerror(errno)); - } - } - - g_free (wav->path); -} - -static void wav_capture (void *opaque, void *buf, int size) -{ - WAVState *wav = opaque; - - if (fwrite (buf, size, 1, wav->f) != 1) { - monitor_printf (cur_mon, "wav_capture: fwrite error\nReason: %s", - strerror (errno)); - } - wav->bytes += size; -} - -static void wav_capture_destroy (void *opaque) -{ - WAVState *wav = opaque; - - AUD_del_capture (wav->cap, wav); -} - -static void wav_capture_info (void *opaque) -{ - WAVState *wav = opaque; - char *path = wav->path; - - monitor_printf (cur_mon, "Capturing audio(%d,%d,%d) to %s: %d bytes\n", - wav->freq, wav->bits, wav->nchannels, - path ? path : "<not available>", wav->bytes); -} - -static struct capture_ops wav_capture_ops = { - .destroy = wav_capture_destroy, - .info = wav_capture_info -}; - -int wav_start_capture (CaptureState *s, const char *path, int freq, - int bits, int nchannels) -{ - Monitor *mon = cur_mon; - WAVState *wav; - uint8_t hdr[] = { - 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, - 0x45, 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x02, 0x00, 0x44, 0xac, 0x00, 0x00, 0x10, 0xb1, 0x02, 0x00, 0x04, - 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0x00, 0x00, 0x00 - }; - struct audsettings as; - struct audio_capture_ops ops; - int stereo, bits16, shift; - CaptureVoiceOut *cap; - - if (bits != 8 && bits != 16) { - monitor_printf (mon, "incorrect bit count %d, must be 8 or 16\n", bits); - return -1; - } - - if (nchannels != 1 && nchannels != 2) { - monitor_printf (mon, "incorrect channel count %d, must be 1 or 2\n", - nchannels); - return -1; - } - - stereo = nchannels == 2; - bits16 = bits == 16; - - as.freq = freq; - as.nchannels = 1 << stereo; - as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8; - as.endianness = 0; - - ops.notify = wav_notify; - ops.capture = wav_capture; - ops.destroy = wav_destroy; - - wav = g_malloc0 (sizeof (*wav)); - - shift = bits16 + stereo; - hdr[34] = bits16 ? 0x10 : 0x08; - - le_store (hdr + 22, as.nchannels, 2); - le_store (hdr + 24, freq, 4); - le_store (hdr + 28, freq << shift, 4); - le_store (hdr + 32, 1 << shift, 2); - - wav->f = fopen (path, "wb"); - if (!wav->f) { - monitor_printf (mon, "Failed to open wave file `%s'\nReason: %s\n", - path, strerror (errno)); - g_free (wav); - return -1; - } - - wav->path = g_strdup (path); - wav->bits = bits; - wav->nchannels = nchannels; - wav->freq = freq; - - if (fwrite (hdr, sizeof (hdr), 1, wav->f) != 1) { - monitor_printf (mon, "Failed to write header\nReason: %s\n", - strerror (errno)); - goto error_free; - } - - cap = AUD_add_capture (&as, &ops, wav); - if (!cap) { - monitor_printf (mon, "Failed to add audio capture\n"); - goto error_free; - } - - wav->cap = cap; - s->opaque = wav; - s->ops = wav_capture_ops; - return 0; - -error_free: - g_free (wav->path); - if (fclose (wav->f)) { - monitor_printf (mon, "Failed to close wave file\nReason: %s\n", - strerror (errno)); - } - g_free (wav); - return -1; -} |