diff options
author | Christian Gmeiner <christian.gmeiner@gmail.com> | 2009-02-25 09:06:44 +0100 |
---|---|---|
committer | Christian Gmeiner <christian.gmeiner@gmail.com> | 2009-02-25 09:06:44 +0100 |
commit | e900f1d40ca151d6c5a7aa976971325d13416f02 (patch) | |
tree | aff1084f50beb2050f6e569570b5d0e3bfe112ad | |
parent | 48856f12734897c27f6dc2429bc259707d65d0f9 (diff) | |
download | vdr-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-- | Makefile | 9 | ||||
-rw-r--r-- | dxr3audio-alsa.c | 184 | ||||
-rw-r--r-- | dxr3audio-alsa.h | 49 | ||||
-rw-r--r-- | dxr3audio.h | 3 | ||||
-rw-r--r-- | dxr3device.c | 2 |
5 files changed, 243 insertions, 4 deletions
@@ -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); } |