From 8aa595e9f7dad67dcb2c66763177957b6c81edd0 Mon Sep 17 00:00:00 2001 From: Bob van Loosen Date: Tue, 26 Mar 2013 21:57:03 +0100 Subject: [PATCH] added: use a trylock in the jack process function, if the log fails, copy the audio into a temp buffer, if the lock succeeds, copy audio from the temp buffer into the main buffer, this way the realtime jack thread will never block on locking the mutex --- src/bitvis/jackclient.cpp | 118 +++++++++++++++++++++++++++----------- src/bitvis/jackclient.h | 8 +-- src/util/lock.h | 27 ++++++++- 3 files changed, 113 insertions(+), 40 deletions(-) diff --git a/src/bitvis/jackclient.cpp b/src/bitvis/jackclient.cpp index 9b46b0d..944cec0 100644 --- a/src/bitvis/jackclient.cpp +++ b/src/bitvis/jackclient.cpp @@ -46,11 +46,15 @@ CJackClient::CJackClient() m_exitstatus = (jack_status_t)0; m_samplerate = 0; m_outsamplerate = 40000; - m_buf = NULL; - m_bufsize = 0; m_srcstate = NULL; - m_outsamples = 0; - m_audiotime = 0; + + for (int i = 0; i < 2; i++) + { + m_buf[i] = NULL; + m_bufsize[i] = 0; + m_outsamples[i] = 0; + m_audiotime[i] = 0; + } if (pipe2(m_pipe, O_NONBLOCK) == -1) { @@ -129,9 +133,17 @@ bool CJackClient::ConnectInternal() return false; } + //initialize the resampler int error; m_srcstate = src_new(SRC_SINC_FASTEST, 1, &error); + //alloc one second buffers + for (int i = 0; i < 2; i++) + { + m_bufsize[i] = m_outsamplerate; + m_buf[i] = (float*)malloc(m_bufsize[i] * sizeof(float)); + } + //everything set up, activate returnv = jack_activate(m_client); if (returnv != 0) @@ -167,9 +179,12 @@ void CJackClient::Disconnect() m_exitstatus = (jack_status_t)0; m_samplerate = 0; - free(m_buf); - m_buf = NULL; - m_bufsize = 0; + for (int i = 0; i < 2; i++) + { + free(m_buf[i]); + m_buf[i] = NULL; + m_bufsize[i] = 0; + } if (m_srcstate) { @@ -235,64 +250,97 @@ int CJackClient::SJackProcessCallback(jack_nframes_t nframes, void *arg) void CJackClient::PJackProcessCallback(jack_nframes_t nframes) { + int64_t now = GetTimeUs(); int outsamples = Round32((double)nframes / m_samplerate * m_outsamplerate + 2.0); - int neededsize = m_outsamples + outsamples; - if (neededsize > m_outsamplerate) + + //use a trylock, so the realtime jack thread doesn't block + CLock lock(m_condition, true); + + int index; + if (lock.HasLock()) { - return; + //the mutex is locked, copy samples from the temp buffer into the main buffer + if (m_outsamples[1] > 0) + { + //if the main buffer is empty, use the time from the temp buffer + if (m_outsamples[0] == 0) + m_audiotime[0] = m_audiotime[1]; + + //copy as many samples as possible from the temp buffer to the main buffer + int size = Min(m_outsamples[1], m_bufsize[0] - m_outsamples[0]); + memcpy(m_buf[0] + m_outsamples[0], m_buf[1], size * sizeof(float)); + m_outsamples[1] -= size; + m_outsamples[0] += size; + } + + //if the main buffer has enough room, put the audio samples there + //otherwise put them into the temp buffer + if (m_bufsize[0] - m_outsamples[0] >= outsamples) + index = 0; + else + index = 1; } - else if (m_bufsize < neededsize) + else { - m_bufsize = neededsize; - m_buf = (float*)realloc(m_buf, m_bufsize * sizeof(float)); + //the mutex couldn't be locked, copy samples into the temp buffer + index = 1; } - CLock lock(m_condition); + if (m_bufsize[index] - m_outsamples[index] < outsamples) + return; //no room, drop the samples - if (m_outsamples == 0) - m_audiotime = GetTimeUs(); + if (m_outsamples[index] == 0) + m_audiotime[index] = now; float* jackptr = (float*)jack_port_get_buffer(m_jackport, nframes); - SRC_DATA srcdata = {}; - srcdata.data_in = jackptr; - srcdata.data_out = m_buf + m_outsamples; - srcdata.input_frames = nframes; - srcdata.output_frames = outsamples; - srcdata.src_ratio = (double)m_outsamplerate / m_samplerate; + if (m_outsamplerate != m_samplerate) + { + SRC_DATA srcdata = {}; + srcdata.data_in = jackptr; + srcdata.data_out = m_buf[index] + m_outsamples[index]; + srcdata.input_frames = nframes; + srcdata.output_frames = outsamples; + srcdata.src_ratio = (double)m_outsamplerate / m_samplerate; - src_process(m_srcstate, &srcdata); - m_outsamples += srcdata.output_frames_gen; + src_process(m_srcstate, &srcdata); + m_outsamples[index] += srcdata.output_frames_gen; + + if (srcdata.input_frames_used < (int)nframes) + Log("WARNING: %i out of %i frames used", (int)srcdata.input_frames_used, (int)nframes); + } + else + { + memcpy(m_buf[index] + m_outsamples[index], jackptr, nframes * sizeof(float)); + m_outsamples[index] += nframes; + } lock.Leave(); m_condition.Signal(); - - if (srcdata.input_frames_used < (int)nframes) - Log("WARNING: %i out of %i frames used", (int)srcdata.input_frames_used, (int)nframes); } int CJackClient::GetAudio(float*& buf, int& bufsize, int& samplerate, int64_t& audiotime) { CLock lock(m_condition); - m_condition.Wait(1000000, m_outsamples, 0); + m_condition.Wait(1000000, m_outsamples[0], 0); - if (m_outsamples == 0) + if (m_outsamples[0] == 0) return 0; samplerate = m_outsamplerate; - if (bufsize < m_outsamples) + if (bufsize < m_outsamples[0]) { - bufsize = m_outsamples; + bufsize = m_outsamples[0]; buf = (float*)realloc(buf, bufsize * sizeof(float)); } - memcpy(buf, m_buf, m_outsamples * sizeof(float)); + memcpy(buf, m_buf[0], m_outsamples[0] * sizeof(float)); - int outsamples = m_outsamples; - m_outsamples = 0; + int outsamples = m_outsamples[0]; + m_outsamples[0] = 0; - audiotime = m_audiotime; + audiotime = m_audiotime[0]; return outsamples; } diff --git a/src/bitvis/jackclient.h b/src/bitvis/jackclient.h index f4edee2..df96147 100644 --- a/src/bitvis/jackclient.h +++ b/src/bitvis/jackclient.h @@ -60,11 +60,11 @@ class CJackClient int m_portevents; int m_pipe[2]; CCondition m_condition; - float* m_buf; - int m_bufsize; + float* m_buf[2]; + int m_bufsize[2]; + int m_outsamples[2]; + int64_t m_audiotime[2]; SRC_STATE* m_srcstate; - int m_outsamples; - int64_t m_audiotime; bool ConnectInternal(); void CheckMessages(); diff --git a/src/util/lock.h b/src/util/lock.h index 66259da..52a04d9 100644 --- a/src/util/lock.h +++ b/src/util/lock.h @@ -31,6 +31,15 @@ class CLock Enter(); } + CLock(CMutex& mutex, bool trylock) : m_mutex(mutex) + { + m_haslock = false; + if (trylock) + TryEnter(); + else + Enter(); + } + ~CLock() { Leave(); @@ -45,6 +54,17 @@ class CLock } } + void TryEnter() + { + if (!m_haslock) + { + if (m_mutex.TryLock()) + { + m_haslock = true; + } + } + } + void Leave() { if (m_haslock) @@ -54,9 +74,14 @@ class CLock } } + bool HasLock() + { + return m_haslock; + } + private: CMutex& m_mutex; bool m_haslock; }; -#endif //CLOCK \ No newline at end of file +#endif //CLOCK