Commit c0fe3827 authored by bellard's avatar bellard
Browse files

audio merge (malc)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1601 c046a42c-6fe2-441c-8c8c-71466251a162
parent f04308e4
......@@ -453,8 +453,8 @@ ifneq ($(wildcard .depend),)
include .depend
endif
ifeq (0, 1)
ifeq (1, 0)
audio.o sdlaudio.o dsoundaudio.o ossaudio.o wavaudio.o noaudio.o \
fmodaudio.o alsaaudio.o mixeng.o: \
fmodaudio.o alsaaudio.o mixeng.o sb16.o es1370.o gus.o adlib.o: \
CFLAGS := $(CFLAGS) -Wall -Werror -W -Wsign-compare
endif
......@@ -98,7 +98,7 @@ struct alsa_params_obt {
audfmt_e fmt;
int nchannels;
int can_pause;
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t samples;
};
static void GCC_FMT_ATTR (2, 3) alsa_logerr (int err, const char *fmt, ...)
......@@ -121,7 +121,7 @@ static void GCC_FMT_ATTR (3, 4) alsa_logerr2 (
{
va_list ap;
AUD_log (AUDIO_CAP, "Can not initialize %s\n", typ);
AUD_log (AUDIO_CAP, "Could not initialize %s\n", typ);
va_start (ap, fmt);
AUD_vlog (AUDIO_CAP, fmt, ap);
......@@ -209,7 +209,7 @@ static int alsa_to_audfmt (int alsafmt, audfmt_e *fmt, int *endianness)
return 0;
}
#ifdef DEBUG_MISMATCHES
#if defined DEBUG_MISMATCHES || defined DEBUG
static void alsa_dump_info (struct alsa_params_req *req,
struct alsa_params_obt *obt)
{
......@@ -221,7 +221,7 @@ static void alsa_dump_info (struct alsa_params_req *req,
dolog ("============================================\n");
dolog ("requested: buffer size %d period size %d\n",
req->buffer_size, req->period_size);
dolog ("obtained: buffer size %ld\n", obt->buffer_size);
dolog ("obtained: samples %ld\n", obt->samples);
}
#endif
......@@ -234,14 +234,14 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
err = snd_pcm_sw_params_current (handle, sw_params);
if (err < 0) {
dolog ("Can not fully initialize DAC\n");
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to get current software parameters\n");
return;
}
err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, threshold);
if (err < 0) {
dolog ("Can not fully initialize DAC\n");
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software threshold to %ld\n",
threshold);
return;
......@@ -249,7 +249,7 @@ static void alsa_set_threshold (snd_pcm_t *handle, snd_pcm_uframes_t threshold)
err = snd_pcm_sw_params (handle, sw_params);
if (err < 0) {
dolog ("Can not fully initialize DAC\n");
dolog ("Could not fully initialize DAC\n");
alsa_logerr (err, "Failed to set software parameters\n");
return;
}
......@@ -344,7 +344,8 @@ static int alsa_open (int in, struct alsa_params_req *req,
handle,
hw_params,
&period_size,
0);
0
);
if (err < 0) {
alsa_logerr2 (err, typ,
"Failed to set period time %d\n",
......@@ -357,7 +358,8 @@ static int alsa_open (int in, struct alsa_params_req *req,
handle,
hw_params,
&buffer_size,
0);
0
);
if (err < 0) {
alsa_logerr2 (err, typ,
......@@ -382,7 +384,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
if (err < 0) {
alsa_logerr (
err,
"Can not get minmal period size for %s\n",
"Could not get minmal period size for %s\n",
typ
);
}
......@@ -419,7 +421,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
&minval
);
if (err < 0) {
alsa_logerr (err, "Can not get minmal buffer size for %s\n",
alsa_logerr (err, "Could not get minmal buffer size for %s\n",
typ);
}
else {
......@@ -451,7 +453,7 @@ static int alsa_open (int in, struct alsa_params_req *req,
}
}
else {
dolog ("warning: buffer size is not set\n");
dolog ("warning: Buffer size is not set\n");
}
err = snd_pcm_hw_params (handle, hw_params);
......@@ -468,13 +470,13 @@ static int alsa_open (int in, struct alsa_params_req *req,
err = snd_pcm_prepare (handle);
if (err < 0) {
alsa_logerr2 (err, typ, "Can not prepare handle %p\n", handle);
alsa_logerr2 (err, typ, "Could not prepare handle %p\n", handle);
goto err;
}
obt->can_pause = snd_pcm_hw_params_can_pause (hw_params);
if (obt->can_pause < 0) {
alsa_logerr (err, "Can not get pause capability for %s\n", typ);
alsa_logerr (err, "Could not get pause capability for %s\n", typ);
obt->can_pause = 0;
}
......@@ -493,17 +495,17 @@ static int alsa_open (int in, struct alsa_params_req *req,
obt->fmt = req->fmt;
obt->nchannels = nchannels;
obt->freq = freq;
obt->buffer_size = snd_pcm_frames_to_bytes (handle, obt_buffer_size);
obt->samples = obt_buffer_size;
*handlep = handle;
#if defined DEBUG_MISMATCHES || defined DEBUG
if (obt->fmt != req->fmt ||
obt->nchannels != req->nchannels ||
obt->freq != req->freq) {
#ifdef DEBUG_MISMATCHES
dolog ("Audio paramters mismatch for %s\n", typ);
alsa_dump_info (req, obt);
#endif
}
#endif
#ifdef DEBUG
alsa_dump_info (req, obt);
......@@ -550,7 +552,7 @@ static int alsa_run_out (HWVoiceOut *hw)
}
}
alsa_logerr (avail, "Can not get amount free space\n");
alsa_logerr (avail, "Could not get amount free space\n");
return 0;
}
......@@ -618,7 +620,7 @@ static void alsa_fini_out (HWVoiceOut *hw)
}
}
static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt)
static int alsa_init_out (HWVoiceOut *hw, audsettings_t *as)
{
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
struct alsa_params_req req;
......@@ -627,10 +629,11 @@ static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt)
int endianness;
int err;
snd_pcm_t *handle;
audsettings_t obt_as;
req.fmt = aud_to_alsafmt (fmt);
req.freq = freq;
req.nchannels = nchannels;
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;
......@@ -644,18 +647,22 @@ static int alsa_init_out (HWVoiceOut *hw, int freq, int nchannels, audfmt_e fmt)
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
audio_pcm_init_info (
&hw->info,
obt.freq,
obt.nchannels,
effective_fmt,
&obt_as,
audio_need_to_swap_endian (endianness)
);
alsa->can_pause = obt.can_pause;
hw->bufsize = obt.buffer_size;
hw->samples = obt.samples;
alsa->pcm_buf = qemu_mallocz (hw->bufsize);
alsa->pcm_buf = audio_calloc (AUDIO_FUNC, obt.samples, 1 << hw->info.shift);
if (!alsa->pcm_buf) {
dolog ("Could not allocate DAC buffer (%d bytes)\n",
hw->samples << hw->info.shift);
alsa_anal_close (&handle);
return -1;
}
......@@ -703,8 +710,7 @@ static int alsa_ctl_out (HWVoiceOut *hw, int cmd, ...)
return 0;
}
static int alsa_init_in (HWVoiceIn *hw,
int freq, int nchannels, audfmt_e fmt)
static int alsa_init_in (HWVoiceIn *hw, audsettings_t *as)
{
ALSAVoiceIn *alsa = (ALSAVoiceIn *) hw;
struct alsa_params_req req;
......@@ -713,10 +719,11 @@ static int alsa_init_in (HWVoiceIn *hw,
int err;
audfmt_e effective_fmt;
snd_pcm_t *handle;
audsettings_t obt_as;
req.fmt = aud_to_alsafmt (fmt);
req.freq = freq;
req.nchannels = nchannels;
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;
......@@ -730,17 +737,22 @@ static int alsa_init_in (HWVoiceIn *hw,
return -1;
}
obt_as.freq = obt.freq;
obt_as.nchannels = obt.nchannels;
obt_as.fmt = effective_fmt;
audio_pcm_init_info (
&hw->info,
obt.freq,
obt.nchannels,
effective_fmt,
&obt_as,
audio_need_to_swap_endian (endianness)
);
alsa->can_pause = obt.can_pause;
hw->bufsize = obt.buffer_size;
alsa->pcm_buf = qemu_mallocz (hw->bufsize);
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 bytes)\n",
hw->samples << hw->info.shift);
alsa_anal_close (&handle);
return -1;
}
......
This diff is collapsed.
......@@ -24,18 +24,33 @@
#ifndef QEMU_AUDIO_H
#define QEMU_AUDIO_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_U8,
AUD_FMT_S8,
AUD_FMT_U16,
AUD_FMT_S16
} audfmt_e;
typedef struct {
int freq;
int nchannels;
audfmt_e fmt;
} audsettings_t;
typedef struct AudioState AudioState;
typedef struct SWVoiceOut SWVoiceOut;
typedef struct SWVoiceIn SWVoiceIn;
typedef struct QEMUSoundCard {
AudioState *audio;
char *name;
LIST_ENTRY (QEMUSoundCard) entries;
} QEMUSoundCard;
typedef struct QEMUAudioTimeStamp {
uint64_t old_ts;
} QEMUAudioTimeStamp;
......@@ -47,46 +62,45 @@ void AUD_log (const char *cap, const char *fmt, ...)
#endif
;
void AUD_init (void);
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);
SWVoiceOut *AUD_open_out (
SWVoiceOut *AUD_open_out (
QEMUSoundCard *card,
SWVoiceOut *sw,
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
int freq,
int nchannels,
audfmt_e fmt
audsettings_t *settings
);
void AUD_close_out (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_time_stamp_get_elapsed_usec_out (SWVoiceOut *sw,
QEMUAudioTimeStamp *ts);
SWVoiceIn *AUD_open_in (
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);
SWVoiceIn *AUD_open_in (
QEMUSoundCard *card,
SWVoiceIn *sw,
const char *name,
void *callback_opaque,
audio_callback_fn_t callback_fn,
int freq,
int nchannels,
audfmt_e fmt
audsettings_t *settings
);
void AUD_close_in (SWVoiceIn *sw);
int AUD_read (SWVoiceIn *sw, void *pcm_buf, int size);
void AUD_adjust_in (SWVoiceIn *sw, int leftover);
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_time_stamp_get_elapsed_usec_in (SWVoiceIn *sw,
QEMUAudioTimeStamp *ts);
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)
{
......
......@@ -24,16 +24,12 @@
#ifndef QEMU_AUDIO_INT_H
#define QEMU_AUDIO_INT_H
#include "sys-queue.h"
#ifdef CONFIG_COREAUDIO
#define FLOAT_MIXENG
/* #define RECIPROCAL */
#endif
#include "mixeng.h"
int audio_bug (const char *funcname, int cond);
struct audio_pcm_ops;
typedef enum {
......@@ -69,7 +65,6 @@ struct audio_pcm_info {
};
typedef struct HWVoiceOut {
int active;
int enabled;
int pending_disable;
int valid;
......@@ -78,7 +73,6 @@ typedef struct HWVoiceOut {
f_sample *clip;
int rpos;
int bufsize;
uint64_t ts_helper;
st_sample_t *mix_buf;
......@@ -91,13 +85,11 @@ typedef struct HWVoiceOut {
typedef struct HWVoiceIn {
int enabled;
int active;
struct audio_pcm_info info;
t_sample *conv;
int wpos;
int bufsize;
int total_samples_captured;
uint64_t ts_helper;
......@@ -109,58 +101,6 @@ typedef struct HWVoiceIn {
LIST_ENTRY (HWVoiceIn) entries;
} HWVoiceIn;
extern struct audio_driver no_audio_driver;
extern struct audio_driver oss_audio_driver;
extern struct audio_driver sdl_audio_driver;
extern struct audio_driver wav_audio_driver;
extern struct audio_driver fmod_audio_driver;
extern struct audio_driver alsa_audio_driver;
extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern volume_t nominal_volume;
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;
};
typedef struct AudioState {
int fixed_settings_out;
int fixed_freq_out;
int fixed_channels_out;
int fixed_fmt_out;
int nb_hw_voices_out;
int greedy_out;
int fixed_settings_in;
int fixed_freq_in;
int fixed_channels_in;
int fixed_fmt_in;
int nb_hw_voices_in;
int greedy_in;
void *opaque;
struct audio_driver *drv;
QEMUTimer *ts;
union {
int usec;
int64_t ticks;
} period;
int plive;
} AudioState;
extern AudioState audio_state;
struct SWVoiceOut {
struct audio_pcm_info info;
t_sample *conv;
......@@ -192,22 +132,58 @@ struct SWVoiceIn {
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, int freq, int nchannels, audfmt_e fmt);
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, int freq, int nchannels, audfmt_e fmt);
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, ...);
};
void audio_pcm_init_info (struct audio_pcm_info *info, int freq,
int nchannels, audfmt_e fmt, int swap_endian);
struct AudioState {
struct audio_driver *drv;
void *drv_opaque;
QEMUTimer *ts;
LIST_HEAD (card_head, QEMUSoundCard) card_head;
LIST_HEAD (hw_in_listhead, HWVoiceIn) hw_head_in;
LIST_HEAD (hw_out_listhead, HWVoiceOut) hw_head_out;
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 wav_audio_driver;
extern struct audio_driver fmod_audio_driver;
extern struct audio_driver alsa_audio_driver;
extern struct audio_driver coreaudio_audio_driver;
extern struct audio_driver dsound_audio_driver;
extern volume_t nominal_volume;
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as,
int swap_endian);
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);
......@@ -217,6 +193,9 @@ 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
......
......@@ -32,6 +32,43 @@
#define SW glue (SWVoice, In)
#endif
static int glue (audio_pcm_hw_init_, TYPE) (
HW *hw,
audsettings_t *as
)
{
glue (audio_pcm_hw_free_resources_, TYPE) (hw);
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
return -1;
}
if (audio_bug (AUDIO_FUNC, hw->samples <= 0)) {
dolog ("hw->samples=%d\n", hw->samples);
return -1;
}
LIST_INIT (&hw->sw_head);
#ifdef DAC
hw->clip =
mixeng_clip
#else
hw->conv =
mixeng_conv
#endif
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endian]
[hw->info.bits == 16];
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
glue (hw->pcm_ops->fini_, TYPE) (hw);
return -1;
}
return 0;
}
static void glue (audio_pcm_sw_fini_, TYPE) (SW *sw)
{
glue (audio_pcm_sw_free_resources_, TYPE) (sw);
......@@ -51,89 +88,86 @@ static void glue (audio_pcm_hw_del_sw_, TYPE) (SW *sw)
LIST_REMOVE (sw, entries);
}
static void glue (audio_pcm_hw_fini_, TYPE) (HW *hw)
static void glue (audio_pcm_hw_gc_, TYPE) (AudioState *s, HW **hwp)
{
if (hw->active) {
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
glue (hw->pcm_ops->fini_, TYPE) (hw);
memset (hw, 0, glue (audio_state.drv->voice_size_, TYPE));
}
}
HW *hw = *hwp;
static void glue (audio_pcm_hw_gc_, TYPE) (HW *hw)
{
if (!hw->sw_head.lh_first) {
glue (audio_pcm_hw_fini_, TYPE) (hw);
LIST_REMOVE (hw, entries);
glue (s->nb_hw_voices_, TYPE) += 1;
glue (audio_pcm_hw_free_resources_ ,TYPE) (hw);
glue (hw->pcm_ops->fini_, TYPE) (hw);
qemu_free (hw);
*hwp = NULL;
}
}
static HW *glue (audio_pcm_hw_find_any_, TYPE) (HW *hw)
static HW *glue (audio_pcm_hw_find_any_, TYPE) (AudioState *s, HW *hw)
{
return hw ? hw->entries.le_next : glue (hw_head_, TYPE).lh_first;
return hw ? hw->entries.le_next : s->glue (hw_head_, TYPE).lh_first;