diff --git a/ChangeLog b/ChangeLog index 149600d..2923fcb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,10 @@ User johns 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. Search audio sync inside PES packets, for insane dvb streams. Use only the needed number of surfaces. diff --git a/README.txt b/README.txt index 8229087..7c06269 100644 --- a/README.txt +++ b/README.txt @@ -85,6 +85,8 @@ Setup: environment oss dsp device name OSS_MIXERDEV=/dev/mixer oss mixer device name + OSS_MIXER_CHANNEL=pcm + oss mixer channel name Setup: /etc/vdr/setup.conf ------ diff --git a/Todo b/Todo index 7a2d69b..e6570b0 100644 --- a/Todo +++ b/Todo @@ -68,6 +68,8 @@ audio/alsa: CodecAudioOpen can fail "can't open audio codec" and does Fatal exit. audio/oss: + alsa oss emulation mixer "pcm" not working + ring buffer overflow with alsa oss emulation playback of recording play back is too fast diff --git a/audio.c b/audio.c index 40f684e..b618250 100644 --- a/audio.c +++ b/audio.c @@ -96,9 +96,9 @@ // Variables //---------------------------------------------------------------------------- -static const char *AudioPCMDevice; ///< alsa PCM device name -static const char *AudioMixerDevice; ///< alsa mixer device name -static const char *AudioMixerChannel; ///< alsa mixer channel name +static const char *AudioPCMDevice; ///< alsa/oss PCM 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 static int AudioPaused; ///< audio paused static unsigned AudioSampleRate; ///< audio sample rate in hz @@ -635,7 +635,7 @@ static void AlsaInitMixer(void) AlsaMixer = alsa_mixer; AlsaMixerElem = alsa_mixer_elem; } 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); // min 333ms - if (AlsaStartThreshold < (*freq * *channels * 2U) / 3) { - AlsaStartThreshold = (*freq * *channels * 2U) / 3; + if (AlsaStartThreshold < (*freq * *channels * AudioBytesProSample) / 3U) { + 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)); return ret; @@ -926,6 +930,7 @@ static void AlsaExit(void) static int OssPcmFildes = -1; ///< pcm file descriptor static int OssMixerFildes = -1; ///< mixer file descriptor +static int OssMixerChannel; ///< mixer channel index static RingBuffer *OssRingBuffer; ///< audio ring buffer 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 bi.bytes = n; } - if (!bi.bytes) { // full or buffer empty - break; + if (bi.bytes <= 0) { // full or buffer empty + break; // bi.bytes could become negative! } n = write(OssPcmFildes, p, bi.bytes); @@ -1076,7 +1081,7 @@ static void OssInitPCM(void) } } 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)); return; } @@ -1084,6 +1089,85 @@ static void OssInitPCM(void) 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 //---------------------------------------------------------------------------- @@ -1120,8 +1204,10 @@ static uint64_t OssGetDelay(void) / (AudioSampleRate * AudioChannels * AudioBytesProSample); pts += ((uint64_t) RingBufferUsedBytes(OssRingBuffer) * 90 * 1000) / (AudioSampleRate * AudioChannels * AudioBytesProSample); - Debug(4, "audio/oss: hw+sw delay %zd %" PRId64 " ms\n", - RingBufferUsedBytes(OssRingBuffer), pts / 90); + if (pts > 600 * 90) { + Debug(4, "audio/oss: hw+sw delay %zd %" PRId64 " ms\n", + RingBufferUsedBytes(OssRingBuffer), pts / 90); + } return pts; } @@ -1211,7 +1297,7 @@ static int OssSetup(int *freq, int *channels) Error(_("audio/oss: ioctl(SNDCTL_DSP_GETOSPACE): %s\n"), strerror(errno)); } else { - Info(_("audio/oss: %d bytes buffered\n"), bi.bytes); + Debug(3, "audio/oss: %d bytes buffered\n", bi.bytes); } tmp = -1; @@ -1226,8 +1312,16 @@ static int OssSetup(int *freq, int *channels) } // start when enough bytes for initial write 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)); } @@ -1242,7 +1336,7 @@ static void OssInit(void) OssRingBuffer = RingBufferNew(48000 * 8 * 2); // ~1s 8ch 16bit OssInitPCM(); - // OssInitMixer(); + OssInitMixer(); } /** @@ -1429,7 +1523,7 @@ void AudioSetVolume(int volume) AlsaSetVolume(volume); #endif #ifdef USE_OSS -#warning "AudioSetVolume not written" + OssSetVolume(volume); #endif (void)volume; }