Implemented support for the new mixer thread in the lowlevel sound module
'alsa'. Cleaned up the code a little bit. TODO #1: Implement mixer thread support in the OSX sound driver. TODO #2: Code cleanups in the Bochs sound code. TODO #3: Resampling support and improvements in the wave recording code.
This commit is contained in:
parent
bfb5ec8cf9
commit
9c1070cbed
@ -27,6 +27,10 @@
|
|||||||
|
|
||||||
#if BX_HAVE_ALSASOUND && BX_SUPPORT_SOUNDLOW
|
#if BX_HAVE_ALSASOUND && BX_SUPPORT_SOUNDLOW
|
||||||
|
|
||||||
|
#ifndef WIN32
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#define LOG_THIS
|
#define LOG_THIS
|
||||||
|
|
||||||
bx_sound_alsa_c::bx_sound_alsa_c()
|
bx_sound_alsa_c::bx_sound_alsa_c()
|
||||||
@ -202,6 +206,9 @@ int bx_sound_alsa_c::closemidioutput()
|
|||||||
int bx_sound_alsa_c::openwaveoutput(const char *wavedev)
|
int bx_sound_alsa_c::openwaveoutput(const char *wavedev)
|
||||||
{
|
{
|
||||||
set_pcm_params(real_pcm_param);
|
set_pcm_params(real_pcm_param);
|
||||||
|
pcm_callback_id = register_wave_callback(this, pcm_callback);
|
||||||
|
BX_INIT_MUTEX(mixer_mutex);
|
||||||
|
start_mixer_thread();
|
||||||
return BX_SOUNDLOW_OK;
|
return BX_SOUNDLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +223,7 @@ int bx_sound_alsa_c::alsa_pcm_open(bx_bool mode, int frequency, int bits, bx_boo
|
|||||||
alsa_pcm[mode].audio_bufsize = 0;
|
alsa_pcm[mode].audio_bufsize = 0;
|
||||||
|
|
||||||
if (alsa_pcm[mode].handle == NULL) {
|
if (alsa_pcm[mode].handle == NULL) {
|
||||||
ret = snd_pcm_open(&alsa_pcm[mode].handle, "default", mode ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
ret = snd_pcm_open(&alsa_pcm[mode].handle, "default", mode ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK, 0);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return BX_SOUNDLOW_ERR;
|
return BX_SOUNDLOW_ERR;
|
||||||
}
|
}
|
||||||
@ -226,16 +233,18 @@ int bx_sound_alsa_c::alsa_pcm_open(bx_bool mode, int frequency, int bits, bx_boo
|
|||||||
snd_pcm_hw_params_any(alsa_pcm[mode].handle, params);
|
snd_pcm_hw_params_any(alsa_pcm[mode].handle, params);
|
||||||
snd_pcm_hw_params_set_access(alsa_pcm[mode].handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
snd_pcm_hw_params_set_access(alsa_pcm[mode].handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||||
|
|
||||||
if ((frequency == wave_ch[mode].oldfreq) &&
|
if (mode == 1) {
|
||||||
(bits == wave_ch[mode].oldbits) &&
|
if ((frequency == wavein_param.samplerate) &&
|
||||||
(stereo == wave_ch[mode].oldstereo) &&
|
(bits == wavein_param.bits) &&
|
||||||
(format == wave_ch[mode].oldformat))
|
(stereo == (wavein_param.channels == 2)) &&
|
||||||
return BX_SOUNDLOW_OK; // nothing to do
|
(format == wavein_param.format))
|
||||||
|
return BX_SOUNDLOW_OK; // nothing to do
|
||||||
|
|
||||||
wave_ch[mode].oldfreq = frequency;
|
wavein_param.samplerate = frequency;
|
||||||
wave_ch[mode].oldbits = bits;
|
wavein_param.bits = bits;
|
||||||
wave_ch[mode].oldstereo = stereo;
|
wavein_param.channels = stereo + 1;
|
||||||
wave_ch[mode].oldformat = format;
|
wavein_param.format = format;
|
||||||
|
}
|
||||||
|
|
||||||
freq = (unsigned int)frequency;
|
freq = (unsigned int)frequency;
|
||||||
|
|
||||||
@ -283,82 +292,26 @@ int bx_sound_alsa_c::set_pcm_params(bx_pcm_param_t param)
|
|||||||
return alsa_pcm_open(0, param.samplerate, param.bits, param.channels == 2, param.format);
|
return alsa_pcm_open(0, param.samplerate, param.bits, param.channels == 2, param.format);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bx_sound_alsa_c::alsa_pcm_write()
|
int bx_sound_alsa_c::get_waveout_packetsize()
|
||||||
{
|
{
|
||||||
int ret;
|
return alsa_pcm[0].alsa_bufsize;
|
||||||
|
|
||||||
if (alsa_pcm[0].buffer == NULL) {
|
|
||||||
alsa_pcm[0].buffer = (char *)malloc(alsa_pcm[0].alsa_bufsize);
|
|
||||||
}
|
|
||||||
while (alsa_pcm[0].audio_bufsize >= alsa_pcm[0].alsa_bufsize) {
|
|
||||||
memcpy(alsa_pcm[0].buffer, audio_buffer[0], alsa_pcm[0].alsa_bufsize);
|
|
||||||
ret = snd_pcm_writei(alsa_pcm[0].handle, alsa_pcm[0].buffer, alsa_pcm[0].frames);
|
|
||||||
if (ret == -EAGAIN)
|
|
||||||
continue;
|
|
||||||
if (ret == -EPIPE) {
|
|
||||||
/* EPIPE means underrun */
|
|
||||||
BX_ERROR(("ALSA: underrun occurred"));
|
|
||||||
snd_pcm_prepare(alsa_pcm[0].handle);
|
|
||||||
} else if (ret < 0) {
|
|
||||||
BX_ERROR(("ALSA: error from writei: %s", snd_strerror(ret)));
|
|
||||||
} else if (ret != (int)alsa_pcm[0].frames) {
|
|
||||||
BX_ERROR(("ALSA: short write, write %d frames", ret));
|
|
||||||
}
|
|
||||||
alsa_pcm[0].audio_bufsize -= alsa_pcm[0].alsa_bufsize;
|
|
||||||
memmove(audio_buffer[0], audio_buffer[0]+alsa_pcm[0].alsa_bufsize, alsa_pcm[0].audio_bufsize);
|
|
||||||
}
|
|
||||||
if ((alsa_pcm[0].audio_bufsize == 0) && (alsa_pcm[0].buffer != NULL)) {
|
|
||||||
free(alsa_pcm[0].buffer);
|
|
||||||
alsa_pcm[0].buffer = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BX_SOUNDLOW_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int bx_sound_alsa_c::sendwavepacket(int length, Bit8u data[], bx_pcm_param_t *src_param)
|
int bx_sound_alsa_c::waveout(int length, Bit8u data[])
|
||||||
{
|
{
|
||||||
int len2;
|
if (!alsa_pcm[0].handle || (length > alsa_pcm[0].alsa_bufsize)) {
|
||||||
|
return BX_SOUNDLOW_ERR;
|
||||||
if (memcmp(src_param, &emu_pcm_param, sizeof(bx_pcm_param_t)) != 0) {
|
|
||||||
emu_pcm_param = *src_param;
|
|
||||||
cvt_mult = (src_param->bits == 8) ? 2 : 1;
|
|
||||||
if (src_param->channels == 1) cvt_mult <<= 1;
|
|
||||||
if (src_param->samplerate != real_pcm_param.samplerate) {
|
|
||||||
real_pcm_param.samplerate = src_param->samplerate;
|
|
||||||
set_pcm_params(real_pcm_param);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
len2 = length * cvt_mult;
|
int ret = snd_pcm_writei(alsa_pcm[0].handle, data, alsa_pcm[0].frames);
|
||||||
if (!alsa_pcm[0].handle) {
|
if (ret == -EPIPE) {
|
||||||
// Alert indicating that caller is probably erroneous
|
/* EPIPE means underrun */
|
||||||
BX_ERROR(("sendwavepacket(): pcm is not open"));
|
BX_ERROR(("ALSA: underrun occurred"));
|
||||||
return BX_SOUNDLOW_ERR;
|
snd_pcm_prepare(alsa_pcm[0].handle);
|
||||||
|
} else if (ret < 0) {
|
||||||
|
BX_ERROR(("ALSA: error from writei: %s", snd_strerror(ret)));
|
||||||
|
} else if (ret != (int)alsa_pcm[0].frames) {
|
||||||
|
BX_ERROR(("ALSA: short write, write %d frames", ret));
|
||||||
}
|
}
|
||||||
if ((alsa_pcm[0].audio_bufsize+len2) > BX_SOUND_ALSA_BUFSIZE) {
|
|
||||||
len2 = BX_SOUND_ALSA_BUFSIZE - alsa_pcm[0].audio_bufsize;
|
|
||||||
BX_ERROR(("ALSA: audio buffer overflow"));
|
|
||||||
}
|
|
||||||
if (len2 > 0) {
|
|
||||||
convert_pcm_data(data, length, audio_buffer[0]+alsa_pcm[0].audio_bufsize, len2, src_param);
|
|
||||||
alsa_pcm[0].audio_bufsize += len2;
|
|
||||||
}
|
|
||||||
if (alsa_pcm[0].audio_bufsize < alsa_pcm[0].alsa_bufsize) {
|
|
||||||
return BX_SOUNDLOW_OK;
|
|
||||||
} else {
|
|
||||||
return alsa_pcm_write();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int bx_sound_alsa_c::stopwaveplayback()
|
|
||||||
{
|
|
||||||
if (alsa_pcm[0].handle && alsa_pcm[0].audio_bufsize > 0) {
|
|
||||||
if (alsa_pcm[0].audio_bufsize < alsa_pcm[0].alsa_bufsize) {
|
|
||||||
memset(audio_buffer[0]+alsa_pcm[0].audio_bufsize, 0, alsa_pcm[0].alsa_bufsize-alsa_pcm[0].audio_bufsize);
|
|
||||||
alsa_pcm[0].audio_bufsize = alsa_pcm[0].alsa_bufsize;
|
|
||||||
}
|
|
||||||
alsa_pcm_write();
|
|
||||||
}
|
|
||||||
|
|
||||||
return BX_SOUNDLOW_OK;
|
return BX_SOUNDLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,7 +322,6 @@ int bx_sound_alsa_c::closewaveoutput()
|
|||||||
snd_pcm_close(alsa_pcm[0].handle);
|
snd_pcm_close(alsa_pcm[0].handle);
|
||||||
alsa_pcm[0].handle = NULL;
|
alsa_pcm[0].handle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return BX_SOUNDLOW_OK;
|
return BX_SOUNDLOW_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,6 +332,7 @@ int bx_sound_alsa_c::openwaveinput(const char *wavedev, sound_record_handler_t r
|
|||||||
record_timer_index = bx_pc_system.register_timer(this, record_timer_handler, 1, 1, 0, "soundlnx");
|
record_timer_index = bx_pc_system.register_timer(this, record_timer_handler, 1, 1, 0, "soundlnx");
|
||||||
// record timer: inactive, continuous, frequency variable
|
// record timer: inactive, continuous, frequency variable
|
||||||
}
|
}
|
||||||
|
wavein_param.samplerate = 0;
|
||||||
|
|
||||||
return BX_SOUNDLOW_OK;
|
return BX_SOUNDLOW_OK;
|
||||||
}
|
}
|
||||||
@ -422,10 +375,10 @@ int bx_sound_alsa_c::getwavepacket(int length, Bit8u data[])
|
|||||||
} else if (ret != (int)alsa_pcm[1].frames) {
|
} else if (ret != (int)alsa_pcm[1].frames) {
|
||||||
BX_ERROR(("short read, read %d frames", ret));
|
BX_ERROR(("short read, read %d frames", ret));
|
||||||
}
|
}
|
||||||
memcpy(audio_buffer[1]+alsa_pcm[1].audio_bufsize, alsa_pcm[1].buffer, alsa_pcm[1].alsa_bufsize);
|
memcpy(audio_buffer+alsa_pcm[1].audio_bufsize, alsa_pcm[1].buffer, alsa_pcm[1].alsa_bufsize);
|
||||||
alsa_pcm[1].audio_bufsize += alsa_pcm[1].alsa_bufsize;
|
alsa_pcm[1].audio_bufsize += alsa_pcm[1].alsa_bufsize;
|
||||||
}
|
}
|
||||||
memcpy(data, audio_buffer[1], length);
|
memcpy(data, audio_buffer, length);
|
||||||
alsa_pcm[1].audio_bufsize -= length;
|
alsa_pcm[1].audio_bufsize -= length;
|
||||||
if ((alsa_pcm[1].audio_bufsize <= 0) && (alsa_pcm[1].buffer != NULL)) {
|
if ((alsa_pcm[1].audio_bufsize <= 0) && (alsa_pcm[1].buffer != NULL)) {
|
||||||
free(alsa_pcm[1].buffer);
|
free(alsa_pcm[1].buffer);
|
||||||
@ -470,4 +423,14 @@ void bx_sound_alsa_c::record_timer(void)
|
|||||||
record_handler(this, record_packet_size);
|
record_handler(this, record_packet_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int bx_sound_alsa_c::register_wave_callback(void *arg, get_wave_cb_t wd_cb)
|
||||||
|
{
|
||||||
|
if (cb_count < BX_MAX_WAVE_CALLBACKS) {
|
||||||
|
get_wave[cb_count].device = arg;
|
||||||
|
get_wave[cb_count].cb = wd_cb;
|
||||||
|
return cb_count++;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -42,8 +42,8 @@ public:
|
|||||||
|
|
||||||
virtual int openwaveoutput(const char *wavedev);
|
virtual int openwaveoutput(const char *wavedev);
|
||||||
virtual int set_pcm_params(bx_pcm_param_t param);
|
virtual int set_pcm_params(bx_pcm_param_t param);
|
||||||
virtual int sendwavepacket(int length, Bit8u data[], bx_pcm_param_t *src_param);
|
virtual int get_waveout_packetsize();
|
||||||
virtual int stopwaveplayback();
|
virtual int waveout(int length, Bit8u data[]);
|
||||||
virtual int closewaveoutput();
|
virtual int closewaveoutput();
|
||||||
|
|
||||||
virtual int openwaveinput(const char *wavedev, sound_record_handler_t rh);
|
virtual int openwaveinput(const char *wavedev, sound_record_handler_t rh);
|
||||||
@ -54,11 +54,12 @@ public:
|
|||||||
|
|
||||||
static void record_timer_handler(void *);
|
static void record_timer_handler(void *);
|
||||||
void record_timer(void);
|
void record_timer(void);
|
||||||
|
|
||||||
|
virtual int register_wave_callback(void *, get_wave_cb_t wd_cb);
|
||||||
private:
|
private:
|
||||||
int alsa_seq_open(const char *alsadev);
|
int alsa_seq_open(const char *alsadev);
|
||||||
int alsa_seq_output(int delta, int command, int length, Bit8u data[]);
|
int alsa_seq_output(int delta, int command, int length, Bit8u data[]);
|
||||||
int alsa_pcm_open(bx_bool input, int frequency, int bits, bx_bool stereo, int format);
|
int alsa_pcm_open(bx_bool input, int frequency, int bits, bx_bool stereo, int format);
|
||||||
int alsa_pcm_write();
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
snd_seq_t *handle;
|
snd_seq_t *handle;
|
||||||
@ -70,11 +71,8 @@ private:
|
|||||||
int alsa_bufsize, audio_bufsize;
|
int alsa_bufsize, audio_bufsize;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
} alsa_pcm[2];
|
} alsa_pcm[2];
|
||||||
struct {
|
bx_pcm_param_t wavein_param;
|
||||||
int oldfreq, oldbits, oldformat;
|
Bit8u audio_buffer[BX_SOUND_ALSA_BUFSIZE];
|
||||||
bx_bool oldstereo;
|
|
||||||
} wave_ch[2];
|
|
||||||
Bit8u audio_buffer[2][BX_SOUND_ALSA_BUFSIZE];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user