aboutsummaryrefslogtreecommitdiffstats
path: root/src/audioOutputs/audioOutput_alsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/audioOutputs/audioOutput_alsa.c')
-rw-r--r--src/audioOutputs/audioOutput_alsa.c251
1 files changed, 134 insertions, 117 deletions
diff --git a/src/audioOutputs/audioOutput_alsa.c b/src/audioOutputs/audioOutput_alsa.c
index 5150dd502..c98d8b537 100644
--- a/src/audioOutputs/audioOutput_alsa.c
+++ b/src/audioOutputs/audioOutput_alsa.c
@@ -39,13 +39,13 @@
#include <alsa/asoundlib.h>
-typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t *pcm, const void *buffer,
- snd_pcm_uframes_t size);
+typedef snd_pcm_sframes_t alsa_writei_t(snd_pcm_t * pcm, const void *buffer,
+ snd_pcm_uframes_t size);
typedef struct _AlsaData {
- char * device;
- snd_pcm_t * pcmHandle;
- alsa_writei_t * writei;
+ char *device;
+ snd_pcm_t *pcmHandle;
+ alsa_writei_t *writei;
unsigned int buffer_time;
unsigned int period_time;
int sampleSize;
@@ -54,8 +54,9 @@ typedef struct _AlsaData {
int canResume;
} AlsaData;
-static AlsaData * newAlsaData(void) {
- AlsaData * ret = malloc(sizeof(AlsaData));
+static AlsaData *newAlsaData(void)
+{
+ AlsaData *ret = malloc(sizeof(AlsaData));
ret->device = NULL;
ret->pcmHandle = NULL;
@@ -67,22 +68,25 @@ static AlsaData * newAlsaData(void) {
return ret;
}
-static void freeAlsaData(AlsaData * ad) {
- if(ad->device) free(ad->device);
+static void freeAlsaData(AlsaData * ad)
+{
+ if (ad->device)
+ free(ad->device);
free(ad);
}
-static int alsa_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
- AlsaData * ad = newAlsaData();
+static int alsa_initDriver(AudioOutput * audioOutput, ConfigParam * param)
+{
+ AlsaData *ad = newAlsaData();
if (param) {
- BlockParam * bp = getBlockParam(param, "device");
+ BlockParam *bp = getBlockParam(param, "device");
ad->device = bp ? strdup(bp->value) : strdup("default");
if ((bp = getBlockParam(param, "use_mmap")) &&
- (!strcasecmp(bp->value, "yes") ||
- !strcasecmp(bp->value, "true")))
+ (!strcasecmp(bp->value, "yes") ||
+ !strcasecmp(bp->value, "true")))
ad->useMmap = 1;
if ((bp = getBlockParam(param, "buffer_time")))
ad->buffer_time = atoi(bp->value);
@@ -94,45 +98,46 @@ static int alsa_initDriver(AudioOutput * audioOutput, ConfigParam * param) {
return 0;
}
-static void alsa_finishDriver(AudioOutput * audioOutput) {
- AlsaData * ad = audioOutput->data;
+static void alsa_finishDriver(AudioOutput * audioOutput)
+{
+ AlsaData *ad = audioOutput->data;
freeAlsaData(ad);
}
static int alsa_testDefault(void)
{
- snd_pcm_t * handle;
+ snd_pcm_t *handle;
- int ret = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK,
- SND_PCM_NONBLOCK);
+ int ret = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK,
+ SND_PCM_NONBLOCK);
snd_config_update_free_global();
-
- if(ret) {
+
+ if (ret) {
WARNING("Error opening default alsa device: %s\n",
- snd_strerror(-ret));
+ snd_strerror(-ret));
return -1;
- }
- else snd_pcm_close(handle);
+ } else
+ snd_pcm_close(handle);
return 0;
}
-static int alsa_openDevice(AudioOutput * audioOutput)
+static int alsa_openDevice(AudioOutput * audioOutput)
{
- AlsaData * ad = audioOutput->data;
- AudioFormat * audioFormat = &audioOutput->outAudioFormat;
+ AlsaData *ad = audioOutput->data;
+ AudioFormat *audioFormat = &audioOutput->outAudioFormat;
snd_pcm_format_t bitformat;
- snd_pcm_hw_params_t * hwparams;
- snd_pcm_sw_params_t * swparams;
+ snd_pcm_hw_params_t *hwparams;
+ snd_pcm_sw_params_t *swparams;
unsigned int sampleRate = audioFormat->sampleRate;
unsigned int channels = audioFormat->channels;
snd_pcm_uframes_t alsa_buffer_size;
snd_pcm_uframes_t alsa_period_size;
int err;
- char * cmd = NULL;
+ char *cmd = NULL;
- switch(audioFormat->bits) {
+ switch (audioFormat->bits) {
case 8:
bitformat = SND_PCM_FORMAT_S8;
break;
@@ -147,101 +152,107 @@ static int alsa_openDevice(AudioOutput * audioOutput)
break;
default:
ERROR("Alsa device \"%s\" doesn't support %i bit audio\n",
- ad->device, audioFormat->bits);
+ ad->device, audioFormat->bits);
return -1;
}
- err = snd_pcm_open(&ad->pcmHandle, ad->device,
- SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
+ err = snd_pcm_open(&ad->pcmHandle, ad->device,
+ SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK);
snd_config_update_free_global();
- if(err < 0) {
+ if (err < 0) {
ad->pcmHandle = NULL;
goto error;
}
cmd = "snd_pcm_nonblock";
err = snd_pcm_nonblock(ad->pcmHandle, 0);
- if(err < 0) goto error;
+ if (err < 0)
+ goto error;
/* configure HW params */
snd_pcm_hw_params_alloca(&hwparams);
cmd = "snd_pcm_hw_params_any";
err = snd_pcm_hw_params_any(ad->pcmHandle, hwparams);
- if(err < 0) goto error;
+ if (err < 0)
+ goto error;
- if(ad->useMmap) {
+ if (ad->useMmap) {
err = snd_pcm_hw_params_set_access(ad->pcmHandle, hwparams,
- SND_PCM_ACCESS_MMAP_INTERLEAVED);
- if(err < 0) {
+ SND_PCM_ACCESS_MMAP_INTERLEAVED);
+ if (err < 0) {
ERROR("Cannot set mmap'ed mode on alsa device \"%s\": "
- " %s\n", ad->device,
- snd_strerror(-err));
+ " %s\n", ad->device, snd_strerror(-err));
ERROR("Falling back to direct write mode\n");
ad->useMmap = 0;
- }
- else ad->writei = snd_pcm_mmap_writei;
+ } else
+ ad->writei = snd_pcm_mmap_writei;
}
- if(!ad->useMmap) {
+ if (!ad->useMmap) {
cmd = "snd_pcm_hw_params_set_access";
err = snd_pcm_hw_params_set_access(ad->pcmHandle, hwparams,
- SND_PCM_ACCESS_RW_INTERLEAVED);
- if(err < 0) goto error;
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err < 0)
+ goto error;
ad->writei = snd_pcm_writei;
}
err = snd_pcm_hw_params_set_format(ad->pcmHandle, hwparams, bitformat);
- if(err < 0) {
+ if (err < 0) {
ERROR("Alsa device \"%s\" does not support %i bit audio: "
- "%s\n", ad->device, (int)bitformat,
- snd_strerror(-err));
+ "%s\n", ad->device, (int)bitformat, snd_strerror(-err));
goto fail;
}
- err = snd_pcm_hw_params_set_channels_near(ad->pcmHandle, hwparams,
- &channels);
- if(err < 0) {
+ err = snd_pcm_hw_params_set_channels_near(ad->pcmHandle, hwparams,
+ &channels);
+ if (err < 0) {
ERROR("Alsa device \"%s\" does not support %i channels: "
- "%s\n", ad->device, (int)audioFormat->channels,
- snd_strerror(-err));
+ "%s\n", ad->device, (int)audioFormat->channels,
+ snd_strerror(-err));
goto fail;
}
audioFormat->channels = channels;
- err = snd_pcm_hw_params_set_rate_near(ad->pcmHandle, hwparams,
- &sampleRate, NULL);
- if(err < 0 || sampleRate == 0) {
+ err = snd_pcm_hw_params_set_rate_near(ad->pcmHandle, hwparams,
+ &sampleRate, NULL);
+ if (err < 0 || sampleRate == 0) {
ERROR("Alsa device \"%s\" does not support %i Hz audio\n",
- ad->device, (int)audioFormat->sampleRate);
+ ad->device, (int)audioFormat->sampleRate);
goto fail;
}
audioFormat->sampleRate = sampleRate;
cmd = "snd_pcm_hw_params_set_buffer_time_near";
err = snd_pcm_hw_params_set_buffer_time_near(ad->pcmHandle, hwparams,
- &ad->buffer_time, NULL);
- if(err < 0) goto error;
+ &ad->buffer_time, NULL);
+ if (err < 0)
+ goto error;
if (!ad->period_time && sampleRate > 0)
ad->period_time = 1000000 * MPD_ALSA_SAMPLE_XFER / sampleRate;
cmd = "snd_pcm_hw_params_set_period_time_near";
err = snd_pcm_hw_params_set_period_time_near(ad->pcmHandle, hwparams,
- &ad->period_time, NULL);
- if(err < 0) goto error;
+ &ad->period_time, NULL);
+ if (err < 0)
+ goto error;
cmd = "snd_pcm_hw_params";
err = snd_pcm_hw_params(ad->pcmHandle, hwparams);
- if(err < 0) goto error;
+ if (err < 0)
+ goto error;
cmd = "snd_pcm_hw_params_get_buffer_size";
err = snd_pcm_hw_params_get_buffer_size(hwparams, &alsa_buffer_size);
- if(err < 0) goto error;
+ if (err < 0)
+ goto error;
cmd = "snd_pcm_hw_params_get_period_size";
err = snd_pcm_hw_params_get_period_size(hwparams, &alsa_period_size,
- NULL);
- if(err < 0) goto error;
+ NULL);
+ if (err < 0)
+ goto error;
ad->canPause = snd_pcm_hw_params_can_pause(hwparams);
ad->canResume = snd_pcm_hw_params_can_resume(hwparams);
@@ -251,68 +262,74 @@ static int alsa_openDevice(AudioOutput * audioOutput)
cmd = "snd_pcm_sw_params_current";
err = snd_pcm_sw_params_current(ad->pcmHandle, swparams);
- if(err < 0) goto error;
+ if (err < 0)
+ goto error;
cmd = "snd_pcm_sw_params_set_start_threshold";
err = snd_pcm_sw_params_set_start_threshold(ad->pcmHandle, swparams,
- alsa_buffer_size - alsa_period_size);
- if(err < 0) goto error;
+ alsa_buffer_size -
+ alsa_period_size);
+ if (err < 0)
+ goto error;
cmd = "snd_pcm_sw_params_set_avail_min";
- err = snd_pcm_sw_params_set_avail_min(ad->pcmHandle, swparams,
- alsa_period_size);
- if(err < 0) goto error;
+ err = snd_pcm_sw_params_set_avail_min(ad->pcmHandle, swparams,
+ alsa_period_size);
+ if (err < 0)
+ goto error;
cmd = "snd_pcm_sw_params_set_xfer_align";
err = snd_pcm_sw_params_set_xfer_align(ad->pcmHandle, swparams, 1);
- if(err < 0) goto error;
+ if (err < 0)
+ goto error;
cmd = "snd_pcm_sw_params";
err = snd_pcm_sw_params(ad->pcmHandle, swparams);
- if(err < 0) goto error;
-
- ad->sampleSize = (audioFormat->bits/8)*audioFormat->channels;
+ if (err < 0)
+ goto error;
+
+ ad->sampleSize = (audioFormat->bits / 8) * audioFormat->channels;
audioOutput->open = 1;
DEBUG("alsa device \"%s\" will be playing %i bit, %i channel audio at "
- "%i Hz\n", ad->device, (int)audioFormat->bits,
- channels, sampleRate);
+ "%i Hz\n", ad->device, (int)audioFormat->bits,
+ channels, sampleRate);
return 0;
-error:
- if(cmd) {
- ERROR("Error opening alsa device \"%s\" (%s): %s\n",
- ad->device, cmd, snd_strerror(-err));
- }
- else {
- ERROR("Error opening alsa device \"%s\": %s\n", ad->device,
- snd_strerror(-err));
+ error:
+ if (cmd) {
+ ERROR("Error opening alsa device \"%s\" (%s): %s\n",
+ ad->device, cmd, snd_strerror(-err));
+ } else {
+ ERROR("Error opening alsa device \"%s\": %s\n", ad->device,
+ snd_strerror(-err));
}
-fail:
- if(ad->pcmHandle) snd_pcm_close(ad->pcmHandle);
+ fail:
+ if (ad->pcmHandle)
+ snd_pcm_close(ad->pcmHandle);
ad->pcmHandle = NULL;
audioOutput->open = 0;
return -1;
}
-static int alsa_errorRecovery(AlsaData * ad, int err) {
- if(err == -EPIPE) {
+static int alsa_errorRecovery(AlsaData * ad, int err)
+{
+ if (err == -EPIPE) {
DEBUG("Underrun on alsa device \"%s\"\n", ad->device);
- }
- else if(err == -ESTRPIPE) {
+ } else if (err == -ESTRPIPE) {
DEBUG("alsa device \"%s\" was suspended\n", ad->device);
}
- switch(snd_pcm_state(ad->pcmHandle)) {
+ switch (snd_pcm_state(ad->pcmHandle)) {
case SND_PCM_STATE_PAUSED:
err = snd_pcm_pause(ad->pcmHandle, /* disable */ 0);
break;
case SND_PCM_STATE_SUSPENDED:
err = ad->canResume ?
- snd_pcm_resume(ad->pcmHandle) :
- snd_pcm_prepare(ad->pcmHandle);
+ snd_pcm_resume(ad->pcmHandle) :
+ snd_pcm_prepare(ad->pcmHandle);
break;
case SND_PCM_STATE_SETUP:
case SND_PCM_STATE_XRUN:
@@ -331,16 +348,18 @@ static int alsa_errorRecovery(AlsaData * ad, int err) {
return err;
}
-static void alsa_dropBufferedAudio(AudioOutput * audioOutput) {
- AlsaData * ad = audioOutput->data;
+static void alsa_dropBufferedAudio(AudioOutput * audioOutput)
+{
+ AlsaData *ad = audioOutput->data;
- alsa_errorRecovery( ad, snd_pcm_drop(ad->pcmHandle) );
+ alsa_errorRecovery(ad, snd_pcm_drop(ad->pcmHandle));
}
-static void alsa_closeDevice(AudioOutput * audioOutput) {
- AlsaData * ad = audioOutput->data;
+static void alsa_closeDevice(AudioOutput * audioOutput)
+{
+ AlsaData *ad = audioOutput->data;
- if(ad->pcmHandle) {
+ if (ad->pcmHandle) {
snd_pcm_drain(ad->pcmHandle);
snd_pcm_close(ad->pcmHandle);
ad->pcmHandle = NULL;
@@ -349,10 +368,9 @@ static void alsa_closeDevice(AudioOutput * audioOutput) {
audioOutput->open = 0;
}
-static int alsa_playAudio(AudioOutput * audioOutput, char * playChunk,
- int size)
+static int alsa_playAudio(AudioOutput * audioOutput, char *playChunk, int size)
{
- AlsaData * ad = audioOutput->data;
+ AlsaData *ad = audioOutput->data;
int ret;
size /= ad->sampleSize;
@@ -360,13 +378,14 @@ static int alsa_playAudio(AudioOutput * audioOutput, char * playChunk,
while (size > 0) {
ret = ad->writei(ad->pcmHandle, playChunk, size);
- if(ret == -EAGAIN || ret == -EINTR) continue;
-
- if(ret < 0) {
- if( alsa_errorRecovery(ad, ret) < 0) {
+ if (ret == -EAGAIN || ret == -EINTR)
+ continue;
+
+ if (ret < 0) {
+ if (alsa_errorRecovery(ad, ret) < 0) {
ERROR("closing alsa device \"%s\" due to write "
- "error: %s\n", ad->device,
- snd_strerror(-errno));
+ "error: %s\n", ad->device,
+ snd_strerror(-errno));
alsa_closeDevice(audioOutput);
return -1;
}
@@ -380,8 +399,7 @@ static int alsa_playAudio(AudioOutput * audioOutput, char * playChunk,
return 0;
}
-AudioOutputPlugin alsaPlugin =
-{
+AudioOutputPlugin alsaPlugin = {
"alsa",
alsa_testDefault,
alsa_initDriver,
@@ -390,11 +408,10 @@ AudioOutputPlugin alsaPlugin =
alsa_playAudio,
alsa_dropBufferedAudio,
alsa_closeDevice,
- NULL, /* sendMetadataFunc */
+ NULL, /* sendMetadataFunc */
};
-#else /* HAVE ALSA */
+#else /* HAVE ALSA */
DISABLED_AUDIO_OUTPUT_PLUGIN(alsaPlugin)
-
-#endif /* HAVE_ALSA */
+#endif /* HAVE_ALSA */