summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Gmeiner <christian.gmeiner@gmail.com>2009-02-25 09:06:44 +0100
committerChristian Gmeiner <christian.gmeiner@gmail.com>2009-02-25 09:06:44 +0100
commite900f1d40ca151d6c5a7aa976971325d13416f02 (patch)
treeaff1084f50beb2050f6e569570b5d0e3bfe112ad
parent48856f12734897c27f6dc2429bc259707d65d0f9 (diff)
downloadvdr-plugin-dxr3-e900f1d40ca151d6c5a7aa976971325d13416f02.tar.gz
vdr-plugin-dxr3-e900f1d40ca151d6c5a7aa976971325d13416f02.tar.bz2
working alsa support
At the moment alsa support is disabled, but it is working (with some problems)
-rw-r--r--Makefile9
-rw-r--r--dxr3audio-alsa.c184
-rw-r--r--dxr3audio-alsa.h49
-rw-r--r--dxr3audio.h3
-rw-r--r--dxr3device.c2
5 files changed, 243 insertions, 4 deletions
diff --git a/Makefile b/Makefile
index c695108..9a19a21 100644
--- a/Makefile
+++ b/Makefile
@@ -32,6 +32,9 @@ FFMPEG_INC = $(shell pkg-config --cflags-only-I libavcodec)
# as is if FFmpeg was installed properly and pkg-config is available.
FFMPEG_LIBS = $(shell pkg-config --libs libavcodec)
+ALSA_INC = $(shell pkg-config --cflags-only-I alsa)
+ALSA_LIBS = $(shell pkg-config --libs alsa)
+
# Usually something like -I/path/to/em8300/include,should work as is (empty)
# if em8300 headers were installed properly.
EM8300_INC =
@@ -51,8 +54,8 @@ PACKAGE = $(shell echo vdr-$(ARCHIVE) | sed -e 's/git$$/git'`date +%Y%m%d`/)
### Includes and Defines (add further entries here):
-INCLUDES += -I$(VDRDIR)/include $(FFMPEG_INC) $(EM8300_INC)
-LIBS = $(FFMPEG_LIBS)
+INCLUDES += -I$(VDRDIR)/include $(FFMPEG_INC) $(EM8300_INC) $(ALSA_INC)
+LIBS = $(FFMPEG_LIBS) $(ALSA_LIBS)
DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
DEFINES += -D_GNU_SOURCE
@@ -72,7 +75,7 @@ OBJS = $(PLUGIN).o dxr3multichannelaudio.o dxr3sysclock.o dxr3colormanager.o \
dxr3pesframe.o dxr3demuxdevice.o dxr3configdata.o dxr3ffmpeg.o \
dxr3interface_spu_encoder.o dxr3interface.o dxr3device.o \
dxr3output.o dxr3output-video.o dxr3output-audio.o dxr3osd.o dxr3spudecoder.o \
- dxr3audio-oss.o
+ dxr3audio-oss.o dxr3audio-alsa.o
### Default target:
diff --git a/dxr3audio-alsa.c b/dxr3audio-alsa.c
new file mode 100644
index 0000000..c0350de
--- /dev/null
+++ b/dxr3audio-alsa.c
@@ -0,0 +1,184 @@
+/*
+ *
+ * Copyright (C) 2009 Christian Gmeiner
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <string>
+using namespace std;
+
+#include "dxr3audio-alsa.h"
+
+void cAudioAlsa::openDevice()
+{
+ string device = "default";
+ releaseDevice();
+
+ dsyslog("opening alsa device %s", device.c_str());
+ int err = snd_pcm_open(&handle, device.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
+
+ if (err < 0) {
+ esyslog("[dxr3-audio-alsa] Playback open error: %s", snd_strerror(err));
+ exit(1);
+ }
+}
+
+void cAudioAlsa::releaseDevice()
+{
+ if (handle) {
+ snd_pcm_drain(handle);
+ snd_pcm_close(handle);
+ handle = NULL;
+ }
+}
+
+void cAudioAlsa::setup(SampleContext ctx)
+{
+ // look if ctx is different
+ if (curContext.channels == ctx.channels && curContext.samplerate == ctx.samplerate) {
+ return;
+ }
+
+ dsyslog("[dxr3-audio-alsa] changing samplerate to %d (old %d) ", ctx.samplerate, curContext.samplerate);
+ dsyslog("[dxr3-audio-alsa] changing num of channels to %d (old %d)", ctx.channels, curContext.channels);
+
+ snd_pcm_hw_params_t* alsa_hwparams;
+ snd_pcm_hw_params_alloca(&alsa_hwparams);
+
+ int err = snd_pcm_hw_params_any(handle, alsa_hwparams);
+ if (err < 0) {
+ esyslog("[dxr3-audio-alsa] Broken config for this PCM: no configurations available");
+ exit(1);
+ }
+
+ // set access type
+ err = snd_pcm_hw_params_set_access(handle, alsa_hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (err < 0) {
+ esyslog("[dxr3-audio-alsa] Unable to set access type: %s", snd_strerror(err));
+ }
+
+ // set format
+ err = snd_pcm_hw_params_set_format(handle, alsa_hwparams, SND_PCM_FORMAT_S16_LE);
+ if (err < 0) {
+ esyslog("[dxr3-audio-alsa] Unable to set format: %s", snd_strerror(err));
+ }
+
+ // set channels
+ err = snd_pcm_hw_params_set_channels(handle, alsa_hwparams, ctx.channels);
+ if (err < 0) {
+ esyslog("[dxr3-audio-alsa] Unable to set channels %d: %s", ctx.channels, snd_strerror(err));
+ }
+
+ // set samplerate
+ err = snd_pcm_hw_params_set_rate_near(handle, alsa_hwparams, &ctx.samplerate, NULL);
+ if (err < 0) {
+ esyslog("[dxr3-audio-alsa] Unable to set samplerate %d: %s", ctx.samplerate, snd_strerror(err));
+ }
+
+ if (snd_pcm_state(handle) == SND_PCM_STATE_RUNNING) {
+ if ((err = snd_pcm_drain(handle)) < 0) {
+ esyslog("[dxr3-audio-alsa] Cannot drain (%s); will try to set parameters anyway\n", snd_strerror(err));
+ }
+ }
+
+ // set hardware pararmeters
+ err = snd_pcm_hw_params(handle, alsa_hwparams);
+ if (err < 0) {
+ esyslog("[dxr3-audio-alsa] Unable to set hw pararmeters: %s", snd_strerror(err));
+ }
+
+ // prepare for playback
+ err = snd_pcm_prepare(handle);
+ if (err < 0) {
+ esyslog("[dxr3-audio-alsa] Cannot prepare audio interface for use: %s", snd_strerror(err));
+ }
+
+ curContext.channels = ctx.channels;
+ curContext.samplerate = ctx.samplerate;
+
+ bytesFrame = snd_pcm_format_physical_width(SND_PCM_FORMAT_S16_LE) / 8;
+ bytesFrame *= curContext.channels;
+}
+
+void cAudioAlsa::write(uchar* data, size_t size)
+{
+ snd_pcm_uframes_t frames = size / bytesFrame;
+
+ if (frames == 0) {
+ dsyslog("[dxr3-audio-alsa] no frames");
+ return;
+ }
+
+ uchar *output_samples = data;
+ snd_pcm_sframes_t res = 0;
+
+ while (frames > 0) {
+ res = snd_pcm_writei(handle, output_samples, frames);
+
+ if (res == -EAGAIN) {
+ snd_pcm_wait(handle, 500);
+ } else if (res == -EINTR) {
+ // nothing to do
+ res = 0;
+ } else if (res == -EPIPE) {
+ Xrun();
+ } else if (res == -ESTRPIPE) {
+ // suspend
+ dsyslog("[dxr3-audio-alsa] pcm in suspend");
+ while ((res = snd_pcm_resume(handle)) == -EAGAIN) {
+ sleep(1);
+ }
+ }
+
+ if (res > 0) {
+ output_samples += res * bytesFrame;
+ frames -= res;
+ }
+ }
+}
+
+void cAudioAlsa::setAudioMode(AudioMode mode)
+{
+}
+
+void cAudioAlsa::Xrun()
+{
+ int res;
+ snd_pcm_status_alloca(&status);
+
+ dsyslog("[dxr3-audio-alsa] Xrun");
+
+ res = snd_pcm_status(handle, status);
+ if (res < 0) {
+ esyslog("[dxr3-audio-alsa]: Xrun status error: %s FATAL exiting", snd_strerror(res));
+ exit(EXIT_FAILURE);
+ }
+
+ if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN) {
+
+ res = snd_pcm_prepare(handle);
+ if (res < 0) {
+ esyslog("[dxr3-audio-alsa]: Xrun prepare error: %s FATAL exiting", snd_strerror(res));
+ exit(EXIT_FAILURE);
+ }
+ return; // ok, data should be accepted again
+ }
+
+ esyslog("[dxr3-audio-alsa]: read/write error FATAL exiting");
+ exit(-1);
+}
+
diff --git a/dxr3audio-alsa.h b/dxr3audio-alsa.h
new file mode 100644
index 0000000..7a6a337
--- /dev/null
+++ b/dxr3audio-alsa.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * Copyright (C) 2009 Christian Gmeiner
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _AUDIO_ALSA_H_
+#define _AUDIO_ALSA_H_
+
+#define ALSA_PCM_NEW_HW_PARAMS_API
+#define ALSA_PCM_NEW_SW_PARAMS_API
+#include <alsa/asoundlib.h>
+
+#include "dxr3audio.h"
+
+class cAudioAlsa : public iAudio {
+public:
+ cAudioAlsa() : iAudio(), handle(NULL), status(NULL) {}
+ ~cAudioAlsa() {}
+
+ virtual void openDevice();
+ virtual void releaseDevice();
+ virtual void setup(SampleContext ctx);
+ virtual void write(uchar* data, size_t size);
+ virtual void setAudioMode(AudioMode m);
+
+private:
+ snd_pcm_t *handle;
+ snd_pcm_status_t *status;
+ size_t bytesFrame;
+
+ void Xrun();
+};
+
+#endif /*_AUDIO_ALSA_H_*/
diff --git a/dxr3audio.h b/dxr3audio.h
index 384fff9..1f0bbda 100644
--- a/dxr3audio.h
+++ b/dxr3audio.h
@@ -21,6 +21,7 @@
#ifndef _AUDIO_H_
#define _AUDIO_H_
+#include <string.h>
#include <vdr/tools.h> // for uchar
struct SampleContext {
@@ -36,7 +37,7 @@ public:
Ac3,
};
- iAudio() : vol(0), audioChannel(0) {}
+ iAudio() : vol(0), audioChannel(0) { memset(&curContext, 0, sizeof(SampleContext)); }
virtual ~iAudio() {}
virtual void openDevice() = 0;
diff --git a/dxr3device.c b/dxr3device.c
index f744254..b612abe 100644
--- a/dxr3device.c
+++ b/dxr3device.c
@@ -28,6 +28,7 @@
#include "dxr3tools.h"
#include "dxr3osd.h"
#include "dxr3audio-oss.h"
+#include "dxr3audio-alsa.h"
// ==================================
//! constructor
@@ -42,6 +43,7 @@ cDxr3Device::cDxr3Device() : m_DemuxDevice(cDxr3Interface::Instance())
// where we will decide what kind of
// audio output system we will use.
audioOut = new cAudioOss();
+ //audioOut = new cAudioAlsa();
m_DemuxDevice.setAudio(audioOut);
}