Use different alsa device for AC3/pass-through.

This commit is contained in:
Morone 2012-01-22 16:54:22 +01:00 committed by Johns
parent 329dbc5f07
commit 970493fb23
6 changed files with 105 additions and 33 deletions

View File

@ -1,5 +1,10 @@
User Morone
Data: Sun Jan 22 16:43:23 CET 2012
Use different alsa devices for AC3/pass-through and pcm.
User johns User johns
Data: Data: Sun Jan 22 11:12:57 CET 2012
Add dummy player and control for suspend mode. Add dummy player and control for suspend mode.
Buffertime compile time configurable in ms. Buffertime compile time configurable in ms.

View File

@ -79,6 +79,8 @@ Setup: environment
only if alsa is configured only if alsa is configured
ALSA_DEVICE=default ALSA_DEVICE=default
alsa PCM device name alsa PCM device name
ALSA_AC3_DEVICE=
alsa AC3/pass-though device name
ALSA_MIXER=default ALSA_MIXER=default
alsa control device name alsa control device name
ALSA_MIXER_CHANNEL=PCM ALSA_MIXER_CHANNEL=PCM
@ -128,6 +130,8 @@ Setup: /etc/vdr/setup.conf
softhddevice.AudioPassthrough = 0 softhddevice.AudioPassthrough = 0
0 = none, 1 = AC-3 0 = none, 1 = AC-3
for AC-3 the pass-through device is used.
softhddevice.AutoCrop.Interval = 0 softhddevice.AutoCrop.Interval = 0
0 disables auto-crop 0 disables auto-crop
n each 'n' frames auto-crop is checked. n each 'n' frames auto-crop is checked.

67
audio.c
View File

@ -112,7 +112,7 @@ typedef struct _audio_module_
int (*FreeBytes) (void); ///< number of bytes free in buffer int (*FreeBytes) (void); ///< number of bytes free in buffer
uint64_t(*GetDelay) (void); ///< get current audio delay uint64_t(*GetDelay) (void); ///< get current audio delay
void (*SetVolume) (int); ///< set output volume void (*SetVolume) (int); ///< set output volume
int (*Setup) (int *, int *); ///< setup channels, samplerate int (*Setup) (int *, int *, int); ///< setup channels, samplerate
void (*Init) (void); ///< initialize audio output module void (*Init) (void); ///< initialize audio output module
void (*Exit) (void); ///< cleanup audio output module void (*Exit) (void); ///< cleanup audio output module
} AudioModule; } AudioModule;
@ -128,6 +128,7 @@ static const char *AudioModuleName; ///< which audio module to use
/// Selected audio module. /// Selected audio module.
static const AudioModule *AudioUsedModule = &NoopModule; static const AudioModule *AudioUsedModule = &NoopModule;
static const char *AudioPCMDevice; ///< alsa/OSS PCM device name static const char *AudioPCMDevice; ///< alsa/OSS PCM device name
static const char *AudioAC3Device; ///< alsa/OSS AC3 device name
static const char *AudioMixerDevice; ///< alsa/OSS mixer device name static const char *AudioMixerDevice; ///< alsa/OSS mixer device name
static const char *AudioMixerChannel; ///< alsa/OSS mixer channel name static const char *AudioMixerChannel; ///< alsa/OSS mixer channel name
static volatile char AudioRunning; ///< thread running / stopped static volatile char AudioRunning; ///< thread running / stopped
@ -696,18 +697,24 @@ static void AlsaThreadFlushBuffers(void)
/** /**
** Open alsa pcm device. ** Open alsa pcm device.
**
** @param use_ac3 use ac3/pass-through device
*/ */
static snd_pcm_t *AlsaOpenPCM(void) static snd_pcm_t *AlsaOpenPCM(int use_ac3)
{ {
const char *device; const char *device;
snd_pcm_t *handle; snd_pcm_t *handle;
int err; int err;
if (!(device = AudioPCMDevice)) { // &&|| hell
if (!(device = getenv("ALSA_DEVICE"))) { if (!(use_ac3 && ((device = AudioAC3Device)
|| (device = getenv("ALSA_PASSTHROUGH_DEVICE"))))
&& !(device = AudioPCMDevice) && !(device = getenv("ALSA_DEVICE"))) {
device = "default"; device = "default";
} }
} Debug(3, "audio/alsa: &&|| hell '%s'\n", device);
// open none blocking; if device is already used, we don't want wait
if ((err = if ((err =
snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK)) < 0) { SND_PCM_NONBLOCK)) < 0) {
@ -734,7 +741,7 @@ static void AlsaInitPCM(void)
int err; int err;
snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t buffer_size;
if (!(handle = AlsaOpenPCM())) { if (!(handle = AlsaOpenPCM(0))) {
return; return;
} }
@ -878,6 +885,7 @@ static uint64_t AlsaGetDelay(void)
** **
** @param freq sample frequency ** @param freq sample frequency
** @param channels number of channels ** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
** **
** @retval 0 everything ok ** @retval 0 everything ok
** @retval 1 didn't support frequency/channels combination ** @retval 1 didn't support frequency/channels combination
@ -885,7 +893,7 @@ static uint64_t AlsaGetDelay(void)
** **
** @todo audio changes must be queued and done when the buffer is empty ** @todo audio changes must be queued and done when the buffer is empty
*/ */
static int AlsaSetup(int *freq, int *channels) static int AlsaSetup(int *freq, int *channels, int use_ac3)
{ {
snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size; snd_pcm_uframes_t period_size;
@ -904,7 +912,7 @@ static int AlsaSetup(int *freq, int *channels)
handle = AlsaPCMHandle; handle = AlsaPCMHandle;
AlsaPCMHandle = NULL; AlsaPCMHandle = NULL;
snd_pcm_close(handle); snd_pcm_close(handle);
if (!(handle = AlsaOpenPCM())) { if (!(handle = AlsaOpenPCM(use_ac3))) {
return -1; return -1;
} }
AlsaPCMHandle = handle; AlsaPCMHandle = handle;
@ -1584,6 +1592,7 @@ static uint64_t OssGetDelay(void)
** **
** @param freq sample frequency ** @param freq sample frequency
** @param channels number of channels ** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
** **
** @retval 0 everything ok ** @retval 0 everything ok
** @retval 1 didn't support frequency/channels combination ** @retval 1 didn't support frequency/channels combination
@ -1591,7 +1600,8 @@ static uint64_t OssGetDelay(void)
** **
** @todo audio changes must be queued and done when the buffer is empty ** @todo audio changes must be queued and done when the buffer is empty
*/ */
static int OssSetup(int *freq, int *channels) static int OssSetup(int *freq, int *channels, __attribute__ ((unused))
int use_ac3)
{ {
int ret; int ret;
int tmp; int tmp;
@ -1690,6 +1700,8 @@ static int OssSetup(int *freq, int *channels)
/** /**
** Initialize OSS audio output module. ** Initialize OSS audio output module.
**
** @param use_ac3 use ac3/pass-through device
*/ */
static void OssInit(void) static void OssInit(void)
{ {
@ -1790,7 +1802,8 @@ static void NoopSetVolume( __attribute__ ((unused))
*/ */
static int NoopSetup( __attribute__ ((unused)) static int NoopSetup( __attribute__ ((unused))
int *channels, __attribute__ ((unused)) int *channels, __attribute__ ((unused))
int *freq) int *freq, __attribute__ ((unused))
int use_ac3)
{ {
return -1; return -1;
} }
@ -2040,6 +2053,7 @@ void AudioSetVolume(int volume)
** **
** @param freq sample frequency ** @param freq sample frequency
** @param channels number of channels ** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
** **
** @retval 0 everything ok ** @retval 0 everything ok
** @retval 1 didn't support frequency/channels combination ** @retval 1 didn't support frequency/channels combination
@ -2047,9 +2061,10 @@ void AudioSetVolume(int volume)
** **
** @todo audio changes must be queued and done when the buffer is empty ** @todo audio changes must be queued and done when the buffer is empty
*/ */
int AudioSetup(int *freq, int *channels) int AudioSetup(int *freq, int *channels, int use_ac3)
{ {
Debug(3, "audio: channels %d frequency %d hz\n", *channels, *freq); Debug(3, "audio: channels %d frequency %d hz %s\n", *channels, *freq,
use_ac3 ? "ac3" : "pcm");
// invalid parameter // invalid parameter
if (!freq || !channels || !*freq || !*channels) { if (!freq || !channels || !*freq || !*channels) {
@ -2059,9 +2074,9 @@ int AudioSetup(int *freq, int *channels)
} }
#ifdef USE_AUDIORING #ifdef USE_AUDIORING
// FIXME: need to store possible combination and report this // FIXME: need to store possible combination and report this
return AudioRingAdd(*freq, *channels); return AudioRingAdd(*freq, *channels, use_ac3);
#endif #endif
return AudioUsedModule->Setup(freq, channels); return AudioUsedModule->Setup(freq, channels, use_ac3);
} }
/** /**
@ -2073,15 +2088,37 @@ int AudioSetup(int *freq, int *channels)
*/ */
void AudioSetDevice(const char *device) void AudioSetDevice(const char *device)
{ {
if (!AudioModuleName) {
AudioModuleName = "alsa"; // detect alsa/OSS AudioModuleName = "alsa"; // detect alsa/OSS
if (!device[0]) { if (!device[0]) {
AudioModuleName = "noop"; AudioModuleName = "noop";
} else if (device[0] == '/') { } else if (device[0] == '/') {
AudioModuleName = "oss"; AudioModuleName = "oss";
} }
}
AudioPCMDevice = device; AudioPCMDevice = device;
} }
/**
** Set pass-through audio device.
**
** @param device name of pass-through device (fe. "hw:0,1")
**
** @note this is currently usable with alsa only.
*/
void AudioSetDeviceAC3(const char *device)
{
if (!AudioModuleName) {
AudioModuleName = "alsa"; // detect alsa/OSS
if (!device[0]) {
AudioModuleName = "noop";
} else if (device[0] == '/') {
AudioModuleName = "oss";
}
}
AudioAC3Device = device;
}
/** /**
** Initialize audio output module. ** Initialize audio output module.
** **
@ -2125,7 +2162,7 @@ void AudioInit(void)
AudioUsedModule->Init(); AudioUsedModule->Init();
freq = 48000; freq = 48000;
chan = 2; chan = 2;
if (AudioSetup(&freq, &chan)) { // set default parameters if (AudioSetup(&freq, &chan, 0)) { // set default parameters
Error(_("audio: can't do initial setup\n")); Error(_("audio: can't do initial setup\n"));
} }
#ifdef USE_AUDIO_THREAD #ifdef USE_AUDIO_THREAD

View File

@ -37,12 +37,13 @@ extern uint64_t AudioGetDelay(void); ///< get current audio delay
extern void AudioSetClock(int64_t); ///< set audio clock base extern void AudioSetClock(int64_t); ///< set audio clock base
extern int64_t AudioGetClock(); ///< get current audio clock extern int64_t AudioGetClock(); ///< get current audio clock
extern void AudioSetVolume(int); ///< set volume extern void AudioSetVolume(int); ///< set volume
extern int AudioSetup(int *, int *); ///< setup audio output extern int AudioSetup(int *, int *, int); ///< setup audio output
//extern void AudioPlay(void); ///< play audio //extern void AudioPlay(void); ///< play audio
//extern void AudioPause(void); ///< pause audio //extern void AudioPause(void); ///< pause audio
extern void AudioSetDevice(const char *); ///< set PCM audio device extern void AudioSetDevice(const char *); ///< set PCM audio device
extern void AudioSetDeviceAC3(const char *); ///< set Passthrough device
extern void AudioInit(void); ///< setup audio module extern void AudioInit(void); ///< setup audio module
extern void AudioExit(void); ///< cleanup and exit audio module extern void AudioExit(void); ///< cleanup and exit audio module

35
codec.c
View File

@ -320,20 +320,30 @@ static void Codec_draw_horiz_band(AVCodecContext * video_ctx,
** **
** @param hw_decoder video hardware decoder ** @param hw_decoder video hardware decoder
** **
** @returns private decoder pointer for audio/video decoder. ** @returns private decoder pointer for video decoder.
*/ */
VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder * hw_decoder) VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder * hw_decoder)
{ {
VideoDecoder *decoder; VideoDecoder *decoder;
if (!(decoder = calloc(1, sizeof(*decoder)))) { if (!(decoder = calloc(1, sizeof(*decoder)))) {
Fatal(_("codec: Can't allocate vodeo decoder\n")); Fatal(_("codec: can't allocate vodeo decoder\n"));
} }
decoder->HwDecoder = hw_decoder; decoder->HwDecoder = hw_decoder;
return decoder; return decoder;
} }
/**
** Deallocate a video decoder context.
**
** @param decoder private video decoder
*/
void CodecVideoDelDecoder(VideoDecoder * decoder)
{
free(decoder);
}
/** /**
** Open video decoder. ** Open video decoder.
** **
@ -613,21 +623,29 @@ static char CodecPassthroughAC3; ///< pass ac3 through
/** /**
** Allocate a new audio decoder context. ** Allocate a new audio decoder context.
** **
** @param hw_decoder video hardware decoder ** @returns private decoder pointer for audio decoder.
**
** @returns private decoder pointer for audio/video decoder.
*/ */
AudioDecoder *CodecAudioNewDecoder(void) AudioDecoder *CodecAudioNewDecoder(void)
{ {
AudioDecoder *audio_decoder; AudioDecoder *audio_decoder;
if (!(audio_decoder = calloc(1, sizeof(*audio_decoder)))) { if (!(audio_decoder = calloc(1, sizeof(*audio_decoder)))) {
Fatal(_("codec: Can't allocate audio decoder\n")); Fatal(_("codec: can't allocate audio decoder\n"));
} }
return audio_decoder; return audio_decoder;
} }
/**
** Deallocate an audio decoder context.
**
** @param decoder private audio decoder
*/
void CodecAudioDelDecoder(AudioDecoder * decoder)
{
free(decoder);
}
/** /**
** Open audio decoder. ** Open audio decoder.
** **
@ -794,6 +812,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
if (audio_decoder->SampleRate != audio_ctx->sample_rate if (audio_decoder->SampleRate != audio_ctx->sample_rate
|| audio_decoder->Channels != audio_ctx->channels) { || audio_decoder->Channels != audio_ctx->channels) {
int err; int err;
int isAC3;
if (audio_decoder->ReSample) { if (audio_decoder->ReSample) {
audio_resample_close(audio_decoder->ReSample); audio_resample_close(audio_decoder->ReSample);
@ -807,16 +826,18 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
// SPDIF/HDMI passthrough // SPDIF/HDMI passthrough
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) { if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
audio_decoder->HwChannels = 2; audio_decoder->HwChannels = 2;
isAC3 = 1;
} else } else
#endif #endif
{ {
audio_decoder->HwChannels = audio_ctx->channels; audio_decoder->HwChannels = audio_ctx->channels;
isAC3 = 0;
} }
// channels not support? // channels not support?
if ((err = if ((err =
AudioSetup(&audio_decoder->HwSampleRate, AudioSetup(&audio_decoder->HwSampleRate,
&audio_decoder->HwChannels))) { &audio_decoder->HwChannels, isAC3))) {
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n", Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
audio_ctx->sample_rate, audio_ctx->channels, audio_ctx->sample_rate, audio_ctx->channels,
audio_decoder->HwSampleRate, audio_decoder->HwSampleRate,

View File

@ -989,6 +989,7 @@ static char ConfigStartX11Server; ///< flag start the x11 server
const char *CommandLineHelp(void) const char *CommandLineHelp(void)
{ {
return " -a device\taudio device (fe. alsa: hw:0,0 oss: /dev/dsp)\n" return " -a device\taudio device (fe. alsa: hw:0,0 oss: /dev/dsp)\n"
" -p device\taudio device (alsa only) for pass-through (hw:0,1)\n"
" -d display\tdisplay of x11 server (fe. :0.0)\n" " -d display\tdisplay of x11 server (fe. :0.0)\n"
" -f\t\tstart with fullscreen window (only with window manager)\n" " -f\t\tstart with fullscreen window (only with window manager)\n"
" -g geometry\tx11 window geometry wxh+x+y\n" " -g geometry\tx11 window geometry wxh+x+y\n"
@ -1007,10 +1008,13 @@ int ProcessArgs(int argc, char *const argv[])
// Parse arguments. // Parse arguments.
// //
for (;;) { for (;;) {
switch (getopt(argc, argv, "-a:d:fg:x")) { switch (getopt(argc, argv, "-a:p:d:fg:x")) {
case 'a': // audio device case 'a': // audio device
AudioSetDevice(optarg); AudioSetDevice(optarg);
continue; continue;
case 'p': // pass-through audio device
AudioSetDeviceAC3(optarg);
continue;
case 'd': // x11 display name case 'd': // x11 display name
X11DisplayName = optarg; X11DisplayName = optarg;
continue; continue;
@ -1154,12 +1158,12 @@ void SoftHdDeviceExit(void)
if (MyVideoDecoder) { if (MyVideoDecoder) {
CodecVideoClose(MyVideoDecoder); CodecVideoClose(MyVideoDecoder);
// FIXME: CodecDelVideoDecoder(MyVideoDecoder); CodecVideoDelDecoder(MyVideoDecoder);
MyVideoDecoder = NULL; MyVideoDecoder = NULL;
} }
if (MyAudioDecoder) { if (MyAudioDecoder) {
CodecAudioClose(MyAudioDecoder); CodecAudioClose(MyAudioDecoder);
// FIXME: CodecDelAudioDecoder(MyAudioDecoder); CodecAudioDelDecoder(MyAudioDecoder);
MyAudioDecoder = NULL; MyAudioDecoder = NULL;
} }