diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:35 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:35 -0800 |
commit | f721e3ac031f892af46f255a47d7f54a91317b30 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /audio | |
parent | bae1bc39312d5019bd9a5b8d840a529213a69a17 (diff) | |
download | external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.zip external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.tar.gz external_qemu-f721e3ac031f892af46f255a47d7f54a91317b30.tar.bz2 |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'audio')
-rw-r--r-- | audio/alsaaudio.c | 1067 | ||||
-rw-r--r-- | audio/audio.c | 2172 | ||||
-rw-r--r-- | audio/audio.h | 185 | ||||
-rw-r--r-- | audio/audio_int.h | 287 | ||||
-rw-r--r-- | audio/audio_pt_int.c | 148 | ||||
-rw-r--r-- | audio/audio_pt_int.h | 22 | ||||
-rw-r--r-- | audio/audio_template.h | 577 | ||||
-rw-r--r-- | audio/coreaudio.c | 821 | ||||
-rw-r--r-- | audio/dsound_template.h | 291 | ||||
-rw-r--r-- | audio/dsoundaudio.c | 1086 | ||||
-rw-r--r-- | audio/esdaudio.c | 682 | ||||
-rw-r--r-- | audio/fmodaudio.c | 685 | ||||
-rw-r--r-- | audio/mixeng.c | 336 | ||||
-rw-r--r-- | audio/mixeng.h | 51 | ||||
-rw-r--r-- | audio/mixeng_template.h | 177 | ||||
-rw-r--r-- | audio/noaudio.c | 172 | ||||
-rw-r--r-- | audio/ossaudio.c | 773 | ||||
-rw-r--r-- | audio/rate_template.h | 111 | ||||
-rw-r--r-- | audio/sdlaudio.c | 660 | ||||
-rw-r--r-- | audio/sys-queue.h | 241 | ||||
-rw-r--r-- | audio/wavaudio.c | 482 | ||||
-rw-r--r-- | audio/wavcapture.c | 166 | ||||
-rw-r--r-- | audio/winaudio.c | 666 |
23 files changed, 0 insertions, 11858 deletions
diff --git a/audio/alsaaudio.c b/audio/alsaaudio.c deleted file mode 100644 index 1cc4d6e..0000000 --- a/audio/alsaaudio.c +++ /dev/null @@ -1,1067 +0,0 @@ -/* - * QEMU ALSA audio driver - * - * Copyright (c) 2008 The Android Open Source Project - * 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 <alsa/asoundlib.h> -#include "audio.h" - -#define AUDIO_CAP "alsa" -#include "audio_int.h" -#include <dlfcn.h> -#include <pthread.h> -#include "qemu_debug.h" - -#define DEBUG 1 - -#if DEBUG -# include <stdio.h> -# define D(...) VERBOSE_PRINT(audio,__VA_ARGS__) -# define D_ACTIVE VERBOSE_CHECK(audio) -# define O(...) VERBOSE_PRINT(audioout,__VA_ARGS__) -# define I(...) VERBOSE_PRINT(audioin,__VA_ARGS__) -#else -# define D(...) ((void)0) -# define D_ACTIVE 0 -# define O(...) ((void)0) -# define I(...) ((void)0) -#endif - - -#define STRINGIFY_(x) #x -#define STRINGIFY(x) STRINGIFY_(x) - -#define DYNLINK_FUNCTIONS \ - DYNLINK_FUNC(size_t,snd_pcm_sw_params_sizeof,(void)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_current,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \ - DYNLINK_FUNC(int,snd_pcm_sw_params_set_start_threshold,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params, snd_pcm_uframes_t val)) \ - DYNLINK_FUNC(int,snd_pcm_sw_params,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \ - DYNLINK_FUNC(int,snd_pcm_sw_params_current,(snd_pcm_t *pcm, snd_pcm_sw_params_t *params)) \ - DYNLINK_FUNC(size_t,snd_pcm_hw_params_sizeof,(void)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_any,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_access,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_access_t _access)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_get_format,(const snd_pcm_hw_params_t *params, snd_pcm_format_t *val)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_format,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_format_t val)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_rate_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_channels_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_get_buffer_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \ - DYNLINK_FUNC(int,snd_pcm_prepare,(snd_pcm_t *pcm)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_get_period_size,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_get_period_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *frames, int *dir)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val, int dir)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_get_buffer_size_min,(const snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_size,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t val)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_time_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, unsigned int *val, int *dir)) \ - DYNLINK_FUNC(snd_pcm_sframes_t,snd_pcm_avail_update,(snd_pcm_t *pcm)) \ - DYNLINK_FUNC(int,snd_pcm_drop,(snd_pcm_t *pcm)) \ - DYNLINK_FUNC(snd_pcm_sframes_t,snd_pcm_writei,(snd_pcm_t *pcm, const void *buffer, snd_pcm_uframes_t size)) \ - DYNLINK_FUNC(snd_pcm_sframes_t,snd_pcm_readi,(snd_pcm_t *pcm, void *buffer, snd_pcm_uframes_t size)) \ - DYNLINK_FUNC(snd_pcm_state_t,snd_pcm_state,(snd_pcm_t *pcm)) \ - DYNLINK_FUNC(const char*,snd_strerror,(int errnum)) \ - DYNLINK_FUNC(int,snd_pcm_open,(snd_pcm_t **pcm, const char *name,snd_pcm_stream_t stream, int mode)) \ - DYNLINK_FUNC(int,snd_pcm_close,(snd_pcm_t *pcm)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_buffer_size_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_set_period_size_near,(snd_pcm_t *pcm, snd_pcm_hw_params_t *params, snd_pcm_uframes_t *val, int *dir)) \ - DYNLINK_FUNC(int,snd_pcm_hw_params_get_format,(const snd_pcm_hw_params_t *params, snd_pcm_format_t *val)) \ - -#define DYNLINK_FUNCTIONS_INIT \ - alsa_dynlink_init - -#include "dynlink.h" - -/* these are inlined functions in the original headers */ -#define FF_snd_pcm_hw_params_alloca(ptr) \ - do { assert(ptr); *ptr = (snd_pcm_hw_params_t *) alloca(FF(snd_pcm_hw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_hw_params_sizeof)()); } while (0) - -#define FF_snd_pcm_sw_params_alloca(ptr) \ - do { assert(ptr); *ptr = (snd_pcm_sw_params_t *) alloca(FF(snd_pcm_sw_params_sizeof)()); memset(*ptr, 0, FF(snd_pcm_sw_params_sizeof)()); } while (0) - -static void* alsa_lib; - -typedef struct ALSAVoiceOut { - HWVoiceOut hw; - void *pcm_buf; - snd_pcm_t *handle; -} ALSAVoiceOut; - -typedef struct ALSAVoiceIn { - HWVoiceIn hw; - snd_pcm_t *handle; - void *pcm_buf; -} ALSAVoiceIn; - -static struct { - 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; - int verbose; -} conf = { - .buffer_size_out = 1024, - .pcm_name_out = "default", - .pcm_name_in = "default", -}; - -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", FF(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", FF(snd_strerror) (err)); -} - -static void alsa_anal_close (snd_pcm_t **handlep) -{ - int err = FF(snd_pcm_close) (*handlep); - if (err) { - alsa_logerr (err, "Failed to close PCM handle %p\n", *handlep); - } - *handlep = NULL; -} - -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) -{ - switch (fmt) { - case AUD_FMT_S8: - return SND_PCM_FORMAT_S8; - - case AUD_FMT_U8: - return SND_PCM_FORMAT_U8; - - case AUD_FMT_S16: - return SND_PCM_FORMAT_S16_LE; - - case AUD_FMT_U16: - return SND_PCM_FORMAT_U16_LE; - - case AUD_FMT_S32: - return SND_PCM_FORMAT_S32_LE; - - case AUD_FMT_U32: - 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) -{ - 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 ("============================================\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; - - FF_snd_pcm_sw_params_alloca (&sw_params); - - err = FF(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 = FF(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 = FF(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) -{ - 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; - - FF_snd_pcm_hw_params_alloca (&hw_params); - - err = FF(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 = FF(snd_pcm_hw_params_any) (handle, hw_params); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to initialize hardware parameters\n"); - goto err; - } - - err = FF(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 = FF(snd_pcm_hw_params_set_format) (handle, hw_params, req->fmt); - if (err < 0 && conf.verbose) { - alsa_logerr2 (err, typ, "Failed to set format %d\n", req->fmt); - goto err; - } - - err = FF(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 = FF(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 = FF(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 = FF(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 = FF(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 = FF(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 = FF(snd_pcm_hw_params) (handle, hw_params); - if (err < 0) { - alsa_logerr2 (err, typ, "Failed to apply audio parameters\n"); - goto err; - } - - err = FF(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 = FF(snd_pcm_hw_params_get_format)(hw_params, &obtfmt); - err = FF(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 = FF(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 (conf.verbose && - (obt->fmt != req->fmt || - obt->nchannels != req->nchannels || - obt->freq != req->freq)) { - dolog ("Audio paramters for %s\n", typ); - alsa_dump_info (req, obt); - } - -#ifdef DEBUG - alsa_dump_info (req, obt); -#endif - return 0; - - err: - alsa_anal_close (&handle); - return -1; -} - -static int alsa_recover (snd_pcm_t *handle) -{ - int err = FF(snd_pcm_prepare) (handle); - if (err < 0) { - alsa_logerr (err, "Failed to prepare handle %p\n", handle); - return -1; - } - return 0; -} - -static snd_pcm_sframes_t alsa_get_avail (snd_pcm_t *handle) -{ - snd_pcm_sframes_t avail; - - avail = FF(snd_pcm_avail_update) (handle); - if (avail < 0) { - if (avail == -EPIPE) { - if (!alsa_recover (handle)) { - avail = FF(snd_pcm_avail_update) (handle); - } - } - - if (avail < 0) { - alsa_logerr (avail, - "Could not obtain number of available frames\n"); - return -1; - } - } - - return avail; -} - -static int alsa_run_out (HWVoiceOut *hw) -{ - ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; - int rpos, live, decr; - int samples; - uint8_t *dst; - st_sample_t *src; - snd_pcm_sframes_t avail; - - live = audio_pcm_hw_get_live_out (hw); - if (!live) { - return 0; - } - - 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); - samples = decr; - rpos = hw->rpos; - while (samples) { - int left_till_end_samples = hw->samples - rpos; - int len = audio_MIN (samples, left_till_end_samples); - snd_pcm_sframes_t written; - - src = hw->mix_buf + rpos; - dst = advance (alsa->pcm_buf, rpos << hw->info.shift); - - hw->clip (dst, src, len); - - while (len) { - written = FF(snd_pcm_writei) (alsa->handle, dst, len); - - if (written <= 0) { - switch (written) { - case 0: - if (conf.verbose) { - dolog ("Failed to write %d frames (wrote zero)\n", len); - } - goto exit; - - case -EPIPE: - if (alsa_recover (alsa->handle)) { - alsa_logerr (written, "Failed to write %d frames\n", - len); - goto exit; - } - if (conf.verbose) { - dolog ("Recovering from playback xrun\n"); - } - continue; - - case -EAGAIN: - goto exit; - - default: - alsa_logerr (written, "Failed to write %d frames to %p\n", - len, dst); - goto exit; - } - } - - rpos = (rpos + written) % hw->samples; - samples -= written; - len -= written; - dst = advance (dst, written << hw->info.shift); - src += written; - } - } - - exit: - hw->rpos = rpos; - return decr; -} - -static void alsa_fini_out (HWVoiceOut *hw) -{ - ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; - - ldebug ("alsa_fini\n"); - alsa_anal_close (&alsa->handle); - - if (alsa->pcm_buf) { - qemu_free (alsa->pcm_buf); - alsa->pcm_buf = NULL; - } -} - -static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as) -{ - ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; - struct alsa_params_req req; - struct alsa_params_obt obt; - snd_pcm_t *handle; - audsettings_t obt_as; - int result = -1; - - /* shut alsa debug spew */ - if (!D_ACTIVE) - stdio_disable(); - - req.fmt = aud_to_alsafmt (as->fmt); - 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 - | (!!conf.buffer_size_out_overridden << 1); - - if (alsa_open (0, &req, &obt, &handle)) { - goto Exit; - } - - 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_close (&handle); - goto Exit; - } - - alsa->handle = handle; - result = 0; /* success */ - -Exit: - if (!D_ACTIVE) - stdio_enable(); - - return result; -} - -static int alsa_voice_ctl (snd_pcm_t *handle, const char *typ, int pause) -{ - int err; - - if (pause) { - err = FF(snd_pcm_drop) (handle); - if (err < 0) { - alsa_logerr (err, "Could not stop %s\n", typ); - return -1; - } - } - else { - err = FF(snd_pcm_prepare) (handle); - if (err < 0) { - alsa_logerr (err, "Could not prepare 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: - ldebug ("enabling voice\n"); - return alsa_voice_ctl (alsa->handle, "playback", 0); - - case VOICE_DISABLE: - ldebug ("disabling voice\n"); - return alsa_voice_ctl (alsa->handle, "playback", 1); - } - - return -1; -} - -static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as) -{ - ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; - struct alsa_params_req req; - struct alsa_params_obt obt; - snd_pcm_t *handle; - audsettings_t obt_as; - int result = -1; - - /* shut alsa debug spew */ - if (!D_ACTIVE) - stdio_disable(); - - req.fmt = aud_to_alsafmt (as->fmt); - 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 - | (!!conf.buffer_size_in_overridden << 1); - - if (alsa_open (1, &req, &obt, &handle)) { - goto Exit; - } - - 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_close (&handle); - goto Exit; - } - - alsa->handle = handle; - result = 0; /* success */ - -Exit: - if (!D_ACTIVE) - stdio_enable(); - - return result; -} - -static void alsa_fini_in (HWVoiceIn *hw) -{ - ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw; - - alsa_anal_close (&alsa->handle); - - if (alsa->pcm_buf) { - qemu_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] = { - { hw->wpos, 0 }, - { 0, 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 && (FF(snd_pcm_state) (alsa->handle) == SND_PCM_STATE_PREPARED)) { - avail = hw->samples; - } - - 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; - st_sample_t *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 = FF(snd_pcm_readi) (alsa->handle, src, len); - - if (nread <= 0) { - switch (nread) { - case 0: - if (conf.verbose) { - dolog ("Failed to read %ld frames (read zero)\n", len); - } - goto exit; - - case -EPIPE: - if (alsa_recover (alsa->handle)) { - alsa_logerr (nread, "Failed to read %ld frames\n", len); - goto exit; - } - if (conf.verbose) { - dolog ("Recovering from capture xrun\n"); - } - 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, &nominal_volume); - - 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: - ldebug ("enabling voice\n"); - return alsa_voice_ctl (alsa->handle, "capture", 0); - - case VOICE_DISABLE: - ldebug ("disabling voice\n"); - return alsa_voice_ctl (alsa->handle, "capture", 1); - } - - return -1; -} - -static void *alsa_audio_init (void) -{ - void* result = NULL; - - alsa_lib = dlopen( "libasound.so", RTLD_NOW ); - if (alsa_lib == NULL) - alsa_lib = dlopen( "libasound.so.2", RTLD_NOW ); - - if (alsa_lib == NULL) { - ldebug("could not find libasound on this system\n"); - goto Exit; - } - - if (alsa_dynlink_init(alsa_lib) < 0) - goto Fail; - - result = &conf; - goto Exit; - -Fail: - ldebug("%s: failed to open library\n", __FUNCTION__); - dlclose(alsa_lib); - -Exit: - return result; -} - -static void alsa_audio_fini (void *opaque) -{ - if (alsa_lib != NULL) { - dlclose(alsa_lib); - alsa_lib = NULL; - } - (void) opaque; -} - -static struct audio_option alsa_options[] = { - {"DAC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_out, - "DAC period/buffer size in microseconds (otherwise in frames)", NULL, 0}, - {"DAC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_out, - "DAC period size (0 to go with system default)", - &conf.period_size_out_overridden, 0}, - {"DAC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_out, - "DAC buffer size (0 to go with system default)", - &conf.buffer_size_out_overridden, 0}, - - {"ADC_SIZE_IN_USEC", AUD_OPT_BOOL, &conf.size_in_usec_in, - "ADC period/buffer size in microseconds (otherwise in frames)", NULL, 0}, - {"ADC_PERIOD_SIZE", AUD_OPT_INT, &conf.period_size_in, - "ADC period size (0 to go with system default)", - &conf.period_size_in_overridden, 0}, - {"ADC_BUFFER_SIZE", AUD_OPT_INT, &conf.buffer_size_in, - "ADC buffer size (0 to go with system default)", - &conf.buffer_size_in_overridden, 0}, - - {"THRESHOLD", AUD_OPT_INT, &conf.threshold, - "(undocumented)", NULL, 0}, - - {"DAC_DEV", AUD_OPT_STR, &conf.pcm_name_out, - "DAC device name (for instance dmix)", NULL, 0}, - - {"ADC_DEV", AUD_OPT_STR, &conf.pcm_name_in, - "ADC device name", NULL, 0}, - - {"VERBOSE", AUD_OPT_BOOL, &conf.verbose, - "Behave in a more verbose way", NULL, 0}, - - {NULL, 0, NULL, NULL, NULL, 0} -}; - -static struct audio_pcm_ops alsa_pcm_ops = { - alsa_init_out, - alsa_fini_out, - alsa_run_out, - alsa_write, - alsa_ctl_out, - - alsa_init_in, - alsa_fini_in, - alsa_run_in, - alsa_read, - alsa_ctl_in -}; - -struct audio_driver alsa_audio_driver = { - INIT_FIELD (name = ) "alsa", - INIT_FIELD (descr = ) "ALSA audio (www.alsa-project.org)", - INIT_FIELD (options = ) alsa_options, - INIT_FIELD (init = ) alsa_audio_init, - INIT_FIELD (fini = ) alsa_audio_fini, - INIT_FIELD (pcm_ops = ) &alsa_pcm_ops, - INIT_FIELD (can_be_default = ) 1, - INIT_FIELD (max_voices_out = ) INT_MAX, - INIT_FIELD (max_voices_in = ) INT_MAX, - INIT_FIELD (voice_size_out = ) sizeof (ALSAVoiceOut), - INIT_FIELD (voice_size_in = ) sizeof (ALSAVoiceIn) -}; diff --git a/audio/audio.c b/audio/audio.c deleted file mode 100644 index 5a77dac..0000000 --- a/audio/audio.c +++ /dev/null @@ -1,2172 +0,0 @@ -/* - * QEMU Audio subsystem - * - * Copyright (c) 2007-2008 The Android Open Source Project - * 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 "hw/hw.h" -#include "audio.h" -#include "console.h" -#include "qemu-timer.h" -#include "sysemu.h" - -#define AUDIO_CAP "audio" -#include "audio_int.h" -#include "android/utils/system.h" -#include "qemu_debug.h" -#include "android/android.h" - -/* #define DEBUG_PLIVE */ -/* #define DEBUG_LIVE */ -/* #define DEBUG_OUT */ -/* #define DEBUG_CAPTURE */ - -#define SW_NAME(sw) (sw)->name ? (sw)->name : "unknown" - -static struct audio_driver *drvtab[] = { -#ifdef CONFIG_ESD - &esd_audio_driver, -#endif -#ifdef CONFIG_ALSA - &alsa_audio_driver, -#endif -#ifdef CONFIG_COREAUDIO - &coreaudio_audio_driver, -#endif -#ifdef CONFIG_DSOUND - &dsound_audio_driver, -#endif -#ifdef CONFIG_FMOD - &fmod_audio_driver, -#endif -#ifdef CONFIG_WINAUDIO - &win_audio_driver, -#endif -#ifdef CONFIG_SDL - &sdl_audio_driver, -#endif -#ifdef CONFIG_OSS - &oss_audio_driver, -#endif - &no_audio_driver, -#if 0 /* disabled WAV audio for now - until we find a user-friendly way to use it */ - &wav_audio_driver -#endif -}; - - -int -audio_get_backend_count( int is_input ) -{ - int nn, count = 0; - - for (nn = 0; nn < sizeof(drvtab)/sizeof(drvtab[0]); nn++) - { - if (is_input) { - if ( drvtab[nn]->max_voices_in > 0 ) - count += 1; - } else { - if ( drvtab[nn]->max_voices_out > 0 ) - count += 1; - } - } - return count; -} - -const char* -audio_get_backend_name( int is_input, int index, const char* *pinfo ) -{ - int nn; - - index += 1; - for (nn = 0; nn < sizeof(drvtab)/sizeof(drvtab[0]); nn++) - { - if (is_input) { - if ( drvtab[nn]->max_voices_in > 0 ) { - if ( --index == 0 ) { - *pinfo = drvtab[nn]->descr; - return drvtab[nn]->name; - } - } - } else { - if ( drvtab[nn]->max_voices_out > 0 ) { - if ( --index == 0 ) { - *pinfo = drvtab[nn]->descr; - return drvtab[nn]->name; - } - } - } - } - *pinfo = NULL; - return NULL; -} - - -int -audio_check_backend_name( int is_input, const char* name ) -{ - int nn; - - for (nn = 0; nn < sizeof(drvtab)/sizeof(drvtab[0]); nn++) - { - if ( !strcmp(drvtab[nn]->name, name) ) { - if (is_input) { - if (drvtab[nn]->max_voices_in > 0) - return 1; - } else { - if (drvtab[nn]->max_voices_out > 0) - return 1; - } - break; - } - } - return 0; -} - - -struct fixed_settings { - int enabled; - int nb_voices; - int greedy; - audsettings_t settings; -}; - -static struct { - struct fixed_settings fixed_out; - struct fixed_settings fixed_in; - union { - int hz; - int64_t ticks; - } period; - int plive; - int log_to_monitor; -} conf = { - { /* DAC fixed settings */ - 1, /* enabled */ - 1, /* nb_voices */ - 1, /* greedy */ - { - 44100, /* freq */ - 2, /* nchannels */ - AUD_FMT_S16, /* fmt */ - AUDIO_HOST_ENDIANNESS - } - }, - - { /* ADC fixed settings */ - 1, /* enabled */ - 1, /* nb_voices */ - 1, /* greedy */ - { - 44100, /* freq */ - 2, /* nchannels */ - AUD_FMT_S16, /* fmt */ - AUDIO_HOST_ENDIANNESS - } - }, - - { 0 }, /* period */ - 0, /* plive */ - 0 /* log_to_monitor */ -}; - -AudioState glob_audio_state; - -volume_t nominal_volume = { - 0, -#ifdef FLOAT_MIXENG - 1.0, - 1.0 -#else - 1ULL << 32, - 1ULL << 32 -#endif -}; - -/* http://www.df.lth.se/~john_e/gems/gem002d.html */ -/* http://www.multi-platforms.com/Tips/PopCount.htm */ -uint32_t popcount (uint32_t u) -{ - u = ((u&0x55555555) + ((u>>1)&0x55555555)); - u = ((u&0x33333333) + ((u>>2)&0x33333333)); - u = ((u&0x0f0f0f0f) + ((u>>4)&0x0f0f0f0f)); - u = ((u&0x00ff00ff) + ((u>>8)&0x00ff00ff)); - u = ( u&0x0000ffff) + (u>>16); - return u; -} - -inline uint32_t lsbindex (uint32_t u) -{ - return popcount ((u&-u)-1); -} - -#ifdef AUDIO_IS_FLAWLESS_AND_NO_CHECKS_ARE_REQURIED -#error No its not -#else -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) { - shown = 1; - AUD_log (NULL, "Save all your work and restart without audio\n"); - AUD_log (NULL, "Please send bug report to malc@pulsesoft.com\n"); - AUD_log (NULL, "I am sorry\n"); - } - 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 qemu_mallocz (len); -} - -static char *audio_alloc_prefix (const char *s) -{ - const char qemu_prefix[] = "QEMU_"; - size_t len; - char *r; - - if (!s) { - return NULL; - } - - len = strlen (s); - r = qemu_malloc (len + sizeof (qemu_prefix)); - - if (r) { - size_t i; - char *u = r + sizeof (qemu_prefix) - 1; - - strcpy (r, qemu_prefix); - strcat (r, s); - - for (i = 0; i < len; ++i) { - u[i] = 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; - } -} - -/* defined in android_sdl.c */ -extern void dprintn(const char* fmt, ...); -extern void dprintnv(const char* fmt, va_list args); - -void AUD_vlog (const char *cap, const char *fmt, va_list ap) -{ - if (conf.log_to_monitor) { - if (cap) { - term_printf ("%s: ", cap); - } - - term_vprintf (fmt, ap); - } - else { - if (!VERBOSE_CHECK(audio)) - return; - - if (cap) { - dprintn("%s: ", cap); - } - - dprintnv(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); - } - - qemu_free (uprefix); -} - -static void audio_process_options (const char *prefix, - struct audio_option *opt) -{ - char *optname; - const char qemu_prefix[] = "QEMU_"; - size_t preflen; - - 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) */ - optname = qemu_malloc (len + preflen + sizeof (qemu_prefix) + 1); - if (!optname) { - dolog ("Could not allocate memory for option name `%s'\n", - opt->name); - continue; - } - - strcpy (optname, qemu_prefix); - - /* copy while upper-casing, including trailing zero */ - for (i = 0; i <= preflen; ++i) { - optname[i + sizeof (qemu_prefix) - 1] = toupper (prefix[i]); - } - strcat (optname, "_"); - strcat (optname, 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; - qemu_free (optname); - } -} - -static void audio_print_settings (audsettings_t *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; - 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 (audsettings_t *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, audsettings_t *as) -{ - int bits = 8, sign = 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; - break; - case AUD_FMT_S32: - sign = 1; - 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, audsettings_t *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 (st_sample_t *dst, const void *src, - int samples, volume_t *vol) -{ - (void) src; - (void) dst; - (void) samples; - (void) vol; -} - -static CaptureVoiceOut *audio_pcm_capture_find_specific ( - AudioState *s, - audsettings_t *as - ) -{ - CaptureVoiceOut *cap; - - 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; - } - - LIST_REMOVE (sw, entries); - LIST_REMOVE (sc, entries); - qemu_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 (AudioState *s, HWVoiceOut *hw) -{ - 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->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)); - qemu_free (sw); - return -1; - } - LIST_INSERT_HEAD (&hw_cap->sw_head, sw, entries); - LIST_INSERT_HEAD (&hw->cap_head, sc, entries); -#ifdef DEBUG_CAPTURE - asprintf (&sw->name, "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; -} - -/* - * 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; - st_sample_t *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; - } - - 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; -} - -int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live) -{ - int smin; - - smin = audio_pcm_hw_find_min_out (hw, nb_live); - - if (!*nb_live) { - return 0; - } - else { - 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; - } -} - -int audio_pcm_hw_get_live_out (HWVoiceOut *hw) -{ - int nb_live; - int live; - - live = audio_pcm_hw_get_live_out2 (hw, &nb_live); - if (audio_bug (AUDIO_FUNC, live < 0 || live > hw->samples)) { - dolog ("live=%d hw->samples=%d\n", live, hw->samples); - return 0; - } - return live; -} - -/* - * 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, &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" - -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; - } - - BEGIN_NOSIGALRM - bytes = sw->hw->pcm_ops->write (sw, buf, size); - END_NOSIGALRM - 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; - } - - BEGIN_NOSIGALRM - bytes = sw->hw->pcm_ops->read (sw, buf, size); - END_NOSIGALRM - 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) { - SWVoiceOut *temp_sw; - SWVoiceCap *sc; - - if (on) { - hw->pending_disable = 0; - if (!hw->enabled) { - hw->enabled = 1; - BEGIN_NOSIGALRM - hw->pcm_ops->ctl_out (hw, VOICE_ENABLE); - END_NOSIGALRM - } - } - 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) { - SWVoiceIn *temp_sw; - - if (on) { - if (!hw->enabled) { - hw->enabled = 1; - BEGIN_NOSIGALRM - hw->pcm_ops->ctl_in (hw, VOICE_ENABLE); - END_NOSIGALRM - } - 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; - BEGIN_NOSIGALRM - hw->pcm_ops->ctl_in (hw, VOICE_DISABLE); - END_NOSIGALRM - } - } - } - 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 (s, hw))) { - int played; - int live, free, nb_live, cleanup_required, prev_rpos; - - live = audio_pcm_hw_get_live_out2 (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; - BEGIN_NOSIGALRM - hw->pcm_ops->ctl_out (hw, VOICE_DISABLE); - END_NOSIGALRM - 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; - BEGIN_NOSIGALRM - played = hw->pcm_ops->run_out (hw); - END_NOSIGALRM - 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) { -#ifdef DEBUG_PLIVE - dolog ("Finishing with old voice\n"); -#endif - audio_close_out (s, sw); - } - sw = sw1; - } - } - } -} - -static void audio_run_in (AudioState *s) -{ - HWVoiceIn *hw = NULL; - - while ((hw = audio_pcm_hw_find_any_enabled_in (s, hw))) { - SWVoiceIn *sw; - int captured, min; - - BEGIN_NOSIGALRM - captured = hw->pcm_ops->run_in (hw); - END_NOSIGALRM - - 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); - rpos = hw->rpos; - while (live) { - int left = hw->samples - rpos; - int to_capture = audio_MIN (live, left); - st_sample_t *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; - } - } -} - -static void audio_timer (void *opaque) -{ - AudioState* s = opaque; -#if 0 -#define MAX_DIFFS 1000 - int64_t now = qemu_get_clock(vm_clock); - static int64_t last = 0; - static float diffs[MAX_DIFFS]; - static int num_diffs; - - if (last == 0) - last = now; - else { - diffs[num_diffs] = (float)((now-last)/1e6); /* last diff in ms */ - if (++num_diffs == MAX_DIFFS) { - double min_diff = 1e6, max_diff = -1e6; - double all_diff = 0.; - int nn; - - for (nn = 0; nn < num_diffs; nn++) { - if (diffs[nn] < min_diff) min_diff = diffs[nn]; - if (diffs[nn] > max_diff) max_diff = diffs[nn]; - all_diff += diffs[nn]; - } - all_diff *= 1.0/num_diffs; - printf("audio timer: min_diff=%6.2g max_diff=%6.2g avg_diff=%6.2g samples=%d\n", - min_diff, max_diff, all_diff, num_diffs); - num_diffs = 0; - } - } - last = now; -#endif - audio_run_out (s); - audio_run_in (s); - audio_run_capture (s); - - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); -} - -static struct audio_option audio_options[] = { - /* DAC */ - {"DAC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_out.enabled, - "Use fixed settings for host DAC", NULL, 0}, - - {"DAC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_out.settings.freq, - "Frequency for fixed host DAC", NULL, 0}, - - {"DAC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_out.settings.fmt, - "Format for fixed host DAC", NULL, 0}, - - {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_out.settings.nchannels, - "Number of channels for fixed DAC (1 - mono, 2 - stereo)", NULL, 0}, - - {"DAC_VOICES", AUD_OPT_INT, &conf.fixed_out.nb_voices, - "Number of voices for DAC", NULL, 0}, - - /* ADC */ - {"ADC_FIXED_SETTINGS", AUD_OPT_BOOL, &conf.fixed_in.enabled, - "Use fixed settings for host ADC", NULL, 0}, - - {"ADC_FIXED_FREQ", AUD_OPT_INT, &conf.fixed_in.settings.freq, - "Frequency for fixed host ADC", NULL, 0}, - - {"ADC_FIXED_FMT", AUD_OPT_FMT, &conf.fixed_in.settings.fmt, - "Format for fixed host ADC", NULL, 0}, - - {"ADC_FIXED_CHANNELS", AUD_OPT_INT, &conf.fixed_in.settings.nchannels, - "Number of channels for fixed ADC (1 - mono, 2 - stereo)", NULL, 0}, - - {"ADC_VOICES", AUD_OPT_INT, &conf.fixed_in.nb_voices, - "Number of voices for ADC", NULL, 0}, - - /* Misc */ - {"TIMER_PERIOD", AUD_OPT_INT, &conf.period.hz, - "Timer period in HZ (0 - use lowest possible)", NULL, 0}, - - {"PLIVE", AUD_OPT_BOOL, &conf.plive, - "(undocumented)", NULL, 0}, - - {"LOG_TO_MONITOR", AUD_OPT_BOOL, &conf.log_to_monitor, - "print logging messages to monitor instead of stderr", NULL, 0}, - - {NULL, 0, NULL, NULL, NULL, 0} -}; - -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 upto %d %s voices\n", nb, typ); - break; - } - -} - -void AUD_help (void) -{ - size_t i; - - audio_process_options ("AUDIO", audio_options); - for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); 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 < sizeof (drvtab) / sizeof (drvtab[0]); 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, int out) -{ - void* opaque; - - if (drv->options) { - audio_process_options (drv->name, drv->options); - } - - /* is the driver already initialized ? */ - if (out) { - if (drv == s->drv_in) { - s->drv_out = drv; - s->drv_out_opaque = s->drv_in_opaque; - return 0; - } - } else { - if (drv == s->drv_out) { - s->drv_in = drv; - s->drv_in_opaque = s->drv_out_opaque; - return 0; - } - } - - BEGIN_NOSIGALRM - opaque = drv->init(); - END_NOSIGALRM - - if (opaque != NULL) { - audio_init_nb_voices_out (s, drv); - audio_init_nb_voices_in (s, drv); - if (out) { - s->drv_out = drv; - s->drv_out_opaque = opaque; - } else { - s->drv_in = drv; - s->drv_in_opaque = opaque; - } - 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) -{ - AudioState *s = opaque; - HWVoiceOut *hwo = NULL; - HWVoiceIn *hwi = NULL; - int op = running ? VOICE_ENABLE : VOICE_DISABLE; - - BEGIN_NOSIGALRM - while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) { - hwo->pcm_ops->ctl_out (hwo, op); - } - - while ((hwi = audio_pcm_hw_find_any_enabled_in (s, hwi))) { - hwi->pcm_ops->ctl_in (hwi, op); - } - END_NOSIGALRM -} - -// to make sure audio_atexit() is only called once -static int initialized = 0; - -static void audio_atexit (void) -{ - AudioState *s = &glob_audio_state; - HWVoiceOut *hwo = NULL; - HWVoiceIn *hwi = NULL; - - if (!initialized) return; - initialized = 0; - - BEGIN_NOSIGALRM - while ((hwo = audio_pcm_hw_find_any_enabled_out (s, hwo))) { - SWVoiceCap *sc; - - 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_enabled_in (s, hwi))) { - hwi->pcm_ops->ctl_in (hwi, VOICE_DISABLE); - hwi->pcm_ops->fini_in (hwi); - } - - if (s->drv_in) { - s->drv_in->fini (s->drv_in_opaque); - } - if (s->drv_out) { - s->drv_out->fini (s->drv_out_opaque); - } - END_NOSIGALRM -} - -static void audio_save (QEMUFile *f, void *opaque) -{ - (void) f; - (void) opaque; -} - -static int audio_load (QEMUFile *f, void *opaque, int version_id) -{ - (void) f; - (void) opaque; - - if (version_id != 1) { - return -EINVAL; - } - - return 0; -} - -void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card) -{ - card->audio = s; - card->name = qemu_strdup (name); - memset (&card->entries, 0, sizeof (card->entries)); - LIST_INSERT_HEAD (&s->card_head, card, entries); -} - -void AUD_remove_card (QEMUSoundCard *card) -{ - LIST_REMOVE (card, entries); - card->audio = NULL; - qemu_free (card->name); -} - -static int -find_audio_driver( AudioState* s, int out ) -{ - int i, done = 0, def; - const char* envname; - const char* drvname; - struct audio_driver* drv = NULL; - const char* drvtype = out ? "output" : "input"; - - envname = out ? "QEMU_AUDIO_OUT_DRV" : "QEMU_AUDIO_IN_DRV"; - drvname = audio_get_conf_str(envname, NULL, &def); - if (drvname == NULL) { - drvname = audio_get_conf_str("QEMU_AUDIO_DRV", NULL, &def); - } - - if (drvname != NULL) { /* look for a specific driver */ - for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { - if (!strcmp (drvname, drvtab[i]->name)) { - drv = drvtab[i]; - break; - } - } - } - - if (drv != NULL) { - done = !audio_driver_init (s, drv, out); - if (!done) { - dolog ("Could not initialize '%s' %s audio backend, trying default one.\n", - drvname, drvtype); - dolog ("Run with -qemu -audio-help to list available backends\n"); - drv = NULL; - } - } - - if (!drv) { - for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { - if (drvtab[i]->can_be_default) { - drv = drvtab[i]; - done = !audio_driver_init (s, drv, out); - if (done) - break; - } - } - } - - if (!done) { - drv = &no_audio_driver; - done = !audio_driver_init (s, drv, out); - if (!done) { - /* this should never happen */ - dolog ("Could not initialize audio subsystem\n"); - return -1; - } - dolog ("warning: Could not find suitable audio %s backend\n", drvtype); - } - - if (VERBOSE_CHECK(init)) - dprint("using '%s' audio %s backend", drv->name, drvtype ); - return 0; -} - - -AudioState *AUD_init (void) -{ - AudioState *s = &glob_audio_state; - - LIST_INIT (&s->hw_head_out); - LIST_INIT (&s->hw_head_in); - LIST_INIT (&s->cap_head); - atexit (audio_atexit); - - s->ts = qemu_new_timer (vm_clock, audio_timer, s); - if (!s->ts) { - dolog ("Could not create audio timer\n"); - return NULL; - } - - 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; - } - - if ( find_audio_driver (s, 0) == 0 && - find_audio_driver (s, 1) == 0 ) - { - VMChangeStateEntry *e; - - if (conf.period.hz <= 0) { - if (conf.period.hz < 0) { - dolog ("warning: Timer period is negative - %d " - "treating as zero\n", - conf.period.hz); - } - conf.period.ticks = 1; - } - else { - conf.period.ticks = ticks_per_sec / conf.period.hz; - } - - 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"); - } - } - else { - qemu_del_timer (s->ts); - return NULL; - } - - initialized = 1; - - LIST_INIT (&s->card_head); - register_savevm ("audio", 0, 1, audio_save, audio_load, s); - qemu_mod_timer (s->ts, qemu_get_clock (vm_clock) + conf.period.ticks); - return s; -} - -// this was added to work around a deadlock in SDL when quitting -void AUD_cleanup() -{ - audio_atexit(); -} - -CaptureVoiceOut *AUD_add_capture ( - AudioState *s, - audsettings_t *as, - struct audio_capture_ops *ops, - void *cb_opaque - ) -{ - CaptureVoiceOut *cap; - struct capture_callback *cb; - - if (!s) { - /* XXX suppress */ - s = &glob_audio_state; - } - - 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 (s, as); - if (cap) { - LIST_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; - LIST_INIT (&hw->sw_head); - LIST_INIT (&cap->cb_head); - - /* XXX find a more elegant way */ - hw->samples = 4096 * 4; - hw->mix_buf = audio_calloc (AUDIO_FUNC, hw->samples, - sizeof (st_sample_t)); - 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)]; - - LIST_INSERT_HEAD (&s->cap_head, cap, entries); - LIST_INSERT_HEAD (&cap->cb_head, cb, entries); - - hw = NULL; - while ((hw = audio_pcm_hw_find_any_out (s, hw))) { - audio_attach_capture (s, hw); - } - return cap; - - err3: - qemu_free (cap->hw.mix_buf); - err2: - qemu_free (cap); - err1: - qemu_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); - LIST_REMOVE (cb, entries); - qemu_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; - } - LIST_REMOVE (sw, entries); - LIST_REMOVE (sc, entries); - qemu_free (sc); - sw = sw1; - } - LIST_REMOVE (cap, entries); - qemu_free (cap); - } - return; - } - } -} - -void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) -{ - if (sw) { - sw->vol.mute = mute; - sw->vol.l = nominal_volume.l * lvol / 255; - sw->vol.r = nominal_volume.r * rvol / 255; - } -} - -void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) -{ - if (sw) { - sw->vol.mute = mute; - sw->vol.l = nominal_volume.l * lvol / 255; - sw->vol.r = nominal_volume.r * rvol / 255; - } -} diff --git a/audio/audio.h b/audio/audio.h deleted file mode 100644 index 2c347bf..0000000 --- a/audio/audio.h +++ /dev/null @@ -1,185 +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 "config.h" -#include "qemu-common.h" -#include "sys-queue.h" - -typedef void (*audio_callback_fn_t) (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 WORDS_BIGENDIAN -#define AUDIO_HOST_ENDIANNESS 1 -#else -#define AUDIO_HOST_ENDIANNESS 0 -#endif - -typedef struct { - int freq; - int nchannels; - audfmt_e fmt; - int endianness; -} audsettings_t; - -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; - LIST_ENTRY (CaptureState) entries; -} CaptureState; - -typedef struct SWVoiceOut SWVoiceOut; -typedef struct CaptureVoiceOut CaptureVoiceOut; -typedef struct SWVoiceIn SWVoiceIn; - -typedef struct QEMUSoundCard { - AudioState *audio; - char *name; - LIST_ENTRY (QEMUSoundCard) entries; -} QEMUSoundCard; - -typedef struct QEMUAudioTimeStamp { - uint64_t old_ts; -} QEMUAudioTimeStamp; - -void AUD_vlog (const char *cap, const char *fmt, va_list ap); -void AUD_log (const char *cap, const char *fmt, ...) -#ifdef __GNUC__ - __attribute__ ((__format__ (__printf__, 2, 3))) -#endif - ; - -extern AudioState glob_audio_state; - -AudioState *AUD_init (void); -void AUD_help (void); -void AUD_register_card (AudioState *s, const char *name, QEMUSoundCard *card); -void AUD_remove_card (QEMUSoundCard *card); -CaptureVoiceOut *AUD_add_capture ( - AudioState *s, - audsettings_t *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_t callback_fn, - audsettings_t *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_t callback_fn, - audsettings_t *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); -} - -uint32_t popcount (uint32_t u); -uint32_t lsbindex (uint32_t u); - -#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 - -extern int -audio_get_backend_count( int is_input ); - -extern const char* -audio_get_backend_name( int is_input, int index, const char* *pinfo ); - -extern int -audio_check_backend_name( int is_input, const char* name ); - -#endif /* audio.h */ diff --git a/audio/audio_int.h b/audio/audio_int.h deleted file mode 100644 index 6677ec1..0000000 --- a/audio/audio_int.h +++ /dev/null @@ -1,287 +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 - -#include "audio/audio.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_t 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 pending_disable; - struct audio_pcm_info info; - - f_sample *clip; - - int rpos; - uint64_t ts_helper; - - st_sample_t *mix_buf; - - int samples; - LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; - LIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; - struct audio_pcm_ops *pcm_ops; - LIST_ENTRY (HWVoiceOut) entries; -} HWVoiceOut; - -typedef struct HWVoiceIn { - int enabled; - struct audio_pcm_info info; - - t_sample *conv; - - int wpos; - int total_samples_captured; - uint64_t ts_helper; - - st_sample_t *conv_buf; - - int samples; - LIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; - struct audio_pcm_ops *pcm_ops; - LIST_ENTRY (HWVoiceIn) entries; -} HWVoiceIn; - -struct SWVoiceOut { - struct audio_pcm_info info; - t_sample *conv; - int64_t ratio; - st_sample_t *buf; - void *rate; - int total_hw_samples_mixed; - int active; - int empty; - HWVoiceOut *hw; - char *name; - volume_t vol; - struct audio_callback callback; - LIST_ENTRY (SWVoiceOut) entries; -}; - -struct SWVoiceIn { - int active; - struct audio_pcm_info info; - int64_t ratio; - void *rate; - int total_hw_samples_acquired; - st_sample_t *buf; - f_sample *clip; - HWVoiceIn *hw; - char *name; - volume_t vol; - struct audio_callback callback; - LIST_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; -}; - -struct audio_pcm_ops { - int (*init_out)(HWVoiceOut *hw, audsettings_t *as); - void (*fini_out)(HWVoiceOut *hw); - int (*run_out) (HWVoiceOut *hw); - int (*write) (SWVoiceOut *sw, void *buf, int size); - int (*ctl_out) (HWVoiceOut *hw, int cmd, ...); - - int (*init_in) (HWVoiceIn *hw, audsettings_t *as); - 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; - LIST_ENTRY (capture_callback) entries; -}; - -struct CaptureVoiceOut { - HWVoiceOut hw; - void *buf; - LIST_HEAD (cb_listhead, capture_callback) cb_head; - LIST_ENTRY (CaptureVoiceOut) entries; -}; - -struct SWVoiceCap { - SWVoiceOut sw; - CaptureVoiceOut *cap; - LIST_ENTRY (SWVoiceCap) entries; -}; - -struct AudioState { - struct audio_driver* drv_in; - void* drv_in_opaque; - struct audio_driver* drv_out; - void* drv_out_opaque; - - QEMUTimer *ts; - LIST_HEAD (card_listhead, QEMUSoundCard) card_head; - LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in; - LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out; - LIST_HEAD (cap_listhead, CaptureVoiceOut) cap_head; - int nb_hw_voices_out; - int nb_hw_voices_in; -}; - -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 win_audio_driver; -extern struct audio_driver wav_audio_driver; -extern struct audio_driver fmod_audio_driver; -extern struct audio_driver esd_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 esd_audio_driver; -extern volume_t nominal_volume; - -void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *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_get_live_out (HWVoiceOut *hw); -int audio_pcm_hw_get_live_out2 (HWVoiceOut *hw, int *nb_live); - -int audio_bug (const char *funcname, int cond); -void *audio_calloc (const char *funcname, int nmemb, size_t size); - -#define VOICE_ENABLE 1 -#define VOICE_DISABLE 2 - -static inline int audio_ring_dist (int dst, int src, int len) -{ - return (dst >= src) ? (dst - src) : (len - src + dst); -} - -#if defined __GNUC__ -#define GCC_ATTR __attribute__ ((__unused__, __format__ (__printf__, 1, 2))) -#define INIT_FIELD(f) . f -#define GCC_FMT_ATTR(n, m) __attribute__ ((__format__ (__printf__, n, m))) -#else -#define GCC_ATTR /**/ -#define INIT_FIELD(f) /**/ -#define GCC_FMT_ATTR(n, m) -#endif - -static void GCC_ATTR dolog (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); -} - -#ifdef DEBUG -static void GCC_ATTR ldebug (const char *fmt, ...) -{ - va_list ap; - - va_start (ap, fmt); - AUD_vlog (AUDIO_CAP, fmt, ap); - va_end (ap); -} -#else -#if defined NDEBUG && defined __GNUC__ -#define ldebug(...) -#elif defined NDEBUG && defined _MSC_VER -#define ldebug __noop -#else -static void GCC_ATTR ldebug (const char *fmt, ...) -{ - (void) fmt; -} -#endif -#endif - -#undef GCC_ATTR - -#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/audio/audio_pt_int.c b/audio/audio_pt_int.c deleted file mode 100644 index c753774..0000000 --- a/audio/audio_pt_int.c +++ /dev/null @@ -1,148 +0,0 @@ -#include "audio.h" - -#define AUDIO_CAP "audio-pt" - -#include "audio_int.h" -#include "audio_pt_int.h" - -static void 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; - - p->drv = drv; - - 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_create (&p->thread, NULL, func, opaque); - 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/audio/audio_pt_int.h b/audio/audio_pt_int.h deleted file mode 100644 index 0dfff76..0000000 --- a/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/audio/audio_template.h b/audio/audio_template.h deleted file mode 100644 index 6f8e166..0000000 --- a/audio/audio_template.h +++ /dev/null @@ -1,577 +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) ( - AudioState *s, - struct audio_driver *drv - ) -{ - 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) -{ - if (HWBUF) { - qemu_free (HWBUF); - } - - HWBUF = NULL; -} - -static int glue (audio_pcm_hw_alloc_resources_, TYPE) (HW *hw) -{ - HWBUF = audio_calloc (AUDIO_FUNC, hw->samples, sizeof (st_sample_t)); - 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) -{ - if (sw->buf) { - qemu_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; - -#ifdef DAC - samples = sw->hw->samples; -#else - samples = ((int64_t) sw->hw->samples << 32) / sw->ratio; -#endif - - sw->buf = audio_calloc (AUDIO_FUNC, samples, sizeof (st_sample_t)); - 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) { - qemu_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, - audsettings_t *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 = qemu_strdup (name); - err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw); - if (err) { - qemu_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); - if (sw->name) { - qemu_free (sw->name); - sw->name = NULL; - } -} - -static void glue (audio_pcm_hw_add_sw_, TYPE) (HW *hw, SW *sw) -{ - LIST_INSERT_HEAD (&hw->sw_head, sw, entries); -} - -static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw) -{ - LIST_REMOVE (sw, entries); -} - -static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp) -{ - HW *hw = *hwp; - - if (!hw->sw_head.lh_first) { -#ifdef DAC - audio_detach_capture (hw); -#endif - LIST_REMOVE (hw, entries); - glue (s->nb_hw_voices_, TYPE) += 1; - glue (audio_pcm_hw_free_resources_ ,TYPE) (hw); - BEGIN_NOSIGALRM - glue (hw->pcm_ops->fini_, TYPE) (hw); - END_NOSIGALRM - qemu_free (hw); - *hwp = NULL; - } -} - -static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw) -{ - return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first; -} - -static HW *glue (audio_pcm_hw_find_any_enabled_, TYPE) (AudioState *s, HW *hw) -{ - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) { - if (hw->enabled) { - return hw; - } - } - return NULL; -} - -static HW *glue (audio_pcm_hw_find_specific_, TYPE) ( - AudioState *s, - HW *hw, - audsettings_t *as - ) -{ - while ((hw = glue (audio_pcm_hw_find_any_, TYPE) (s, hw))) { - if (audio_pcm_info_eq (&hw->info, as)) { - return hw; - } - } - return NULL; -} - -static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as) -{ - HW *hw; - struct audio_driver *drv = glue(s->drv_, TYPE); - int err; - - 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; - LIST_INIT (&hw->sw_head); -#ifdef DAC - LIST_INIT (&hw->cap_head); -#endif - BEGIN_NOSIGALRM - err = glue (hw->pcm_ops->init_, TYPE) (hw, as); - END_NOSIGALRM - if (err) - 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; - } - - LIST_INSERT_HEAD (&s->glue (hw_head_, TYPE), hw, entries); - glue (s->nb_hw_voices_, TYPE) -= 1; -#ifdef DAC - audio_attach_capture (s, hw); -#endif - return hw; - - err1: - BEGIN_NOSIGALRM - glue (hw->pcm_ops->fini_, TYPE) (hw); - END_NOSIGALRM - err0: - qemu_free (hw); - return NULL; -} - -static HW *glue (audio_pcm_hw_add_, TYPE) (AudioState *s, audsettings_t *as) -{ - HW *hw; - - if (glue (conf.fixed_, TYPE).enabled && glue (conf.fixed_, TYPE).greedy) { - hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); - if (hw) { - return hw; - } - } - - hw = glue (audio_pcm_hw_find_specific_, TYPE) (s, NULL, as); - if (hw) { - return hw; - } - - hw = glue (audio_pcm_hw_add_new_, TYPE) (s, as); - if (hw) { - return hw; - } - - return glue (audio_pcm_hw_find_any_, TYPE) (s, NULL); -} - -static SW *glue (audio_pcm_create_voice_pair_, TYPE) ( - AudioState *s, - const char *sw_name, - audsettings_t *as - ) -{ - SW *sw; - HW *hw; - audsettings_t 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) (s, &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) (s, &hw); -err2: - qemu_free (sw); -err1: - return NULL; -} - -static void glue (audio_close_, TYPE) (AudioState *s, SW *sw) -{ - glue (audio_pcm_sw_fini_, TYPE) (sw); - glue (audio_pcm_hw_del_sw_, TYPE) (sw); - glue (audio_pcm_hw_gc_, TYPE) (s, &sw->hw); - qemu_free (sw); -} - -void glue (AUD_close_, TYPE) (QEMUSoundCard *card, SW *sw) -{ - if (sw) { - if (audio_bug (AUDIO_FUNC, !card || !card->audio)) { - dolog ("card=%p card->audio=%p\n", - card, card ? card->audio : NULL); - return; - } - - glue (audio_close_, TYPE) (card->audio, sw); - } -} - -SW *glue (AUD_open_, TYPE) ( - QEMUSoundCard *card, - SW *sw, - const char *name, - void *callback_opaque , - audio_callback_fn_t callback_fn, - audsettings_t *as - ) -{ - AudioState *s; -#ifdef DAC - int live = 0; - SW *old_sw = NULL; -#endif - - ldebug ("open %s, freq %d, nchannels %d, fmt %d\n", - name, as->freq, as->nchannels, as->fmt); - - if (audio_bug (AUDIO_FUNC, - !card || !card->audio || !name || !callback_fn || !as)) { - dolog ("card=%p card->audio=%p name=%p callback_fn=%p as=%p\n", - card, card ? card->audio : NULL, name, callback_fn, as); - goto fail; - } - - s = card->audio; - - if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) { - audio_print_settings (as); - goto fail; - } - - if (audio_bug (AUDIO_FUNC, !glue (s->drv_, TYPE))) { - dolog ("Can not open `%s' (no host audio driver)\n", name); - goto fail; - } - - if (sw && audio_pcm_info_eq (&sw->info, as)) { - return sw; - } - -#ifdef DAC - if (conf.plive && sw && (!sw->active && !sw->empty)) { - live = sw->total_hw_samples_mixed; - -#ifdef DEBUG_PLIVE - dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live); - dolog ("Old %s freq %d, bits %d, channels %d\n", - SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels); - dolog ("New %s freq %d, bits %d, channels %d\n", - name, - freq, - (fmt == AUD_FMT_S16 || fmt == AUD_FMT_U16) ? 16 : 8, - nchannels); -#endif - - if (live) { - old_sw = sw; - old_sw->callback.fn = NULL; - sw = NULL; - } - } -#endif - - 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) (s, name, as); - if (!sw) { - dolog ("Failed to create voice `%s'\n", name); - return NULL; - } - } - - if (sw) { - sw->vol = nominal_volume; - sw->callback.fn = callback_fn; - sw->callback.opaque = callback_opaque; - -#ifdef DAC - if (live) { - int mixed = - (live << old_sw->info.shift) - * old_sw->info.bytes_per_second - / sw->info.bytes_per_second; - -#ifdef DEBUG_PLIVE - dolog ("Silence will be mixed %d\n", mixed); -#endif - sw->total_hw_samples_mixed += mixed; - } -#endif - -#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 %lld old %lld\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 (delta * sw->hw->info.freq) / 1000000; -} - -#undef TYPE -#undef HW -#undef SW -#undef HWBUF -#undef NAME diff --git a/audio/coreaudio.c b/audio/coreaudio.c deleted file mode 100644 index f23ebee..0000000 --- a/audio/coreaudio.c +++ /dev/null @@ -1,821 +0,0 @@ -/* - * QEMU OS X CoreAudio audio driver - * - * Copyright (c) 2008 The Android Open Source Project - * 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 <CoreAudio/CoreAudio.h> -#include <string.h> /* strerror */ -#include <pthread.h> /* pthread_X */ - -#include "audio.h" - -#define AUDIO_CAP "coreaudio" -#include "audio_int.h" - -#define ENABLE_IN 1 - -#if 0 -# define D(...) fprintf(stderr, __VA_ARGS__) -#else -# define D(...) ((void)0) -#endif - -struct { - int out_buffer_frames; - int out_nbuffers; - int in_buffer_frames; - int in_nbuffers; - int isAtexit; -} conf = { - .out_buffer_frames = 512, - .out_nbuffers = 4, - .in_buffer_frames = 512, - .in_nbuffers = 4, - .isAtexit = 0 -}; - -/***************************************************************************************/ -/***************************************************************************************/ -/*** ***/ -/*** U T I L I T Y R O U T I N E S ***/ -/*** ***/ -/***************************************************************************************/ -/***************************************************************************************/ - -static void coreaudio_logstatus (OSStatus status) -{ - 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 %ld\n", 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 void coreaudio_atexit (void) -{ - conf.isAtexit = 1; -} - -/***************************************************************************************/ -/***************************************************************************************/ -/*** ***/ -/*** S H A R E D I N / O U T V O I C E ***/ -/*** ***/ -/***************************************************************************************/ -/***************************************************************************************/ - -typedef struct coreAudioVoice { - pthread_mutex_t mutex; - AudioDeviceID deviceID; - Boolean isInput; - UInt32 bufferFrameSize; - AudioStreamBasicDescription streamBasicDescription; - AudioDeviceIOProc ioproc; - int live; - int decr; - int pos; -} coreaudioVoice; - - -static inline UInt32 -coreaudio_voice_isPlaying (coreaudioVoice* core) -{ - OSStatus status; - UInt32 result = 0; - UInt32 propertySize = sizeof(core->deviceID); - status = AudioDeviceGetProperty( - core->deviceID, 0, core->isInput, - kAudioDevicePropertyDeviceIsRunning, &propertySize, &result); - if (status != kAudioHardwareNoError) { - coreaudio_logerr(status, - "Could not determine whether Device is playing\n"); - } - return result; -} - -static int -coreaudio_voice_lock (coreaudioVoice* 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_voice_unlock (coreaudioVoice* 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_voice_ctl (coreaudioVoice* core, int cmd) -{ - OSStatus status; - - switch (cmd) { - case VOICE_ENABLE: - /* start playback */ - D("%s: %s started\n", __FUNCTION__, core->isInput ? "input" : "output"); - if (!coreaudio_voice_isPlaying(core)) { - status = AudioDeviceStart(core->deviceID, core->ioproc); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not resume playback\n"); - } - } - break; - - case VOICE_DISABLE: - /* stop playback */ - D("%s: %s stopped\n", __FUNCTION__, core->isInput ? "input" : "output"); - if (!conf.isAtexit) { - if (coreaudio_voice_isPlaying(core)) { - status = AudioDeviceStop(core->deviceID, core->ioproc); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not pause playback\n"); - } - } - } - break; - } - return 0; -} - -static void -coreaudio_voice_fini (coreaudioVoice* core) -{ - OSStatus status; - int err; - - if (!conf.isAtexit) { - /* stop playback */ - coreaudio_voice_ctl(core, VOICE_DISABLE); - - /* remove callback */ - status = AudioDeviceRemoveIOProc(core->deviceID, core->ioproc); - if (status != kAudioHardwareNoError) { - coreaudio_logerr (status, "Could not remove IOProc\n"); - } - } - core->deviceID = kAudioDeviceUnknown; - - /* destroy mutex */ - err = pthread_mutex_destroy(&core->mutex); - if (err) { - dolog("Could not destroy mutex\nReason: %s\n", strerror (err)); - } -} - - -static int -coreaudio_voice_init (coreaudioVoice* core, - audsettings_t* as, - int frameSize, - AudioDeviceIOProc ioproc, - void* hw, - int input) -{ - OSStatus status; - UInt32 propertySize; - int err; - int bits = 8; - AudioValueRange frameRange; - const char* typ = input ? "input" : "playback"; - - core->isInput = input ? true : false; - - /* create mutex */ - err = pthread_mutex_init(&core->mutex, NULL); - if (err) { - dolog("Could not create mutex\nReason: %s\n", strerror (err)); - return -1; - } - - if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) { - bits = 16; - } - - // TODO: audio_pcm_init_info (&hw->info, as); - /* open default output device */ - /* note: we use DefaultSystemOutputDevice because DefaultOutputDevice seems to - * always link to the internal speakers, and not the ones selected through system properties - * go figure... - */ - propertySize = sizeof(core->deviceID); - status = AudioHardwareGetProperty( - input ? kAudioHardwarePropertyDefaultInputDevice : - kAudioHardwarePropertyDefaultSystemOutputDevice, - &propertySize, - &core->deviceID); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not get default %s device\n", typ); - return -1; - } - if (core->deviceID == kAudioDeviceUnknown) { - dolog ("Could not initialize %s - Unknown Audiodevice\n", typ); - return -1; - } - - /* get minimum and maximum buffer frame sizes */ - propertySize = sizeof(frameRange); - status = AudioDeviceGetProperty( - core->deviceID, - 0, - core->isInput, - kAudioDevicePropertyBufferFrameSizeRange, - &propertySize, - &frameRange); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not get device buffer frame range\n"); - return -1; - } - - if (frameRange.mMinimum > frameSize) { - core->bufferFrameSize = (UInt32) frameRange.mMinimum; - dolog ("warning: Upsizing Output Buffer Frames to %f\n", frameRange.mMinimum); - } - else if (frameRange.mMaximum < frameSize) { - core->bufferFrameSize = (UInt32) frameRange.mMaximum; - dolog ("warning: Downsizing Output Buffer Frames to %f\n", frameRange.mMaximum); - } - else { - core->bufferFrameSize = frameSize; - } - - /* set Buffer Frame Size */ - propertySize = sizeof(core->bufferFrameSize); - status = AudioDeviceSetProperty( - core->deviceID, - NULL, - 0, - core->isInput, - kAudioDevicePropertyBufferFrameSize, - propertySize, - &core->bufferFrameSize); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not set device buffer frame size %ld\n", - core->bufferFrameSize); - return -1; - } - - /* get Buffer Frame Size */ - propertySize = sizeof(core->bufferFrameSize); - status = AudioDeviceGetProperty( - core->deviceID, - 0, - core->isInput, - kAudioDevicePropertyBufferFrameSize, - &propertySize, - &core->bufferFrameSize); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not get device buffer frame size\n"); - return -1; - } - // TODO: hw->samples = *pNBuffers * core->bufferFrameSize; - - /* get StreamFormat */ - propertySize = sizeof(core->streamBasicDescription); - status = AudioDeviceGetProperty( - core->deviceID, - 0, - core->isInput, - kAudioDevicePropertyStreamFormat, - &propertySize, - &core->streamBasicDescription); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, - "Could not get Device Stream properties\n"); - core->deviceID = kAudioDeviceUnknown; - return -1; - } - - /* set Samplerate */ - core->streamBasicDescription.mSampleRate = (Float64) as->freq; - propertySize = sizeof(core->streamBasicDescription); - status = AudioDeviceSetProperty( - core->deviceID, - 0, - 0, - core->isInput, - kAudioDevicePropertyStreamFormat, - propertySize, - &core->streamBasicDescription); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Could not set samplerate %d\n", - as->freq); - core->deviceID = kAudioDeviceUnknown; - return -1; - } - - /* set Callback */ - core->ioproc = ioproc; - status = AudioDeviceAddIOProc(core->deviceID, ioproc, hw); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Could not set IOProc\n"); - core->deviceID = kAudioDeviceUnknown; - return -1; - } - - /* start Playback */ - if (!input && !coreaudio_voice_isPlaying(core)) { - status = AudioDeviceStart(core->deviceID, core->ioproc); - if (status != kAudioHardwareNoError) { - coreaudio_logerr2 (status, typ, "Could not start playback\n"); - AudioDeviceRemoveIOProc(core->deviceID, core->ioproc); - core->deviceID = kAudioDeviceUnknown; - return -1; - } - } - - return 0; -} - - -/***************************************************************************************/ -/***************************************************************************************/ -/*** ***/ -/*** O U T P U T V O I C E ***/ -/*** ***/ -/***************************************************************************************/ -/***************************************************************************************/ - -typedef struct coreaudioVoiceOut { - HWVoiceOut hw; - coreaudioVoice core[1]; -} coreaudioVoiceOut; - -#define CORE_OUT(hw) ((coreaudioVoiceOut*)(hw))->core - - -static int -coreaudio_run_out (HWVoiceOut *hw) -{ - int live, decr; - coreaudioVoice *core = CORE_OUT(hw); - - if (coreaudio_voice_lock (core, "coreaudio_run_out")) { - return 0; - } - - live = audio_pcm_hw_get_live_out (hw); - - 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->pos; - - coreaudio_voice_unlock (core, "coreaudio_run_out"); - return decr; -} - - -/* callback to feed audiooutput buffer */ -static OSStatus -audioOutDeviceIOProc( - 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; - coreaudioVoice *core = CORE_OUT(hw); - int rpos, live; - st_sample_t *src; -#ifndef FLOAT_MIXENG -#ifdef RECIPROCAL - const float scale = 1.f / UINT_MAX; -#else - const float scale = UINT_MAX; -#endif -#endif - - if (coreaudio_voice_lock (core, "audioDeviceIOProc")) { - inInputTime = 0; - return 0; - } - - frameCount = core->bufferFrameSize; - live = core->live; - - /* if there are not enough samples, set signal and return */ - if (live < frameCount) { - inInputTime = 0; - coreaudio_voice_unlock (core, "audioDeviceIOProc(empty)"); - return 0; - } - - rpos = core->pos; - 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->pos = rpos; - - coreaudio_voice_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, audsettings_t *as) -{ - coreaudioVoice* core = CORE_OUT(hw); - int err; - - audio_pcm_init_info (&hw->info, as); - - err = coreaudio_voice_init( core, as, conf.out_buffer_frames, audioOutDeviceIOProc, hw, 0 ); - if (err < 0) - return err; - - hw->samples = core->bufferFrameSize * conf.out_nbuffers; - return 0; -} - -static void -coreaudio_fini_out (HWVoiceOut *hw) -{ - - coreaudioVoice* core = CORE_OUT(hw); - - coreaudio_voice_fini(core); -} - -static int -coreaudio_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - coreaudioVoice* core = CORE_OUT(hw); - - return coreaudio_voice_ctl(core, cmd); -} - -/***************************************************************************************/ -/***************************************************************************************/ -/*** ***/ -/*** I N P U T V O I C E ***/ -/*** ***/ -/***************************************************************************************/ -/***************************************************************************************/ - - - -typedef struct coreaudioVoiceIn { - HWVoiceIn hw; - coreaudioVoice core[1]; -} coreaudioVoiceIn; - -#define CORE_IN(hw) ((coreaudioVoiceIn*)(hw))->core - - -static int -coreaudio_run_in (HWVoiceIn *hw) -{ - int decr; - - coreaudioVoice *core = CORE_IN(hw); - - if (coreaudio_voice_lock (core, "coreaudio_run_in")) { - return 0; - } - D("%s: core.decr=%d core.pos=%d\n", __FUNCTION__, core->decr, core->pos); - decr = core->decr; - core->decr -= decr; - hw->wpos = core->pos; - - coreaudio_voice_unlock (core, "coreaudio_run_in"); - return decr; -} - - -/* callback to feed audiooutput buffer */ -static OSStatus -audioInDeviceIOProc( - AudioDeviceID inDevice, - const AudioTimeStamp* inNow, - const AudioBufferList* inInputData, - const AudioTimeStamp* inInputTime, - AudioBufferList* outOutputData, - const AudioTimeStamp* inOutputTime, - void* hwptr) -{ - UInt32 frame, frameCount; - float *in = inInputData->mBuffers[0].mData; - HWVoiceIn *hw = hwptr; - coreaudioVoice *core = CORE_IN(hw); - int wpos, avail; - st_sample_t *dst; -#ifndef FLOAT_MIXENG -#ifdef RECIPROCAL - const float scale = 1.f / UINT_MAX; -#else - const float scale = UINT_MAX; -#endif -#endif - - if (coreaudio_voice_lock (core, "audioDeviceIOProc")) { - inInputTime = 0; - return 0; - } - - frameCount = core->bufferFrameSize; - avail = hw->samples - hw->total_samples_captured - core->decr; - - D("%s: enter avail=%d core.decr=%d core.pos=%d hw.samples=%d hw.total_samples_captured=%d frameCount=%d\n", - __FUNCTION__, avail, core->decr, core->pos, hw->samples, hw->total_samples_captured, (int)frameCount); - - /* if there are not enough samples, set signal and return */ - if (avail < frameCount) { - inInputTime = 0; - coreaudio_voice_unlock (core, "audioDeviceIOProc(empty)"); - return 0; - } - - wpos = core->pos; - dst = hw->conv_buf + wpos; - - /* fill buffer */ - for (frame = 0; frame < frameCount; frame++) { -#ifdef FLOAT_MIXENG - dst[frame].l = *in++; /* left channel */ - dst[frame].r = *in++; /* right channel */ -#else -#ifdef RECIPROCAL - dst[frame].l = *in++ * scale; /* left channel */ - dst[frame].r = *in++ * scale; /* right channel */ -#else - dst[frame].l = *in++ / scale; /* left channel */ - dst[frame].r = *in++ / scale; /* right channel */ -#endif -#endif - } - - wpos = (wpos + frameCount) % hw->samples; - core->decr += frameCount; - core->pos = wpos; - - D("exit: core.decr=%d core.pos=%d\n", core->decr, core->pos); - coreaudio_voice_unlock (core, "audioDeviceIOProc"); - return 0; -} - -static int -coreaudio_read (SWVoiceIn *sw, void *buf, int len) -{ - int result = audio_pcm_sw_read(sw, buf, len); - D("%s: audio_pcm_sw_read(%d) returned %d\n", __FUNCTION__, len, result); - return result; -} - -static int -coreaudio_init_in (HWVoiceIn *hw, audsettings_t *as) -{ - coreaudioVoice* core = CORE_IN(hw); - int err; - - audio_pcm_init_info (&hw->info, as); - - err = coreaudio_voice_init( core, as, conf.in_buffer_frames, audioInDeviceIOProc, hw, 1 ); - if (err < 0) { - return err; - } - - hw->samples = core->bufferFrameSize * conf.in_nbuffers; - return 0; -} - -static void -coreaudio_fini_in (HWVoiceIn *hw) -{ - - coreaudioVoice* core = CORE_IN(hw); - - coreaudio_voice_fini(core); -} - -static int -coreaudio_ctl_in (HWVoiceIn *hw, int cmd, ...) -{ - coreaudioVoice* core = CORE_IN(hw); - - return coreaudio_voice_ctl(core, cmd); -} - -static void* -coreaudio_audio_init (void) -{ - atexit(coreaudio_atexit); - return &coreaudio_audio_init; -} - -static void -coreaudio_audio_fini (void *opaque) -{ - (void) opaque; -} - -static struct audio_option coreaudio_options[] = { - {"OUT_BUFFER_SIZE", AUD_OPT_INT, &conf.out_buffer_frames, - "Size of the output buffer in frames", NULL, 0}, - {"OUT_BUFFER_COUNT", AUD_OPT_INT, &conf.out_nbuffers, - "Number of output buffers", NULL, 0}, - {"IN_BUFFER_SIZE", AUD_OPT_INT, &conf.in_buffer_frames, - "Size of the input buffer in frames", NULL, 0}, - {"IN_BUFFER_COUNT", AUD_OPT_INT, &conf.in_nbuffers, - "Number of input buffers", NULL, 0}, - {NULL, 0, NULL, NULL, NULL, 0} -}; - -static struct audio_pcm_ops coreaudio_pcm_ops = { - coreaudio_init_out, - coreaudio_fini_out, - coreaudio_run_out, - coreaudio_write, - coreaudio_ctl_out, - -#if ENABLE_IN - coreaudio_init_in, - coreaudio_fini_in, - coreaudio_run_in, - coreaudio_read, - coreaudio_ctl_in -#else - NULL, - NULL, - NULL, - NULL, - NULL -#endif -}; - -struct audio_driver coreaudio_audio_driver = { - INIT_FIELD (name = ) "coreaudio", - INIT_FIELD (descr = ) - "CoreAudio (developer.apple.com/audio/coreaudio.html)", - INIT_FIELD (options = ) coreaudio_options, - INIT_FIELD (init = ) coreaudio_audio_init, - INIT_FIELD (fini = ) coreaudio_audio_fini, - INIT_FIELD (pcm_ops = ) &coreaudio_pcm_ops, - INIT_FIELD (can_be_default = ) 1, -#if ENABLE_IN - INIT_FIELD (max_voices_out = ) 1, - INIT_FIELD (max_voices_in = ) 1, - INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut), - INIT_FIELD (voice_size_in = ) sizeof (coreaudioVoiceIn), -#else - INIT_FIELD (max_voices_out = ) 1, - INIT_FIELD (max_voices_in = ) 0, - INIT_FIELD (voice_size_out = ) sizeof (coreaudioVoiceOut), - INIT_FIELD (voice_size_in = ) 0, -#endif -}; diff --git a/audio/dsound_template.h b/audio/dsound_template.h deleted file mode 100644 index 9cc0b9d..0000000 --- a/audio/dsound_template.h +++ /dev/null @@ -1,291 +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 - ) -{ - HRESULT hr; - int i; - 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 - for (i = 0; i < conf.lock_retries; ++i) { - 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)) { - dsound_logerr (hr, "Could not lock " NAME "\n"); - goto fail; - } - continue; - } -#endif - dsound_logerr (hr, "Could not lock " NAME "\n"); - goto fail; - } - - break; - } - - if (i == conf.lock_retries) { - dolog ("%d attempts to lock " NAME " failed\n", i); - 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, audsettings_t *as) -#else -static int dsound_init_out (HWVoiceOut *hw, audsettings_t *as) -#endif -{ - int err; - HRESULT hr; - dsound *s = &glob_dsound; - WAVEFORMATEX wfx; - audsettings_t obt_as; -#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; - -#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 TYPE -#undef IFACE -#undef BUFPTR -#undef FIELD diff --git a/audio/dsoundaudio.c b/audio/dsoundaudio.c deleted file mode 100644 index 8284067..0000000 --- a/audio/dsoundaudio.c +++ /dev/null @@ -1,1086 +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 "audio.h" - -#define AUDIO_CAP "dsound" -#include "audio_int.h" - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <mmsystem.h> -#include <objbase.h> -#include <dsound.h> - -/* #define DEBUG_DSOUND */ - -static struct { - int lock_retries; - int restore_retries; - int getstatus_retries; - int set_primary; - int bufsize_in; - int bufsize_out; - audsettings_t settings; - int latency_millis; -} conf = { - 1, - 1, - 1, - 0, - 16384, - 16384, - { - 44100, - 2, - AUD_FMT_S16 - }, - 10 -}; - -typedef struct { - LPDIRECTSOUND dsound; - LPDIRECTSOUNDCAPTURE dsound_capture; - LPDIRECTSOUNDBUFFER dsound_primary_buffer; - audsettings_t settings; -} dsound; - -static dsound glob_dsound; - -typedef struct { - HWVoiceOut hw; - LPDIRECTSOUNDBUFFER dsound_buffer; - DWORD old_pos; - int first_time; -#ifdef DEBUG_DSOUND - DWORD old_ppos; - DWORD played; - DWORD mixed; -#endif -} DSoundVoiceOut; - -typedef struct { - HWVoiceIn hw; - int first_time; - LPDIRECTSOUNDCAPTUREBUFFER dsound_capture_buffer; -} 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) -{ - HRESULT hr; - int i; - - for (i = 0; i < conf.restore_retries; ++i) { - hr = IDirectSoundBuffer_Restore (dsb); - - switch (hr) { - case DS_OK: - return 0; - - case DSERR_BUFFERLOST: - continue; - - default: - dsound_logerr (hr, "Could not restore playback buffer\n"); - return -1; - } - } - - dolog ("%d attempts to restore playback buffer failed\n", i); - return -1; -} - -static int waveformat_from_audio_settings (WAVEFORMATEX *wfx, audsettings_t *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; -} - -static int waveformat_to_audio_settings (WAVEFORMATEX *wfx, audsettings_t *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; -} - -#include "dsound_template.h" -#define DSBTYPE_IN -#include "dsound_template.h" -#undef DSBTYPE_IN - -static int dsound_get_status_out (LPDIRECTSOUNDBUFFER dsb, DWORD *statusp) -{ - HRESULT hr; - int i; - - for (i = 0; i < conf.getstatus_retries; ++i) { - hr = IDirectSoundBuffer_GetStatus (dsb, statusp); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not get playback buffer status\n"); - return -1; - } - - if (*statusp & DSERR_BUFFERLOST) { - if (dsound_restore_out (dsb)) { - return -1; - } - continue; - } - break; - } - - 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; - st_sample_t *src1 = hw->mix_buf + hw->rpos; - st_sample_t *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) -{ - 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 - ); - 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 void dsound_close (dsound *s) -{ - HRESULT hr; - - if (s->dsound_primary_buffer) { - hr = IDirectSoundBuffer_Release (s->dsound_primary_buffer); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not release primary buffer\n"); - } - s->dsound_primary_buffer = NULL; - } -} - -static int dsound_open (dsound *s) -{ - int err; - HRESULT hr; - WAVEFORMATEX wfx; - DSBUFFERDESC dsbd; - HWND hwnd; - - 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; - } - - if (!conf.set_primary) { - return 0; - } - - err = waveformat_from_audio_settings (&wfx, &conf.settings); - if (err) { - return -1; - } - - memset (&dsbd, 0, sizeof (dsbd)); - dsbd.dwSize = sizeof (dsbd); - dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER; - dsbd.dwBufferBytes = 0; - dsbd.lpwfxFormat = NULL; - - hr = IDirectSound_CreateSoundBuffer ( - s->dsound, - &dsbd, - &s->dsound_primary_buffer, - NULL - ); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not create primary playback buffer\n"); - return -1; - } - - hr = IDirectSoundBuffer_SetFormat (s->dsound_primary_buffer, &wfx); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not set primary playback buffer format\n"); - } - - hr = IDirectSoundBuffer_GetFormat ( - s->dsound_primary_buffer, - &wfx, - sizeof (wfx), - NULL - ); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not get primary playback buffer format\n"); - goto fail0; - } - -#ifdef DEBUG_DSOUND - dolog ("Primary\n"); - print_wave_format (&wfx); -#endif - - err = waveformat_to_audio_settings (&wfx, &s->settings); - if (err) { - goto fail0; - } - - return 0; - - fail0: - dsound_close (s); - return -1; -} - -static int dsound_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - HRESULT hr; - DWORD status; - DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; - LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer; - - 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)) { - return -1; - } - - if (status & DSBSTATUS_PLAYING) { - dolog ("warning: Voice is already playing\n"); - return 0; - } - - dsound_clear_sample (hw, dsb); - - 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)) { - 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 err; - HRESULT hr; - DSoundVoiceOut *ds = (DSoundVoiceOut *) hw; - LPDIRECTSOUNDBUFFER dsb = ds->dsound_buffer; - int live, len, hwshift; - DWORD blen1, blen2; - DWORD len1, len2; - DWORD decr; - DWORD wpos, ppos, old_pos; - LPVOID p1, p2; - int bufsize; - - if (!dsb) { - dolog ("Attempt to run empty with playback buffer\n"); - return 0; - } - - hwshift = hw->info.shift; - bufsize = hw->samples << hwshift; - - live = audio_pcm_hw_get_live_out (hw); - - 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 - ); - 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; - - 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 - ); - 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, &nominal_volume); - } - - if (p2 && len2) { - hw->conv (hw->conv_buf, p2, len2, &nominal_volume); - } - - dsound_unlock_in (dscb, p1, p2, blen1, blen2); - hw->wpos = (hw->wpos + decr) % hw->samples; - return decr; -} - -static void dsound_audio_fini (void *opaque) -{ - HRESULT hr; - dsound *s = opaque; - - if (!s->dsound) { - return; - } - - hr = IDirectSound_Release (s->dsound); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not release DirectSound\n"); - } - s->dsound = NULL; - - if (!s->dsound_capture) { - return; - } - - hr = IDirectSoundCapture_Release (s->dsound_capture); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not release DirectSoundCapture\n"); - } - s->dsound_capture = NULL; -} - -static void *dsound_audio_init (void) -{ - int err; - HRESULT hr; - dsound *s = &glob_dsound; - - hr = CoInitialize (NULL); - if (FAILED (hr)) { - dsound_logerr (hr, "Could not initialize COM\n"); - 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"); - 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"); - } - s->dsound = NULL; - 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[] = { - {"LOCK_RETRIES", AUD_OPT_INT, &conf.lock_retries, - "Number of times to attempt locking the buffer", NULL, 0}, - {"RESTOURE_RETRIES", AUD_OPT_INT, &conf.restore_retries, - "Number of times to attempt restoring the buffer", NULL, 0}, - {"GETSTATUS_RETRIES", AUD_OPT_INT, &conf.getstatus_retries, - "Number of times to attempt getting status of the buffer", NULL, 0}, - {"SET_PRIMARY", AUD_OPT_BOOL, &conf.set_primary, - "Set the parameters of primary buffer", NULL, 0}, - {"LATENCY_MILLIS", AUD_OPT_INT, &conf.latency_millis, - "(undocumented)", NULL, 0}, - {"PRIMARY_FREQ", AUD_OPT_INT, &conf.settings.freq, - "Primary buffer frequency", NULL, 0}, - {"PRIMARY_CHANNELS", AUD_OPT_INT, &conf.settings.nchannels, - "Primary buffer number of channels (1 - mono, 2 - stereo)", NULL, 0}, - {"PRIMARY_FMT", AUD_OPT_FMT, &conf.settings.fmt, - "Primary buffer format", NULL, 0}, - {"BUFSIZE_OUT", AUD_OPT_INT, &conf.bufsize_out, - "(undocumented)", NULL, 0}, - {"BUFSIZE_IN", AUD_OPT_INT, &conf.bufsize_in, - "(undocumented)", NULL, 0}, - {NULL, 0, NULL, NULL, NULL, 0} -}; - -static struct audio_pcm_ops dsound_pcm_ops = { - dsound_init_out, - dsound_fini_out, - dsound_run_out, - dsound_write, - dsound_ctl_out, - - dsound_init_in, - dsound_fini_in, - dsound_run_in, - dsound_read, - dsound_ctl_in -}; - -struct audio_driver dsound_audio_driver = { - INIT_FIELD (name = ) "dsound", - INIT_FIELD (descr = ) - "DirectSound audio (www.wikipedia.org/wiki/DirectSound)", - INIT_FIELD (options = ) dsound_options, - INIT_FIELD (init = ) dsound_audio_init, - INIT_FIELD (fini = ) dsound_audio_fini, - INIT_FIELD (pcm_ops = ) &dsound_pcm_ops, - INIT_FIELD (can_be_default = ) 1, - INIT_FIELD (max_voices_out = ) INT_MAX, - INIT_FIELD (max_voices_in = ) 1, - INIT_FIELD (voice_size_out = ) sizeof (DSoundVoiceOut), - INIT_FIELD (voice_size_in = ) sizeof (DSoundVoiceIn) -}; diff --git a/audio/esdaudio.c b/audio/esdaudio.c deleted file mode 100644 index 05c030f..0000000 --- a/audio/esdaudio.c +++ /dev/null @@ -1,682 +0,0 @@ -/* - * QEMU ESD audio driver - * - * Copyright (c) 2008 The Android Open Source Project - * Copyright (c) 2006 Frederick Reeve (brushed up by 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 <esd.h> -#include "audio.h" -#include <signal.h> - -#define AUDIO_CAP "esd" -#include "audio_int.h" -#include "audio_pt_int.h" -#include <dlfcn.h> - -#include "qemu_debug.h" - -#define DEBUG 1 - -#if DEBUG -# include <stdio.h> -# define D(...) VERBOSE_PRINT(audio,__VA_ARGS__) -# define D_ACTIVE VERBOSE_CHECK(audio) -# define O(...) VERBOSE_PRINT(audioout,__VA_ARGS__) -# define I(...) VERBOSE_PRINT(audioin,__VA_ARGS__) -#else -# define D(...) ((void)0) -# define D_ACTIVE 0 -# define O(...) ((void)0) -# define I(...) ((void)0) -#endif - -#define STRINGIFY_(x) #x -#define STRINGIFY(x) STRINGIFY_(x) - -typedef struct { - HWVoiceOut hw; - int done; - int live; - int decr; - int rpos; - void *pcm_buf; - int fd; - struct audio_pt pt; -} ESDVoiceOut; - -typedef struct { - HWVoiceIn hw; - int done; - int dead; - int incr; - int wpos; - void *pcm_buf; - int fd; - struct audio_pt pt; -} ESDVoiceIn; - -static struct { - int samples; - int divisor; - char *dac_host; - char *adc_host; -} conf = { - 1024, - 2, - NULL, - NULL -}; - -/* link dynamically to the libesd.so */ - -#define DYNLINK_FUNCTIONS \ - DYNLINK_FUNC(int,esd_play_stream,(esd_format_t,int,const char*,const char*)) \ - DYNLINK_FUNC(int,esd_record_stream,(esd_format_t,int,const char*,const char*)) \ - DYNLINK_FUNC(int,esd_open_sound,( const char *host )) \ - DYNLINK_FUNC(int,esd_close,(int)) \ - -#define DYNLINK_FUNCTIONS_INIT \ - esd_dynlink_init - -#include "dynlink.h" - -static void* esd_lib; - -static void GCC_FMT_ATTR (2, 3) qesd_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)); -} - -/* playback */ -static void *qesd_thread_out (void *arg) -{ - ESDVoiceOut* esd = arg; - HWVoiceOut* hw = &esd->hw; - int threshold; - sigset_t set; - - threshold = conf.divisor ? hw->samples / conf.divisor : 0; - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - /* ignore SIGALRM in this thread */ - sigemptyset(&set); - sigaddset(&set, SIGALRM); - - pthread_sigmask( SIG_BLOCK, &set, NULL); - - O("EsounD output thread starting, threshold is %d samples", threshold); - for (;;) { - int decr, to_mix, rpos; - - for (;;) { - if (esd->done) { - goto exit; - } - - if (esd->live > threshold) { - break; - } - - if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) { - O("EsounD output thread aborting on wait error"); - goto exit; - } - } - - decr = to_mix = esd->live; - rpos = hw->rpos; - - if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) { - O("EsounD output thread aborting on unlock error"); - return NULL; - } - - while (to_mix) { - ssize_t written; - int chunk = audio_MIN (to_mix, hw->samples - rpos); - st_sample_t *src = hw->mix_buf + rpos; - - hw->clip (esd->pcm_buf, src, chunk); - - again: - written = write (esd->fd, esd->pcm_buf, chunk << hw->info.shift); - if (written == -1) { - if (errno == EINTR || errno == EAGAIN) { - goto again; - } - qesd_logerr (errno, "write failed\n"); - O("EsounD output thread aborting on write error: %s", strerror(errno)); - return NULL; - } - - if (written != chunk << hw->info.shift) { - int wsamples = written >> hw->info.shift; - int wbytes = wsamples << hw->info.shift; - if (wbytes != written) { - dolog ("warning: Misaligned write %d (requested %d), " - "alignment %d\n", - wbytes, written, hw->info.align + 1); - } - to_mix -= wsamples; - rpos = (rpos + wsamples) % hw->samples; - break; - } - - rpos = (rpos + chunk) % hw->samples; - to_mix -= chunk; - } - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - O("EsounD output thread aborting on lock error\n"); - return NULL; - } - - esd->rpos = rpos; - esd->live -= decr; - esd->decr += decr; - } - O("EsounD output thread exiting"); - - exit: - audio_pt_unlock (&esd->pt, AUDIO_FUNC); - return NULL; -} - -static int qesd_run_out (HWVoiceOut *hw) -{ - int live, decr; - ESDVoiceOut *esd = (ESDVoiceOut *) hw; - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - O("%s: exiting on lock error", __FUNCTION__); - return 0; - } - - live = audio_pcm_hw_get_live_out (hw); - decr = audio_MIN (live, esd->decr); - esd->decr -= decr; - esd->live = live - decr; - hw->rpos = esd->rpos; - if (esd->live > 0) { - O("%s: signaling %d samples\n", esd->live); - audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); - } - else { - O("."); - audio_pt_unlock (&esd->pt, AUDIO_FUNC); - } - return decr; -} - -static int qesd_write (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -static int qesd_init_out (HWVoiceOut *hw, audsettings_t *as) -{ - ESDVoiceOut *esd = (ESDVoiceOut *) hw; - audsettings_t obt_as = *as; - int esdfmt = ESD_STREAM | ESD_PLAY; - int result = -1; - - /* shut down verbose debug spew */ - if (!D_ACTIVE) - stdio_disable(); - - O("initializing EsoundD audio output"); - esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; - switch (as->fmt) { - case AUD_FMT_S8: - case AUD_FMT_U8: - esdfmt |= ESD_BITS8; - obt_as.fmt = AUD_FMT_U8; - break; -#if 0 - case AUD_FMT_S32: - case AUD_FMT_U32: - dolog ("Will use 16 instead of 32 bit samples\n"); -#endif - case AUD_FMT_S16: - case AUD_FMT_U16: - deffmt: - esdfmt |= ESD_BITS16; - obt_as.fmt = AUD_FMT_S16; - break; - - default: - dolog ("Internal logic error: Bad audio format %d\n", as->fmt); - goto deffmt; - - } - obt_as.endianness = AUDIO_HOST_ENDIANNESS; - - audio_pcm_init_info (&hw->info, &obt_as); - - hw->samples = conf.samples; - esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - if (!esd->pcm_buf) { - dolog ("Could not allocate buffer (%d bytes)\n", - hw->samples << hw->info.shift); - goto exit; - } - - esd->fd = FF(esd_play_stream) (esdfmt, as->freq, conf.dac_host, NULL); - if (esd->fd < 0) { - if (conf.dac_host == NULL) { - esd->fd = FF(esd_play_stream) (esdfmt, as->freq, "localhost", NULL); - } - if (esd->fd < 0) { - qesd_logerr (errno, "esd_play_stream failed\n"); - goto fail2; - } - } - - if (audio_pt_init (&esd->pt, qesd_thread_out, esd, AUDIO_CAP, AUDIO_FUNC)) { - goto fail3; - } - - result = 0; /* success */ - goto exit; - - fail3: - if (close (esd->fd)) { - qesd_logerr (errno, "%s: close on esd socket(%d) failed\n", - AUDIO_FUNC, esd->fd); - } - esd->fd = -1; - - fail2: - qemu_free (esd->pcm_buf); - esd->pcm_buf = NULL; - - exit: - if (!D_ACTIVE) - stdio_enable(); - - return result; -} - -static void qesd_fini_out (HWVoiceOut *hw) -{ - void *ret; - ESDVoiceOut *esd = (ESDVoiceOut *) hw; - - audio_pt_lock (&esd->pt, AUDIO_FUNC); - esd->done = 1; - audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); - audio_pt_join (&esd->pt, &ret, AUDIO_FUNC); - - if (esd->fd >= 0) { - if (close (esd->fd)) { - qesd_logerr (errno, "failed to close esd socket\n"); - } - esd->fd = -1; - } - - audio_pt_fini (&esd->pt, AUDIO_FUNC); - - qemu_free (esd->pcm_buf); - esd->pcm_buf = NULL; -} - -static int qesd_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - -/* capture */ -static void *qesd_thread_in (void *arg) -{ - ESDVoiceIn *esd = arg; - HWVoiceIn *hw = &esd->hw; - int threshold; - - threshold = conf.divisor ? hw->samples / conf.divisor : 0; - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - for (;;) { - int incr, to_grab, wpos; - - for (;;) { - if (esd->done) { - goto exit; - } - - if (esd->dead > threshold) { - break; - } - - if (audio_pt_wait (&esd->pt, AUDIO_FUNC)) { - goto exit; - } - } - - incr = to_grab = esd->dead; - wpos = hw->wpos; - - if (audio_pt_unlock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - while (to_grab) { - ssize_t nread; - int chunk = audio_MIN (to_grab, hw->samples - wpos); - void *buf = advance (esd->pcm_buf, wpos); - - again: - nread = read (esd->fd, buf, chunk << hw->info.shift); - if (nread == -1) { - if (errno == EINTR || errno == EAGAIN) { - goto again; - } - qesd_logerr (errno, "read failed\n"); - return NULL; - } - - if (nread != chunk << hw->info.shift) { - int rsamples = nread >> hw->info.shift; - int rbytes = rsamples << hw->info.shift; - if (rbytes != nread) { - dolog ("warning: Misaligned write %d (requested %d), " - "alignment %d\n", - rbytes, nread, hw->info.align + 1); - } - to_grab -= rsamples; - wpos = (wpos + rsamples) % hw->samples; - break; - } - - hw->conv (hw->conv_buf + wpos, buf, nread >> hw->info.shift, - &nominal_volume); - wpos = (wpos + chunk) % hw->samples; - to_grab -= chunk; - } - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return NULL; - } - - esd->wpos = wpos; - esd->dead -= incr; - esd->incr += incr; - } - - exit: - audio_pt_unlock (&esd->pt, AUDIO_FUNC); - return NULL; -} - -static int qesd_run_in (HWVoiceIn *hw) -{ - int live, incr, dead; - ESDVoiceIn *esd = (ESDVoiceIn *) hw; - - if (audio_pt_lock (&esd->pt, AUDIO_FUNC)) { - return 0; - } - - live = audio_pcm_hw_get_live_in (hw); - dead = hw->samples - live; - incr = audio_MIN (dead, esd->incr); - esd->incr -= incr; - esd->dead = dead - incr; - hw->wpos = esd->wpos; - if (esd->dead > 0) { - audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); - } - else { - audio_pt_unlock (&esd->pt, AUDIO_FUNC); - } - return incr; -} - -static int qesd_read (SWVoiceIn *sw, void *buf, int len) -{ - return audio_pcm_sw_read (sw, buf, len); -} - -static int qesd_init_in (HWVoiceIn *hw, audsettings_t *as) -{ - ESDVoiceIn *esd = (ESDVoiceIn *) hw; - audsettings_t obt_as = *as; - int esdfmt = ESD_STREAM | ESD_RECORD; - int result = -1; - - /* shut down verbose debug spew */ - if (!D_ACTIVE) - stdio_disable(); - - esdfmt |= (as->nchannels == 2) ? ESD_STEREO : ESD_MONO; - switch (as->fmt) { - case AUD_FMT_S8: - case AUD_FMT_U8: - esdfmt |= ESD_BITS8; - obt_as.fmt = AUD_FMT_U8; - break; - - case AUD_FMT_S16: - case AUD_FMT_U16: - esdfmt |= ESD_BITS16; - obt_as.fmt = AUD_FMT_S16; - break; - case AUD_FMT_S32: - case AUD_FMT_U32: - dolog ("Will use 16 instead of 32 bit samples\n"); - esdfmt |= ESD_BITS16; - obt_as.fmt = AUD_FMT_S16; - break; - } - obt_as.endianness = AUDIO_HOST_ENDIANNESS; - - audio_pcm_init_info (&hw->info, &obt_as); - - hw->samples = conf.samples; - esd->pcm_buf = audio_calloc (AUDIO_FUNC, hw->samples, 1 << hw->info.shift); - if (!esd->pcm_buf) { - dolog ("Could not allocate buffer (%d bytes)\n", - hw->samples << hw->info.shift); - goto exit; - } - - esd->fd = FF(esd_record_stream) (esdfmt, as->freq, conf.adc_host, NULL); - if (esd->fd < 0) { - if (conf.adc_host == NULL) { - esd->fd = FF(esd_record_stream) (esdfmt, as->freq, "localhost", NULL); - } - if (esd->fd < 0) { - qesd_logerr (errno, "esd_record_stream failed\n"); - goto fail2; - } - } - - if (audio_pt_init (&esd->pt, qesd_thread_in, esd, AUDIO_CAP, AUDIO_FUNC)) { - goto fail3; - } - - result = 0; /* success */ - goto exit; - - fail3: - if (close (esd->fd)) { - qesd_logerr (errno, "%s: close on esd socket(%d) failed\n", - AUDIO_FUNC, esd->fd); - } - esd->fd = -1; - - fail2: - qemu_free (esd->pcm_buf); - esd->pcm_buf = NULL; - - exit: - if (!D_ACTIVE) - stdio_enable(); - - return result; -} - -static void qesd_fini_in (HWVoiceIn *hw) -{ - void *ret; - ESDVoiceIn *esd = (ESDVoiceIn *) hw; - - audio_pt_lock (&esd->pt, AUDIO_FUNC); - esd->done = 1; - audio_pt_unlock_and_signal (&esd->pt, AUDIO_FUNC); - audio_pt_join (&esd->pt, &ret, AUDIO_FUNC); - - if (esd->fd >= 0) { - if (close (esd->fd)) { - qesd_logerr (errno, "failed to close esd socket\n"); - } - esd->fd = -1; - } - - audio_pt_fini (&esd->pt, AUDIO_FUNC); - - qemu_free (esd->pcm_buf); - esd->pcm_buf = NULL; -} - -static int qesd_ctl_in (HWVoiceIn *hw, int cmd, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - -/* common */ -static void *qesd_audio_init (void) -{ - void* result = NULL; - - D("%s: entering", __FUNCTION__); - - if (esd_lib == NULL) { - int fd; - - esd_lib = dlopen( "libesd.so", RTLD_NOW ); - if (esd_lib == NULL) - esd_lib = dlopen( "libesd.so.0", RTLD_NOW ); - - if (esd_lib == NULL) { - D("could not find libesd on this system"); - goto Exit; - } - - if (esd_dynlink_init(esd_lib) < 0) - goto Fail; - - fd = FF(esd_open_sound)(conf.dac_host); - if (fd < 0) { - D("%s: could not open direct sound server connection, trying localhost", - __FUNCTION__); - fd = FF(esd_open_sound)("localhost"); - if (fd < 0) { - D("%s: could not open localhost sound server connection", __FUNCTION__); - goto Fail; - } - } - - D("%s: EsounD server connection succeeded", __FUNCTION__); - /* FF(esd_close)(fd); */ - } - result = &conf; - goto Exit; - -Fail: - D("%s: failed to open library", __FUNCTION__); - dlclose(esd_lib); - esd_lib = NULL; - -Exit: - return result; -} - -static void qesd_audio_fini (void *opaque) -{ - (void) opaque; - if (esd_lib != NULL) { - dlclose(esd_lib); - esd_lib = NULL; - } - ldebug ("esd_fini"); -} - -struct audio_option qesd_options[] = { - {"SAMPLES", AUD_OPT_INT, &conf.samples, - "buffer size in samples", NULL, 0}, - - {"DIVISOR", AUD_OPT_INT, &conf.divisor, - "threshold divisor", NULL, 0}, - - {"DAC_HOST", AUD_OPT_STR, &conf.dac_host, - "playback host", NULL, 0}, - - {"ADC_HOST", AUD_OPT_STR, &conf.adc_host, - "capture host", NULL, 0}, - - {NULL, 0, NULL, NULL, NULL, 0} -}; - -struct audio_pcm_ops qesd_pcm_ops = { - qesd_init_out, - qesd_fini_out, - qesd_run_out, - qesd_write, - qesd_ctl_out, - - qesd_init_in, - qesd_fini_in, - qesd_run_in, - qesd_read, - qesd_ctl_in, -}; - -struct audio_driver esd_audio_driver = { - INIT_FIELD (name = ) "esd", - INIT_FIELD (descr = ) - "EsounD audio (en.wikipedia.org/wiki/Esound)", - INIT_FIELD (options = ) qesd_options, - INIT_FIELD (init = ) qesd_audio_init, - INIT_FIELD (fini = ) qesd_audio_fini, - INIT_FIELD (pcm_ops = ) &qesd_pcm_ops, - INIT_FIELD (can_be_default = ) 1, - INIT_FIELD (max_voices_out = ) INT_MAX, - INIT_FIELD (max_voices_in = ) 1, - INIT_FIELD (voice_size_out = ) sizeof (ESDVoiceOut), - INIT_FIELD (voice_size_in = ) sizeof (ESDVoiceIn) -}; diff --git a/audio/fmodaudio.c b/audio/fmodaudio.c deleted file mode 100644 index e230e8b..0000000 --- a/audio/fmodaudio.c +++ /dev/null @@ -1,685 +0,0 @@ -/* - * QEMU FMOD 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 <fmod.h> -#include <fmod_errors.h> -#include "audio.h" - -#define AUDIO_CAP "fmod" -#include "audio_int.h" - -typedef struct FMODVoiceOut { - HWVoiceOut hw; - unsigned int old_pos; - FSOUND_SAMPLE *fmod_sample; - int channel; -} FMODVoiceOut; - -typedef struct FMODVoiceIn { - HWVoiceIn hw; - FSOUND_SAMPLE *fmod_sample; -} FMODVoiceIn; - -static struct { - const char *drvname; - int nb_samples; - int freq; - int nb_channels; - int bufsize; - int threshold; - int broken_adc; -} conf = { - NULL, - 2048 * 2, - 44100, - 2, - 0, - 0, - 0 -}; - -static void GCC_FMT_ATTR (1, 2) fmod_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", - FMOD_ErrorString (FSOUND_GetError ())); -} - -static void GCC_FMT_ATTR (2, 3) fmod_logerr2 ( - 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", - FMOD_ErrorString (FSOUND_GetError ())); -} - -static int fmod_write (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -static void fmod_clear_sample (FMODVoiceOut *fmd) -{ - HWVoiceOut *hw = &fmd->hw; - int status; - void *p1 = 0, *p2 = 0; - unsigned int len1 = 0, len2 = 0; - - status = FSOUND_Sample_Lock ( - fmd->fmod_sample, - 0, - hw->samples << hw->info.shift, - &p1, - &p2, - &len1, - &len2 - ); - - if (!status) { - fmod_logerr ("Failed to lock sample\n"); - return; - } - - if ((len1 & hw->info.align) || (len2 & hw->info.align)) { - dolog ("Lock returned misaligned length %d, %d, alignment %d\n", - len1, len2, hw->info.align + 1); - goto fail; - } - - if ((len1 + len2) - (hw->samples << hw->info.shift)) { - dolog ("Lock returned incomplete length %d, %d\n", - len1 + len2, hw->samples << hw->info.shift); - goto fail; - } - - audio_pcm_info_clear_buf (&hw->info, p1, hw->samples); - - fail: - status = FSOUND_Sample_Unlock (fmd->fmod_sample, p1, p2, len1, len2); - if (!status) { - fmod_logerr ("Failed to unlock sample\n"); - } -} - -static void fmod_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; - st_sample_t *src1 = hw->mix_buf + hw->rpos; - st_sample_t *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 int fmod_unlock_sample (FSOUND_SAMPLE *sample, void *p1, void *p2, - unsigned int blen1, unsigned int blen2) -{ - int status = FSOUND_Sample_Unlock (sample, p1, p2, blen1, blen2); - if (!status) { - fmod_logerr ("Failed to unlock sample\n"); - return -1; - } - return 0; -} - -static int fmod_lock_sample ( - FSOUND_SAMPLE *sample, - struct audio_pcm_info *info, - int pos, - int len, - void **p1, - void **p2, - unsigned int *blen1, - unsigned int *blen2 - ) -{ - int status; - - status = FSOUND_Sample_Lock ( - sample, - pos << info->shift, - len << info->shift, - p1, - p2, - blen1, - blen2 - ); - - if (!status) { - fmod_logerr ("Failed to lock sample\n"); - return -1; - } - - if ((*blen1 & info->align) || (*blen2 & info->align)) { - dolog ("Lock returned misaligned length %d, %d, alignment %d\n", - *blen1, *blen2, info->align + 1); - - fmod_unlock_sample (sample, *p1, *p2, *blen1, *blen2); - - *p1 = NULL - 1; - *p2 = NULL - 1; - *blen1 = ~0U; - *blen2 = ~0U; - return -1; - } - - if (!*p1 && *blen1) { - dolog ("warning: !p1 && blen1=%d\n", *blen1); - *blen1 = 0; - } - - if (!p2 && *blen2) { - dolog ("warning: !p2 && blen2=%d\n", *blen2); - *blen2 = 0; - } - - return 0; -} - -static int fmod_run_out (HWVoiceOut *hw) -{ - FMODVoiceOut *fmd = (FMODVoiceOut *) hw; - int live, decr; - void *p1 = 0, *p2 = 0; - unsigned int blen1 = 0, blen2 = 0; - unsigned int len1 = 0, len2 = 0; - int nb_live; - - live = audio_pcm_hw_get_live_out2 (hw, &nb_live); - if (!live) { - return 0; - } - - if (!hw->pending_disable - && nb_live - && (conf.threshold && live <= conf.threshold)) { - ldebug ("live=%d nb_live=%d\n", live, nb_live); - return 0; - } - - decr = live; - - if (fmd->channel >= 0) { - int len = decr; - int old_pos = fmd->old_pos; - int ppos = FSOUND_GetCurrentPosition (fmd->channel); - - if (ppos == old_pos || !ppos) { - return 0; - } - - if ((old_pos < ppos) && ((old_pos + len) > ppos)) { - len = ppos - old_pos; - } - else { - if ((old_pos > ppos) && ((old_pos + len) > (ppos + hw->samples))) { - len = hw->samples - old_pos + ppos; - } - } - decr = len; - - if (audio_bug (AUDIO_FUNC, decr < 0)) { - dolog ("decr=%d live=%d ppos=%d old_pos=%d len=%d\n", - decr, live, ppos, old_pos, len); - return 0; - } - } - - - if (!decr) { - return 0; - } - - if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info, - fmd->old_pos, decr, - &p1, &p2, - &blen1, &blen2)) { - return 0; - } - - len1 = blen1 >> hw->info.shift; - len2 = blen2 >> hw->info.shift; - ldebug ("%p %p %d %d %d %d\n", p1, p2, len1, len2, blen1, blen2); - decr = len1 + len2; - - if (p1 && len1) { - fmod_write_sample (hw, p1, len1); - } - - if (p2 && len2) { - fmod_write_sample (hw, p2, len2); - } - - fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2); - - fmd->old_pos = (fmd->old_pos + decr) % hw->samples; - return decr; -} - -static int aud_to_fmodfmt (audfmt_e fmt, int stereo) -{ - int mode = FSOUND_LOOP_NORMAL; - - switch (fmt) { - case AUD_FMT_S8: - mode |= FSOUND_SIGNED | FSOUND_8BITS; - break; - - case AUD_FMT_U8: - mode |= FSOUND_UNSIGNED | FSOUND_8BITS; - break; - - case AUD_FMT_S16: - mode |= FSOUND_SIGNED | FSOUND_16BITS; - break; - - case AUD_FMT_U16: - mode |= FSOUND_UNSIGNED | FSOUND_16BITS; - break; - - default: - dolog ("Internal logic error: Bad audio format %d\n", fmt); -#ifdef DEBUG_FMOD - abort (); -#endif - mode |= FSOUND_8BITS; - } - mode |= stereo ? FSOUND_STEREO : FSOUND_MONO; - return mode; -} - -static void fmod_fini_out (HWVoiceOut *hw) -{ - FMODVoiceOut *fmd = (FMODVoiceOut *) hw; - - if (fmd->fmod_sample) { - FSOUND_Sample_Free (fmd->fmod_sample); - fmd->fmod_sample = 0; - - if (fmd->channel >= 0) { - FSOUND_StopSound (fmd->channel); - } - } -} - -static int fmod_init_out (HWVoiceOut *hw, audsettings_t *as) -{ - int bits16, mode, channel; - FMODVoiceOut *fmd = (FMODVoiceOut *) hw; - audsettings_t obt_as = *as; - - mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0); - fmd->fmod_sample = FSOUND_Sample_Alloc ( - FSOUND_FREE, /* index */ - conf.nb_samples, /* length */ - mode, /* mode */ - as->freq, /* freq */ - 255, /* volume */ - 128, /* pan */ - 255 /* priority */ - ); - - if (!fmd->fmod_sample) { - fmod_logerr2 ("DAC", "Failed to allocate FMOD sample\n"); - return -1; - } - - channel = FSOUND_PlaySoundEx (FSOUND_FREE, fmd->fmod_sample, 0, 1); - if (channel < 0) { - fmod_logerr2 ("DAC", "Failed to start playing sound\n"); - FSOUND_Sample_Free (fmd->fmod_sample); - return -1; - } - fmd->channel = channel; - - /* FMOD always operates on little endian frames? */ - obt_as.endianness = 0; - audio_pcm_init_info (&hw->info, &obt_as); - bits16 = (mode & FSOUND_16BITS) != 0; - hw->samples = conf.nb_samples; - return 0; -} - -static int fmod_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - int status; - FMODVoiceOut *fmd = (FMODVoiceOut *) hw; - - switch (cmd) { - case VOICE_ENABLE: - fmod_clear_sample (fmd); - status = FSOUND_SetPaused (fmd->channel, 0); - if (!status) { - fmod_logerr ("Failed to resume channel %d\n", fmd->channel); - } - break; - - case VOICE_DISABLE: - status = FSOUND_SetPaused (fmd->channel, 1); - if (!status) { - fmod_logerr ("Failed to pause channel %d\n", fmd->channel); - } - break; - } - return 0; -} - -static int fmod_init_in (HWVoiceIn *hw, audsettings_t *as) -{ - int bits16, mode; - FMODVoiceIn *fmd = (FMODVoiceIn *) hw; - audsettings_t obt_as = *as; - - if (conf.broken_adc) { - return -1; - } - - mode = aud_to_fmodfmt (as->fmt, as->nchannels == 2 ? 1 : 0); - fmd->fmod_sample = FSOUND_Sample_Alloc ( - FSOUND_FREE, /* index */ - conf.nb_samples, /* length */ - mode, /* mode */ - as->freq, /* freq */ - 255, /* volume */ - 128, /* pan */ - 255 /* priority */ - ); - - if (!fmd->fmod_sample) { - fmod_logerr2 ("ADC", "Failed to allocate FMOD sample\n"); - return -1; - } - - /* FMOD always operates on little endian frames? */ - obt_as.endianness = 0; - audio_pcm_init_info (&hw->info, &obt_as); - bits16 = (mode & FSOUND_16BITS) != 0; - hw->samples = conf.nb_samples; - return 0; -} - -static void fmod_fini_in (HWVoiceIn *hw) -{ - FMODVoiceIn *fmd = (FMODVoiceIn *) hw; - - if (fmd->fmod_sample) { - FSOUND_Record_Stop (); - FSOUND_Sample_Free (fmd->fmod_sample); - fmd->fmod_sample = 0; - } -} - -static int fmod_run_in (HWVoiceIn *hw) -{ - FMODVoiceIn *fmd = (FMODVoiceIn *) hw; - int hwshift = hw->info.shift; - int live, dead, new_pos, len; - unsigned int blen1 = 0, blen2 = 0; - unsigned int len1, len2; - unsigned int decr; - void *p1, *p2; - - live = audio_pcm_hw_get_live_in (hw); - dead = hw->samples - live; - if (!dead) { - return 0; - } - - new_pos = FSOUND_Record_GetPosition (); - if (new_pos < 0) { - fmod_logerr ("Could not get recording position\n"); - return 0; - } - - len = audio_ring_dist (new_pos, hw->wpos, hw->samples); - if (!len) { - return 0; - } - len = audio_MIN (len, dead); - - if (fmod_lock_sample (fmd->fmod_sample, &fmd->hw.info, - hw->wpos, len, - &p1, &p2, - &blen1, &blen2)) { - return 0; - } - - len1 = blen1 >> hwshift; - len2 = blen2 >> hwshift; - decr = len1 + len2; - - if (p1 && blen1) { - hw->conv (hw->conv_buf + hw->wpos, p1, len1, &nominal_volume); - } - if (p2 && len2) { - hw->conv (hw->conv_buf, p2, len2, &nominal_volume); - } - - fmod_unlock_sample (fmd->fmod_sample, p1, p2, blen1, blen2); - hw->wpos = (hw->wpos + decr) % hw->samples; - return decr; -} - -static struct { - const char *name; - int type; -} drvtab[] = { - {"none", FSOUND_OUTPUT_NOSOUND}, -#ifdef _WIN32 - {"winmm", FSOUND_OUTPUT_WINMM}, - {"dsound", FSOUND_OUTPUT_DSOUND}, - {"a3d", FSOUND_OUTPUT_A3D}, - {"asio", FSOUND_OUTPUT_ASIO}, -#endif -#ifdef __linux__ - {"oss", FSOUND_OUTPUT_OSS}, - {"alsa", FSOUND_OUTPUT_ALSA}, - {"esd", FSOUND_OUTPUT_ESD}, -#endif -#ifdef __APPLE__ - {"mac", FSOUND_OUTPUT_MAC}, -#endif -#if 0 - {"xbox", FSOUND_OUTPUT_XBOX}, - {"ps2", FSOUND_OUTPUT_PS2}, - {"gcube", FSOUND_OUTPUT_GC}, -#endif - {"none-realtime", FSOUND_OUTPUT_NOSOUND_NONREALTIME} -}; - -static void *fmod_audio_init (void) -{ - size_t i; - double ver; - int status; - int output_type = -1; - const char *drv = conf.drvname; - - ver = FSOUND_GetVersion (); - if (ver < FMOD_VERSION) { - dolog ("Wrong FMOD version %f, need at least %f\n", ver, FMOD_VERSION); - return NULL; - } - -#ifdef __linux__ - if (ver < 3.75) { - dolog ("FMOD before 3.75 has bug preventing ADC from working\n" - "ADC will be disabled.\n"); - conf.broken_adc = 1; - } -#endif - - if (drv) { - int found = 0; - for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { - if (!strcmp (drv, drvtab[i].name)) { - output_type = drvtab[i].type; - found = 1; - break; - } - } - if (!found) { - dolog ("Unknown FMOD driver `%s'\n", drv); - dolog ("Valid drivers:\n"); - for (i = 0; i < sizeof (drvtab) / sizeof (drvtab[0]); i++) { - dolog (" %s\n", drvtab[i].name); - } - } - } - - if (output_type != -1) { - status = FSOUND_SetOutput (output_type); - if (!status) { - fmod_logerr ("FSOUND_SetOutput(%d) failed\n", output_type); - return NULL; - } - } - - if (conf.bufsize) { - status = FSOUND_SetBufferSize (conf.bufsize); - if (!status) { - fmod_logerr ("FSOUND_SetBufferSize (%d) failed\n", conf.bufsize); - } - } - - status = FSOUND_Init (conf.freq, conf.nb_channels, 0); - if (!status) { - fmod_logerr ("FSOUND_Init failed\n"); - return NULL; - } - - return &conf; -} - -static int fmod_read (SWVoiceIn *sw, void *buf, int size) -{ - return audio_pcm_sw_read (sw, buf, size); -} - -static int fmod_ctl_in (HWVoiceIn *hw, int cmd, ...) -{ - int status; - FMODVoiceIn *fmd = (FMODVoiceIn *) hw; - - switch (cmd) { - case VOICE_ENABLE: - status = FSOUND_Record_StartSample (fmd->fmod_sample, 1); - if (!status) { - fmod_logerr ("Failed to start recording\n"); - } - break; - - case VOICE_DISABLE: - status = FSOUND_Record_Stop (); - if (!status) { - fmod_logerr ("Failed to stop recording\n"); - } - break; - } - return 0; -} - -static void fmod_audio_fini (void *opaque) -{ - (void) opaque; - FSOUND_Close (); -} - -static struct audio_option fmod_options[] = { - {"DRV", AUD_OPT_STR, &conf.drvname, - "FMOD driver", NULL, 0}, - {"FREQ", AUD_OPT_INT, &conf.freq, - "Default frequency", NULL, 0}, - {"SAMPLES", AUD_OPT_INT, &conf.nb_samples, - "Buffer size in samples", NULL, 0}, - {"CHANNELS", AUD_OPT_INT, &conf.nb_channels, - "Number of default channels (1 - mono, 2 - stereo)", NULL, 0}, - {"BUFSIZE", AUD_OPT_INT, &conf.bufsize, - "(undocumented)", NULL, 0}, -#if 0 - {"THRESHOLD", AUD_OPT_INT, &conf.threshold, - "(undocumented)"}, -#endif - - {NULL, 0, NULL, NULL, NULL, 0} -}; - -static struct audio_pcm_ops fmod_pcm_ops = { - fmod_init_out, - fmod_fini_out, - fmod_run_out, - fmod_write, - fmod_ctl_out, - - fmod_init_in, - fmod_fini_in, - fmod_run_in, - fmod_read, - fmod_ctl_in -}; - -struct audio_driver fmod_audio_driver = { - INIT_FIELD (name = ) "fmod", - INIT_FIELD (descr = ) "FMOD 3.xx http://www.fmod.org", - INIT_FIELD (options = ) fmod_options, - INIT_FIELD (init = ) fmod_audio_init, - INIT_FIELD (fini = ) fmod_audio_fini, - INIT_FIELD (pcm_ops = ) &fmod_pcm_ops, - INIT_FIELD (can_be_default = ) 1, - INIT_FIELD (max_voices_out = ) INT_MAX, - INIT_FIELD (max_voices_in = ) INT_MAX, - INIT_FIELD (voice_size_out = ) sizeof (FMODVoiceOut), - INIT_FIELD (voice_size_in = ) sizeof (FMODVoiceIn) -}; diff --git a/audio/mixeng.c b/audio/mixeng.c deleted file mode 100644 index 34fc6df..0000000 --- a/audio/mixeng.c +++ /dev/null @@ -1,336 +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 "audio.h" - -#define AUDIO_CAP "mixeng" -#include "audio_int.h" - -#define NOVOL - -/* 8 bit */ -#define ENDIAN_CONVERSION natural -#define ENDIAN_CONVERT(v) (v) - -/* Signed 8 bit */ -#define IN_T int8_t -#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 IN_T -#undef SHIFT - -/* Unsigned 8 bit */ -#define IN_T uint8_t -#define IN_MIN 0 -#define IN_MAX UCHAR_MAX -#define SHIFT 8 -#include "mixeng_template.h" -#undef IN_MAX -#undef IN_MIN -#undef IN_T -#undef SHIFT - -#undef ENDIAN_CONVERT -#undef ENDIAN_CONVERSION - -/* Signed 16 bit */ -#define IN_T int16_t -#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 IN_T -#undef SHIFT - -/* Unsigned 16 bit */ -#define IN_T uint16_t -#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 IN_T -#undef SHIFT - -/* Signed 32 bit */ -#define IN_T int32_t -#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 IN_T -#undef SHIFT - -/* Unsigned 16 bit */ -#define IN_T uint32_t -#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 IN_T -#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) */ - st_sample_t 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) -{ - qemu_free (opaque); -} - -void mixeng_clear (st_sample_t *buf, int len) -{ - memset (buf, 0, len * sizeof (st_sample_t)); -} diff --git a/audio/mixeng.h b/audio/mixeng.h deleted file mode 100644 index 95b68df..0000000 --- a/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 real_t; -typedef struct { int mute; real_t r; real_t l; } volume_t; -typedef struct { real_t l; real_t r; } st_sample_t; -#else -typedef struct { int mute; int64_t r; int64_t l; } volume_t; -typedef struct { int64_t l; int64_t r; } st_sample_t; -#endif - -typedef void (t_sample) (st_sample_t *dst, const void *src, - int samples, volume_t *vol); -typedef void (f_sample) (void *dst, const st_sample_t *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, st_sample_t *ibuf, st_sample_t *obuf, - int *isamp, int *osamp); -void st_rate_flow_mix (void *opaque, st_sample_t *ibuf, st_sample_t *obuf, - int *isamp, int *osamp); -void st_rate_stop (void *opaque); -void mixeng_clear (st_sample_t *buf, int len); - -#endif /* mixeng.h */ diff --git a/audio/mixeng_template.h b/audio/mixeng_template.h deleted file mode 100644 index d726441..0000000 --- a/audio/mixeng_template.h +++ /dev/null @@ -1,177 +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 - -#ifdef NOVOL -#define VOL(a, b) a -#else -#ifdef FLOAT_MIXENG -#define VOL(a, b) ((a) * (b)) -#else -#define VOL(a, b) ((a) * (b)) >> 32 -#endif -#endif - -#define ET glue (ENDIAN_CONVERSION, glue (_, IN_T)) - -#ifdef FLOAT_MIXENG -static real_t inline glue (conv_, ET) (IN_T v) -{ - IN_T nv = ENDIAN_CONVERT (v); - -#ifdef RECIPROCAL -#ifdef SIGNED - return nv * (1.f / (real_t) (IN_MAX - IN_MIN)); -#else - return (nv - HALF) * (1.f / (real_t) IN_MAX); -#endif -#else /* !RECIPROCAL */ -#ifdef SIGNED - return nv / (real_t) (IN_MAX - IN_MIN); -#else - return (nv - HALF) / (real_t) IN_MAX; -#endif -#endif -} - -static IN_T inline glue (clip_, ET) (real_t v) -{ - if (v >= 0.5) { - return IN_MAX; - } - else if (v < -0.5) { - return IN_MIN; - } - -#ifdef SIGNED - return ENDIAN_CONVERT ((IN_T) (v * (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) - (st_sample_t *dst, const void *src, int samples, volume_t *vol) -{ - st_sample_t *out = dst; - IN_T *in = (IN_T *) src; -#ifndef NOVOL - if (vol->mute) { - mixeng_clear (dst, samples); - return; - } -#else - (void) vol; -#endif - while (samples--) { - out->l = VOL (glue (conv_, ET) (*in++), vol->l); - out->r = VOL (glue (conv_, ET) (*in++), vol->r); - out += 1; - } -} - -static void glue (glue (conv_, ET), _to_mono) - (st_sample_t *dst, const void *src, int samples, volume_t *vol) -{ - st_sample_t *out = dst; - IN_T *in = (IN_T *) src; -#ifndef NOVOL - if (vol->mute) { - mixeng_clear (dst, samples); - return; - } -#else - (void) vol; -#endif - while (samples--) { - out->l = VOL (glue (conv_, ET) (in[0]), vol->l); - out->r = out->l; - out += 1; - in += 1; - } -} - -static void glue (glue (clip_, ET), _from_stereo) - (void *dst, const st_sample_t *src, int samples) -{ - const st_sample_t *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 st_sample_t *src, int samples) -{ - const st_sample_t *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 VOL diff --git a/audio/noaudio.c b/audio/noaudio.c deleted file mode 100644 index 8788a41..0000000 --- a/audio/noaudio.c +++ /dev/null @@ -1,172 +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-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) -{ - NoVoiceOut *no = (NoVoiceOut *) hw; - int live, decr, samples; - int64_t now; - int64_t ticks; - int64_t bytes; - - live = audio_pcm_hw_get_live_out (&no->hw); - if (!live) { - return 0; - } - - now = qemu_get_clock (vm_clock); - ticks = now - no->old_ticks; - bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; - 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, audsettings_t *as) -{ - 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, audsettings_t *as) -{ - 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_get_clock (vm_clock); - int64_t ticks = now - no->old_ticks; - int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; - - 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) -{ - 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); - audio_pcm_info_clear_buf (&sw->info, buf, to_clear); - return to_clear; -} - -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 = { - no_init_out, - no_fini_out, - no_run_out, - no_write, - no_ctl_out, - - no_init_in, - no_fini_in, - no_run_in, - no_read, - no_ctl_in -}; - -struct audio_driver no_audio_driver = { - INIT_FIELD (name = ) "none", - INIT_FIELD (descr = ) "disabled audio", - INIT_FIELD (options = ) NULL, - INIT_FIELD (init = ) no_audio_init, - INIT_FIELD (fini = ) no_audio_fini, - INIT_FIELD (pcm_ops = ) &no_pcm_ops, - INIT_FIELD (can_be_default = ) 1, - INIT_FIELD (max_voices_out = ) INT_MAX, - INIT_FIELD (max_voices_in = ) INT_MAX, - INIT_FIELD (voice_size_out = ) sizeof (NoVoiceOut), - INIT_FIELD (voice_size_in = ) sizeof (NoVoiceIn) -}; diff --git a/audio/ossaudio.c b/audio/ossaudio.c deleted file mode 100644 index 2ccaade..0000000 --- a/audio/ossaudio.c +++ /dev/null @@ -1,773 +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 <sys/mman.h> -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/soundcard.h> - -#define AUDIO_CAP "oss" -#include "audio_int.h" - -typedef struct OSSVoiceOut { - HWVoiceOut hw; - void *pcm_buf; - int fd; - int nfrags; - int fragsize; - int mmapped; - int old_optr; -} OSSVoiceOut; - -typedef struct OSSVoiceIn { - HWVoiceIn hw; - void *pcm_buf; - int fd; - int nfrags; - int fragsize; - int old_optr; -} OSSVoiceIn; - -static struct { - int try_mmap; - int nfrags; - int fragsize; - const char *devpath_out; - const char *devpath_in; - int debug; -} conf = { - .try_mmap = 0, - .nfrags = 4, - .fragsize = 4096, - .devpath_out = "/dev/dsp", - .devpath_in = "/dev/dsp", - .debug = 0 -}; - -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 = close (*fdp); - if (err) { - oss_logerr (errno, "Failed to close file(fd=%d)\n", *fdp); - } - *fdp = -1; -} - -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) -{ - switch (fmt) { - case AUD_FMT_S8: - return AFMT_S8; - - case AUD_FMT_U8: - return AFMT_U8; - - case AUD_FMT_S16: - return AFMT_S16_LE; - - case AUD_FMT_U16: - 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 - -static int oss_open (int in, struct oss_params *req, - struct oss_params *obt, int *pfd) -{ - int fd; - int mmmmssss; - audio_buf_info abinfo; - int fmt, freq, nchannels; - const char *dspname = in ? conf.devpath_in : conf.devpath_out; - const char *typ = in ? "ADC" : "DAC"; - - fd = open (dspname, (in ? O_RDONLY : O_WRONLY) | 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; - } - - mmmmssss = (req->nfrags << 16) | lsbindex (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 int oss_run_out (HWVoiceOut *hw) -{ - OSSVoiceOut *oss = (OSSVoiceOut *) hw; - int err, rpos, live, decr; - int samples; - uint8_t *dst; - st_sample_t *src; - struct audio_buf_info abinfo; - struct count_info cntinfo; - int bufsize; - - live = audio_pcm_hw_get_live_out (hw); - if (!live) { - return 0; - } - - bufsize = hw->samples << hw->info.shift; - - if (oss->mmapped) { - int bytes; - - err = ioctl (oss->fd, SNDCTL_DSP_GETOPTR, &cntinfo); - if (err < 0) { - oss_logerr (errno, "SNDCTL_DSP_GETOPTR failed\n"); - return 0; - } - - if (cntinfo.ptr == oss->old_optr) { - if (abs (hw->samples - live) < 64) { - dolog ("warning: Overrun\n"); - } - return 0; - } - - if (cntinfo.ptr > oss->old_optr) { - bytes = cntinfo.ptr - oss->old_optr; - } - else { - bytes = bufsize + cntinfo.ptr - oss->old_optr; - } - - 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) { - if (conf.debug) { - dolog ("warning: Invalid available size, size=%d bufsize=%d\n" - "please report your OS/audio hw to malc@pulsesoft.com\n", - abinfo.bytes, bufsize); - } - abinfo.bytes = bufsize; - } - - if (abinfo.bytes < 0) { - if (conf.debug) { - dolog ("warning: Invalid available size, size=%d bufsize=%d\n", - abinfo.bytes, bufsize); - } - return 0; - } - - decr = audio_MIN (abinfo.bytes >> hw->info.shift, live); - if (!decr) { - return 0; - } - } - - 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 (oss->pcm_buf, rpos << hw->info.shift); - - hw->clip (dst, src, convert_samples); - if (!oss->mmapped) { - int written; - - written = write (oss->fd, dst, convert_samples << hw->info.shift); - /* XXX: follow errno recommendations ? */ - if (written == -1) { - oss_logerr ( - errno, - "Failed to write %d bytes of audio data from %p\n", - convert_samples << hw->info.shift, - dst - ); - continue; - } - - if (written != convert_samples << hw->info.shift) { - int wsamples = written >> hw->info.shift; - int wbytes = wsamples << hw->info.shift; - if (wbytes != written) { - dolog ("warning: Misaligned write %d (requested %d), " - "alignment %d\n", - wbytes, written, hw->info.align + 1); - } - decr -= wsamples; - rpos = (rpos + wsamples) % hw->samples; - break; - } - } - - rpos = (rpos + convert_samples) % hw->samples; - samples -= convert_samples; - } - if (oss->mmapped) { - oss->old_optr = cntinfo.ptr; - } - - hw->rpos = rpos; - 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 { - qemu_free (oss->pcm_buf); - } - oss->pcm_buf = NULL; - } -} - -static int oss_init_out (HWVoiceOut *hw, audsettings_t *as) -{ - OSSVoiceOut *oss = (OSSVoiceOut *) hw; - struct oss_params req, obt; - int endianness; - int err; - int fd; - audfmt_e effective_fmt; - audsettings_t obt_as; - - oss->fd = -1; - - req.fmt = aud_to_ossfmt (as->fmt); - req.freq = as->freq; - req.nchannels = as->nchannels; - req.fragsize = conf.fragsize; - req.nfrags = conf.nfrags; - - if (oss_open (0, &req, &obt, &fd)) { - 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 ( - 0, - 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; - return 0; -} - -static int oss_ctl_out (HWVoiceOut *hw, int cmd, ...) -{ - int trig; - OSSVoiceOut *oss = (OSSVoiceOut *) hw; - - if (!oss->mmapped) { - return 0; - } - - switch (cmd) { - case VOICE_ENABLE: - ldebug ("enabling voice\n"); - 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: - 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, audsettings_t *as) -{ - OSSVoiceIn *oss = (OSSVoiceIn *) hw; - struct oss_params req, obt; - int endianness; - int err; - int fd; - audfmt_e effective_fmt; - audsettings_t obt_as; - - oss->fd = -1; - - req.fmt = aud_to_ossfmt (as->fmt); - req.freq = as->freq; - req.nchannels = as->nchannels; - req.fragsize = conf.fragsize; - req.nfrags = conf.nfrags; - if (oss_open (1, &req, &obt, &fd)) { - 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; - return 0; -} - -static void oss_fini_in (HWVoiceIn *hw) -{ - OSSVoiceIn *oss = (OSSVoiceIn *) hw; - - oss_anal_close (&oss->fd); - - if (oss->pcm_buf) { - qemu_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] = { - { hw->wpos, 0 }, - { 0, 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, - &nominal_volume); - } - - 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, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - -static void *oss_audio_init (void) -{ - return &conf; -} - -static void oss_audio_fini (void *opaque) -{ - (void) opaque; -} - -static struct audio_option oss_options[] = { - {"FRAGSIZE", AUD_OPT_INT, &conf.fragsize, - "Fragment size in bytes", NULL, 0}, - {"NFRAGS", AUD_OPT_INT, &conf.nfrags, - "Number of fragments", NULL, 0}, - {"MMAP", AUD_OPT_BOOL, &conf.try_mmap, - "Try using memory mapped access", NULL, 0}, - {"DAC_DEV", AUD_OPT_STR, &conf.devpath_out, - "Path to DAC device", NULL, 0}, - {"ADC_DEV", AUD_OPT_STR, &conf.devpath_in, - "Path to ADC device", NULL, 0}, - {"DEBUG", AUD_OPT_BOOL, &conf.debug, - "Turn on some debugging messages", NULL, 0}, - {NULL, 0, NULL, NULL, NULL, 0} -}; - -static struct audio_pcm_ops oss_pcm_ops = { - oss_init_out, - oss_fini_out, - oss_run_out, - oss_write, - oss_ctl_out, - - oss_init_in, - oss_fini_in, - oss_run_in, - oss_read, - oss_ctl_in -}; - -struct audio_driver oss_audio_driver = { - INIT_FIELD (name = ) "oss", - INIT_FIELD (descr = ) "OSS audio (www.opensound.com)", - INIT_FIELD (options = ) oss_options, - INIT_FIELD (init = ) oss_audio_init, - INIT_FIELD (fini = ) oss_audio_fini, - INIT_FIELD (pcm_ops = ) &oss_pcm_ops, - INIT_FIELD (can_be_default = ) 1, - INIT_FIELD (max_voices_out = ) INT_MAX, - INIT_FIELD (max_voices_in = ) INT_MAX, - INIT_FIELD (voice_size_out = ) sizeof (OSSVoiceOut), - INIT_FIELD (voice_size_in = ) sizeof (OSSVoiceIn) -}; diff --git a/audio/rate_template.h b/audio/rate_template.h deleted file mode 100644 index 398d305..0000000 --- a/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, st_sample_t *ibuf, st_sample_t *obuf, - int *isamp, int *osamp) -{ - struct rate *rate = opaque; - st_sample_t *istart, *iend; - st_sample_t *ostart, *oend; - st_sample_t ilast, icur, out; -#ifdef FLOAT_MIXENG - real_t 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) / (real_t) 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/audio/sdlaudio.c b/audio/sdlaudio.c deleted file mode 100644 index ea5bccd..0000000 --- a/audio/sdlaudio.c +++ /dev/null @@ -1,660 +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 <SDL.h> -#include <SDL_thread.h> - -#ifndef _WIN32 -#ifdef __sun__ -#define _POSIX_PTHREAD_SEMANTICS 1 -#endif -#include <signal.h> -#endif - -#define AUDIO_CAP "sdl" -#include "audio_int.h" - -/* define DEBUG to 1 to dump audio debugging info at runtime to stderr */ -#define DEBUG 0 - -/* define NEW_AUDIO to 1 to activate the new audio thread callback */ -#define NEW_AUDIO 1 - -#if DEBUG -# define D(...) fprintf(stderr, __VA_ARGS__) -#else -# define D(...) ((void)0) -#endif - -static struct { - int nb_samples; -} conf = { - 1024 -}; - -#if DEBUG -int64_t start_time; -#endif - -#if NEW_AUDIO - -#define AUDIO_BUFFER_SIZE (8192) - -typedef HWVoiceOut SDLVoiceOut; - -struct SDLAudioState { - int exit; - SDL_mutex* mutex; - int initialized; - uint8_t data[ AUDIO_BUFFER_SIZE ]; - int pos, count; -} glob_sdl; -#else /* !NEW_AUDIO */ - -typedef struct SDLVoiceOut { - HWVoiceOut hw; - int live; - int rpos; - int decr; -} SDLVoiceOut; - -struct SDLAudioState { - int exit; - SDL_mutex *mutex; - SDL_sem *sem; - int initialized; -} glob_sdl; - -#endif /* !NEW_AUDIO */ - -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; -} - -#if !NEW_AUDIO -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); -} -#endif - -static int aud_to_sdlfmt (audfmt_e fmt, int *shift) -{ - switch (fmt) { - case AUD_FMT_S8: - *shift = 0; - return AUDIO_S8; - - case AUD_FMT_U8: - *shift = 0; - return AUDIO_U8; - - case AUD_FMT_S16: - *shift = 1; - return AUDIO_S16LSB; - - case AUD_FMT_U16: - *shift = 1; - 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 *endianess) -{ - switch (sdlfmt) { - case AUDIO_S8: - *endianess = 0; - *fmt = AUD_FMT_S8; - break; - - case AUDIO_U8: - *endianess = 0; - *fmt = AUD_FMT_U8; - break; - - case AUDIO_S16LSB: - *endianess = 0; - *fmt = AUD_FMT_S16; - break; - - case AUDIO_U16LSB: - *endianess = 0; - *fmt = AUD_FMT_U16; - break; - - case AUDIO_S16MSB: - *endianess = 1; - *fmt = AUD_FMT_S16; - break; - - case AUDIO_U16MSB: - *endianess = 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 - sigset_t new, old; - - /* Make sure potential threads created by SDL don't hog signals. */ - sigfillset (&new); - pthread_sigmask (SIG_BLOCK, &new, &old); -#endif - - status = SDL_OpenAudio (req, obt); - if (status) { - sdl_logerr ("SDL_OpenAudio failed\n"); - } -#ifndef _WIN32 - pthread_sigmask (SIG_SETMASK, &old, 0); -#endif - return status; -} - -static void sdl_close (SDLAudioState *s) -{ - if (s->initialized) { - sdl_lock (s, "sdl_close"); - s->exit = 1; -#if NEW_AUDIO - sdl_unlock (s, "sdl_close"); -#else - sdl_unlock_and_post (s, "sdl_close"); -#endif - SDL_PauseAudio (1); - SDL_CloseAudio (); - s->initialized = 0; - } -} - -#if NEW_AUDIO - -static void sdl_callback (void *opaque, Uint8 *buf, int len) -{ -#if DEBUG - int64_t now; -#endif - SDLAudioState *s = &glob_sdl; - - if (s->exit) { - return; - } - - sdl_lock (s, "sdl_callback"); -#if DEBUG - if (s->count > 0) { - now = qemu_get_clock(vm_clock); - if (start_time == 0) - start_time = now; - now = now - start_time; - D( "R %6.3f: pos:%5d count:%5d len:%5d\n", now/1e9, s->pos, s->count, len ); - } -#endif - while (len > 0) { - int avail = audio_MIN( AUDIO_BUFFER_SIZE - s->pos, s->count ); - - if (avail == 0) - break; - - if (avail > len) - avail = len; - - memcpy( buf, s->data + s->pos, avail ); - buf += avail; - len -= avail; - - s->count -= avail; - s->pos += avail; - if (s->pos == AUDIO_BUFFER_SIZE) - s->pos = 0; - } - sdl_unlock (s, "sdl_callback"); -} - -#else /* !NEW_AUDIO */ -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); - st_sample_t *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); */ -} -#endif /* !NEW_AUDIO */ - -static int sdl_write_out (SWVoiceOut *sw, void *buf, int len) -{ - return audio_pcm_sw_write (sw, buf, len); -} - -#if NEW_AUDIO - -static int sdl_run_out (HWVoiceOut *hw) -{ - SDLAudioState *s = &glob_sdl; - int live, avail, end, total; - - if (sdl_lock (s, "sdl_run_out")) { - return 0; - } - avail = AUDIO_BUFFER_SIZE - s->count; - end = s->pos + s->count; - if (end >= AUDIO_BUFFER_SIZE) - end -= AUDIO_BUFFER_SIZE; - sdl_unlock (s, "sdl_run_out"); - - live = audio_pcm_hw_get_live_out (hw); - - total = 0; - while (live > 0) { - int bytes = audio_MIN(AUDIO_BUFFER_SIZE - end, avail); - int samples = bytes >> hw->info.shift; - int hwsamples = audio_MIN(hw->samples - hw->rpos, live); - uint8_t* dst = s->data + end; - st_sample_t* src = hw->mix_buf + hw->rpos; - - if (samples == 0) - break; - - if (samples > hwsamples) { - samples = hwsamples; - bytes = hwsamples << hw->info.shift; - } - - hw->clip (dst, src, samples); - hw->rpos += samples; - if (hw->rpos == hw->samples) - hw->rpos = 0; - - live -= samples; - avail -= bytes; - end += bytes; - if (end == AUDIO_BUFFER_SIZE) - end = 0; - - total += bytes; - } - - sdl_lock (s, "sdl_run_out"); - s->count += total; - sdl_unlock (s, "sdl_run_out"); - - return total >> hw->info.shift; -} - -#else /* !NEW_AUDIO */ -static int sdl_run_out (HWVoiceOut *hw) -{ - int decr, live; - SDLVoiceOut *sdl = (SDLVoiceOut *) hw; - SDLAudioState *s = &glob_sdl; - - if (sdl_lock (s, "sdl_callback")) { - return 0; - } - - live = audio_pcm_hw_get_live_out (hw); - - 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_callback"); - } - else { - sdl_unlock (s, "sdl_callback"); - } - return decr; -} -#endif /* !NEW_AUDIO */ - -static void sdl_fini_out (HWVoiceOut *hw) -{ - (void) hw; - - sdl_close (&glob_sdl); -} - -#if DEBUG - -typedef struct { int value; const char* name; } MatchRec; -typedef const MatchRec* Match; - -static const char* -match_find( Match matches, int value, char* temp ) -{ - int nn; - for ( nn = 0; matches[nn].name != NULL; nn++ ) { - if ( matches[nn].value == value ) - return matches[nn].name; - } - sprintf( temp, "(%d?)", value ); - return temp; -} - -static const MatchRec sdl_audio_format_matches[] = { - { AUDIO_U8, "AUDIO_U8" }, - { AUDIO_S8, "AUDIO_S8" }, - { AUDIO_U16, "AUDIO_U16LE" }, - { AUDIO_S16, "AUDIO_S16LE" }, - { AUDIO_U16MSB, "AUDIO_U16BE" }, - { AUDIO_S16MSB, "AUDIO_S16BE" }, - { 0, NULL } -}; - -static void -print_sdl_audiospec( SDL_AudioSpec* spec, const char* prefix ) -{ - char temp[64]; - const char* fmt; - - if (!prefix) - prefix = ""; - - printf( "%s audiospec [freq:%d format:%s channels:%d samples:%d bytes:%d", - prefix, - spec->freq, - match_find( sdl_audio_format_matches, spec->format, temp ), - spec->channels, - spec->samples, - spec->size - ); - printf( "]\n" ); -} -#endif - -static int sdl_init_out (HWVoiceOut *hw, audsettings_t *as) -{ - SDLVoiceOut *sdl = (SDLVoiceOut *) hw; - SDLAudioState *s = &glob_sdl; - SDL_AudioSpec req, obt; - int shift; - int endianess; - int err; - audfmt_e effective_fmt; - audsettings_t obt_as; - - shift <<= as->nchannels == 2; - - req.freq = as->freq; - req.format = aud_to_sdlfmt (as->fmt, &shift); - req.channels = as->nchannels; - req.samples = conf.nb_samples; - req.callback = sdl_callback; - req.userdata = sdl; - -#if DEBUG - print_sdl_audiospec( &req, "wanted" ); -#endif - - if (sdl_open (&req, &obt)) { - return -1; - } - -#if DEBUG - print_sdl_audiospec( &req, "obtained" ); -#endif - - err = sdl_to_audfmt (obt.format, &effective_fmt, &endianess); - 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 = endianess; - - audio_pcm_init_info (&hw->info, &obt_as); - hw->samples = obt.samples; - -#if DEBUG - start_time = qemu_get_clock(vm_clock); -#endif - - 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 (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; - } -#if !NEW_AUDIO - 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; - } -#endif - return s; -} - -static void sdl_audio_fini (void *opaque) -{ - SDLAudioState *s = opaque; - sdl_close (s); -#if !NEW_AUDIO - if (s->sem) { - SDL_DestroySemaphore (s->sem); - s->sem = NULL; - } -#endif - if (s->mutex) { - SDL_DestroyMutex (s->mutex); - s->mutex = NULL; - } - SDL_QuitSubSystem (SDL_INIT_AUDIO); -} - -static struct audio_option sdl_options[] = { - {"SAMPLES", AUD_OPT_INT, &conf.nb_samples, - "Size of SDL buffer in samples", NULL, 0}, - {NULL, 0, NULL, NULL, NULL, 0} -}; - -static struct audio_pcm_ops sdl_pcm_ops = { - sdl_init_out, - sdl_fini_out, - sdl_run_out, - sdl_write_out, - sdl_ctl_out, - - NULL, - NULL, - NULL, - NULL, - NULL -}; - -struct audio_driver sdl_audio_driver = { - INIT_FIELD (name = ) "sdl", - INIT_FIELD (descr = ) "SDL audio (www.libsdl.org)", - INIT_FIELD (options = ) sdl_options, - INIT_FIELD (init = ) sdl_audio_init, - INIT_FIELD (fini = ) sdl_audio_fini, - INIT_FIELD (pcm_ops = ) &sdl_pcm_ops, - INIT_FIELD (can_be_default = ) 1, - INIT_FIELD (max_voices_out = ) 1, - INIT_FIELD (max_voices_in = ) 0, - INIT_FIELD (voice_size_out = ) sizeof (SDLVoiceOut), - INIT_FIELD (voice_size_in = ) 0 -}; diff --git a/audio/sys-queue.h b/audio/sys-queue.h deleted file mode 100644 index 5b6e2a0..0000000 --- a/audio/sys-queue.h +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.3 (Berkeley) 12/13/93 - */ - -#ifndef _SYS_QUEUE_H -#define _SYS_QUEUE_H 1 - -/* - * This file defines three types of data structures: lists, tail queues, - * and circular queues. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list after - * an existing element or at the head of the list. A list may only be - * traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list after - * an existing element, at the head of the list, or at the end of the - * list. A tail queue may only be traversed in the forward direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -/* - * List definitions. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ -#define LIST_INIT(head) { \ - (head)->lh_first = NULL; \ -} - -#define LIST_INSERT_AFTER(listelm, elm, field) { \ - if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ - (listelm)->field.le_next->field.le_prev = \ - &(elm)->field.le_next; \ - (listelm)->field.le_next = (elm); \ - (elm)->field.le_prev = &(listelm)->field.le_next; \ -} - -#define LIST_INSERT_HEAD(head, elm, field) { \ - if (((elm)->field.le_next = (head)->lh_first) != NULL) \ - (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ - (head)->lh_first = (elm); \ - (elm)->field.le_prev = &(head)->lh_first; \ -} - -#define LIST_REMOVE(elm, field) { \ - if ((elm)->field.le_next != NULL) \ - (elm)->field.le_next->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = (elm)->field.le_next; \ -} - -/* - * Tail queue definitions. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ -} - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} - -/* - * Tail queue functions. - */ -#define TAILQ_INIT(head) { \ - (head)->tqh_first = NULL; \ - (head)->tqh_last = &(head)->tqh_first; \ -} - -#define TAILQ_INSERT_HEAD(head, elm, field) { \ - if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (head)->tqh_first = (elm); \ - (elm)->field.tqe_prev = &(head)->tqh_first; \ -} - -#define TAILQ_INSERT_TAIL(head, elm, field) { \ - (elm)->field.tqe_next = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &(elm)->field.tqe_next; \ -} - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) { \ - if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ - (elm)->field.tqe_next->field.tqe_prev = \ - &(elm)->field.tqe_next; \ - else \ - (head)->tqh_last = &(elm)->field.tqe_next; \ - (listelm)->field.tqe_next = (elm); \ - (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ -} - -#define TAILQ_REMOVE(head, elm, field) { \ - if (((elm)->field.tqe_next) != NULL) \ - (elm)->field.tqe_next->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ -} - -/* - * Circular queue definitions. - */ -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue functions. - */ -#define CIRCLEQ_INIT(head) { \ - (head)->cqh_first = (void *)(head); \ - (head)->cqh_last = (void *)(head); \ -} - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) { \ - (elm)->field.cqe_next = (listelm)->field.cqe_next; \ - (elm)->field.cqe_prev = (listelm); \ - if ((listelm)->field.cqe_next == (void *)(head)) \ - (head)->cqh_last = (elm); \ - else \ - (listelm)->field.cqe_next->field.cqe_prev = (elm); \ - (listelm)->field.cqe_next = (elm); \ -} - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) { \ - (elm)->field.cqe_next = (listelm); \ - (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ - if ((listelm)->field.cqe_prev == (void *)(head)) \ - (head)->cqh_first = (elm); \ - else \ - (listelm)->field.cqe_prev->field.cqe_next = (elm); \ - (listelm)->field.cqe_prev = (elm); \ -} - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) { \ - (elm)->field.cqe_next = (head)->cqh_first; \ - (elm)->field.cqe_prev = (void *)(head); \ - if ((head)->cqh_last == (void *)(head)) \ - (head)->cqh_last = (elm); \ - else \ - (head)->cqh_first->field.cqe_prev = (elm); \ - (head)->cqh_first = (elm); \ -} - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) { \ - (elm)->field.cqe_next = (void *)(head); \ - (elm)->field.cqe_prev = (head)->cqh_last; \ - if ((head)->cqh_first == (void *)(head)) \ - (head)->cqh_first = (elm); \ - else \ - (head)->cqh_last->field.cqe_next = (elm); \ - (head)->cqh_last = (elm); \ -} - -#define CIRCLEQ_REMOVE(head, elm, field) { \ - if ((elm)->field.cqe_next == (void *)(head)) \ - (head)->cqh_last = (elm)->field.cqe_prev; \ - else \ - (elm)->field.cqe_next->field.cqe_prev = \ - (elm)->field.cqe_prev; \ - if ((elm)->field.cqe_prev == (void *)(head)) \ - (head)->cqh_first = (elm)->field.cqe_next; \ - else \ - (elm)->field.cqe_prev->field.cqe_next = \ - (elm)->field.cqe_next; \ -} -#endif /* sys/queue.h */ diff --git a/audio/wavaudio.c b/audio/wavaudio.c deleted file mode 100644 index 8a500b9..0000000 --- a/audio/wavaudio.c +++ /dev/null @@ -1,482 +0,0 @@ -/* - * QEMU WAV audio driver - * - * Copyright (c) 2007 The Android Open Source Project - * 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. - */ -#define AUDIO_CAP "wav" -#include "qemu-timer.h" -#include "audio_int.h" -#include "qemu_file.h" - -#define WAV_AUDIO_IN 1 - -/** VOICE OUT (Saving to a .WAV file) - **/ -typedef struct WAVVoiceOut { - HWVoiceOut hw; - QEMUFile *f; - int64_t old_ticks; - void *pcm_buf; - int total_samples; -} WAVVoiceOut; - -static struct { - audsettings_t settings; - const char *wav_path; -} conf_out = { - { - 44100, - 2, - AUD_FMT_S16, - 0 - }, - "qemu.wav" -}; - -static int wav_out_run (HWVoiceOut *hw) -{ - WAVVoiceOut *wav = (WAVVoiceOut *) hw; - int rpos, live, decr, samples; - uint8_t *dst; - st_sample_t *src; - int64_t now = qemu_get_clock (vm_clock); - int64_t ticks = now - wav->old_ticks; - int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; - - if (bytes > INT_MAX) { - samples = INT_MAX >> hw->info.shift; - } - else { - samples = bytes >> hw->info.shift; - } - - live = audio_pcm_hw_get_live_out (hw); - if (!live) { - return 0; - } - - 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); - qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift); - - rpos = (rpos + convert_samples) % hw->samples; - samples -= convert_samples; - wav->total_samples += convert_samples; - } - - hw->rpos = rpos; - return decr; -} - -static int wav_out_write (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_out_init (HWVoiceOut *hw, audsettings_t *as) -{ - 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 - }; - audsettings_t wav_as = conf_out.settings; - - (void) as; - - 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 = qemu_fopen (conf_out.wav_path, "wb"); - if (!wav->f) { - dolog ("Failed to open wave file `%s'\nReason: %s\n", - conf_out.wav_path, strerror (errno)); - qemu_free (wav->pcm_buf); - wav->pcm_buf = NULL; - return -1; - } - - qemu_put_buffer (wav->f, hdr, sizeof (hdr)); - return 0; -} - -static void wav_out_fini (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); - - qemu_fseek (wav->f, 4, SEEK_SET); - qemu_put_buffer (wav->f, rlen, 4); - - qemu_fseek (wav->f, 32, SEEK_CUR); - qemu_put_buffer (wav->f, dlen, 4); - - qemu_fclose (wav->f); - wav->f = NULL; - - qemu_free (wav->pcm_buf); - wav->pcm_buf = NULL; -} - -static int wav_out_ctl (HWVoiceOut *hw, int cmd, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - - -#if WAV_AUDIO_IN - -/** WAV IN (Reading from a .WAV file) - **/ - - static struct { - const char *wav_path; -} conf_in = { - "qemu.wav" -}; - -typedef struct WAVVoiceIn { - HWVoiceIn hw; - QEMUFile* f; - int64_t old_ticks; - void* pcm_buf; - int total_samples; - int total_size; -} WAVVoiceIn; - - -static int -le_read( const uint8_t* p, int size ) { - int shift = 0; - int result = 0; - for ( ; size > 0; size-- ) { - result = result | (p[0] << shift); - p += 1; - shift += 8; - } - return result; -} - -static int -wav_in_init (HWVoiceIn *hw, audsettings_t *as) -{ - WAVVoiceIn* wav = (WAVVoiceIn *) hw; - const char* path = conf_in.wav_path; - uint8_t hdr[44]; - audsettings_t wav_as = *as; - int nchannels, freq, format, bits; - - wav->f = qemu_fopen (path, "rb"); - if (wav->f == NULL) { - dolog("Failed to open wave file '%s'\nReason: %s\n", path, - strerror(errno)); - return -1; - } - - if (qemu_get_buffer (wav->f, hdr, sizeof(hdr)) != (int)sizeof(hdr)) { - dolog("File '%s' to be a .wav file\n", path); - goto Fail; - } - - /* check that this is a wave file */ - if ( hdr[0] != 'R' || hdr[1] != 'I' || hdr[2] != 'F' || hdr[3] != 'F' || - hdr[8] != 'W' || hdr[9] != 'A' || hdr[10]!= 'V' || hdr[11]!= 'E' || - hdr[12]!= 'f' || hdr[13]!= 'm' || hdr[14]!= 't' || hdr[15]!= ' ' || - hdr[40]!= 'd' || hdr[41]!= 'a' || hdr[42]!= 't' || hdr[43]!= 'a') { - dolog("File '%s' is not a valid .wav file\n", path); - goto Fail; - } - - nchannels = le_read( hdr+22, 2 ); - freq = le_read( hdr+24, 4 ); - format = le_read( hdr+32, 2 ); - bits = le_read( hdr+34, 2 ); - - wav->total_size = le_read( hdr+40, 4 ); - - /* perform some sainty checks */ - switch (nchannels) { - case 1: - case 2: break; - default: - dolog("unsupported number of channels (%d) in '%s'\n", - nchannels, path); - goto Fail; - } - - switch (format) { - case 1: - case 2: - case 4: break; - default: - dolog("unsupported bytes per sample (%d) in '%s'\n", - format, path); - goto Fail; - } - - if (format*8/nchannels != bits) { - dolog("invalid bits per sample (%d, expected %d) in '%s'\n", - bits, format*8/nchannels, path); - goto Fail; - } - - wav_as.nchannels = nchannels; - wav_as.fmt = (bits == 8) ? AUD_FMT_U8 : AUD_FMT_S16; - wav_as.freq = freq; - wav_as.endianness = 0; /* always little endian */ - - 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) { - goto Fail; - } - return 0; - -Fail: - qemu_fclose (wav->f); - wav->f = NULL; - return -1; -} - - -static void wav_in_fini (HWVoiceIn *hw) -{ - WAVVoiceIn *wav = (WAVVoiceIn *) hw; - - if (!wav->f) { - return; - } - - qemu_fclose (wav->f); - wav->f = NULL; - - qemu_free (wav->pcm_buf); - wav->pcm_buf = NULL; -} - -static int wav_in_run (HWVoiceIn *hw) -{ - WAVVoiceIn* wav = (WAVVoiceIn *) hw; - int wpos, live, decr, samples; - uint8_t* src; - st_sample_t* dst; - - int64_t now = qemu_get_clock (vm_clock); - int64_t ticks = now - wav->old_ticks; - int64_t bytes = (ticks * hw->info.bytes_per_second) / ticks_per_sec; - - if (bytes > INT_MAX) { - samples = INT_MAX >> hw->info.shift; - } - else { - samples = bytes >> hw->info.shift; - } - - live = audio_pcm_hw_get_live_in (hw); - if (!live) { - return 0; - } - - wav->old_ticks = now; - - decr = audio_MIN (live, samples); - samples = decr; - wpos = hw->wpos; - while (samples) { - int left_till_end_samples = hw->samples - wpos; - int convert_samples = audio_MIN (samples, left_till_end_samples); - - dst = hw->conv_buf + wpos; - src = advance (wav->pcm_buf, wpos << hw->info.shift); - - qemu_get_buffer (wav->f, src, convert_samples << hw->info.shift); - memcpy (dst, src, convert_samples << hw->info.shift); - - wpos = (wpos + convert_samples) % hw->samples; - samples -= convert_samples; - wav->total_samples += convert_samples; - } - - hw->wpos = wpos; - return decr; -} - -static int wav_in_read (SWVoiceIn *sw, void *buf, int len) -{ - return audio_pcm_sw_read (sw, buf, len); -} - -static int wav_in_ctl (HWVoiceIn *hw, int cmd, ...) -{ - (void) hw; - (void) cmd; - return 0; -} - -#endif /* WAV_AUDIO_IN */ - -/** COMMON CODE - **/ -static void *wav_audio_init (void) -{ - return &conf_out; -} - -static void wav_audio_fini (void *opaque) -{ - (void) opaque; - ldebug ("wav_fini"); -} - -struct audio_option wav_options[] = { - {"FREQUENCY", AUD_OPT_INT, &conf_out.settings.freq, - "Frequency", NULL, 0}, - - {"FORMAT", AUD_OPT_FMT, &conf_out.settings.fmt, - "Format", NULL, 0}, - - {"DAC_FIXED_CHANNELS", AUD_OPT_INT, &conf_out.settings.nchannels, - "Number of channels (1 - mono, 2 - stereo)", NULL, 0}, - - {"PATH", AUD_OPT_STR, &conf_out.wav_path, - "Path to output .wav file", NULL, 0}, - -#if WAV_AUDIO_IN - {"IN_PATH", AUD_OPT_STR, &conf_in.wav_path, - "Path to input .wav file", NULL, 0}, -#endif - {NULL, 0, NULL, NULL, NULL, 0} -}; - -struct audio_pcm_ops wav_pcm_ops = { - wav_out_init, - wav_out_fini, - wav_out_run, - wav_out_write, - wav_out_ctl, - -#if WAV_AUDIO_IN - wav_in_init, - wav_in_fini, - wav_in_run, - wav_in_read, - wav_in_ctl -#else - NULL, - NULL, - NULL, - NULL, - NULL -#endif -}; - -struct audio_driver wav_audio_driver = { - INIT_FIELD (name = ) "wav", - INIT_FIELD (descr = ) - "WAV file read/write (www.wikipedia.org/wiki/WAV)", - INIT_FIELD (options = ) wav_options, - INIT_FIELD (init = ) wav_audio_init, - INIT_FIELD (fini = ) wav_audio_fini, - INIT_FIELD (pcm_ops = ) &wav_pcm_ops, - INIT_FIELD (can_be_default = ) 0, -#if WAV_AUDIO_IN - INIT_FIELD (max_voices_in = ) 1, - INIT_FIELD (max_voices_out = ) 1, - INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut), - INIT_FIELD (voice_size_in = ) sizeof (WAVVoiceIn) -#else - INIT_FIELD (max_voices_out = ) 1, - INIT_FIELD (max_voices_in = ) 0, - INIT_FIELD (voice_size_out = ) sizeof (WAVVoiceOut), - INIT_FIELD (voice_size_in = ) 0 -#endif -}; diff --git a/audio/wavcapture.c b/audio/wavcapture.c deleted file mode 100644 index d6f733e..0000000 --- a/audio/wavcapture.c +++ /dev/null @@ -1,166 +0,0 @@ -#include "audio/audio.h" -#include "qemu_file.h" -#include "console.h" - -typedef struct { - QEMUFile *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; - - if (!wav->f) { - return; - } - - le_store (rlen, rifflen, 4); - le_store (dlen, datalen, 4); - - qemu_fseek (wav->f, 4, SEEK_SET); - qemu_put_buffer (wav->f, rlen, 4); - - qemu_fseek (wav->f, 32, SEEK_CUR); - qemu_put_buffer (wav->f, dlen, 4); - qemu_fclose (wav->f); - if (wav->path) { - qemu_free (wav->path); - } -} - -static void wav_capture (void *opaque, void *buf, int size) -{ - WAVState *wav = opaque; - - qemu_put_buffer (wav->f, buf, size); - 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; - - term_printf ("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) -{ - 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 - }; - audsettings_t as; - struct audio_capture_ops ops; - int stereo, bits16, shift; - CaptureVoiceOut *cap; - - if (bits != 8 && bits != 16) { - term_printf ("incorrect bit count %d, must be 8 or 16\n", bits); - return -1; - } - - if (nchannels != 1 && nchannels != 2) { - term_printf ("incorrect channel count %d, must be 1 or 2\n", bits); - 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 = qemu_mallocz (sizeof (*wav)); - if (!wav) { - AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav)); - return -1; - } - - 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 = qemu_fopen (path, "wb"); - if (!wav->f) { - term_printf ("Failed to open wave file `%s'\nReason: %s\n", - path, strerror (errno)); - qemu_free (wav); - return -1; - } - - wav->path = qemu_strdup (path); - wav->bits = bits; - wav->nchannels = nchannels; - wav->freq = freq; - - qemu_put_buffer (wav->f, hdr, sizeof (hdr)); - - cap = AUD_add_capture (NULL, &as, &ops, wav); - if (!cap) { - term_printf ("Failed to add audio capture\n"); - qemu_free (wav->path); - qemu_fclose (wav->f); - qemu_free (wav); - return -1; - } - - wav->cap = cap; - s->opaque = wav; - s->ops = wav_capture_ops; - return 0; -} diff --git a/audio/winaudio.c b/audio/winaudio.c deleted file mode 100644 index 6e8daef..0000000 --- a/audio/winaudio.c +++ /dev/null @@ -1,666 +0,0 @@ -/*
- * QEMU "simple" Windows audio driver
- *
- * Copyright (c) 2007 The Android Open Source Project
- *
- * 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.
- */
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <mmsystem.h>
-
-#define AUDIO_CAP "winaudio"
-#include "audio_int.h"
-
-/* define DEBUG to 1 to dump audio debugging info at runtime to stderr */
-#define DEBUG 0
-
-#if 1
-# define D_ACTIVE 1
-#else
-# define D_ACTIVE DEBUG
-#endif
-
-#if DEBUG
-# define D(...) do{ if (D_ACTIVE) printf(__VA_ARGS__); } while(0)
-#else
-# define D(...) ((void)0)
-#endif
-
-static struct {
- int nb_samples;
-} conf = {
- 1024
-};
-
-#if DEBUG
-int64_t start_time;
-int64_t last_time;
-#endif
-
-#define NUM_OUT_BUFFERS 8 /* must be at least 2 */
-
-/** COMMON UTILITIES
- **/
-
-#if DEBUG
-static void
-dump_mmerror( const char* func, MMRESULT error )
-{
- const char* reason = NULL;
-
- fprintf(stderr, "%s returned error: ", func);
- switch (error) {
- case MMSYSERR_ALLOCATED: reason="specified resource is already allocated"; break;
- case MMSYSERR_BADDEVICEID: reason="bad device id"; break;
- case MMSYSERR_NODRIVER: reason="no driver is present"; break;
- case MMSYSERR_NOMEM: reason="unable to allocate or lock memory"; break;
- case WAVERR_BADFORMAT: reason="unsupported waveform-audio format"; break;
- case WAVERR_SYNC: reason="device is synchronous"; break;
- default:
- fprintf(stderr, "unknown(%d)\n", error);
- }
- if (reason)
- fprintf(stderr, "%s\n", reason);
-}
-#else
-# define dump_mmerror(func,error) ((void)0)
-#endif
-
-
-/** AUDIO OUT
- **/
-
-typedef struct WinAudioOut {
- HWVoiceOut hw;
- HWAVEOUT waveout;
- int silence;
- CRITICAL_SECTION lock;
- unsigned char* buffer_bytes;
- WAVEHDR buffers[ NUM_OUT_BUFFERS ];
- int write_index; /* starting first writable buffer */
- int write_count; /* available writable buffers count */
- int write_pos; /* position in current writable buffer */
- int write_size; /* size in bytes of each buffer */
-} WinAudioOut;
-
-/* The Win32 callback that is called when a buffer has finished playing */
-static void CALLBACK
-winaudio_out_buffer_done (HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
- DWORD dwParam1, DWORD dwParam2)
-{
- WinAudioOut* s = (WinAudioOut*) dwInstance;
-
- /* Only service "buffer done playing" messages */
- if ( uMsg != WOM_DONE )
- return;
-
- /* Signal that we are done playing a buffer */
- EnterCriticalSection( &s->lock );
- if (s->write_count < NUM_OUT_BUFFERS)
- s->write_count += 1;
- LeaveCriticalSection( &s->lock );
-}
-
-static int
-winaudio_out_write (SWVoiceOut *sw, void *buf, int len)
-{
- return audio_pcm_sw_write (sw, buf, len);
-}
-
-static void
-winaudio_out_fini (HWVoiceOut *hw)
-{
- WinAudioOut* s = (WinAudioOut*) hw;
- int i;
-
- if (s->waveout) {
- waveOutReset(s->waveout);
- s->waveout = 0;
- }
-
- for ( i=0; i<NUM_OUT_BUFFERS; ++i ) {
- if ( s->buffers[i].dwUser != 0xFFFF ) {
- waveOutUnprepareHeader(
- s->waveout, &s->buffers[i], sizeof(s->buffers[i]) );
- s->buffers[i].dwUser = 0xFFFF;
- }
- }
-
- if (s->buffer_bytes != NULL) {
- qemu_free(s->buffer_bytes);
- s->buffer_bytes = NULL;
- }
-
- if (s->waveout) {
- waveOutClose(s->waveout);
- s->waveout = NULL;
- }
-}
-
-
-static int
-winaudio_out_init (HWVoiceOut *hw, audsettings_t *as)
-{
- WinAudioOut* s = (WinAudioOut*) hw;
- MMRESULT result;
- WAVEFORMATEX format;
- int shift, i, samples_size;
-
- s->waveout = NULL;
- InitializeCriticalSection( &s->lock );
- for (i = 0; i < NUM_OUT_BUFFERS; i++) {
- s->buffers[i].dwUser = 0xFFFF;
- }
- s->buffer_bytes = NULL;
-
- /* compute desired wave output format */
- format.wFormatTag = WAVE_FORMAT_PCM;
- format.nChannels = as->nchannels;
- format.nSamplesPerSec = as->freq;
- format.nAvgBytesPerSec = as->freq*as->nchannels;
-
- s->silence = 0;
-
- switch (as->fmt) {
- case AUD_FMT_S8: shift = 0; break;
- case AUD_FMT_U8: shift = 0; s->silence = 0x80; break;
- case AUD_FMT_S16: shift = 1; break;
- case AUD_FMT_U16: shift = 1; s->silence = 0x8000; break;
- default:
- fprintf(stderr, "qemu: winaudio: Bad output audio format: %d\n",
- as->fmt);
- return -1;
- }
-
- format.nAvgBytesPerSec = (format.nSamplesPerSec & format.nChannels) << shift;
- format.nBlockAlign = format.nChannels << shift;
- format.wBitsPerSample = 8 << shift;
- format.cbSize = 0;
-
- /* open the wave out device */
- result = waveOutOpen( &s->waveout, WAVE_MAPPER, &format,
- (DWORD_PTR)winaudio_out_buffer_done, (DWORD_PTR) hw,
- CALLBACK_FUNCTION);
- if ( result != MMSYSERR_NOERROR ) {
- dump_mmerror( "qemu: winaudio: waveOutOpen()", result);
- return -1;
- }
-
- samples_size = format.nBlockAlign * conf.nb_samples;
- s->buffer_bytes = qemu_malloc( NUM_OUT_BUFFERS * samples_size );
- if (s->buffer_bytes == NULL) {
- waveOutClose( s->waveout );
- s->waveout = NULL;
- fprintf(stderr, "not enough memory for Windows audio buffers\n");
- return -1;
- }
-
- for (i = 0; i < NUM_OUT_BUFFERS; i++) {
- memset( &s->buffers[i], 0, sizeof(s->buffers[i]) );
- s->buffers[i].lpData = (LPSTR)(s->buffer_bytes + i*samples_size);
- s->buffers[i].dwBufferLength = samples_size;
- s->buffers[i].dwFlags = WHDR_DONE;
-
- result = waveOutPrepareHeader( s->waveout, &s->buffers[i],
- sizeof(s->buffers[i]) );
- if ( result != MMSYSERR_NOERROR ) {
- dump_mmerror("waveOutPrepareHeader()", result);
- return -1;
- }
- }
-
-#if DEBUG
- /* Check the sound device we retrieved */
- {
- WAVEOUTCAPS caps;
-
- result = waveOutGetDevCaps((UINT) s->waveout, &caps, sizeof(caps));
- if ( result != MMSYSERR_NOERROR ) {
- dump_mmerror("waveOutGetDevCaps()", result);
- } else
- printf("Audio out device: %s\n", caps.szPname);
- }
-#endif
-
- audio_pcm_init_info (&hw->info, as);
- hw->samples = conf.nb_samples*2;
-
- s->write_index = 0;
- s->write_count = NUM_OUT_BUFFERS;
- s->write_pos = 0;
- s->write_size = samples_size;
- return 0;
-}
-
-
-static int
-winaudio_out_run (HWVoiceOut *hw)
-{
- WinAudioOut* s = (WinAudioOut*) hw;
- int played = 0;
- int has_buffer;
- int live = audio_pcm_hw_get_live_out (hw);
-
- if (!live) {
- return 0;
- }
-
- EnterCriticalSection( &s->lock );
- has_buffer = (s->write_count > 0);
- LeaveCriticalSection( &s->lock );
-
- if (has_buffer) {
- while (live > 0) {
- WAVEHDR* wav_buffer = s->buffers + s->write_index;
- int wav_bytes = (s->write_size - s->write_pos);
- int wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);
- int hw_samples = audio_MIN(hw->samples - hw->rpos, live);
- st_sample_t* src = hw->mix_buf + hw->rpos;
- uint8_t* dst = (uint8_t*)wav_buffer->lpData + s->write_pos;
-
- if (wav_samples > hw_samples) {
- wav_samples = hw_samples;
- }
-
- wav_bytes = wav_samples << hw->info.shift;
-
- //D("run_out: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d rpos:%d hwsamples:%d\n", s->write_index,
- // s->write_pos, s->write_size, wav_samples, wav_bytes, live, hw->rpos, hw->samples);
- hw->clip (dst, src, wav_samples);
- hw->rpos += wav_samples;
- if (hw->rpos >= hw->samples)
- hw->rpos -= hw->samples;
-
- live -= wav_samples;
- played += wav_samples;
- s->write_pos += wav_bytes;
- if (s->write_pos == s->write_size) {
-#if xxDEBUG
- int64_t now = qemu_get_clock(vm_clock) - start_time;
- int64_t diff = now - last_time;
-
- D("run_out: (%7.3f:%7d):waveOutWrite buffer:%d\n",
- now/1e9, (now-last_time)/1e9, s->write_index);
- last_time = now;
-#endif
- waveOutWrite( s->waveout, wav_buffer, sizeof(*wav_buffer) );
- s->write_pos = 0;
- s->write_index += 1;
- if (s->write_index == NUM_OUT_BUFFERS)
- s->write_index = 0;
-
- EnterCriticalSection( &s->lock );
- if (--s->write_count == 0) {
- live = 0;
- }
- LeaveCriticalSection( &s->lock );
- }
- }
-
- }
- return played;
-}
-
-static int
-winaudio_out_ctl (HWVoiceOut *hw, int cmd, ...)
-{
- WinAudioOut* s = (WinAudioOut*) hw;
-
- switch (cmd) {
- case VOICE_ENABLE:
- waveOutRestart( s->waveout );
- break;
-
- case VOICE_DISABLE:
- waveOutPause( s->waveout );
- break;
- }
- return 0;
-}
-
-/** AUDIO IN
- **/
-
-#define NUM_IN_BUFFERS 2
-
-typedef struct WinAudioIn {
- HWVoiceIn hw;
- HWAVEIN wavein;
- CRITICAL_SECTION lock;
- unsigned char* buffer_bytes;
- WAVEHDR buffers[ NUM_IN_BUFFERS ];
- int read_index;
- int read_count;
- int read_pos;
- int read_size;
-} WinAudioIn;
-
-/* The Win32 callback that is called when a buffer has finished playing */
-static void CALLBACK
-winaudio_in_buffer_done (HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance,
- DWORD dwParam1, DWORD dwParam2)
-{
- WinAudioIn* s = (WinAudioIn*) dwInstance;
-
- /* Only service "buffer done playing" messages */
- if ( uMsg != WIM_DATA )
- return;
-
- /* Signal that we are done playing a buffer */
- EnterCriticalSection( &s->lock );
- if (s->read_count < NUM_IN_BUFFERS)
- s->read_count += 1;
- //D(".%c",s->read_count + '0'); fflush(stdout);
- LeaveCriticalSection( &s->lock );
-}
-
-static void
-winaudio_in_fini (HWVoiceIn *hw)
-{
- WinAudioIn* s = (WinAudioIn*) hw;
- int i;
-
- if (s->wavein) {
- waveInReset(s->wavein);
- s->wavein = 0;
- }
-
- for ( i=0; i<NUM_OUT_BUFFERS; ++i ) {
- if ( s->buffers[i].dwUser != 0xFFFF ) {
- waveInUnprepareHeader(
- s->wavein, &s->buffers[i], sizeof(s->buffers[i]) );
- s->buffers[i].dwUser = 0xFFFF;
- }
- }
-
- if (s->buffer_bytes != NULL) {
- qemu_free(s->buffer_bytes);
- s->buffer_bytes = NULL;
- }
-
- if (s->wavein) {
- waveInClose(s->wavein);
- s->wavein = NULL;
- }
-}
-
-
-static int
-winaudio_in_init (HWVoiceIn *hw, audsettings_t *as)
-{
- WinAudioIn* s = (WinAudioIn*) hw;
- MMRESULT result;
- WAVEFORMATEX format;
- int shift, i, samples_size;
-
- s->wavein = NULL;
- InitializeCriticalSection( &s->lock );
- for (i = 0; i < NUM_OUT_BUFFERS; i++) {
- s->buffers[i].dwUser = 0xFFFF;
- }
- s->buffer_bytes = NULL;
-
- /* compute desired wave input format */
- format.wFormatTag = WAVE_FORMAT_PCM;
- format.nChannels = as->nchannels;
- format.nSamplesPerSec = as->freq;
- format.nAvgBytesPerSec = as->freq*as->nchannels;
-
- switch (as->fmt) {
- case AUD_FMT_S8: shift = 0; break;
- case AUD_FMT_U8: shift = 0; break;
- case AUD_FMT_S16: shift = 1; break;
- case AUD_FMT_U16: shift = 1; break;
- default:
- fprintf(stderr, "qemu: winaudio: Bad input audio format: %d\n",
- as->fmt);
- return -1;
- }
-
- format.nAvgBytesPerSec = (format.nSamplesPerSec * format.nChannels) << shift;
- format.nBlockAlign = format.nChannels << shift;
- format.wBitsPerSample = 8 << shift;
- format.cbSize = 0;
-
- /* open the wave in device */
- result = waveInOpen( &s->wavein, WAVE_MAPPER, &format,
- (DWORD_PTR)winaudio_in_buffer_done, (DWORD_PTR) hw,
- CALLBACK_FUNCTION);
- if ( result != MMSYSERR_NOERROR ) {
- dump_mmerror( "qemu: winaudio: waveInOpen()", result);
- return -1;
- }
-
- samples_size = format.nBlockAlign * conf.nb_samples;
- s->buffer_bytes = qemu_malloc( NUM_IN_BUFFERS * samples_size );
- if (s->buffer_bytes == NULL) {
- waveInClose( s->wavein );
- s->wavein = NULL;
- fprintf(stderr, "not enough memory for Windows audio buffers\n");
- return -1;
- }
-
- for (i = 0; i < NUM_IN_BUFFERS; i++) {
- memset( &s->buffers[i], 0, sizeof(s->buffers[i]) );
- s->buffers[i].lpData = (LPSTR)(s->buffer_bytes + i*samples_size);
- s->buffers[i].dwBufferLength = samples_size;
- s->buffers[i].dwFlags = WHDR_DONE;
-
- result = waveInPrepareHeader( s->wavein, &s->buffers[i],
- sizeof(s->buffers[i]) );
- if ( result != MMSYSERR_NOERROR ) {
- dump_mmerror("waveInPrepareHeader()", result);
- return -1;
- }
-
- result = waveInAddBuffer( s->wavein, &s->buffers[i],
- sizeof(s->buffers[i]) );
- if ( result != MMSYSERR_NOERROR ) {
- dump_mmerror("waveInAddBuffer()", result);
- return -1;
- }
- }
-
-#if DEBUG
- /* Check the sound device we retrieved */
- {
- WAVEINCAPS caps;
-
- result = waveInGetDevCaps((UINT) s->wavein, &caps, sizeof(caps));
- if ( result != MMSYSERR_NOERROR ) {
- dump_mmerror("waveInGetDevCaps()", result);
- } else
- printf("Audio in device: %s\n", caps.szPname);
- }
-#endif
-
- audio_pcm_init_info (&hw->info, as);
- hw->samples = conf.nb_samples*2;
-
- s->read_index = 0;
- s->read_count = 0;
- s->read_pos = 0;
- s->read_size = samples_size;
- return 0;
-}
-
-
-/* report the number of captured samples to the audio subsystem */
-static int
-winaudio_in_run (HWVoiceIn *hw)
-{
- WinAudioIn* s = (WinAudioIn*) hw;
- int captured = 0;
- int has_buffer;
- int live = hw->samples - hw->total_samples_captured;
-
- if (!live) {
-#if 0
- static int counter;
- if (++counter == 100) {
- D("0"); fflush(stdout);
- counter = 0;
- }
-#endif
- return 0;
- }
-
- EnterCriticalSection( &s->lock );
- has_buffer = (s->read_count > 0);
- LeaveCriticalSection( &s->lock );
-
- if (has_buffer > 0) {
- while (live > 0) {
- WAVEHDR* wav_buffer = s->buffers + s->read_index;
- int wav_bytes = (s->read_size - s->read_pos);
- int wav_samples = audio_MIN(wav_bytes >> hw->info.shift, live);
- int hw_samples = audio_MIN(hw->samples - hw->wpos, live);
- st_sample_t* dst = hw->conv_buf + hw->wpos;
- uint8_t* src = (uint8_t*)wav_buffer->lpData + s->read_pos;
-
- if (wav_samples > hw_samples) {
- wav_samples = hw_samples;
- }
-
- wav_bytes = wav_samples << hw->info.shift;
-
- D("%s: buffer:%d pos:%d size:%d wsamples:%d wbytes:%d live:%d wpos:%d hwsamples:%d\n",
- __FUNCTION__, s->read_index, s->read_pos, s->read_size, wav_samples, wav_bytes, live,
- hw->wpos, hw->samples);
-
- hw->conv(dst, src, wav_samples, &nominal_volume);
-
- hw->wpos += wav_samples;
- if (hw->wpos >= hw->samples)
- hw->wpos -= hw->samples;
-
- live -= wav_samples;
- captured += wav_samples;
- s->read_pos += wav_bytes;
- if (s->read_pos == s->read_size) {
- s->read_pos = 0;
- s->read_index += 1;
- if (s->read_index == NUM_IN_BUFFERS)
- s->read_index = 0;
-
- waveInAddBuffer( s->wavein, wav_buffer, sizeof(*wav_buffer) );
-
- EnterCriticalSection( &s->lock );
- if (--s->read_count == 0) {
- live = 0;
- }
- LeaveCriticalSection( &s->lock );
- }
- }
- }
- return captured;
-}
-
-
-static int
-winaudio_in_read (SWVoiceIn *sw, void *buf, int len)
-{
- int ret = audio_pcm_sw_read (sw, buf, len);
- if (ret > 0)
- D("%s: (%d) returned %d\n", __FUNCTION__, len, ret);
- return ret;
-}
-
-
-static int
-winaudio_in_ctl (HWVoiceIn *hw, int cmd, ...)
-{
- WinAudioIn* s = (WinAudioIn*) hw;
-
- switch (cmd) {
- case VOICE_ENABLE:
- D("%s: enable audio in\n", __FUNCTION__);
- waveInStart( s->wavein );
- break;
-
- case VOICE_DISABLE:
- D("%s: disable audio in\n", __FUNCTION__);
- waveInStop( s->wavein );
- break;
- }
- return 0;
-}
-
-/** AUDIO STATE
- **/
-
-typedef struct WinAudioState {
- int dummy;
-} WinAudioState;
-
-static WinAudioState g_winaudio;
-
-static void*
-winaudio_init(void)
-{
- WinAudioState* s = &g_winaudio;
-
-#if DEBUG
- start_time = qemu_get_clock(vm_clock);
- last_time = 0;
-#endif
-
- return s;
-}
-
-
-static void
-winaudio_fini (void *opaque)
-{
-}
-
-static struct audio_option winaudio_options[] = {
- {"SAMPLES", AUD_OPT_INT, &conf.nb_samples,
- "Size of Windows audio buffer in samples", NULL, 0},
- {NULL, 0, NULL, NULL, NULL, 0}
-};
-
-static struct audio_pcm_ops winaudio_pcm_ops = {
- winaudio_out_init,
- winaudio_out_fini,
- winaudio_out_run,
- winaudio_out_write,
- winaudio_out_ctl,
-
- winaudio_in_init,
- winaudio_in_fini,
- winaudio_in_run,
- winaudio_in_read,
- winaudio_in_ctl
-};
-
-struct audio_driver win_audio_driver = {
- INIT_FIELD (name = ) "winaudio",
- INIT_FIELD (descr = ) "Windows wave audio",
- INIT_FIELD (options = ) winaudio_options,
- INIT_FIELD (init = ) winaudio_init,
- INIT_FIELD (fini = ) winaudio_fini,
- INIT_FIELD (pcm_ops = ) &winaudio_pcm_ops,
- INIT_FIELD (can_be_default = ) 1,
- INIT_FIELD (max_voices_out = ) 1,
- INIT_FIELD (max_voices_in = ) 1,
- INIT_FIELD (voice_size_out = ) sizeof (WinAudioOut),
- INIT_FIELD (voice_size_in = ) sizeof (WinAudioIn)
-};
|