Commit 8ead62cf authored by bellard's avatar bellard

audio fixes + initial audio capture support (malc)


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2040 c046a42c-6fe2-441c-8c8c-71466251a162
parent feea13e1
......@@ -61,8 +61,8 @@ static struct {
.size_in_usec_in = 1,
.size_in_usec_out = 1,
#endif
.pcm_name_out = "hw:0,0",
.pcm_name_in = "hw:0,0",
.pcm_name_out = "default",
.pcm_name_in = "default",
#ifdef HIGH_LATENCY
.buffer_size_in = 400000,
.period_size_in = 400000 / 4,
......@@ -606,7 +606,6 @@ static int alsa_run_out (HWVoiceOut *hw)
}
}
mixeng_clear (src, written);
rpos = (rpos + written) % hw->samples;
samples -= written;
len -= written;
......
This diff is collapsed.
......@@ -41,6 +41,11 @@ typedef struct {
audfmt_e fmt;
} audsettings_t;
struct audio_capture_ops {
void (*state) (void *opaque, int enabled);
void (*capture) (void *opaque, void *buf, int size);
};
typedef struct AudioState AudioState;
typedef struct SWVoiceOut SWVoiceOut;
typedef struct SWVoiceIn SWVoiceIn;
......@@ -66,6 +71,13 @@ 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);
int AUD_add_capture (
AudioState *s,
audsettings_t *as,
int endian,
struct audio_capture_ops *ops,
void *opaque
);
SWVoiceOut *AUD_open_out (
QEMUSoundCard *card,
......@@ -111,7 +123,7 @@ static inline void *advance (void *p, int incr)
}
uint32_t popcount (uint32_t u);
inline uint32_t lsbindex (uint32_t u);
uint32_t lsbindex (uint32_t u);
#ifdef __GNUC__
#define audio_MIN(a, b) ( __extension__ ({ \
......
......@@ -79,6 +79,7 @@ typedef struct HWVoiceOut {
int samples;
LIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head;
LIST_HEAD (sw_cap_listhead, SWVoiceOut) sw_cap_head;
struct audio_pcm_ops *pcm_ops;
LIST_ENTRY (HWVoiceOut) entries;
} HWVoiceOut;
......@@ -115,6 +116,7 @@ struct SWVoiceOut {
volume_t vol;
struct audio_callback callback;
LIST_ENTRY (SWVoiceOut) entries;
LIST_ENTRY (SWVoiceOut) cap_entries;
};
struct SWVoiceIn {
......@@ -160,14 +162,28 @@ struct audio_pcm_ops {
int (*ctl_in) (HWVoiceIn *hw, int cmd, ...);
};
struct capture_callback {
struct audio_capture_ops ops;
void *opaque;
LIST_ENTRY (capture_callback) entries;
};
typedef struct CaptureVoiceOut {
HWVoiceOut hw;
void *buf;
LIST_HEAD (cb_listhead, capture_callback) cb_head;
LIST_ENTRY (CaptureVoiceOut) entries;
} CaptureVoiceOut;
struct AudioState {
struct audio_driver *drv;
void *drv_opaque;
QEMUTimer *ts;
LIST_HEAD (card_head, QEMUSoundCard) card_head;
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;
};
......
......@@ -200,6 +200,9 @@ 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);
......@@ -266,7 +269,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
hw->pcm_ops = drv->pcm_ops;
LIST_INIT (&hw->sw_head);
#ifdef DAC
LIST_INIT (&hw->sw_cap_head);
#endif
if (glue (hw->pcm_ops->init_, TYPE) (hw, as)) {
goto err0;
}
......@@ -292,6 +297,9 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (AudioState *s, audsettings_t *as)
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:
......@@ -542,7 +550,7 @@ uint64_t glue (AUD_get_elapsed_usec_, TYPE) (SW *sw, QEMUAudioTimeStamp *ts)
cur_ts = sw->hw->ts_helper;
old_ts = ts->old_ts;
/* dolog ("cur %" PRId64 " old %" PRId64 "\n", cur_ts, old_ts); */
/* dolog ("cur %lld old %lld\n", cur_ts, old_ts); */
if (cur_ts >= old_ts) {
delta = cur_ts - old_ts;
......
......@@ -275,8 +275,6 @@ static OSStatus audioDeviceIOProc(
#endif
}
/* cleanup */
mixeng_clear (src, frameCount);
rpos = (rpos + frameCount) % hw->samples;
core->decr += frameCount;
core->rpos = rpos;
......
......@@ -70,7 +70,13 @@ static int glue (dsound_lock_, TYPE) (
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,
......@@ -80,13 +86,7 @@ static int glue (dsound_lock_, TYPE) (
&blen1,
&p2,
&blen2,
(entire
#ifdef DSBTYPE_IN
? DSCBLOCK_ENTIREBUFFER
#else
? DSBLOCK_ENTIREBUFFER
#endif
: 0)
flag
);
if (FAILED (hr)) {
......
......@@ -453,13 +453,11 @@ static void dsound_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
if (src_len1) {
hw->clip (dst, src1, src_len1);
mixeng_clear (src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
mixeng_clear (src2, src_len2);
}
hw->rpos = pos % hw->samples;
......@@ -987,6 +985,12 @@ static void *dsound_audio_init (void)
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;
}
......
......@@ -153,13 +153,11 @@ static void fmod_write_sample (HWVoiceOut *hw, uint8_t *dst, int dst_len)
if (src_len1) {
hw->clip (dst, src1, src_len1);
mixeng_clear (src1, src_len1);
}
if (src_len2) {
dst = advance (dst, src_len1 << hw->info.shift);
hw->clip (dst, src2, src_len2);
mixeng_clear (src2, src_len2);
}
hw->rpos = pos % hw->samples;
......
......@@ -40,22 +40,21 @@ static int no_run_out (HWVoiceOut *hw)
{
NoVoiceOut *no = (NoVoiceOut *) hw;
int live, decr, samples;
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;
if (bytes > INT_MAX) {
samples = INT_MAX >> hw->info.shift;
}
else {
samples = bytes >> hw->info.shift;
}
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;
......@@ -101,17 +100,20 @@ static void no_fini_in (HWVoiceIn *hw)
static int no_run_in (HWVoiceIn *hw)
{
NoVoiceIn *no = (NoVoiceIn *) hw;
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;
int live = audio_pcm_hw_get_live_in (hw);
int dead = hw->samples - live;
int samples;
bytes = audio_MIN (bytes, INT_MAX);
samples = bytes >> hw->info.shift;
samples = audio_MIN (samples, dead);
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;
}
......
......@@ -55,12 +55,14 @@ static struct {
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"
.devpath_in = "/dev/dsp",
.debug = 0
};
struct oss_params {
......@@ -324,9 +326,20 @@ static int oss_run_out (HWVoiceOut *hw)
return 0;
}
if (abinfo.bytes < 0 || abinfo.bytes > bufsize) {
ldebug ("warning: Invalid available size, size=%d bufsize=%d\n",
abinfo.bytes, bufsize);
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;
}
......@@ -369,15 +382,12 @@ static int oss_run_out (HWVoiceOut *hw)
"alignment %d\n",
wbytes, written, hw->info.align + 1);
}
mixeng_clear (src, wsamples);
decr -= wsamples;
rpos = (rpos + wsamples) % hw->samples;
break;
}
}
mixeng_clear (src, convert_samples);
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
}
......@@ -730,6 +740,8 @@ static struct audio_option oss_options[] = {
"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}
};
......
......@@ -240,7 +240,6 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len)
/* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */
hw->clip (buf, src, chunk);
mixeng_clear (src, chunk);
sdl->rpos = (sdl->rpos + chunk) % hw->samples;
to_mix -= chunk;
buf += chunk << hw->info.shift;
......
......@@ -81,7 +81,6 @@ static int wav_run_out (HWVoiceOut *hw)
hw->clip (dst, src, convert_samples);
qemu_put_buffer (wav->f, dst, convert_samples << hw->info.shift);
mixeng_clear (src, convert_samples);
rpos = (rpos + convert_samples) % hw->samples;
samples -= convert_samples;
......
#include "vl.h"
typedef struct {
QEMUFile *f;
int bytes;
} 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_state_cb (void *opaque, int enabled)
{
WAVState *wav = opaque;
if (!enabled) {
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);
}
else {
qemu_fseek (wav->f, 0, SEEK_END);
}
}
static void wav_capture_cb (void *opaque, void *buf, int size)
{
WAVState *wav = opaque;
qemu_put_buffer (wav->f, buf, size);
wav->bytes += size;
}
void wav_capture (const char *path, int freq, int bits16, int stereo)
{
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 shift;
stereo = !!stereo;
bits16 = !!bits16;
as.freq = freq;
as.nchannels = 1 << stereo;
as.fmt = bits16 ? AUD_FMT_S16 : AUD_FMT_U8;
ops.state = wav_state_cb;
ops.capture = wav_capture_cb;
wav = qemu_mallocz (sizeof (*wav));
if (!wav) {
AUD_log ("wav", "Could not allocate memory (%zu bytes)", sizeof (*wav));
return;
}
shift = bits16 + stereo;
hdr[34] = bits16 ? 0x10 : 0x08;
le_store (hdr + 22, as.nchannels, 2);
le_store (hdr + 24, freq, 4);
le_store (hdr + 28, freq << shift, 4);
le_store (hdr + 32, 1 << shift, 2);
wav->f = fopen (path, "wb");
if (!wav->f) {
AUD_log ("wav", "Failed to open wave file `%s'\nReason: %s\n",
path, strerror (errno));
qemu_free (wav);
return;
}
qemu_put_buffer (wav->f, hdr, sizeof (hdr));
AUD_add_capture (NULL, &as, 0, &ops, wav);
}
......@@ -479,9 +479,10 @@ static inline uint32_t es1370_fixup (ES1370State *s, uint32_t addr)
IO_WRITE_PROTO (es1370_writeb)
{
ES1370State *s = opaque;
addr = es1370_fixup (s, addr);
uint32_t shift, mask;
addr = es1370_fixup (s, addr);
switch (addr) {
case ES1370_REG_CONTROL:
case ES1370_REG_CONTROL + 1:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment