diff options
author | samr7 <samr7@126591fb-c623-4b62-a76d-97a8e4f34109> | 2008-12-16 10:57:11 +0000 |
---|---|---|
committer | samr7 <samr7@126591fb-c623-4b62-a76d-97a8e4f34109> | 2008-12-16 10:57:11 +0000 |
commit | 1e43261e973311b3e38056689ed74778c8f70bfd (patch) | |
tree | 475afed7571bc33b9011708afc61a45bd9e614ac | |
parent | bf069c36824f59dc5c2865c54c84c4a73836b977 (diff) | |
download | nohands-1e43261e973311b3e38056689ed74778c8f70bfd.tar.gz |
If the playback thread sits idle, periodically wake it up using a timer.
Resolve a set of problems with the mmap access method.
git-svn-id: http://nohands.svn.sourceforge.net/svnroot/nohands/trunk@71 126591fb-c623-4b62-a76d-97a8e4f34109
-rw-r--r-- | libhfp/soundio-alsa.cpp | 87 |
1 files changed, 78 insertions, 9 deletions
diff --git a/libhfp/soundio-alsa.cpp b/libhfp/soundio-alsa.cpp index 9565684..06c1f83 100644 --- a/libhfp/soundio-alsa.cpp +++ b/libhfp/soundio-alsa.cpp @@ -1207,6 +1207,7 @@ class SoundIoAlsaProcThread : public SoundIoAlsaProcBaseThread { pthread_t m_rec_thread; TimerNotifier *m_async_not; bool m_play_idle; + TimerNotifier *m_play_wake; static void *PlayThreadHelper(void *arg) { SoundIoAlsaProcThread *objp = (SoundIoAlsaProcThread *) arg; @@ -1225,7 +1226,8 @@ public: const char *input_devspec) : SoundIoAlsaProcBaseThread(eip, output_devspec, input_devspec), - m_play_thread(0), m_rec_thread(0), m_async_not(0) {} + m_play_thread(0), m_rec_thread(0), + m_async_not(0), m_play_wake(0) {} virtual ~SoundIoAlsaProcThread() {} void RecThread(void) { @@ -1291,6 +1293,7 @@ public: snd_pcm_sframes_t err; bool underrun; ErrorInfo error; + unsigned int msec; m_lock.Lock(); if (m_play_nonblock) { @@ -1307,7 +1310,11 @@ public: m_play_nonblock = false; } + msec = (m_alsa.m_format.packet_samps * 1000) / + m_alsa.m_format.samplerate; + while (m_async_not) { + m_async_not->Set(0); (void) snd_pcm_avail_update(m_alsa.m_play_handle); if (!m_alsa.CheckXrun(m_alsa.m_play_handle, underrun, @@ -1323,15 +1330,20 @@ public: if (!nsamples) { /* * Wait for the master thread - * to submit more samples + * to submit more samples, or to + * wake us up via PlayThreadWakeup. */ m_play_idle = true; - m_async_not->Set(0); + m_play_wake->Set(msec / 2); m_lock.Wait(); continue; } - m_play_idle = false; + if (m_play_idle) { + m_play_wake->Cancel(); + m_play_idle = false; + } + m_lock.Unlock(); err = snd_pcm_writei(m_alsa.m_play_handle, buf, nsamples); @@ -1358,13 +1370,20 @@ public: } m_output.Dequeue(err); - if (m_async_not) - m_async_not->Set(0); } m_lock.Unlock(); } + void PlayThreadWakeup(TimerNotifier *notp) { + m_lock.Lock(); + if (m_play_idle) { + m_play_idle = false; + m_lock.Signal(); + } + m_lock.Unlock(); + } + virtual void SndPushInput(bool nonblock) { /* Nothing to do, except maybe wait for input to arrive */ } @@ -1414,6 +1433,8 @@ public: ErrorInfo *error) { int res; + m_play_idle = false; + m_async_not = m_alsa.m_ei->NewTimer(); if (!m_async_not) { if (error) @@ -1439,6 +1460,17 @@ public: } } if (playback) { + m_play_wake = m_alsa.m_ei->NewTimer(); + if (!m_play_wake) { + if (error) + error->SetNoMem(); + SndAsyncStop(); + return false; + } + + m_play_wake->Register(this, + &SoundIoAlsaProcThread::PlayThreadWakeup); + m_play_idle = true; res = pthread_create(&m_play_thread, 0, &SoundIoAlsaProcThread::PlayThreadHelper, @@ -1482,6 +1514,11 @@ public: m_play_thread = 0; } BufClose(); + + if (m_play_wake) { + delete m_play_wake; + m_play_wake = 0; + } } virtual bool SndIsAsyncStarted(void) const { @@ -1541,9 +1578,17 @@ public: } virtual bool SndOpen(bool play, bool capture, ErrorInfo *error) { - return m_alsa.OpenDevice(SND_PCM_ACCESS_MMAP_INTERLEAVED, - play, capture, error) && - SetPacketSize(error); + if (!m_alsa.OpenDevice(SND_PCM_ACCESS_MMAP_INTERLEAVED, + play, capture, error)) + return false; + if (!SetPacketSize(error)) { + m_alsa.CloseDevice(); + return false; + } + + m_qs.in_overflow = false; + m_qs.out_underflow = false; + return true; } virtual void SndClose(void) { SndAsyncStop(); @@ -1569,6 +1614,8 @@ public: if (!SetPacketSize(error)) { return false; } + m_qs.in_overflow = false; + m_qs.out_underflow = false; return true; } @@ -1623,6 +1670,8 @@ public: virtual void SndDequeueIBuf(sio_sampnum_t deqme) { int err; + m_qs.in_overflow = false; + if (m_rec_areas) { if (deqme < m_rec_size) { m_rec_size -= deqme; @@ -1717,6 +1766,8 @@ public: assert(m_play_areas); assert(qcount <= m_play_size); + m_qs.out_underflow = false; + m_play_areas = NULL; err = snd_pcm_mmap_commit(m_alsa.m_play_handle, m_play_off, qcount); @@ -1800,7 +1851,25 @@ public: if (m_abort) { do_abort: SndHandleAbort(m_abort); + return; + } + + if (m_alsa.m_play_not && + (m_qs.out_queued < m_alsa.m_play_props.bufsize)) { + /* + * ALSA wants to alert us whenever our output + * buffer free space increases above some level. + * We just want to know whenever pktsize samples + * have been processed. + */ + snd_pcm_uframes_t exp; + exp = ((m_alsa.m_play_props.bufsize - + m_qs.out_queued) + + m_alsa.m_play_props.packetsize); + + m_alsa.SetAvailMin(m_alsa.m_play_handle, exp); } + } virtual bool SndAsyncStart(bool playback, bool capture, |