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 User johns
Date: Date:
Add play/pause audio support.
Fix bug: audible glitch when switching AC-3 pass-through <-> none. Fix bug: audible glitch when switching AC-3 pass-through <-> none.
Fix bug: mpeg stills not displayed. Fix bug: mpeg stills not displayed.
Detect audio stream type only after stream switch. Detect audio stream type only after stream switch.

2
Todo
View File

@ -80,7 +80,7 @@ audio:
Combine alsa+oss ringbuffer code. Combine alsa+oss ringbuffer code.
Make alsa thread/polled and oss thread/polled output module runtime Make alsa thread/polled and oss thread/polled output module runtime
selectable. selectable.
software volume support software volume support (could be done with asound.conf)
add pause support for replay pause add pause support for replay pause
Mute should do a real mute and not only set volume to zero. Mute should do a real mute and not only set volume to zero.
Starting suspended and muted, didn't register the mute. 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 uint64_t(*GetDelay) (void); ///< get current audio delay
void (*SetVolume) (int); ///< set output volume void (*SetVolume) (int); ///< set output volume
int (*Setup) (int *, int *, int); ///< setup channels, samplerate int (*Setup) (int *, int *, int); ///< setup channels, samplerate
void (*Play) (void); ///< play
void (*Pause) (void); ///< pause
void (*Init) (void); ///< initialize audio output module void (*Init) (void); ///< initialize audio output module
void (*Exit) (void); ///< cleanup audio output module void (*Exit) (void); ///< cleanup audio output module
} AudioModule; } 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 *AudioMixerDevice; ///< alsa/OSS mixer device name
static const char *AudioMixerChannel; ///< alsa/OSS 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 volatile char AudioPaused; ///< audio paused
static unsigned AudioSampleRate; ///< audio sample rate in hz static unsigned AudioSampleRate; ///< audio sample rate in hz
static unsigned AudioChannels; ///< number of audio channels static unsigned AudioChannels; ///< number of audio channels
static const int AudioBytesProSample = 2; ///< number of bytes per sample 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); state = snd_pcm_state(AlsaPCMHandle);
Debug(3, "audio/alsa: state %s\n", snd_pcm_state_name(state)); Debug(3, "audio/alsa: state %s\n", snd_pcm_state_name(state));
Debug(3, "audio/alsa: unpaused\n"); Debug(3, "audio/alsa: unpaused\n");
AudioPaused = 0;
} }
} }
// Update audio clock // Update audio clock
@ -626,6 +627,9 @@ static void AlsaThread(void)
AlsaFlushBuffer = 0; AlsaFlushBuffer = 0;
break; break;
} }
if (AudioPaused) {
break;
}
// wait for space in kernel buffers // wait for space in kernel buffers
if ((err = snd_pcm_wait(AlsaPCMHandle, 100)) < 0) { if ((err = snd_pcm_wait(AlsaPCMHandle, 100)) < 0) {
Error(_("audio/alsa: wait underrun error?\n")); Error(_("audio/alsa: wait underrun error?\n"));
@ -637,7 +641,7 @@ static void AlsaThread(void)
usleep(100 * 1000); usleep(100 * 1000);
continue; continue;
} }
if (AlsaFlushBuffer) { if (AlsaFlushBuffer || AudioPaused) {
continue; continue;
} }
if ((err = AlsaPlayRingbuffer())) { // empty / error if ((err = AlsaPlayRingbuffer())) { // empty / error
@ -1111,6 +1115,47 @@ static int AlsaSetup(int *freq, int *channels, int use_ac3)
return ret; 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 ** Empty log callback
*/ */
@ -1179,6 +1224,8 @@ static const AudioModule AlsaModule = {
.GetDelay = AlsaGetDelay, .GetDelay = AlsaGetDelay,
.SetVolume = AlsaSetVolume, .SetVolume = AlsaSetVolume,
.Setup = AlsaSetup, .Setup = AlsaSetup,
.Play = AlsaPlay,
.Pause = AlsaPause,
.Init = AlsaInit, .Init = AlsaInit,
.Exit = AlsaExit, .Exit = AlsaExit,
}; };
@ -1388,6 +1435,9 @@ static void OssThread(void)
OssFlushBuffer = 0; OssFlushBuffer = 0;
break; break;
} }
if (AudioPaused) {
break;
}
fds[0].fd = OssPcmFildes; fds[0].fd = OssPcmFildes;
fds[0].events = POLLOUT | POLLERR; fds[0].events = POLLOUT | POLLERR;
@ -1399,7 +1449,7 @@ static void OssThread(void)
continue; continue;
} }
if (OssFlushBuffer) { if (OssFlushBuffer || AudioPaused) {
continue; continue;
} }
@ -1740,6 +1790,20 @@ static int OssSetup(int *freq, int *channels, int use_ac3)
return ret; return ret;
} }
/**
** Play audio.
*/
void OssPlay(void)
{
}
/**
** Pause audio.
*/
void OssPause(void)
{
}
/** /**
** Initialize OSS audio output module. ** Initialize OSS audio output module.
*/ */
@ -1785,6 +1849,8 @@ static const AudioModule OssModule = {
.GetDelay = OssGetDelay, .GetDelay = OssGetDelay,
.SetVolume = OssSetVolume, .SetVolume = OssSetVolume,
.Setup = OssSetup, .Setup = OssSetup,
.Play = OssPlay,
.Pause = OssPause,
.Init = OssInit, .Init = OssInit,
.Exit = OssExit, .Exit = OssExit,
}; };
@ -1868,6 +1934,8 @@ static const AudioModule NoopModule = {
.GetDelay = NoopGetDelay, .GetDelay = NoopGetDelay,
.SetVolume = NoopSetVolume, .SetVolume = NoopSetVolume,
.Setup = NoopSetup, .Setup = NoopSetup,
.Play = NoopVoid,
.Pause = NoopVoid,
.Init = NoopVoid, .Init = NoopVoid,
.Exit = NoopVoid, .Exit = NoopVoid,
}; };
@ -2104,6 +2172,32 @@ int AudioSetup(int *freq, int *channels, int use_ac3)
return AudioUsedModule->Setup(freq, channels, 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. ** Set pcm audio device.
** **
@ -2207,8 +2301,7 @@ void AudioInit(void)
AudioInitThread(); AudioInitThread();
} }
#endif #endif
AudioPaused = 0;
AudioPaused = 1;
} }
/** /**

View File

@ -39,8 +39,8 @@ extern int64_t AudioGetClock(); ///< get current audio clock
extern void AudioSetVolume(int); ///< set volume extern void AudioSetVolume(int); ///< set volume
extern int AudioSetup(int *, int *, int); ///< setup audio output extern int AudioSetup(int *, int *, int); ///< setup audio output
//extern void AudioPlay(void); ///< play audio extern void AudioPlay(void); ///< play audio
//extern void AudioPause(void); ///< pause audio extern void AudioPause(void); ///< pause audio
extern void AudioSetDevice(const char *); ///< set PCM audio device extern void AudioSetDevice(const char *); ///< set PCM audio device
extern void AudioSetDeviceAC3(const char *); ///< set pass-through 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 pthread_mutex_t SuspendLockMutex; ///< suspend lock mutex
static volatile char VideoFreezed; ///< video freezed static volatile char StreamFreezed; ///< stream freezed
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Audio // Audio
@ -211,7 +211,7 @@ int PlayAudio(const uint8_t * data, int size, uint8_t id)
// channel switch: SetAudioChannelDevice: SetDigitalAudioDevice: // channel switch: SetAudioChannelDevice: SetDigitalAudioDevice:
if (VideoFreezed) { // video freezed if (StreamFreezed) { // stream freezed
return 0; return 0;
} }
if (SkipAudio || !MyAudioDecoder) { // skip audio 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) void Mute(void)
{ {
SkipAudio = 1; SkipAudio = 1;
AudioFlushBuffers();
//AudioSetVolume(0); //AudioSetVolume(0);
} }
@ -604,7 +605,7 @@ int VideoDecode(void)
int saved_size; int saved_size;
static int last_codec_id = CODEC_ID_NONE; static int last_codec_id = CODEC_ID_NONE;
if (VideoFreezed) { if (StreamFreezed) { // stream freezed
return 1; return 1;
} }
if (VideoClearBuffers) { if (VideoClearBuffers) {
@ -822,7 +823,7 @@ int PlayVideo(const uint8_t * data, int size)
if (SkipVideo) { // skip video if (SkipVideo) { // skip video
return size; return size;
} }
if (VideoFreezed) { // video freezed if (StreamFreezed) { // stream freezed
return 0; return 0;
} }
if (NewVideoStream) { // channel switched if (NewVideoStream) { // channel switched
@ -1123,9 +1124,7 @@ void SetPlayMode(void)
NewAudioStream = 1; NewAudioStream = 1;
} }
} }
VideoFreezed = 0; StreamFreezed = 0;
// done by Resume: SkipAudio = 0;
// done by Resume: SkipVideo = 0;
} }
/** /**
@ -1150,9 +1149,9 @@ void Clear(void)
*/ */
void Play(void) void Play(void)
{ {
VideoFreezed = 0; StreamFreezed = 0;
SkipAudio = 0; SkipAudio = 0;
// FIXME: restart audio AudioPlay();
} }
/** /**
@ -1160,9 +1159,8 @@ void Play(void)
*/ */
void Freeze(void) void Freeze(void)
{ {
VideoFreezed = 1; StreamFreezed = 1;
// FIXME: freeze audio AudioPause();
AudioFlushBuffers();
} }
/** /**

View File

@ -657,7 +657,6 @@ class cSoftHdDevice:public cDevice
virtual void Play(void); virtual void Play(void);
virtual void Freeze(void); virtual void Freeze(void);
virtual void Mute(void); virtual void Mute(void);
virtual void SetVolumeDevice(int);
virtual void StillPicture(const uchar *, int); virtual void StillPicture(const uchar *, int);
virtual bool Poll(cPoller &, int = 0); virtual bool Poll(cPoller &, int = 0);
virtual bool Flush(int = 0); virtual bool Flush(int = 0);
@ -675,6 +674,7 @@ class cSoftHdDevice:public cDevice
virtual int GetAudioChannelDevice(void); virtual int GetAudioChannelDevice(void);
virtual void SetDigitalAudioDevice(bool); virtual void SetDigitalAudioDevice(bool);
virtual void SetAudioTrackDevice(eTrackType); virtual void SetAudioTrackDevice(eTrackType);
virtual void SetVolumeDevice(int);
virtual int PlayAudio(const uchar *, int, uchar); virtual int PlayAudio(const uchar *, int, uchar);
// Image Grab facilities // Image Grab facilities
@ -700,6 +700,7 @@ cSoftHdDevice::cSoftHdDevice(void)
#if 0 #if 0
spuDecoder = NULL; spuDecoder = NULL;
#endif #endif
SetVideoDisplayFormat(eVideoDisplayFormat(Setup.VideoDisplayFormat));
} }
cSoftHdDevice::~cSoftHdDevice(void) cSoftHdDevice::~cSoftHdDevice(void)
@ -826,6 +827,9 @@ void cSoftHdDevice::Freeze(void)
::Freeze(); ::Freeze();
} }
/**
** Turns off audio while replaying.
*/
void cSoftHdDevice::Mute(void) void cSoftHdDevice::Mute(void)
{ {
dsyslog("[softhddev]%s:\n", __FUNCTION__); dsyslog("[softhddev]%s:\n", __FUNCTION__);
@ -834,13 +838,6 @@ void cSoftHdDevice::Mute(void)
::Mute(); ::Mute();
} }
void cSoftHdDevice::SetVolumeDevice(int volume)
{
dsyslog("[softhddev]%s: %d\n", __FUNCTION__, volume);
::SetVolumeDevice(volume);
}
/** /**
** Display the given I-frame as a still picture. ** 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 ** @note FIXME: this function isn't called on the initial channel
*/ */
void cSoftHdDevice:: SetVideoDisplayFormat(eVideoDisplayFormat void cSoftHdDevice::SetVideoDisplayFormat(
video_display_format) eVideoDisplayFormat video_display_format)
{ {
static int last = -1; static int last = -1;
@ -965,6 +962,18 @@ int cSoftHdDevice::GetAudioChannelDevice(void)
return 0; 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);
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
/** /**