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
Data:
Data: Sun Jan 22 11:12:57 CET 2012
Add dummy player and control for suspend mode.
Buffertime compile time configurable in ms.

View File

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

79
audio.c
View File

@ -112,7 +112,7 @@ typedef struct _audio_module_
int (*FreeBytes) (void); ///< number of bytes free in buffer
uint64_t(*GetDelay) (void); ///< get current audio delay
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 (*Exit) (void); ///< cleanup audio output module
} AudioModule;
@ -128,6 +128,7 @@ static const char *AudioModuleName; ///< which audio module to use
/// Selected audio module.
static const AudioModule *AudioUsedModule = &NoopModule;
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 *AudioMixerChannel; ///< alsa/OSS mixer channel name
static volatile char AudioRunning; ///< thread running / stopped
@ -696,18 +697,24 @@ static void AlsaThreadFlushBuffers(void)
/**
** 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;
snd_pcm_t *handle;
int err;
if (!(device = AudioPCMDevice)) {
if (!(device = getenv("ALSA_DEVICE"))) {
device = "default";
}
// &&|| hell
if (!(use_ac3 && ((device = AudioAC3Device)
|| (device = getenv("ALSA_PASSTHROUGH_DEVICE"))))
&& !(device = AudioPCMDevice) && !(device = getenv("ALSA_DEVICE"))) {
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 =
snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK)) < 0) {
@ -734,7 +741,7 @@ static void AlsaInitPCM(void)
int err;
snd_pcm_uframes_t buffer_size;
if (!(handle = AlsaOpenPCM())) {
if (!(handle = AlsaOpenPCM(0))) {
return;
}
@ -878,6 +885,7 @@ static uint64_t AlsaGetDelay(void)
**
** @param freq sample frequency
** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
**
** @retval 0 everything ok
** @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
*/
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 period_size;
@ -904,7 +912,7 @@ static int AlsaSetup(int *freq, int *channels)
handle = AlsaPCMHandle;
AlsaPCMHandle = NULL;
snd_pcm_close(handle);
if (!(handle = AlsaOpenPCM())) {
if (!(handle = AlsaOpenPCM(use_ac3))) {
return -1;
}
AlsaPCMHandle = handle;
@ -1584,6 +1592,7 @@ static uint64_t OssGetDelay(void)
**
** @param freq sample frequency
** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
**
** @retval 0 everything ok
** @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
*/
static int OssSetup(int *freq, int *channels)
static int OssSetup(int *freq, int *channels, __attribute__ ((unused))
int use_ac3)
{
int ret;
int tmp;
@ -1690,6 +1700,8 @@ static int OssSetup(int *freq, int *channels)
/**
** Initialize OSS audio output module.
**
** @param use_ac3 use ac3/pass-through device
*/
static void OssInit(void)
{
@ -1790,7 +1802,8 @@ static void NoopSetVolume( __attribute__ ((unused))
*/
static int NoopSetup( __attribute__ ((unused))
int *channels, __attribute__ ((unused))
int *freq)
int *freq, __attribute__ ((unused))
int use_ac3)
{
return -1;
}
@ -2040,6 +2053,7 @@ void AudioSetVolume(int volume)
**
** @param freq sample frequency
** @param channels number of channels
** @param use_ac3 use ac3/pass-through device
**
** @retval 0 everything ok
** @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
*/
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
if (!freq || !channels || !*freq || !*channels) {
@ -2059,9 +2074,9 @@ int AudioSetup(int *freq, int *channels)
}
#ifdef USE_AUDIORING
// FIXME: need to store possible combination and report this
return AudioRingAdd(*freq, *channels);
return AudioRingAdd(*freq, *channels, use_ac3);
#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)
{
AudioModuleName = "alsa"; // detect alsa/OSS
if (!device[0]) {
AudioModuleName = "noop";
} else if (device[0] == '/') {
AudioModuleName = "oss";
if (!AudioModuleName) {
AudioModuleName = "alsa"; // detect alsa/OSS
if (!device[0]) {
AudioModuleName = "noop";
} else if (device[0] == '/') {
AudioModuleName = "oss";
}
}
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.
**
@ -2125,7 +2162,7 @@ void AudioInit(void)
AudioUsedModule->Init();
freq = 48000;
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"));
}
#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 int64_t AudioGetClock(); ///< get current audio clock
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 AudioPause(void); ///< pause audio
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 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
**
** @returns private decoder pointer for audio/video decoder.
** @returns private decoder pointer for video decoder.
*/
VideoDecoder *CodecVideoNewDecoder(VideoHwDecoder * hw_decoder)
{
VideoDecoder *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;
return decoder;
}
/**
** Deallocate a video decoder context.
**
** @param decoder private video decoder
*/
void CodecVideoDelDecoder(VideoDecoder * decoder)
{
free(decoder);
}
/**
** Open video decoder.
**
@ -613,21 +623,29 @@ static char CodecPassthroughAC3; ///< pass ac3 through
/**
** Allocate a new audio decoder context.
**
** @param hw_decoder video hardware decoder
**
** @returns private decoder pointer for audio/video decoder.
** @returns private decoder pointer for audio decoder.
*/
AudioDecoder *CodecAudioNewDecoder(void)
{
AudioDecoder *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;
}
/**
** Deallocate an audio decoder context.
**
** @param decoder private audio decoder
*/
void CodecAudioDelDecoder(AudioDecoder * decoder)
{
free(decoder);
}
/**
** Open audio decoder.
**
@ -794,6 +812,7 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
if (audio_decoder->SampleRate != audio_ctx->sample_rate
|| audio_decoder->Channels != audio_ctx->channels) {
int err;
int isAC3;
if (audio_decoder->ReSample) {
audio_resample_close(audio_decoder->ReSample);
@ -807,16 +826,18 @@ void CodecAudioDecode(AudioDecoder * audio_decoder, const AVPacket * avpkt)
// SPDIF/HDMI passthrough
if (CodecPassthroughAC3 && audio_ctx->codec_id == CODEC_ID_AC3) {
audio_decoder->HwChannels = 2;
isAC3 = 1;
} else
#endif
{
audio_decoder->HwChannels = audio_ctx->channels;
isAC3 = 0;
}
// channels not support?
if ((err =
AudioSetup(&audio_decoder->HwSampleRate,
&audio_decoder->HwChannels))) {
&audio_decoder->HwChannels, isAC3))) {
Debug(3, "codec/audio: resample %dHz *%d -> %dHz *%d\n",
audio_ctx->sample_rate, audio_ctx->channels,
audio_decoder->HwSampleRate,

View File

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