Add play/pause audio support.

This commit is contained in:
Johns 2012-02-12 20:14:43 +01:00
parent 24a065e5de
commit 0a2a221fa9
6 changed files with 133 additions and 32 deletions

View File

@ -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.

2
Todo
View File

@ -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.

105
audio.c
View File

@ -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;
}
/**

View File

@ -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

View File

@ -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();
}
/**

View File

@ -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);
}
// ----------------------------------------------------------------------------
/**