mirror of
https://projects.vdr-developer.org/git/vdr-plugin-softhddevice.git
synced 2023-10-10 19:16:51 +02:00
Audio module cleanup (more to come).
Alsa + OSS can be included/build at the same time. Alsa or OSS can be runtime selected with -a. Add audio thread support to OSS module. Add polled audio support to alsa module. Removed some debug source code.
This commit is contained in:
parent
e619f5c836
commit
c0d0a4ae7c
@ -1,4 +1,13 @@
|
|||||||
User johns
|
User johns
|
||||||
|
Date:
|
||||||
|
|
||||||
|
Audio module cleanup:
|
||||||
|
Alsa + OSS can be included/build at the same time.
|
||||||
|
Alsa or OSS can be runtime selected with -a.
|
||||||
|
Add audio thread support to OSS module.
|
||||||
|
Add polled audio support to alsa module.
|
||||||
|
Removed some debug source code.
|
||||||
|
|
||||||
Date: Sun Jan 15 16:56:04 CET 2012
|
Date: Sun Jan 15 16:56:04 CET 2012
|
||||||
|
|
||||||
Release Version 0.3.1
|
Release Version 0.3.1
|
||||||
|
6
Makefile
6
Makefile
@ -14,6 +14,7 @@ PLUGIN = softhddevice
|
|||||||
### The version number of this plugin (taken from the main source file):
|
### The version number of this plugin (taken from the main source file):
|
||||||
|
|
||||||
VERSION = $(shell grep 'static const char \*const VERSION *=' $(PLUGIN).cpp | awk '{ print $$7 }' | sed -e 's/[";]//g')
|
VERSION = $(shell grep 'static const char \*const VERSION *=' $(PLUGIN).cpp | awk '{ print $$7 }' | sed -e 's/[";]//g')
|
||||||
|
GIT_REV = $(shell git describe --always 2>/dev/null)
|
||||||
|
|
||||||
### Configuration (edit this for your needs)
|
### Configuration (edit this for your needs)
|
||||||
|
|
||||||
@ -22,7 +23,7 @@ CONFIG := #-DDEBUG
|
|||||||
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
CONFIG += $(shell pkg-config --exists vdpau && echo "-DUSE_VDPAU")
|
||||||
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
CONFIG += $(shell pkg-config --exists libva && echo "-DUSE_VAAPI")
|
||||||
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
CONFIG += $(shell pkg-config --exists alsa && echo "-DUSE_ALSA")
|
||||||
#CONFIG += -DUSE_OSS
|
CONFIG += -DUSE_OSS
|
||||||
|
|
||||||
### The C++ compiler and options:
|
### The C++ compiler and options:
|
||||||
|
|
||||||
@ -59,7 +60,8 @@ PACKAGE = vdr-$(ARCHIVE)
|
|||||||
|
|
||||||
INCLUDES += -I$(VDRDIR)/include
|
INCLUDES += -I$(VDRDIR)/include
|
||||||
|
|
||||||
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"'
|
DEFINES += $(CONFIG) -D_GNU_SOURCE -DPLUGIN_NAME_I18N='"$(PLUGIN)"' \
|
||||||
|
$(if $(GIT_REV), -DGIT_REV='"$(GIT_REV)"')
|
||||||
|
|
||||||
_CFLAGS = $(DEFINES) $(INCLUDES) \
|
_CFLAGS = $(DEFINES) $(INCLUDES) \
|
||||||
$(shell pkg-config --cflags libavcodec libavformat) \
|
$(shell pkg-config --cflags libavcodec libavformat) \
|
||||||
|
26
Todo
26
Todo
@ -27,6 +27,10 @@ missing:
|
|||||||
Option deinterlace off / deinterlace force!
|
Option deinterlace off / deinterlace force!
|
||||||
Make output drivers better moduluar.
|
Make output drivers better moduluar.
|
||||||
|
|
||||||
|
video:
|
||||||
|
subtitle not cleared
|
||||||
|
subtitle could be asyncron
|
||||||
|
|
||||||
vdpau:
|
vdpau:
|
||||||
1080i with temporal spatial and level 1 scaling too slow with my GT 520
|
1080i with temporal spatial and level 1 scaling too slow with my GT 520
|
||||||
1080i with temporal spatial too slow with my GT 520 on some channels
|
1080i with temporal spatial too slow with my GT 520 on some channels
|
||||||
@ -56,21 +60,18 @@ libva-xvba-driver:
|
|||||||
x11:
|
x11:
|
||||||
disable screensaver
|
disable screensaver
|
||||||
|
|
||||||
audio/alsa:
|
audio:
|
||||||
done? video/audio asyncron
|
write TS -> PES parser, which feeds audio before the next start packet
|
||||||
random crashes in av_parser_parse2, when switching channels
|
CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
|
||||||
sometimes alsa hangs
|
Combine alsa+oss ringbuffer code.
|
||||||
fixed? snd_pcm_state: Assertion `pcm' failed. while switching channels
|
Make alsa thread/polled and oss thread/polled output module runtime
|
||||||
(thread problem)
|
selectable.
|
||||||
|
|
||||||
|
audio/alsa:
|
||||||
better downmix of >2 channels on 2 channel hardware
|
better downmix of >2 channels on 2 channel hardware
|
||||||
remix support of unsupported sample rates
|
remix support of unsupported sample rates
|
||||||
libav supports only resample of mono to 2 channels
|
libav supports only resample of mono to 2 channels
|
||||||
ffmpeg didn't support resample of 5 to 2 channels
|
ffmpeg didn't support resample of 5 to 2 channels
|
||||||
CodecAudioOpen can fail "can't open audio codec" and does Fatal exit.
|
|
||||||
|
|
||||||
audio:
|
|
||||||
write TS -> PES parser, which feeds audio before the next start packet
|
|
||||||
|
|
||||||
audio/oss:
|
audio/oss:
|
||||||
alsa oss emulation mixer "pcm" not working
|
alsa oss emulation mixer "pcm" not working
|
||||||
@ -80,6 +81,7 @@ HDMI/SPDIF Passthrough:
|
|||||||
only AC-3 written
|
only AC-3 written
|
||||||
Channels are wrong setup, if changing setting during operation.
|
Channels are wrong setup, if changing setting during operation.
|
||||||
split pcm and ac-3 out into two devices
|
split pcm and ac-3 out into two devices
|
||||||
|
support oss pass-through
|
||||||
|
|
||||||
playback of recording
|
playback of recording
|
||||||
pause is not reset, when replay exit
|
pause is not reset, when replay exit
|
||||||
@ -94,6 +96,10 @@ setup:
|
|||||||
Can a notice be added to the setup menu?
|
Can a notice be added to the setup menu?
|
||||||
576i, 720p, fake 1080i, 1080i
|
576i, 720p, fake 1080i, 1080i
|
||||||
|
|
||||||
|
unsorted:
|
||||||
|
Menu -> Setup -> Plugins -> skingenigmang -> General
|
||||||
|
-> Try 8bpp single area: no, has missing parts.
|
||||||
|
|
||||||
future features (not planed for 1.0 - 1.5)
|
future features (not planed for 1.0 - 1.5)
|
||||||
|
|
||||||
video out with xv
|
video out with xv
|
||||||
|
624
audio.c
624
audio.c
@ -35,21 +35,19 @@
|
|||||||
///
|
///
|
||||||
///
|
///
|
||||||
/// @todo FIXME: there can be problems with little/big endian.
|
/// @todo FIXME: there can be problems with little/big endian.
|
||||||
/// @todo FIXME: can combine oss and alsa ring buffer
|
/// @todo FIXME: can combine OSS and alsa ring buffer
|
||||||
///
|
///
|
||||||
|
|
||||||
#ifdef USE_ALSA // only with alsa supported
|
|
||||||
#define USE_AUDIO_THREAD ///< use thread for audio playback
|
|
||||||
#endif
|
|
||||||
//#define USE_ALSA ///< enable alsa support
|
//#define USE_ALSA ///< enable alsa support
|
||||||
//#define USE_OSS ///< enable oss support
|
//#define USE_OSS ///< enable OSS support
|
||||||
#define noSEARCH_HDMI_BUG
|
#define USE_AUDIO_THREAD ///< use thread for audio playback
|
||||||
#define noSEARCH_HDMI_BUG2
|
#define noUSE_AUDIORING ///< new audio ring code (incomplete)
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include <libintl.h>
|
#include <libintl.h>
|
||||||
#define _(str) gettext(str) ///< gettext shortcut
|
#define _(str) gettext(str) ///< gettext shortcut
|
||||||
@ -73,10 +71,10 @@
|
|||||||
# error "No valid SNDCTL_DSP_HALT_OUTPUT found."
|
# error "No valid SNDCTL_DSP_HALT_OUTPUT found."
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
#include <poll.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <string.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
@ -96,13 +94,38 @@
|
|||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// Declarations
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Audio output module typedef.
|
||||||
|
*/
|
||||||
|
typedef struct _audio_module_
|
||||||
|
{
|
||||||
|
const char *Name; ///< audio output module name
|
||||||
|
|
||||||
|
void (*Thread) (void); ///< module thread handler
|
||||||
|
void (*Enqueue) (const void *, int); ///< enqueue samples for output
|
||||||
|
void (*FlushBuffers) (void); ///< flush sample buffers
|
||||||
|
void (*Poller) (void); ///< output poller
|
||||||
|
int (*FreeBytes) (void); ///< number of bytes free in buffer
|
||||||
|
uint64_t(*GetDelay) (void); ///< get current audio delay
|
||||||
|
void (*SetVolume) (int); ///< set output volume
|
||||||
|
int (*Setup) (int *, int *); ///< setup channels, samplerate
|
||||||
|
void (*Init) (void); ///< initialize audio output module
|
||||||
|
void (*Exit) (void); ///< cleanup audio output module
|
||||||
|
} AudioModule;
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// Variables
|
// Variables
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
static const char *AudioPCMDevice; ///< alsa/oss PCM device name
|
static const char *AudioModuleName; ///< which audio module to use
|
||||||
static const char *AudioMixerDevice; ///< alsa/oss mixer device name
|
static const AudioModule *UsedAudioModule; ///< Selected audio module.
|
||||||
static const char *AudioMixerChannel; ///< alsa/oss 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 volatile char AudioRunning; ///< thread running / stopped
|
||||||
static int AudioPaused; ///< audio paused
|
static int AudioPaused; ///< audio paused
|
||||||
static unsigned AudioSampleRate; ///< audio sample rate in hz
|
static unsigned AudioSampleRate; ///< audio sample rate in hz
|
||||||
@ -111,16 +134,20 @@ static const int AudioBytesProSample = 2; ///< number of bytes per sample
|
|||||||
static int64_t AudioPTS; ///< audio pts clock
|
static int64_t AudioPTS; ///< audio pts clock
|
||||||
|
|
||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
static pthread_t AudioThread; ///< audio play thread
|
||||||
|
static pthread_mutex_t AudioMutex; ///< audio condition mutex
|
||||||
static pthread_cond_t AudioStartCond; ///< condition variable
|
static pthread_cond_t AudioStartCond; ///< condition variable
|
||||||
|
#else
|
||||||
|
static const int AudioThread; ///< dummy audio thread
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SEARCH_HDMI_BUG2
|
#ifdef USE_AUDIORING
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// ring buffer
|
// ring buffer
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
// FIXME: use this code, to combine alsa&oss ring buffers
|
// FIXME: use this code, to combine alsa&OSS ring buffers
|
||||||
|
|
||||||
#define AUDIO_RING_MAX 8 ///< number of audio ring buffers
|
#define AUDIO_RING_MAX 8 ///< number of audio ring buffers
|
||||||
|
|
||||||
@ -219,7 +246,10 @@ static int AlsaUseMmap; ///< use mmap
|
|||||||
|
|
||||||
static RingBuffer *AlsaRingBuffer; ///< audio ring buffer
|
static RingBuffer *AlsaRingBuffer; ///< audio ring buffer
|
||||||
static unsigned AlsaStartThreshold; ///< start play, if filled
|
static unsigned AlsaStartThreshold; ///< start play, if filled
|
||||||
|
|
||||||
|
#ifdef USE_AUDIO_THREAD
|
||||||
static volatile char AlsaFlushBuffer; ///< flag empty buffer
|
static volatile char AlsaFlushBuffer; ///< flag empty buffer
|
||||||
|
#endif
|
||||||
|
|
||||||
static snd_mixer_t *AlsaMixer; ///< alsa mixer handle
|
static snd_mixer_t *AlsaMixer; ///< alsa mixer handle
|
||||||
static snd_mixer_elem_t *AlsaMixerElem; ///< alsa pcm mixer element
|
static snd_mixer_elem_t *AlsaMixerElem; ///< alsa pcm mixer element
|
||||||
@ -295,26 +325,15 @@ static int AlsaPlayRingbuffer(void)
|
|||||||
if (avail < 256) { // too much overhead
|
if (avail < 256) { // too much overhead
|
||||||
if (first) {
|
if (first) {
|
||||||
// happens with broken alsa drivers
|
// happens with broken alsa drivers
|
||||||
Error(_("audio/alsa: broken driver %d\n"), avail);
|
if (AudioThread) {
|
||||||
usleep(5 * 1000);
|
Error(_("audio/alsa: broken driver %d\n"), avail);
|
||||||
|
usleep(5 * 1000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Debug(4, "audio/alsa: break state %s\n",
|
Debug(4, "audio/alsa: break state %s\n",
|
||||||
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
|
snd_pcm_state_name(snd_pcm_state(AlsaPCMHandle)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#ifdef SEARCH_HDMI_BUG
|
|
||||||
{
|
|
||||||
uint16_t buf[8192];
|
|
||||||
unsigned u;
|
|
||||||
|
|
||||||
for (u = 0; u < sizeof(buf) / 2; u++) {
|
|
||||||
buf[u] = random() & 0xffff;
|
|
||||||
}
|
|
||||||
|
|
||||||
n = sizeof(buf);
|
|
||||||
p = buf;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
n = RingBufferGetReadPointer(AlsaRingBuffer, &p);
|
n = RingBufferGetReadPointer(AlsaRingBuffer, &p);
|
||||||
if (!n) { // ring buffer empty
|
if (!n) { // ring buffer empty
|
||||||
if (first) { // only error on first loop
|
if (first) { // only error on first loop
|
||||||
@ -322,7 +341,6 @@ static int AlsaPlayRingbuffer(void)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
if (n < avail) { // not enough bytes in ring buffer
|
if (n < avail) { // not enough bytes in ring buffer
|
||||||
avail = n;
|
avail = n;
|
||||||
}
|
}
|
||||||
@ -376,21 +394,47 @@ static void AlsaFlushBuffers(void)
|
|||||||
int err;
|
int err;
|
||||||
snd_pcm_state_t state;
|
snd_pcm_state_t state;
|
||||||
|
|
||||||
RingBufferReadAdvance(AlsaRingBuffer, RingBufferUsedBytes(AlsaRingBuffer));
|
if (AlsaRingBuffer && AlsaPCMHandle) {
|
||||||
state = snd_pcm_state(AlsaPCMHandle);
|
RingBufferReadAdvance(AlsaRingBuffer,
|
||||||
Debug(3, "audio/alsa: state %d - %s\n", state, snd_pcm_state_name(state));
|
RingBufferUsedBytes(AlsaRingBuffer));
|
||||||
if (state != SND_PCM_STATE_OPEN) {
|
state = snd_pcm_state(AlsaPCMHandle);
|
||||||
if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) {
|
Debug(3, "audio/alsa: state %d - %s\n", state,
|
||||||
Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err));
|
snd_pcm_state_name(state));
|
||||||
}
|
if (state != SND_PCM_STATE_OPEN) {
|
||||||
// ****ing alsa crash, when in open state here
|
if ((err = snd_pcm_drop(AlsaPCMHandle)) < 0) {
|
||||||
if ((err = snd_pcm_prepare(AlsaPCMHandle)) < 0) {
|
Error(_("audio: snd_pcm_drop(): %s\n"), snd_strerror(err));
|
||||||
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
|
}
|
||||||
|
// ****ing alsa crash, when in open state here
|
||||||
|
if ((err = snd_pcm_prepare(AlsaPCMHandle)) < 0) {
|
||||||
|
Error(_("audio: snd_pcm_prepare(): %s\n"), snd_strerror(err));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AudioRunning = 0;
|
||||||
AudioPTS = INT64_C(0x8000000000000000);
|
AudioPTS = INT64_C(0x8000000000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Call back to play audio polled.
|
||||||
|
*/
|
||||||
|
static void AlsaPoller(void)
|
||||||
|
{
|
||||||
|
if (!AlsaPCMHandle) { // setup failure
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!AudioThread && AudioRunning) {
|
||||||
|
AlsaPlayRingbuffer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Get free bytes in audio output.
|
||||||
|
*/
|
||||||
|
static int AlsaFreeBytes(void)
|
||||||
|
{
|
||||||
|
return AlsaRingBuffer ? RingBufferFreeBytes(AlsaRingBuffer) : INT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -520,8 +564,6 @@ static void AlsaEnqueue(const void *samples, int count)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if 0
|
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// direct playback
|
// direct playback
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -536,39 +578,11 @@ static void AlsaEnqueue(const void *samples, int count)
|
|||||||
*/
|
*/
|
||||||
static void AlsaEnqueue(const void *samples, int count)
|
static void AlsaEnqueue(const void *samples, int count)
|
||||||
{
|
{
|
||||||
snd_pcm_state_t state;
|
if (AlsaAddToRingbuffer(samples, count)) {
|
||||||
int avail;
|
AudioRunning = 1;
|
||||||
int n;
|
|
||||||
int err;
|
|
||||||
int frames;
|
|
||||||
const void *p;
|
|
||||||
|
|
||||||
Debug(3, "audio/alsa: %6zd + %4d\n", RingBufferUsedBytes(AlsaRingBuffer),
|
|
||||||
count);
|
|
||||||
n = RingBufferWrite(AlsaRingBuffer, samples, count);
|
|
||||||
if (n != count) {
|
|
||||||
Error(_("audio/alsa: can't place %d samples in ring buffer\n"), count);
|
|
||||||
}
|
}
|
||||||
// check if running, wait until enough buffered
|
|
||||||
state = snd_pcm_state(AlsaPCMHandle);
|
|
||||||
Debug(4, "audio/alsa: state %d - %s\n", state, snd_pcm_state_name(state));
|
|
||||||
if (state == SND_PCM_STATE_PREPARED) {
|
|
||||||
// FIXME: adjust start ratio
|
|
||||||
if (RingBufferFreeBytes(AlsaRingBuffer)
|
|
||||||
> RingBufferUsedBytes(AlsaRingBuffer)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Debug(3, "audio/alsa: state %d - %s start play\n", state,
|
|
||||||
snd_pcm_state_name(state));
|
|
||||||
}
|
|
||||||
// Update audio clock
|
|
||||||
AudioPTS +=
|
|
||||||
(size * 90000) / (AudioSampleRate * AudioChannels *
|
|
||||||
AudioBytesProSample);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -622,7 +636,7 @@ static void AlsaThread(void)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pthread_yield();
|
pthread_yield();
|
||||||
usleep(20 * 1000); // let fill the buffers
|
usleep(20 * 1000); // let fill/empty the buffers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -633,10 +647,9 @@ static void AlsaThread(void)
|
|||||||
** @param samples sample buffer
|
** @param samples sample buffer
|
||||||
** @param count number of bytes in sample buffer
|
** @param count number of bytes in sample buffer
|
||||||
*/
|
*/
|
||||||
static void AlsaEnqueue(const void *samples, int count)
|
static void AlsaThreadEnqueue(const void *samples, int count)
|
||||||
{
|
{
|
||||||
if (!AlsaRingBuffer || !AlsaPCMHandle || !AudioSampleRate) {
|
if (!AlsaRingBuffer || !AlsaPCMHandle || !AudioSampleRate) {
|
||||||
printf("%p %p %d\n", AlsaRingBuffer, AlsaPCMHandle, AudioSampleRate);
|
|
||||||
Debug(3, "audio/alsa: enqueue not ready\n");
|
Debug(3, "audio/alsa: enqueue not ready\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -652,8 +665,26 @@ static void AlsaEnqueue(const void *samples, int count)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Flush alsa buffers with thread.
|
||||||
|
*/
|
||||||
|
static void AlsaThreadFlushBuffers(void)
|
||||||
|
{
|
||||||
|
// signal thread to flush buffers
|
||||||
|
if (AudioThread) {
|
||||||
|
AlsaFlushBuffer = 1;
|
||||||
|
do {
|
||||||
|
AudioRunning = 1; // wakeup in case of sleeping
|
||||||
|
pthread_cond_signal(&AudioStartCond);
|
||||||
|
usleep(1 * 1000);
|
||||||
|
} while (AlsaFlushBuffer); // wait until flushed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Open alsa pcm device.
|
** Open alsa pcm device.
|
||||||
*/
|
*/
|
||||||
@ -1098,6 +1129,28 @@ static void AlsaExit(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Alsa module.
|
||||||
|
*/
|
||||||
|
static const AudioModule AlsaModule = {
|
||||||
|
.Name = "alsa",
|
||||||
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
.Thread = AlsaThread,
|
||||||
|
.Enqueue = AlsaThreadEnqueue,
|
||||||
|
.FlushBuffers = AlsaThreadFlushBuffers,
|
||||||
|
#else
|
||||||
|
.Enqueue = AlsaEnqueue,
|
||||||
|
.FlushBuffers = AlsaFlushBuffers,
|
||||||
|
#endif
|
||||||
|
.Poller = AlsaPoller,
|
||||||
|
.FreeBytes = AlsaFreeBytes,
|
||||||
|
.GetDelay = AlsaGetDelay,
|
||||||
|
.SetVolume = AlsaSetVolume,
|
||||||
|
.Setup = AlsaSetup,
|
||||||
|
.Init = AlsaInit,
|
||||||
|
.Exit = AlsaExit,
|
||||||
|
};
|
||||||
|
|
||||||
#endif // USE_ALSA
|
#endif // USE_ALSA
|
||||||
|
|
||||||
#ifdef USE_OSS
|
#ifdef USE_OSS
|
||||||
@ -1116,6 +1169,10 @@ static int OssMixerChannel; ///< mixer channel index
|
|||||||
static RingBuffer *OssRingBuffer; ///< audio ring buffer
|
static RingBuffer *OssRingBuffer; ///< audio ring buffer
|
||||||
static unsigned OssStartThreshold; ///< start play, if filled
|
static unsigned OssStartThreshold; ///< start play, if filled
|
||||||
|
|
||||||
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
static volatile char OssFlushBuffer; ///< flag empty buffer
|
||||||
|
#endif
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// OSS pcm
|
// OSS pcm
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
@ -1204,17 +1261,20 @@ static int OssPlayRingbuffer(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Flush oss buffers.
|
** Flush OSS buffers.
|
||||||
*/
|
*/
|
||||||
static void OssFlushBuffers(void)
|
static void OssFlushBuffers(void)
|
||||||
{
|
{
|
||||||
RingBufferReadAdvance(OssRingBuffer, RingBufferUsedBytes(OssRingBuffer));
|
if (OssRingBuffer && OssPcmFildes != -1) {
|
||||||
// flush kernel buffers
|
RingBufferReadAdvance(OssRingBuffer,
|
||||||
if (ioctl(OssPcmFildes, SNDCTL_DSP_HALT_OUTPUT, NULL) < 0) {
|
RingBufferUsedBytes(OssRingBuffer));
|
||||||
Error(_("audio/oss: ioctl(SNDCTL_DSP_HALT_OUTPUT): %s\n"),
|
// flush kernel buffers
|
||||||
strerror(errno));
|
if (ioctl(OssPcmFildes, SNDCTL_DSP_HALT_OUTPUT, NULL) < 0) {
|
||||||
return;
|
Error(_("audio/oss: ioctl(SNDCTL_DSP_HALT_OUTPUT): %s\n"),
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
AudioRunning = 0;
|
||||||
AudioPTS = INT64_C(0x8000000000000000);
|
AudioPTS = INT64_C(0x8000000000000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1256,15 +1316,108 @@ static void OssPoller(void)
|
|||||||
if (OssPcmFildes == -1) { // setup failure
|
if (OssPcmFildes == -1) { // setup failure
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (AudioRunning) {
|
if (!AudioThread && AudioRunning) {
|
||||||
OssPlayRingbuffer();
|
OssPlayRingbuffer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Get free bytes in audio output.
|
||||||
|
*/
|
||||||
|
static int OssFreeBytes(void)
|
||||||
|
{
|
||||||
|
return OssRingBuffer ? RingBufferFreeBytes(OssRingBuffer) : INT32_MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// thread playback
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Initialize oss pcm device.
|
** OSS thread
|
||||||
|
*/
|
||||||
|
static void OssThread(void)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
struct pollfd fds[1];
|
||||||
|
int err;
|
||||||
|
|
||||||
|
pthread_testcancel();
|
||||||
|
if (OssFlushBuffer) {
|
||||||
|
// we can flush too many, but wo cares
|
||||||
|
Debug(3, "audio/oss: flushing buffers\n");
|
||||||
|
OssFlushBuffers();
|
||||||
|
OssFlushBuffer = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fds[0].fd = OssPcmFildes;
|
||||||
|
fds[0].events = POLLOUT | POLLERR;
|
||||||
|
// wait for space in kernel buffers
|
||||||
|
err = poll(fds, 1, 100);
|
||||||
|
if (err < 0) {
|
||||||
|
Error(_("audio/oss: error poll %s\n"), strerror(errno));
|
||||||
|
usleep(100 * 1000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OssFlushBuffer) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((err = OssPlayRingbuffer())) { // empty / error
|
||||||
|
if (err < 0) { // underrun error
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pthread_yield();
|
||||||
|
usleep(20 * 1000); // let fill/empty the buffers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Place samples in audio output queue.
|
||||||
|
**
|
||||||
|
** @param samples sample buffer
|
||||||
|
** @param count number of bytes in sample buffer
|
||||||
|
*/
|
||||||
|
static void OssThreadEnqueue(const void *samples, int count)
|
||||||
|
{
|
||||||
|
if (!OssRingBuffer || OssPcmFildes == -1 || !AudioSampleRate) {
|
||||||
|
Debug(3, "audio/oss: enqueue not ready\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (OssAddToRingbuffer(samples, count)) {
|
||||||
|
// no lock needed, can wakeup next time
|
||||||
|
AudioRunning = 1;
|
||||||
|
pthread_cond_signal(&AudioStartCond);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Flush OSS buffers with thread.
|
||||||
|
*/
|
||||||
|
static void OssThreadFlushBuffers(void)
|
||||||
|
{
|
||||||
|
// signal thread to flush buffers
|
||||||
|
if (AudioThread) {
|
||||||
|
OssFlushBuffer = 1;
|
||||||
|
do {
|
||||||
|
AudioRunning = 1; // wakeup in case of sleeping
|
||||||
|
pthread_cond_signal(&AudioStartCond);
|
||||||
|
usleep(1 * 1000);
|
||||||
|
} while (OssFlushBuffer); // wait until flushed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Initialize OSS pcm device.
|
||||||
**
|
**
|
||||||
** @see AudioPCMDevice
|
** @see AudioPCMDevice
|
||||||
*/
|
*/
|
||||||
@ -1292,7 +1445,7 @@ static void OssInitPCM(void)
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Set oss mixer volume (0-100)
|
** Set OSS mixer volume (0-100)
|
||||||
**
|
**
|
||||||
** @param volume volume (0 .. 100)
|
** @param volume volume (0 .. 100)
|
||||||
*/
|
*/
|
||||||
@ -1317,7 +1470,7 @@ static const char *OssMixerChannelNames[SOUND_MIXER_NRDEVICES] =
|
|||||||
SOUND_DEVICE_NAMES;
|
SOUND_DEVICE_NAMES;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Initialize oss mixer.
|
** Initialize OSS mixer.
|
||||||
*/
|
*/
|
||||||
static void OssInitMixer(void)
|
static void OssInitMixer(void)
|
||||||
{
|
{
|
||||||
@ -1371,7 +1524,7 @@ static void OssInitMixer(void)
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Get oss audio delay in time stamps.
|
** Get OSS audio delay in time stamps.
|
||||||
**
|
**
|
||||||
** @returns audio delay in time stamps.
|
** @returns audio delay in time stamps.
|
||||||
*/
|
*/
|
||||||
@ -1411,7 +1564,7 @@ static uint64_t OssGetDelay(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Setup oss audio for requested format.
|
** Setup OSS audio for requested format.
|
||||||
**
|
**
|
||||||
** @param freq sample frequency
|
** @param freq sample frequency
|
||||||
** @param channels number of channels
|
** @param channels number of channels
|
||||||
@ -1427,14 +1580,11 @@ static int OssSetup(int *freq, int *channels)
|
|||||||
int ret;
|
int ret;
|
||||||
int tmp;
|
int tmp;
|
||||||
|
|
||||||
if (OssPcmFildes == -1) { // oss not ready
|
if (OssPcmFildes == -1) { // OSS not ready
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
// flush any buffered data
|
// flush any buffered data
|
||||||
{
|
AudioFlushBuffers();
|
||||||
AudioRunning = 0;
|
|
||||||
OssFlushBuffers();
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
@ -1519,7 +1669,7 @@ static int OssSetup(int *freq, int *channels)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Initialize oss audio output module.
|
** Initialize OSS audio output module.
|
||||||
*/
|
*/
|
||||||
static void OssInit(void)
|
static void OssInit(void)
|
||||||
{
|
{
|
||||||
@ -1530,7 +1680,7 @@ static void OssInit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Cleanup oss audio output module.
|
** Cleanup OSS audio output module.
|
||||||
*/
|
*/
|
||||||
static void OssExit(void)
|
static void OssExit(void)
|
||||||
{
|
{
|
||||||
@ -1544,17 +1694,116 @@ static void OssExit(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** OSS module.
|
||||||
|
*/
|
||||||
|
static const AudioModule OssModule = {
|
||||||
|
.Name = "oss",
|
||||||
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
.Thread = OssThread,
|
||||||
|
.Enqueue = OssThreadEnqueue,
|
||||||
|
.FlushBuffers = OssThreadFlushBuffers,
|
||||||
|
#else
|
||||||
|
.Enqueue = OssEnqueue,
|
||||||
|
.FlushBuffers = OssFlushBuffers,
|
||||||
|
#endif
|
||||||
|
.Poller = OssPoller,
|
||||||
|
.FreeBytes = OssFreeBytes,
|
||||||
|
.GetDelay = OssGetDelay,
|
||||||
|
.SetVolume = OssSetVolume,
|
||||||
|
.Setup = OssSetup,
|
||||||
|
.Init = OssInit,
|
||||||
|
.Exit = OssExit,
|
||||||
|
};
|
||||||
|
|
||||||
#endif // USE_OSS
|
#endif // USE_OSS
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
// Noop
|
||||||
|
//============================================================================
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Noop enqueue samples.
|
||||||
|
**
|
||||||
|
** @param samples sample buffer
|
||||||
|
** @param count number of bytes in sample buffer
|
||||||
|
*/
|
||||||
|
static void NoopEnqueue( __attribute__ ((unused))
|
||||||
|
const void *samples, __attribute__ ((unused))
|
||||||
|
int count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Get free bytes in audio output.
|
||||||
|
*/
|
||||||
|
static int NoopFreeBytes(void)
|
||||||
|
{
|
||||||
|
return INT32_MAX; // no driver, much space
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Get audio delay in time stamps.
|
||||||
|
**
|
||||||
|
** @returns audio delay in time stamps.
|
||||||
|
*/
|
||||||
|
static uint64_t NoopGetDelay(void)
|
||||||
|
{
|
||||||
|
return 0UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Set mixer volume (0-100)
|
||||||
|
**
|
||||||
|
** @param volume volume (0 .. 100)
|
||||||
|
*/
|
||||||
|
static void NoopSetVolume( __attribute__ ((unused))
|
||||||
|
int volume)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Noop setup.
|
||||||
|
**
|
||||||
|
** @param freq sample frequency
|
||||||
|
** @param channels number of channels
|
||||||
|
*/
|
||||||
|
static int NoopSetup( __attribute__ ((unused))
|
||||||
|
int *channels, __attribute__ ((unused))
|
||||||
|
int *freq)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Noop void
|
||||||
|
*/
|
||||||
|
static void NoopVoid(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Noop module.
|
||||||
|
*/
|
||||||
|
static const AudioModule NoopModule = {
|
||||||
|
.Name = "noop",
|
||||||
|
.Enqueue = NoopEnqueue,
|
||||||
|
.FlushBuffers = NoopVoid,
|
||||||
|
.Poller = NoopVoid,
|
||||||
|
.FreeBytes = NoopFreeBytes,
|
||||||
|
.GetDelay = NoopGetDelay,
|
||||||
|
.SetVolume = NoopSetVolume,
|
||||||
|
.Setup = NoopSetup,
|
||||||
|
.Init = NoopVoid,
|
||||||
|
.Exit = NoopVoid,
|
||||||
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// thread playback
|
// thread playback
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
|
|
||||||
static pthread_t AudioThread; ///< audio play thread
|
|
||||||
static pthread_mutex_t AudioMutex; ///< audio condition mutex
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Audio play thread.
|
** Audio play thread.
|
||||||
*/
|
*/
|
||||||
@ -1565,18 +1814,13 @@ static void *AudioPlayHandlerThread(void *dummy)
|
|||||||
Debug(3, "audio: wait on start condition\n");
|
Debug(3, "audio: wait on start condition\n");
|
||||||
pthread_mutex_lock(&AudioMutex);
|
pthread_mutex_lock(&AudioMutex);
|
||||||
AudioRunning = 0;
|
AudioRunning = 0;
|
||||||
#ifndef SEARCH_HDMI_BUG
|
|
||||||
do {
|
do {
|
||||||
pthread_cond_wait(&AudioStartCond, &AudioMutex);
|
pthread_cond_wait(&AudioStartCond, &AudioMutex);
|
||||||
// cond_wait can return, without signal!
|
// cond_wait can return, without signal!
|
||||||
} while (!AudioRunning);
|
} while (!AudioRunning);
|
||||||
#else
|
|
||||||
usleep(1 * 1000);
|
|
||||||
AudioRunning = 1;
|
|
||||||
#endif
|
|
||||||
pthread_mutex_unlock(&AudioMutex);
|
pthread_mutex_unlock(&AudioMutex);
|
||||||
|
|
||||||
#ifdef SEARCH_HDMI_BUG2
|
#ifdef USE_AUDIORING
|
||||||
if (atomic_read(&AudioRingFilled) > 1) {
|
if (atomic_read(&AudioRingFilled) > 1) {
|
||||||
int sample_rate;
|
int sample_rate;
|
||||||
int channels;
|
int channels;
|
||||||
@ -1619,9 +1863,7 @@ static void *AudioPlayHandlerThread(void *dummy)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
Debug(3, "audio: play start\n");
|
Debug(3, "audio: play start\n");
|
||||||
#ifdef USE_ALSA
|
UsedAudioModule->Thread();
|
||||||
AlsaThread();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return dummy;
|
return dummy;
|
||||||
@ -1636,15 +1878,9 @@ static void AudioInitThread(void)
|
|||||||
pthread_cond_init(&AudioStartCond, NULL);
|
pthread_cond_init(&AudioStartCond, NULL);
|
||||||
pthread_create(&AudioThread, NULL, AudioPlayHandlerThread, NULL);
|
pthread_create(&AudioThread, NULL, AudioPlayHandlerThread, NULL);
|
||||||
pthread_setname_np(AudioThread, "softhddev audio");
|
pthread_setname_np(AudioThread, "softhddev audio");
|
||||||
//pthread_detach(AudioThread);
|
|
||||||
#ifdef very_old_unused_USE_ALSA
|
|
||||||
// wait until thread has opened and is ready
|
|
||||||
do {
|
|
||||||
pthread_yield();
|
|
||||||
} while (!AlsaPCMHandle);
|
|
||||||
#endif
|
|
||||||
pthread_yield();
|
pthread_yield();
|
||||||
usleep(5 * 1000);
|
usleep(5 * 1000); // give thread some time to start
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1671,6 +1907,19 @@ static void AudioExitThread(void)
|
|||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
** Table of all audio modules.
|
||||||
|
*/
|
||||||
|
static const AudioModule *AudioModules[] = {
|
||||||
|
#ifdef USE_ALSA
|
||||||
|
&AlsaModule,
|
||||||
|
#endif
|
||||||
|
#ifdef USE_OSS
|
||||||
|
&OssModule,
|
||||||
|
#endif
|
||||||
|
&NoopModule,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Place samples in audio output queue.
|
** Place samples in audio output queue.
|
||||||
**
|
**
|
||||||
@ -1679,14 +1928,7 @@ static void AudioExitThread(void)
|
|||||||
*/
|
*/
|
||||||
void AudioEnqueue(const void *samples, int count)
|
void AudioEnqueue(const void *samples, int count)
|
||||||
{
|
{
|
||||||
#ifdef USE_ALSA
|
UsedAudioModule->Enqueue(samples, count);
|
||||||
AlsaEnqueue(samples, count);
|
|
||||||
#endif
|
|
||||||
#ifdef USE_OSS
|
|
||||||
OssEnqueue(samples, count);
|
|
||||||
#endif
|
|
||||||
(void)samples;
|
|
||||||
(void)count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1694,24 +1936,7 @@ void AudioEnqueue(const void *samples, int count)
|
|||||||
*/
|
*/
|
||||||
void AudioFlushBuffers(void)
|
void AudioFlushBuffers(void)
|
||||||
{
|
{
|
||||||
#ifdef USE_ALSA
|
UsedAudioModule->FlushBuffers();
|
||||||
#ifdef USE_AUDIO_THREAD
|
|
||||||
// signal thread to flush buffers
|
|
||||||
if (AudioThread) {
|
|
||||||
AlsaFlushBuffer = 1;
|
|
||||||
do {
|
|
||||||
AudioRunning = 1; // wakeup in case of sleeping
|
|
||||||
pthread_cond_signal(&AudioStartCond);
|
|
||||||
usleep(1 * 1000);
|
|
||||||
} while (AlsaFlushBuffer); // wait until flushed
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
AlsaFlushBuffers();
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#ifdef USE_OSS
|
|
||||||
OssFlushBuffers();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1719,14 +1944,7 @@ void AudioFlushBuffers(void)
|
|||||||
*/
|
*/
|
||||||
void AudioPoller(void)
|
void AudioPoller(void)
|
||||||
{
|
{
|
||||||
#ifndef USE_AUDIO_THREAD
|
UsedAudioModule->Poller();
|
||||||
#ifdef USE_ALSA
|
|
||||||
Error(_("audio/alsa: poller not implemented\n"));
|
|
||||||
#endif
|
|
||||||
#ifdef USE_OSS
|
|
||||||
OssPoller();
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1734,13 +1952,17 @@ void AudioPoller(void)
|
|||||||
*/
|
*/
|
||||||
int AudioFreeBytes(void)
|
int AudioFreeBytes(void)
|
||||||
{
|
{
|
||||||
#ifdef USE_ALSA
|
return UsedAudioModule->FreeBytes();
|
||||||
return AlsaRingBuffer ? RingBufferFreeBytes(AlsaRingBuffer) : INT32_MAX;
|
}
|
||||||
#endif
|
|
||||||
#ifdef USE_OSS
|
/**
|
||||||
return OssRingBuffer ? RingBufferFreeBytes(OssRingBuffer) : INT32_MAX;
|
** Get audio delay in time stamps.
|
||||||
#endif
|
**
|
||||||
return INT32_MAX; // no driver, much space
|
** @returns audio delay in time stamps.
|
||||||
|
*/
|
||||||
|
uint64_t AudioGetDelay(void)
|
||||||
|
{
|
||||||
|
return UsedAudioModule->GetDelay();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1760,22 +1982,6 @@ void AudioSetClock(int64_t pts)
|
|||||||
AudioPTS = pts;
|
AudioPTS = pts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
** Get audio delay in time stamps.
|
|
||||||
**
|
|
||||||
** @returns audio delay in time stamps.
|
|
||||||
*/
|
|
||||||
uint64_t AudioGetDelay(void)
|
|
||||||
{
|
|
||||||
#ifdef USE_ALSA
|
|
||||||
return AlsaGetDelay();
|
|
||||||
#endif
|
|
||||||
#ifdef USE_OSS
|
|
||||||
return OssGetDelay();
|
|
||||||
#endif
|
|
||||||
return 0UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Get current audio clock.
|
** Get current audio clock.
|
||||||
**
|
**
|
||||||
@ -1783,11 +1989,12 @@ uint64_t AudioGetDelay(void)
|
|||||||
*/
|
*/
|
||||||
int64_t AudioGetClock(void)
|
int64_t AudioGetClock(void)
|
||||||
{
|
{
|
||||||
int64_t delay;
|
if ((uint64_t) AudioPTS != INT64_C(0x8000000000000000)) {
|
||||||
|
int64_t delay;
|
||||||
|
|
||||||
delay = AudioGetDelay();
|
if ((delay = AudioGetDelay())) {
|
||||||
if (delay && (uint64_t) AudioPTS != INT64_C(0x8000000000000000)) {
|
return AudioPTS - delay;
|
||||||
return AudioPTS - delay;
|
}
|
||||||
}
|
}
|
||||||
return INT64_C(0x8000000000000000);
|
return INT64_C(0x8000000000000000);
|
||||||
}
|
}
|
||||||
@ -1830,53 +2037,81 @@ int AudioSetup(int *freq, int *channels)
|
|||||||
// FIXME: set flag invalid setup
|
// FIXME: set flag invalid setup
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#if defined(SEARCH_HDMI_BUG) || defined(SEARCH_HDMI_BUG2)
|
#ifdef USE_AUDIORING
|
||||||
// FIXME: need to store possible combination and report this
|
// FIXME: need to store possible combination and report this
|
||||||
return AudioRingAdd(*freq, *channels);
|
return AudioRingAdd(*freq, *channels);
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_ALSA
|
return UsedAudioModule->Setup(freq, channels);
|
||||||
return AlsaSetup(freq, channels);
|
|
||||||
#endif
|
|
||||||
#ifdef USE_OSS
|
|
||||||
return OssSetup(freq, channels);
|
|
||||||
#endif
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Set pcm audio device.
|
** Set pcm audio device.
|
||||||
**
|
**
|
||||||
** @param device name of pcm device (fe. "hw:0,9" or "/dev/dsp")
|
** @param device name of pcm device (fe. "hw:0,9" or "/dev/dsp")
|
||||||
|
**
|
||||||
|
** @note this is currently used to select alsa/OSS output module.
|
||||||
*/
|
*/
|
||||||
void AudioSetDevice(const char *device)
|
void AudioSetDevice(const char *device)
|
||||||
{
|
{
|
||||||
|
AudioModuleName = "alsa"; // detect alsa/OSS
|
||||||
|
if (!device[0]) {
|
||||||
|
AudioModuleName = "noop";
|
||||||
|
} else if (device[0] == '/') {
|
||||||
|
AudioModuleName = "oss";
|
||||||
|
}
|
||||||
AudioPCMDevice = device;
|
AudioPCMDevice = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
** Initialize audio output module.
|
** Initialize audio output module.
|
||||||
|
**
|
||||||
|
** @todo FIXME: make audio output module selectable.
|
||||||
*/
|
*/
|
||||||
void AudioInit(void)
|
void AudioInit(void)
|
||||||
{
|
{
|
||||||
int freq;
|
int freq;
|
||||||
int chan;
|
int chan;
|
||||||
|
unsigned u;
|
||||||
|
const char *name;
|
||||||
|
|
||||||
#ifdef SEARCH_HDMI_BUG2
|
name = "noop";
|
||||||
AudioRingInit();
|
#ifdef USE_OSS
|
||||||
|
name = "oss";
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_ALSA
|
#ifdef USE_ALSA
|
||||||
AlsaInit();
|
name = "alsa";
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_OSS
|
if (AudioModuleName) {
|
||||||
OssInit();
|
name = AudioModuleName;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// search selected audio module.
|
||||||
|
//
|
||||||
|
for (u = 0; u < sizeof(AudioModules) / sizeof(*AudioModules); ++u) {
|
||||||
|
if (!strcasecmp(name, AudioModules[u]->Name)) {
|
||||||
|
UsedAudioModule = AudioModules[u];
|
||||||
|
Info(_("audio: '%s' output module used\n"), UsedAudioModule->Name);
|
||||||
|
goto found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Error(_("audio: '%s' output module isn't supported\n"), name);
|
||||||
|
UsedAudioModule = &NoopModule;
|
||||||
|
return;
|
||||||
|
|
||||||
|
found:
|
||||||
|
#ifdef USE_AUDIORING
|
||||||
|
AudioRingInit();
|
||||||
#endif
|
#endif
|
||||||
|
UsedAudioModule->Init();
|
||||||
freq = 48000;
|
freq = 48000;
|
||||||
chan = 2;
|
chan = 2;
|
||||||
if (AudioSetup(&freq, &chan)) { // set default parameters
|
if (AudioSetup(&freq, &chan)) { // set default parameters
|
||||||
Error(_("audio: can't do initial setup\n"));
|
Error(_("audio: can't do initial setup\n"));
|
||||||
}
|
}
|
||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
AudioInitThread();
|
if (UsedAudioModule->Thread) { // supports threads
|
||||||
|
AudioInitThread();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AudioPaused = 1;
|
AudioPaused = 1;
|
||||||
@ -1890,13 +2125,8 @@ void AudioExit(void)
|
|||||||
#ifdef USE_AUDIO_THREAD
|
#ifdef USE_AUDIO_THREAD
|
||||||
AudioExitThread();
|
AudioExitThread();
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_ALSA
|
UsedAudioModule->Exit();
|
||||||
AlsaExit();
|
#ifdef USE_AUDIORING
|
||||||
#endif
|
|
||||||
#ifdef USE_OSS
|
|
||||||
OssExit();
|
|
||||||
#endif
|
|
||||||
#ifdef SEARCH_HDMI_BUG2
|
|
||||||
AudioRingExit();
|
AudioRingExit();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -1942,7 +2172,7 @@ static void PrintVersion(void)
|
|||||||
#ifdef GIT_REV
|
#ifdef GIT_REV
|
||||||
"(GIT-" GIT_REV ")"
|
"(GIT-" GIT_REV ")"
|
||||||
#endif
|
#endif
|
||||||
",\n\t(c) 2009 - 2011 by Johns\n"
|
",\n\t(c) 2009 - 2012 by Johns\n"
|
||||||
"\tLicense AGPLv3: GNU Affero General Public License version 3\n");
|
"\tLicense AGPLv3: GNU Affero General Public License version 3\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
audio.h
8
audio.h
@ -30,21 +30,19 @@
|
|||||||
extern void AudioEnqueue(const void *, int); ///< buffer audio samples
|
extern void AudioEnqueue(const void *, int); ///< buffer audio samples
|
||||||
extern void AudioFlushBuffers(void); ///< flush audio buffers
|
extern void AudioFlushBuffers(void); ///< flush audio buffers
|
||||||
extern void AudioPoller(void); ///< poll audio events/handling
|
extern void AudioPoller(void); ///< poll audio events/handling
|
||||||
|
|
||||||
extern int AudioFreeBytes(void); ///< free bytes in audio output
|
extern int AudioFreeBytes(void); ///< free bytes in audio output
|
||||||
|
|
||||||
//extern int AudioUsedBytes(void); ///< used bytes in audio output
|
//extern int AudioUsedBytes(void); ///< used bytes in audio output
|
||||||
|
extern uint64_t AudioGetDelay(void); ///< get current audio delay
|
||||||
extern void AudioSetClock(int64_t); ///< set audio clock base
|
extern void AudioSetClock(int64_t); ///< set audio clock base
|
||||||
extern int64_t AudioGetClock(); ///< get current audio clock
|
extern int64_t AudioGetClock(); ///< get current audio clock
|
||||||
extern uint64_t AudioGetDelay(void); ///< get current audio delay
|
extern void AudioSetVolume(int); ///< set volume
|
||||||
|
|
||||||
extern int AudioSetup(int *, int *); ///< setup audio output
|
extern int AudioSetup(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 AudioSetVolume(int); ///< set volume
|
|
||||||
|
|
||||||
extern void AudioSetDevice(const char *); ///< set alsa PCM audio device
|
extern void AudioSetDevice(const char *); ///< set PCM audio device
|
||||||
extern void AudioInit(void); ///< setup audio module
|
extern void AudioInit(void); ///< setup audio module
|
||||||
extern void AudioExit(void); ///< cleanup and exit audio module
|
extern void AudioExit(void); ///< cleanup and exit audio module
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user