--- a/sc2src/alsadirect.cpp
+++ b/sc2src/alsadirect.cpp
@@ -33,6 +33,7 @@
#include <iostream>
#include <queue>
+#include <mutex>
#include <alsa/asoundlib.h>
#include <samplerate.h>
@@ -62,13 +63,14 @@
started */
static bool qinit = false;
-static snd_pcm_t *pcm = nullptr;
+/* Alsa. Locked while we work with it */
+static std::mutex alsa_mutex;
+static snd_pcm_t *pcm;
static string alsadevice("default");
-
-static bool alsa_init(const string& dev, AudioMessage *tsk);
-static void alsa_close();
-
-// From MPD recovery code
+static snd_pcm_sframes_t alsa_delay;
+
+// From MPD recovery code.
+// Note: no locking: we're called from alsawriter holding the lock.
static int alsa_recover(snd_pcm_t *pcm, int err)
{
if (err == -EPIPE) {
@@ -124,6 +126,8 @@
static snd_pcm_uframes_t periodframes;
static snd_pcm_uframes_t bufferframes;
+static bool alsa_init(const string& dev, AudioMessage *tsk);
+
static void *alsawriter(void *p)
{
while (true) {
@@ -142,9 +146,9 @@
return (void*)1;
}
+ std::unique_lock<std::mutex> lock(alsa_mutex);
if (pcm == nullptr) {
if (!alsa_init(alsadevice, tsk)) {
- LOGERR("alsawriter: error alsa init\n");
alsaqueue.workerExit();
return (void*)1;
}
@@ -156,6 +160,12 @@
// be necessary, in synchronous mode, alsa is supposed to
// perform complete writes except for errors or interrupts
while (frames > 0) {
+ if (g_quitrequest) {
+ break;
+ }
+ if (snd_pcm_delay(pcm, &alsa_delay) < 0) {
+ alsa_delay = 0;
+ }
// LOGDEB("alsawriter: avail frames " << snd_pcm_avail(pcm) <<
// " writing " << frames << endl);
snd_pcm_sframes_t ret = snd_pcm_writei(pcm, tsk->m_buf, frames);
@@ -313,28 +323,19 @@
error:
LOGERR("alsa_init: " << cmd << " error:" << snd_strerror(err) << endl);
+ alsa_close();
return false;
}
-static void alsa_close()
+void alsa_close()
{
LOGDEB("alsawriter: alsa close\n");
+ std::unique_lock<std::mutex> lock(alsa_mutex);
+ alsa_delay = 0;
if (pcm != nullptr) {
snd_pcm_close(pcm);
pcm = nullptr;
}
-}
-
-// Current in-driver delay in samples
-static int alsadelay()
-{
- snd_pcm_sframes_t delay;
- if (pcm != nullptr) {
- if (snd_pcm_delay(pcm, &delay) >= 0) {
- return delay;
- }
- }
- return 0;
}
class Filter {
@@ -415,7 +416,7 @@
if (qinit) {
// Qsize in frames. This is the variable to control
- qs = alsaqueue.qsize() * bufframes + alsadelay();
+ qs = alsaqueue.qsize() * bufframes + alsa_delay;
// Error term
double qstargframes = qstarg * bufframes;
double et = ((qstargframes - qs) / qstargframes);
@@ -723,12 +724,17 @@
alsaqueue.start(1, alsawriter, 0);
while (true) {
+ if (g_quitrequest) {
+ goto done;
+ }
AudioMessage *tsk = 0;
// Get new data
if (!queue->take(&tsk)) {
LOGDEB("audioEater: alsadirect: queue take failed\n");
goto done;
}
+ alsaAudioEater.pktcounter++;
+
if (tsk->m_bytes == 0 || tsk->m_chans == 0 || tsk->m_bits == 0) {
LOGDEB("Zero buf\n");
continue;