Add OSS Mixer support.

This commit is contained in:
Johns 2012-01-04 16:59:48 +01:00
parent 0f449c2394
commit aba14813c0
4 changed files with 118 additions and 17 deletions

View File

@ -1,7 +1,10 @@
User johns User johns
Date: Date:
New audio driver oss. Release Version 0.1.5
Adds OSS mixer support.
Fix bug: audio new stream is not thread safe.
New audio driver OSS.
Fix bug: needed down sampling of 3/5/6 to 2 channels not reported. Fix bug: needed down sampling of 3/5/6 to 2 channels not reported.
Search audio sync inside PES packets, for insane dvb streams. Search audio sync inside PES packets, for insane dvb streams.
Use only the needed number of surfaces. Use only the needed number of surfaces.

View File

@ -85,6 +85,8 @@ Setup: environment
oss dsp device name oss dsp device name
OSS_MIXERDEV=/dev/mixer OSS_MIXERDEV=/dev/mixer
oss mixer device name oss mixer device name
OSS_MIXER_CHANNEL=pcm
oss mixer channel name
Setup: /etc/vdr/setup.conf Setup: /etc/vdr/setup.conf
------ ------

2
Todo
View File

@ -68,6 +68,8 @@ audio/alsa:
CodecAudioOpen can fail "can't open audio codec" and does Fatal exit. CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
audio/oss: audio/oss:
alsa oss emulation mixer "pcm" not working
ring buffer overflow with alsa oss emulation
playback of recording playback of recording
play back is too fast play back is too fast

126
audio.c
View File

@ -96,9 +96,9 @@
// Variables // Variables
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
static const char *AudioPCMDevice; ///< alsa PCM device name static const char *AudioPCMDevice; ///< alsa/oss PCM device name
static const char *AudioMixerDevice; ///< alsa mixer device name static const char *AudioMixerDevice; ///< alsa/oss mixer device name
static const char *AudioMixerChannel; ///< alsa 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
static int AudioPaused; ///< audio paused static int AudioPaused; ///< audio paused
static unsigned AudioSampleRate; ///< audio sample rate in hz static unsigned AudioSampleRate; ///< audio sample rate in hz
@ -635,7 +635,7 @@ static void AlsaInitMixer(void)
AlsaMixer = alsa_mixer; AlsaMixer = alsa_mixer;
AlsaMixerElem = alsa_mixer_elem; AlsaMixerElem = alsa_mixer_elem;
} else { } else {
Error(_("audio/alsa: can't open alsa mixer '%s'\n"), device); Error(_("audio/alsa: can't open mixer '%s'\n"), device);
} }
} }
@ -854,10 +854,14 @@ static int AlsaSetup(int *freq, int *channels)
AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, period_size); AlsaStartThreshold = snd_pcm_frames_to_bytes(AlsaPCMHandle, period_size);
// min 333ms // min 333ms
if (AlsaStartThreshold < (*freq * *channels * 2U) / 3) { if (AlsaStartThreshold < (*freq * *channels * AudioBytesProSample) / 3U) {
AlsaStartThreshold = (*freq * *channels * 2U) / 3; AlsaStartThreshold = (*freq * *channels * AudioBytesProSample) / 3U;
} }
Debug(3, "audio/alsa: delay %u ms\n", (AlsaStartThreshold * 1000) // no bigger, than the buffer
if (AlsaStartThreshold > RingBufferFreeBytes(AlsaRingBuffer)) {
AlsaStartThreshold = RingBufferFreeBytes(AlsaRingBuffer);
}
Info(_("audio/alsa: delay %u ms\n"), (AlsaStartThreshold * 1000)
/ (AudioSampleRate * AudioChannels * AudioBytesProSample)); / (AudioSampleRate * AudioChannels * AudioBytesProSample));
return ret; return ret;
@ -926,6 +930,7 @@ static void AlsaExit(void)
static int OssPcmFildes = -1; ///< pcm file descriptor static int OssPcmFildes = -1; ///< pcm file descriptor
static int OssMixerFildes = -1; ///< mixer file descriptor static int OssMixerFildes = -1; ///< mixer file descriptor
static int OssMixerChannel; ///< mixer channel index
static RingBuffer *OssRingBuffer; ///< audio ring buffer static RingBuffer *OssRingBuffer; ///< audio ring buffer
static unsigned OssStartThreshold; ///< start play, if filled static unsigned OssStartThreshold; ///< start play, if filled
@ -995,8 +1000,8 @@ static int OssPlayRingbuffer(void)
if (n < bi.bytes) { // not enough bytes in ring buffer if (n < bi.bytes) { // not enough bytes in ring buffer
bi.bytes = n; bi.bytes = n;
} }
if (!bi.bytes) { // full or buffer empty if (bi.bytes <= 0) { // full or buffer empty
break; break; // bi.bytes could become negative!
} }
n = write(OssPcmFildes, p, bi.bytes); n = write(OssPcmFildes, p, bi.bytes);
@ -1076,7 +1081,7 @@ static void OssInitPCM(void)
} }
} }
if ((fildes = open(device, O_WRONLY)) < 0) { if ((fildes = open(device, O_WRONLY)) < 0) {
Error(_("audio/oss: can't open device '%s': %s\n"), device, Error(_("audio/oss: can't open dsp device '%s': %s\n"), device,
strerror(errno)); strerror(errno));
return; return;
} }
@ -1084,6 +1089,85 @@ static void OssInitPCM(void)
OssPcmFildes = fildes; OssPcmFildes = fildes;
} }
//----------------------------------------------------------------------------
// OSS Mixer
//----------------------------------------------------------------------------
/**
** Set oss mixer volume (0-100)
**
** @param volume volume (0 .. 100)
*/
static void OssSetVolume(int volume)
{
int v;
if (OssMixerFildes != -1) {
v = (volume * 255) / 100;
v &= 0xff;
v = (v << 8) | v;
if (ioctl(OssMixerFildes, MIXER_WRITE(OssMixerChannel), &v) < 0) {
Error(_("audio/oss: ioctl(MIXER_WRITE): %s\n"), strerror(errno));
}
}
}
/**
** Mixer channel name table.
*/
static const char *OssMixerChannelNames[SOUND_MIXER_NRDEVICES] =
SOUND_DEVICE_NAMES;
/**
** Initialize oss mixer.
*/
static void OssInitMixer(void)
{
const char *device;
const char *channel;
int fildes;
int devmask;
int i;
if (!(device = AudioMixerDevice)) {
if (!(device = getenv("OSS_MIXERDEV"))) {
device = "/dev/mixer";
}
}
if (!(channel = AudioMixerChannel)) {
if (!(channel = getenv("OSS_MIXER_CHANNEL"))) {
channel = "pcm";
}
}
Debug(3, "audio/oss: mixer %s - %s open\n", device, channel);
if ((fildes = open(device, O_RDWR)) < 0) {
Error(_("audio/oss: can't open mixer device '%s': %s\n"), device,
strerror(errno));
return;
}
// search channel name
if (ioctl(fildes, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) {
Error(_("audio/oss: ioctl(SOUND_MIXER_READ_DEVMASK): %s\n"),
strerror(errno));
close(fildes);
return;
}
for (i = 0; i < SOUND_MIXER_NRDEVICES; ++i) {
if (!strcasecmp(OssMixerChannelNames[i], channel)) {
if (devmask & (1 << i)) {
OssMixerFildes = fildes;
OssMixerChannel = i;
return;
}
Error(_("audio/oss: channel '%s' not supported\n"), channel);
break;
}
}
Error(_("audio/oss: channel '%s' not found\n"), channel);
close(fildes);
}
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
// OSS API // OSS API
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
@ -1120,8 +1204,10 @@ static uint64_t OssGetDelay(void)
/ (AudioSampleRate * AudioChannels * AudioBytesProSample); / (AudioSampleRate * AudioChannels * AudioBytesProSample);
pts += ((uint64_t) RingBufferUsedBytes(OssRingBuffer) * 90 * 1000) pts += ((uint64_t) RingBufferUsedBytes(OssRingBuffer) * 90 * 1000)
/ (AudioSampleRate * AudioChannels * AudioBytesProSample); / (AudioSampleRate * AudioChannels * AudioBytesProSample);
Debug(4, "audio/oss: hw+sw delay %zd %" PRId64 " ms\n", if (pts > 600 * 90) {
RingBufferUsedBytes(OssRingBuffer), pts / 90); Debug(4, "audio/oss: hw+sw delay %zd %" PRId64 " ms\n",
RingBufferUsedBytes(OssRingBuffer), pts / 90);
}
return pts; return pts;
} }
@ -1211,7 +1297,7 @@ static int OssSetup(int *freq, int *channels)
Error(_("audio/oss: ioctl(SNDCTL_DSP_GETOSPACE): %s\n"), Error(_("audio/oss: ioctl(SNDCTL_DSP_GETOSPACE): %s\n"),
strerror(errno)); strerror(errno));
} else { } else {
Info(_("audio/oss: %d bytes buffered\n"), bi.bytes); Debug(3, "audio/oss: %d bytes buffered\n", bi.bytes);
} }
tmp = -1; tmp = -1;
@ -1226,8 +1312,16 @@ static int OssSetup(int *freq, int *channels)
} }
// start when enough bytes for initial write // start when enough bytes for initial write
OssStartThreshold = bi.bytes + tmp; OssStartThreshold = bi.bytes + tmp;
// min 333ms
if (OssStartThreshold < (*freq * *channels * AudioBytesProSample) / 3U) {
OssStartThreshold = (*freq * *channels * AudioBytesProSample) / 3U;
}
// no bigger, than the buffer
if (OssStartThreshold > RingBufferFreeBytes(OssRingBuffer)) {
OssStartThreshold = RingBufferFreeBytes(OssRingBuffer);
}
Debug(3, "audio/alsa: delay %u ms\n", (OssStartThreshold * 1000) Info(_("audio/oss: delay %u ms\n"), (OssStartThreshold * 1000)
/ (AudioSampleRate * AudioChannels * AudioBytesProSample)); / (AudioSampleRate * AudioChannels * AudioBytesProSample));
} }
@ -1242,7 +1336,7 @@ static void OssInit(void)
OssRingBuffer = RingBufferNew(48000 * 8 * 2); // ~1s 8ch 16bit OssRingBuffer = RingBufferNew(48000 * 8 * 2); // ~1s 8ch 16bit
OssInitPCM(); OssInitPCM();
// OssInitMixer(); OssInitMixer();
} }
/** /**
@ -1429,7 +1523,7 @@ void AudioSetVolume(int volume)
AlsaSetVolume(volume); AlsaSetVolume(volume);
#endif #endif
#ifdef USE_OSS #ifdef USE_OSS
#warning "AudioSetVolume not written" OssSetVolume(volume);
#endif #endif
(void)volume; (void)volume;
} }