implemented dropping of current buffered audio, works for oss, but there seems
to be a "blip" for alsa devices, needs more work git-svn-id: https://svn.musicpd.org/mpd/trunk@3011 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
22
src/audio.c
22
src/audio.c
@@ -223,7 +223,10 @@ inline void syncAudioDevicesEnabledArrays() {
|
|||||||
if(myAudioDevicesEnabled[i]) {
|
if(myAudioDevicesEnabled[i]) {
|
||||||
openAudioOutput(audioOutputArray[i], &audio_format);
|
openAudioOutput(audioOutputArray[i], &audio_format);
|
||||||
}
|
}
|
||||||
else closeAudioOutput(audioOutputArray[i]);
|
else {
|
||||||
|
dropBufferedAudioOutput(audioOutputArray[i]);
|
||||||
|
closeAudioOutput(audioOutputArray[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,6 +315,23 @@ int isAudioDeviceOpen() {
|
|||||||
return audioOpened;
|
return audioOpened;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dropBufferedAudio() {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(0 != memcmp(pdAudioDevicesEnabled, myAudioDevicesEnabled,
|
||||||
|
AUDIO_MAX_DEVICES))
|
||||||
|
{
|
||||||
|
syncAudioDevicesEnabledArrays();
|
||||||
|
}
|
||||||
|
|
||||||
|
audioBufferPos = 0;
|
||||||
|
|
||||||
|
for(i = 0; i < audioOutputArraySize; i++) {
|
||||||
|
if(!myAudioDevicesEnabled[i]) continue;
|
||||||
|
dropBufferedAudioOutput(audioOutputArray[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void closeAudioDevice() {
|
void closeAudioDevice() {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@@ -57,6 +57,8 @@ int openAudioDevice(AudioFormat * audioFormat);
|
|||||||
|
|
||||||
int playAudio(char * playChunk,int size);
|
int playAudio(char * playChunk,int size);
|
||||||
|
|
||||||
|
void dropBufferedAudio();
|
||||||
|
|
||||||
void closeAudioDevice();
|
void closeAudioDevice();
|
||||||
|
|
||||||
int isAudioDeviceOpen();
|
int isAudioDeviceOpen();
|
||||||
|
@@ -61,6 +61,7 @@ AudioOutput * newAudioOutput(ConfigParam * param) {
|
|||||||
ret->finishDriverFunc = plugin->finishDriverFunc;
|
ret->finishDriverFunc = plugin->finishDriverFunc;
|
||||||
ret->openDeviceFunc = plugin->openDeviceFunc;
|
ret->openDeviceFunc = plugin->openDeviceFunc;
|
||||||
ret->playFunc = plugin->playFunc;
|
ret->playFunc = plugin->playFunc;
|
||||||
|
ret->dropBufferedAudioFunc = plugin->dropBufferedAudioFunc;
|
||||||
ret->closeDeviceFunc = plugin->closeDeviceFunc;
|
ret->closeDeviceFunc = plugin->closeDeviceFunc;
|
||||||
ret->sendMetdataFunc = plugin->sendMetdataFunc;
|
ret->sendMetdataFunc = plugin->sendMetdataFunc;
|
||||||
ret->open = 0;
|
ret->open = 0;
|
||||||
@@ -165,6 +166,10 @@ int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dropBufferedAudioOutput(AudioOutput * audioOutput) {
|
||||||
|
if(audioOutput->open) audioOutput->dropBufferedAudioFunc(audioOutput);
|
||||||
|
}
|
||||||
|
|
||||||
void closeAudioOutput(AudioOutput * audioOutput) {
|
void closeAudioOutput(AudioOutput * audioOutput) {
|
||||||
if(audioOutput->open) audioOutput->closeDeviceFunc(audioOutput);
|
if(audioOutput->open) audioOutput->closeDeviceFunc(audioOutput);
|
||||||
}
|
}
|
||||||
|
@@ -38,6 +38,8 @@ typedef int (* AudioOutputOpenDeviceFunc) (AudioOutput * audioOutput);
|
|||||||
typedef int (* AudioOutputPlayFunc) (AudioOutput * audioOutput,
|
typedef int (* AudioOutputPlayFunc) (AudioOutput * audioOutput,
|
||||||
char * playChunk, int size);
|
char * playChunk, int size);
|
||||||
|
|
||||||
|
typedef void (* AudioOutputDropBufferedAudioFunc) (AudioOutput * audioOutput);
|
||||||
|
|
||||||
typedef void (* AudioOutputCloseDeviceFunc) (AudioOutput * audioOutput);
|
typedef void (* AudioOutputCloseDeviceFunc) (AudioOutput * audioOutput);
|
||||||
|
|
||||||
typedef void (* AudioOutputSendMetadataFunc) (AudioOutput * audioOutput,
|
typedef void (* AudioOutputSendMetadataFunc) (AudioOutput * audioOutput,
|
||||||
@@ -51,6 +53,7 @@ struct _AudioOutput {
|
|||||||
AudioOutputFinishDriverFunc finishDriverFunc;
|
AudioOutputFinishDriverFunc finishDriverFunc;
|
||||||
AudioOutputOpenDeviceFunc openDeviceFunc;
|
AudioOutputOpenDeviceFunc openDeviceFunc;
|
||||||
AudioOutputPlayFunc playFunc;
|
AudioOutputPlayFunc playFunc;
|
||||||
|
AudioOutputDropBufferedAudioFunc dropBufferedAudioFunc;
|
||||||
AudioOutputCloseDeviceFunc closeDeviceFunc;
|
AudioOutputCloseDeviceFunc closeDeviceFunc;
|
||||||
AudioOutputSendMetadataFunc sendMetdataFunc;
|
AudioOutputSendMetadataFunc sendMetdataFunc;
|
||||||
|
|
||||||
@@ -71,6 +74,7 @@ typedef struct _AudioOutputPlugin {
|
|||||||
AudioOutputFinishDriverFunc finishDriverFunc;
|
AudioOutputFinishDriverFunc finishDriverFunc;
|
||||||
AudioOutputOpenDeviceFunc openDeviceFunc;
|
AudioOutputOpenDeviceFunc openDeviceFunc;
|
||||||
AudioOutputPlayFunc playFunc;
|
AudioOutputPlayFunc playFunc;
|
||||||
|
AudioOutputDropBufferedAudioFunc dropBufferedAudioFunc;
|
||||||
AudioOutputCloseDeviceFunc closeDeviceFunc;
|
AudioOutputCloseDeviceFunc closeDeviceFunc;
|
||||||
AudioOutputSendMetadataFunc sendMetdataFunc;
|
AudioOutputSendMetadataFunc sendMetdataFunc;
|
||||||
} AudioOutputPlugin;
|
} AudioOutputPlugin;
|
||||||
@@ -84,6 +88,7 @@ void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
|
|||||||
AudioOutput * newAudioOutput(ConfigParam * param);
|
AudioOutput * newAudioOutput(ConfigParam * param);
|
||||||
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat);
|
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat);
|
||||||
int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size);
|
int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size);
|
||||||
|
void dropBufferedAudioOutput(AudioOutput * audioOutput);
|
||||||
void closeAudioOutput(AudioOutput * audioOutput);
|
void closeAudioOutput(AudioOutput * audioOutput);
|
||||||
void finishAudioOutput(AudioOutput * audioOutput);
|
void finishAudioOutput(AudioOutput * audioOutput);
|
||||||
int keepAudioOutputAlive(AudioOutput * audioOutput, int ms);
|
int keepAudioOutputAlive(AudioOutput * audioOutput, int ms);
|
||||||
|
@@ -117,14 +117,14 @@ static int alsa_openDevice(AudioOutput * audioOutput)
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = snd_pcm_open(&ad->pcm_handle, ad->device,
|
err = snd_pcm_open(&ad->pcm_handle, ad->device,
|
||||||
SND_PCM_STREAM_PLAYBACK, 0);
|
SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
|
||||||
if(err < 0) {
|
if(err < 0) {
|
||||||
ad->pcm_handle = NULL;
|
ad->pcm_handle = NULL;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*err = snd_pcm_nonblock(ad->pcm_handle, 0);
|
err = snd_pcm_nonblock(ad->pcm_handle, 0);
|
||||||
if(err < 0) goto error;*/
|
if(err < 0) goto error;
|
||||||
|
|
||||||
/* configure HW params */
|
/* configure HW params */
|
||||||
snd_pcm_hw_params_alloca(&hwparams);
|
snd_pcm_hw_params_alloca(&hwparams);
|
||||||
@@ -221,28 +221,46 @@ fail:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alsa_closeDevice(AudioOutput * audioOutput) {
|
static void alsa_dropBufferedAudio(AudioOutput * audioOutput) {
|
||||||
AlsaData * ad = audioOutput->data;
|
AlsaData * ad = audioOutput->data;
|
||||||
|
|
||||||
if(ad->pcm_handle) {
|
snd_pcm_drop(ad->pcm_handle);
|
||||||
snd_pcm_drain(ad->pcm_handle);
|
|
||||||
ad->pcm_handle = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
audioOutput->open = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline static int alsa_errorRecovery(AlsaData * ad, int err) {
|
inline static int alsa_errorRecovery(AlsaData * ad, int err) {
|
||||||
if(err == -EPIPE) {
|
if(err == -EPIPE) {
|
||||||
DEBUG("Underrun on alsa device \"%s\"\n", ad->device);
|
DEBUG("Underrun on alsa device \"%s\"\n", ad->device);
|
||||||
|
}
|
||||||
|
else if(err == -ESTRPIPE) {
|
||||||
|
DEBUG("alsa device \"%s\" was suspended\n", ad->device);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(snd_pcm_state(ad->pcm_handle)) {
|
||||||
|
case SND_PCM_STATE_SETUP:
|
||||||
|
case SND_PCM_STATE_XRUN:
|
||||||
err = snd_pcm_prepare(ad->pcm_handle);
|
err = snd_pcm_prepare(ad->pcm_handle);
|
||||||
if(err < 0) return -1;
|
if(err < 0) return -1;
|
||||||
return 0;
|
return 0;
|
||||||
|
default:
|
||||||
|
/* unknown state, do nothing */
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void alsa_closeDevice(AudioOutput * audioOutput) {
|
||||||
|
AlsaData * ad = audioOutput->data;
|
||||||
|
|
||||||
|
if(ad->pcm_handle) {
|
||||||
|
snd_pcm_drain(ad->pcm_handle);
|
||||||
|
snd_pcm_close(ad->pcm_handle);
|
||||||
|
ad->pcm_handle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
audioOutput->open = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int alsa_playAudio(AudioOutput * audioOutput, char * playChunk,
|
static int alsa_playAudio(AudioOutput * audioOutput, char * playChunk,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
@@ -277,6 +295,7 @@ AudioOutputPlugin alsaPlugin =
|
|||||||
alsa_finishDriver,
|
alsa_finishDriver,
|
||||||
alsa_openDevice,
|
alsa_openDevice,
|
||||||
alsa_playAudio,
|
alsa_playAudio,
|
||||||
|
alsa_dropBufferedAudio,
|
||||||
alsa_closeDevice,
|
alsa_closeDevice,
|
||||||
NULL /* sendMetadataFunc */
|
NULL /* sendMetadataFunc */
|
||||||
};
|
};
|
||||||
|
@@ -171,6 +171,10 @@ static void audioOutputAo_finishDriver(AudioOutput * audioOutput) {
|
|||||||
if(driverInitCount == 0) ao_shutdown();
|
if(driverInitCount == 0) ao_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void audioOutputAo_dropBufferedAudio(AudioOutput * audioOutput) {
|
||||||
|
// not supported by libao
|
||||||
|
}
|
||||||
|
|
||||||
static void audioOutputAo_closeDevice(AudioOutput * audioOutput) {
|
static void audioOutputAo_closeDevice(AudioOutput * audioOutput) {
|
||||||
AoData * ad = (AoData *) audioOutput->data;
|
AoData * ad = (AoData *) audioOutput->data;
|
||||||
|
|
||||||
@@ -237,6 +241,7 @@ AudioOutputPlugin aoPlugin =
|
|||||||
audioOutputAo_finishDriver,
|
audioOutputAo_finishDriver,
|
||||||
audioOutputAo_openDevice,
|
audioOutputAo_openDevice,
|
||||||
audioOutputAo_play,
|
audioOutputAo_play,
|
||||||
|
audioOutputAo_dropBufferedAudio,
|
||||||
audioOutputAo_closeDevice,
|
audioOutputAo_closeDevice,
|
||||||
NULL /* sendMetadataFunc */
|
NULL /* sendMetadataFunc */
|
||||||
};
|
};
|
||||||
@@ -253,6 +258,7 @@ AudioOutputPlugin aoPlugin =
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -48,6 +48,10 @@
|
|||||||
typedef struct _OssData {
|
typedef struct _OssData {
|
||||||
int fd;
|
int fd;
|
||||||
char * device;
|
char * device;
|
||||||
|
int channels;
|
||||||
|
int sampleRate;
|
||||||
|
int bitFormat;
|
||||||
|
int bits;
|
||||||
} OssData;
|
} OssData;
|
||||||
|
|
||||||
static OssData * newOssData() {
|
static OssData * newOssData() {
|
||||||
@@ -154,28 +158,45 @@ static void oss_finishDriver(AudioOutput * audioOutput) {
|
|||||||
freeOssData(od);
|
freeOssData(od);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int oss_openDevice(AudioOutput * audioOutput)
|
static int oss_open(AudioOutput * audioOutput) {
|
||||||
{
|
|
||||||
OssData * od = audioOutput->data;
|
OssData * od = audioOutput->data;
|
||||||
AudioFormat * audioFormat = &audioOutput->outAudioFormat;
|
|
||||||
#ifdef WORDS_BIGENDIAN
|
|
||||||
int i = AFMT_S16_BE;
|
|
||||||
#else
|
|
||||||
int i = AFMT_S16_LE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if((od->fd = open(od->device, O_WRONLY)) < 0) goto fail;
|
|
||||||
|
|
||||||
if(ioctl(od->fd, SNDCTL_DSP_SETFMT, &i)) goto fail;
|
if((od->fd = open(od->device, O_WRONLY)) < 0) {
|
||||||
|
ERROR("Error opening OSS device \"%s\": %s\n", od->device,
|
||||||
|
strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
i = audioFormat->channels;
|
if(ioctl(od->fd, SNDCTL_DSP_SETFMT, &od->bitFormat)) {
|
||||||
if(ioctl(od->fd, SNDCTL_DSP_CHANNELS, &i)) goto fail;
|
ERROR("Error setting bitformat on OSS device \"%s\": %s\n",
|
||||||
|
od->device,
|
||||||
|
strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
i = audioFormat->sampleRate;
|
if(ioctl(od->fd, SNDCTL_DSP_CHANNELS, &od->channels)) {
|
||||||
if(ioctl(od->fd, SNDCTL_DSP_SPEED, &i)) goto fail;
|
ERROR("OSS device \"%s\" does not support %i channels: %s\n",
|
||||||
|
od->device,
|
||||||
|
od->channels,
|
||||||
|
strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
i = audioFormat->bits;
|
if(ioctl(od->fd, SNDCTL_DSP_SPEED, &od->sampleRate)) {
|
||||||
if(ioctl(od->fd, SNDCTL_DSP_SAMPLESIZE, &i)) goto fail;
|
ERROR("OSS device \"%s\" does not support %i Hz audio: %s\n",
|
||||||
|
od->device,
|
||||||
|
od->sampleRate,
|
||||||
|
strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ioctl(od->fd, SNDCTL_DSP_SAMPLESIZE, &od->bits)) {
|
||||||
|
ERROR("OSS device \"%s\" does not support %i bit audio: %s\n",
|
||||||
|
od->device,
|
||||||
|
od->bits,
|
||||||
|
strerror(errno));
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
audioOutput->open = 1;
|
audioOutput->open = 1;
|
||||||
|
|
||||||
@@ -184,11 +205,25 @@ static int oss_openDevice(AudioOutput * audioOutput)
|
|||||||
fail:
|
fail:
|
||||||
if(od->fd >= 0) close(od->fd);
|
if(od->fd >= 0) close(od->fd);
|
||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
ERROR("Error opening OSS device \"%s\": %s\n", od->device,
|
|
||||||
strerror(errno));
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int oss_openDevice(AudioOutput * audioOutput)
|
||||||
|
{
|
||||||
|
OssData * od = audioOutput->data;
|
||||||
|
AudioFormat * audioFormat = &audioOutput->outAudioFormat;
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
od->bitFormat = AFMT_S16_BE;
|
||||||
|
#else
|
||||||
|
od->bitFormat = AFMT_S16_LE;
|
||||||
|
#endif
|
||||||
|
od->channels = audioFormat->channels;
|
||||||
|
od->sampleRate = audioFormat->sampleRate;
|
||||||
|
od->bits = audioFormat->bits;
|
||||||
|
|
||||||
|
return oss_open(audioOutput);
|
||||||
|
}
|
||||||
|
|
||||||
static void oss_closeDevice(AudioOutput * audioOutput) {
|
static void oss_closeDevice(AudioOutput * audioOutput) {
|
||||||
OssData * od = audioOutput->data;
|
OssData * od = audioOutput->data;
|
||||||
|
|
||||||
@@ -200,6 +235,17 @@ static void oss_closeDevice(AudioOutput * audioOutput) {
|
|||||||
audioOutput->open = 0;
|
audioOutput->open = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void oss_dropBufferedAudio(AudioOutput * audioOutput) {
|
||||||
|
OssData * od = audioOutput->data;
|
||||||
|
|
||||||
|
if(od->fd >= 0) {
|
||||||
|
ioctl(od->fd, SNDCTL_DSP_RESET, 0);
|
||||||
|
oss_closeDevice(audioOutput);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*oss_open(audioOutput);*/
|
||||||
|
}
|
||||||
|
|
||||||
static int oss_playAudio(AudioOutput * audioOutput, char * playChunk,
|
static int oss_playAudio(AudioOutput * audioOutput, char * playChunk,
|
||||||
int size)
|
int size)
|
||||||
{
|
{
|
||||||
@@ -227,6 +273,7 @@ AudioOutputPlugin ossPlugin =
|
|||||||
oss_finishDriver,
|
oss_finishDriver,
|
||||||
oss_openDevice,
|
oss_openDevice,
|
||||||
oss_playAudio,
|
oss_playAudio,
|
||||||
|
oss_dropBufferedAudio,
|
||||||
oss_closeDevice,
|
oss_closeDevice,
|
||||||
NULL /* sendMetadataFunc */
|
NULL /* sendMetadataFunc */
|
||||||
};
|
};
|
||||||
@@ -241,6 +288,7 @@ AudioOutputPlugin ossPlugin =
|
|||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
NULL /* sendMetadataFunc */
|
NULL /* sendMetadataFunc */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -361,6 +361,10 @@ static void myShout_finishDriver(AudioOutput * audioOutput) {
|
|||||||
if(shoutInitCount == 0) shout_shutdown();
|
if(shoutInitCount == 0) shout_shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void myShout_dropBufferedAudioDevice(AudioOutput * audioOutput) {
|
||||||
|
// needs to be implemented
|
||||||
|
}
|
||||||
|
|
||||||
static void myShout_closeDevice(AudioOutput * audioOutput) {
|
static void myShout_closeDevice(AudioOutput * audioOutput) {
|
||||||
ShoutData * sd = (ShoutData *)audioOutput->data;
|
ShoutData * sd = (ShoutData *)audioOutput->data;
|
||||||
|
|
||||||
|
@@ -251,6 +251,7 @@ int decodeSeek(PlayerControl * pc, DecoderControl * dc, OutputBuffer * cb,
|
|||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
if(pc->stop) { \
|
if(pc->stop) { \
|
||||||
|
dropBufferedAudio(); \
|
||||||
quitDecode(pc,dc); \
|
quitDecode(pc,dc); \
|
||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user