From 0a2a221fa93bd4177b2a21d2499cef68b47424bd Mon Sep 17 00:00:00 2001 From: Johns Date: Sun, 12 Feb 2012 20:14:43 +0100 Subject: [PATCH] Add play/pause audio support. --- ChangeLog | 1 + Todo | 2 +- audio.c | 105 ++++++++++++++++++++++++++++++++++++++++++++--- audio.h | 4 +- softhddev.c | 24 +++++------ softhddevice.cpp | 29 ++++++++----- 6 files changed, 133 insertions(+), 32 deletions(-) diff --git a/ChangeLog b/ChangeLog index 09819e1..a2f6411 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ User johns Date: + Add play/pause audio support. Fix bug: audible glitch when switching AC-3 pass-through <-> none. Fix bug: mpeg stills not displayed. Detect audio stream type only after stream switch. diff --git a/Todo b/Todo index 66dbec5..ae6a387 100644 --- a/Todo +++ b/Todo @@ -80,7 +80,7 @@ audio: Combine alsa+oss ringbuffer code. Make alsa thread/polled and oss thread/polled output module runtime selectable. - software volume support + software volume support (could be done with asound.conf) add pause support for replay pause Mute should do a real mute and not only set volume to zero. Starting suspended and muted, didn't register the mute. diff --git a/audio.c b/audio.c index a65d63d..5d470f6 100644 --- a/audio.c +++ b/audio.c @@ -113,6 +113,8 @@ typedef struct _audio_module_ uint64_t(*GetDelay) (void); ///< get current audio delay void (*SetVolume) (int); ///< set output volume int (*Setup) (int *, int *, int); ///< setup channels, samplerate + void (*Play) (void); ///< play + void (*Pause) (void); ///< pause void (*Init) (void); ///< initialize audio output module void (*Exit) (void); ///< cleanup audio output module } AudioModule; @@ -134,7 +136,7 @@ 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 -static int AudioPaused; ///< audio paused +static volatile char AudioPaused; ///< audio paused static unsigned AudioSampleRate; ///< audio sample rate in hz static unsigned AudioChannels; ///< number of audio channels static const int AudioBytesProSample = 2; ///< number of bytes per sample @@ -567,7 +569,6 @@ static void AlsaEnqueue(const void *samples, int count) state = snd_pcm_state(AlsaPCMHandle); Debug(3, "audio/alsa: state %s\n", snd_pcm_state_name(state)); Debug(3, "audio/alsa: unpaused\n"); - AudioPaused = 0; } } // Update audio clock @@ -626,6 +627,9 @@ static void AlsaThread(void) AlsaFlushBuffer = 0; break; } + if (AudioPaused) { + break; + } // wait for space in kernel buffers if ((err = snd_pcm_wait(AlsaPCMHandle, 100)) < 0) { Error(_("audio/alsa: wait underrun error?\n")); @@ -637,7 +641,7 @@ static void AlsaThread(void) usleep(100 * 1000); continue; } - if (AlsaFlushBuffer) { + if (AlsaFlushBuffer || AudioPaused) { continue; } if ((err = AlsaPlayRingbuffer())) { // empty / error @@ -1111,6 +1115,47 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3) return ret; } +/** +** Play audio. +*/ +void AlsaPlay(void) +{ + int err; + + if (AlsaCanPause) { + if ((err = snd_pcm_pause(AlsaPCMHandle, 0))) { + Error(_("audio/alsa: snd_pcm_pause(): %s\n"), snd_strerror(err)); + } + } else { + if ((err = snd_pcm_prepare(AlsaPCMHandle)) < 0) { + Error(_("audio/alsa: snd_pcm_prepare(): %s\n"), snd_strerror(err)); + } + } +#ifdef DEBUG + if (snd_pcm_state(AlsaPCMHandle) == SND_PCM_STATE_PAUSED) { + Error(_("audio/alsa: still paused\n")); + } +#endif +} + +/** +** Pause audio. +*/ +void AlsaPause(void) +{ + int err; + + if (AlsaCanPause) { + if ((err = snd_pcm_pause(AlsaPCMHandle, 1))) { + Error(_("snd_pcm_pause(): %s\n"), snd_strerror(err)); + } + } else { + if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) { + Error(_("snd_pcm_drop(): %s\n"), snd_strerror(err)); + } + } +} + /** ** Empty log callback */ @@ -1179,6 +1224,8 @@ static const AudioModule AlsaModule = { .GetDelay = AlsaGetDelay, .SetVolume = AlsaSetVolume, .Setup = AlsaSetup, + .Play = AlsaPlay, + .Pause = AlsaPause, .Init = AlsaInit, .Exit = AlsaExit, }; @@ -1388,6 +1435,9 @@ static void OssThread(void) OssFlushBuffer = 0; break; } + if (AudioPaused) { + break; + } fds[0].fd = OssPcmFildes; fds[0].events = POLLOUT | POLLERR; @@ -1399,7 +1449,7 @@ static void OssThread(void) continue; } - if (OssFlushBuffer) { + if (OssFlushBuffer || AudioPaused) { continue; } @@ -1740,6 +1790,20 @@ static int OssSetup(int *freq, int *channels, int use_ac3) return ret; } +/** +** Play audio. +*/ +void OssPlay(void) +{ +} + +/** +** Pause audio. +*/ +void OssPause(void) +{ +} + /** ** Initialize OSS audio output module. */ @@ -1785,6 +1849,8 @@ static const AudioModule OssModule = { .GetDelay = OssGetDelay, .SetVolume = OssSetVolume, .Setup = OssSetup, + .Play = OssPlay, + .Pause = OssPause, .Init = OssInit, .Exit = OssExit, }; @@ -1868,6 +1934,8 @@ static const AudioModule NoopModule = { .GetDelay = NoopGetDelay, .SetVolume = NoopSetVolume, .Setup = NoopSetup, + .Play = NoopVoid, + .Pause = NoopVoid, .Init = NoopVoid, .Exit = NoopVoid, }; @@ -2104,6 +2172,32 @@ int AudioSetup(int *freq, int *channels, int use_ac3) return AudioUsedModule->Setup(freq, channels, use_ac3); } +/** +** Play audio. +*/ +void AudioPlay(void) +{ + if (!AudioPaused) { + Warning("audio: not paused, check the code\n"); + return; + } + Debug(3, "audio: resumed\n"); + AudioPaused = 0; +} + +/** +** Pause audio. +*/ +void AudioPause(void) +{ + if (AudioPaused) { + Warning("audio: already paused, check the code\n"); + return; + } + Debug(3, "audio: paused\n"); + AudioPaused = 1; +} + /** ** Set pcm audio device. ** @@ -2207,8 +2301,7 @@ void AudioInit(void) AudioInitThread(); } #endif - - AudioPaused = 1; + AudioPaused = 0; } /** diff --git a/audio.h b/audio.h index f0dedab..677fbcf 100644 --- a/audio.h +++ b/audio.h @@ -39,8 +39,8 @@ extern int64_t AudioGetClock(); ///< get current audio clock extern void AudioSetVolume(int); ///< set volume extern int AudioSetup(int *, int *, int); ///< setup audio output -//extern void AudioPlay(void); ///< play audio -//extern void AudioPause(void); ///< pause audio +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 pass-through device diff --git a/softhddev.c b/softhddev.c index 5ce146a..882d2c1 100644 --- a/softhddev.c +++ b/softhddev.c @@ -66,7 +66,7 @@ static char ConfigStartX11Server; ///< flag start the x11 server static pthread_mutex_t SuspendLockMutex; ///< suspend lock mutex -static volatile char VideoFreezed; ///< video freezed +static volatile char StreamFreezed; ///< stream freezed ////////////////////////////////////////////////////////////////////////////// // Audio @@ -211,7 +211,7 @@ int PlayAudio(const uint8_t * data, int size, uint8_t id) // channel switch: SetAudioChannelDevice: SetDigitalAudioDevice: - if (VideoFreezed) { // video freezed + if (StreamFreezed) { // stream freezed return 0; } if (SkipAudio || !MyAudioDecoder) { // skip audio @@ -376,11 +376,12 @@ int PlayAudio(const uint8_t * data, int size, uint8_t id) } /** -** Mute audio device. +** Turns off audio while replaying. */ void Mute(void) { SkipAudio = 1; + AudioFlushBuffers(); //AudioSetVolume(0); } @@ -604,7 +605,7 @@ int VideoDecode(void) int saved_size; static int last_codec_id = CODEC_ID_NONE; - if (VideoFreezed) { + if (StreamFreezed) { // stream freezed return 1; } if (VideoClearBuffers) { @@ -822,7 +823,7 @@ int PlayVideo(const uint8_t * data, int size) if (SkipVideo) { // skip video return size; } - if (VideoFreezed) { // video freezed + if (StreamFreezed) { // stream freezed return 0; } if (NewVideoStream) { // channel switched @@ -1123,9 +1124,7 @@ void SetPlayMode(void) NewAudioStream = 1; } } - VideoFreezed = 0; - // done by Resume: SkipAudio = 0; - // done by Resume: SkipVideo = 0; + StreamFreezed = 0; } /** @@ -1150,9 +1149,9 @@ void Clear(void) */ void Play(void) { - VideoFreezed = 0; + StreamFreezed = 0; SkipAudio = 0; - // FIXME: restart audio + AudioPlay(); } /** @@ -1160,9 +1159,8 @@ void Play(void) */ void Freeze(void) { - VideoFreezed = 1; - // FIXME: freeze audio - AudioFlushBuffers(); + StreamFreezed = 1; + AudioPause(); } /** diff --git a/softhddevice.cpp b/softhddevice.cpp index 9854d97..ad9d0cb 100644 --- a/softhddevice.cpp +++ b/softhddevice.cpp @@ -657,7 +657,6 @@ class cSoftHdDevice:public cDevice virtual void Play(void); virtual void Freeze(void); virtual void Mute(void); - virtual void SetVolumeDevice(int); virtual void StillPicture(const uchar *, int); virtual bool Poll(cPoller &, int = 0); virtual bool Flush(int = 0); @@ -675,6 +674,7 @@ class cSoftHdDevice:public cDevice virtual int GetAudioChannelDevice(void); virtual void SetDigitalAudioDevice(bool); virtual void SetAudioTrackDevice(eTrackType); + virtual void SetVolumeDevice(int); virtual int PlayAudio(const uchar *, int, uchar); // Image Grab facilities @@ -700,6 +700,7 @@ cSoftHdDevice::cSoftHdDevice(void) #if 0 spuDecoder = NULL; #endif + SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat)); } cSoftHdDevice::~cSoftHdDevice(void) @@ -826,6 +827,9 @@ void cSoftHdDevice::Freeze(void) ::Freeze(); } +/** +** Turns off audio while replaying. +*/ void cSoftHdDevice::Mute(void) { dsyslog("[softhddev]%s:\n", __FUNCTION__); @@ -834,13 +838,6 @@ void cSoftHdDevice::Mute(void) ::Mute(); } -void cSoftHdDevice::SetVolumeDevice(int volume) -{ - dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume); - - ::SetVolumeDevice(volume); -} - /** ** Display the given I-frame as a still picture. */ @@ -891,8 +888,8 @@ bool cSoftHdDevice::Flush(int timeout_ms) ** ** @note FIXME: this function isn't called on the initial channel */ -void cSoftHdDevice:: SetVideoDisplayFormat(eVideoDisplayFormat - video_display_format) +void cSoftHdDevice::SetVideoDisplayFormat( + eVideoDisplayFormat video_display_format) { static int last = -1; @@ -965,6 +962,18 @@ int cSoftHdDevice::GetAudioChannelDevice(void) return 0; } +/** +** Sets the audio volume on this device (Volume = 0...255). +** +** @param volume device volume +*/ +void cSoftHdDevice::SetVolumeDevice(int volume) +{ + dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume); + + ::SetVolumeDevice(volume); +} + // ---------------------------------------------------------------------------- /**