mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Add play/pause audio support.
This commit is contained in:
parent
24a065e5de
commit
0a2a221fa9
@ -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
2
Todo
@ -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
105
audio.c
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
4
audio.h
4
audio.h
@ -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
|
||||||
|
24
softhddev.c
24
softhddev.c
@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user