summaryrefslogtreecommitdiff
path: root/modules/alsa/alsa.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/alsa/alsa.c')
-rw-r--r--modules/alsa/alsa.c164
1 files changed, 164 insertions, 0 deletions
diff --git a/modules/alsa/alsa.c b/modules/alsa/alsa.c
new file mode 100644
index 0000000..6ffa5a8
--- /dev/null
+++ b/modules/alsa/alsa.c
@@ -0,0 +1,164 @@
+/**
+ * @file alsa.c ALSA sound driver
+ *
+ * Copyright (C) 2010 Creytiv.com
+ */
+#define _POSIX_SOURCE 1
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <alsa/asoundlib.h>
+#include <re.h>
+#include <rem.h>
+#include <baresip.h>
+#include "alsa.h"
+
+
+/**
+ * @defgroup alsa alsa
+ *
+ * Advanced Linux Sound Architecture (ALSA) audio driver module
+ *
+ *
+ * References:
+ *
+ * http://www.alsa-project.org/main/index.php/Main_Page
+ */
+
+
+char alsa_dev[64] = "default";
+
+static struct ausrc *ausrc;
+static struct auplay *auplay;
+
+
+static inline snd_pcm_format_t audio_fmt(enum aufmt fmt)
+{
+ switch (fmt) {
+
+ default:
+ case AUFMT_S16LE: return SND_PCM_FORMAT_S16_LE;
+ case AUFMT_PCMU: return SND_PCM_FORMAT_MU_LAW;
+ case AUFMT_PCMA: return SND_PCM_FORMAT_A_LAW;
+ }
+}
+
+
+int alsa_reset(snd_pcm_t *pcm, uint32_t srate, uint32_t ch, enum aufmt fmt,
+ uint32_t num_frames)
+{
+ snd_pcm_hw_params_t *hw_params = NULL;
+ const snd_pcm_format_t pcmfmt = audio_fmt(fmt);
+ snd_pcm_uframes_t period = num_frames, bufsize = num_frames * 10;
+ int err;
+
+ err = snd_pcm_hw_params_malloc(&hw_params);
+ if (err < 0) {
+ warning("alsa: cannot allocate hw params (%s)\n",
+ snd_strerror(err));
+ goto out;
+ }
+
+ err = snd_pcm_hw_params_any(pcm, hw_params);
+ if (err < 0) {
+ warning("alsa: cannot initialize hw params (%s)\n",
+ snd_strerror(err));
+ goto out;
+ }
+
+ err = snd_pcm_hw_params_set_access(pcm, hw_params,
+ SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err < 0) {
+ warning("alsa: cannot set access type (%s)\n",
+ snd_strerror(err));
+ goto out;
+ }
+
+ err = snd_pcm_hw_params_set_format(pcm, hw_params, pcmfmt);
+ if (err < 0) {
+ warning("alsa: cannot set sample format %d (%s)\n",
+ pcmfmt, snd_strerror(err));
+ goto out;
+ }
+
+ err = snd_pcm_hw_params_set_rate(pcm, hw_params, srate, 0);
+ if (err < 0) {
+ warning("alsa: cannot set sample rate to %u Hz (%s)\n",
+ srate, snd_strerror(err));
+ goto out;
+ }
+
+ err = snd_pcm_hw_params_set_channels(pcm, hw_params, ch);
+ if (err < 0) {
+ warning("alsa: cannot set channel count to %d (%s)\n",
+ ch, snd_strerror(err));
+ goto out;
+ }
+
+ err = snd_pcm_hw_params_set_period_size_near(pcm, hw_params,
+ &period, 0);
+ if (err < 0) {
+ warning("alsa: cannot set period size to %d (%s)\n",
+ period, snd_strerror(err));
+ }
+
+ err = snd_pcm_hw_params_set_buffer_size_near(pcm, hw_params, &bufsize);
+ if (err < 0) {
+ warning("alsa: cannot set buffer size to %d (%s)\n",
+ bufsize, snd_strerror(err));
+ }
+
+ err = snd_pcm_hw_params(pcm, hw_params);
+ if (err < 0) {
+ warning("alsa: cannot set parameters (%s)\n",
+ snd_strerror(err));
+ goto out;
+ }
+
+ err = snd_pcm_prepare(pcm);
+ if (err < 0) {
+ warning("alsa: cannot prepare audio interface for use (%s)\n",
+ snd_strerror(err));
+ goto out;
+ }
+
+ err = 0;
+
+ out:
+ snd_pcm_hw_params_free(hw_params);
+
+ if (err) {
+ warning("alsa: init failed: err=%d\n", err);
+ }
+
+ return err;
+}
+
+
+static int alsa_init(void)
+{
+ int err;
+
+ err = ausrc_register(&ausrc, "alsa", alsa_src_alloc);
+ err |= auplay_register(&auplay, "alsa", alsa_play_alloc);
+
+ return err;
+}
+
+
+static int alsa_close(void)
+{
+ ausrc = mem_deref(ausrc);
+ auplay = mem_deref(auplay);
+
+ return 0;
+}
+
+
+const struct mod_export DECL_EXPORTS(alsa) = {
+ "alsa",
+ "sound",
+ alsa_init,
+ alsa_close
+};