[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] [gnuradio] 01/09: audio: osx audio fixes
From: |
git |
Subject: |
[Commit-gnuradio] [gnuradio] 01/09: audio: osx audio fixes |
Date: |
Fri, 25 Apr 2014 16:44:34 +0000 (UTC) |
This is an automated email from the git hooks/post-receive script.
trondeau pushed a commit to branch maint
in repository gnuradio.
commit 521e707297f9a5441cca559370a07b03a73b2abe
Author: Michael Dickens <address@hidden>
Date: Thu Apr 24 09:51:04 2014 -0400
audio: osx audio fixes
- fix dequeue to return 3 when the requested number of items to dequeue is
not the same as the actual number of items. fix comments to reflect this change
as well as the actual input and output info for this variable.
- fix comments. fix debug printouts to be consistent.
- fix the AU callback to not throw, since it is not handled robustly by the
OS routines that to the call. Add NOTE to this effect. Return better error
codes when an issue arises.
- correctly convert d_buffer_sample_count to int before using it.
- when stopping: if waiting in ::work, signal the thread to wake up, in the
hopes that it will correctly return and terminate. After stopping the AU,
abort and reset buffers as well as clear our local knowledge about the amount
of data in the queues.
---
gr-audio/lib/osx/circular_buffer.h | 15 ++-
gr-audio/lib/osx/osx_sink.cc | 218 +++++++++++++++++++++++++++----------
2 files changed, 173 insertions(+), 60 deletions(-)
diff --git a/gr-audio/lib/osx/circular_buffer.h
b/gr-audio/lib/osx/circular_buffer.h
index fee9eea..7a5cde0 100644
--- a/gr-audio/lib/osx/circular_buffer.h
+++ b/gr-audio/lib/osx/circular_buffer.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2006,2009,2010 Free Software Foundation, Inc.
+ * Copyright 2006,2009,2010,2014 Free Software Foundation, Inc.
*
* This file is part of GNU Radio.
*
@@ -218,13 +218,17 @@ public:
* inputs:
* buf: a pointer to the buffer into which to copy the data
*
- * bufLen_I: pointer to the number of items to remove in items
- * (of the instantiated type)
+ * bufLen_I: pointer to the requested number of items to remove
+ *
+ * outputs:
+ * bufLen_I: pointer to the actual number of items removed
*
* returns:
* 0: if nothing to do (0 length buffer)
* 1: if success
* 2: in the process of aborting, do doing nothing
+ * 3: if the number of requested items to remove is not the same
+ * as the actual number of items removed.
*
* will throw runtime errors if inputs are improper:
* buffer pointer is NULL
@@ -297,11 +301,14 @@ public:
d_readNdx_I = n_start_I;
} else
d_readNdx_I += n_now_I;
+ int rv = 1;
+ if (*bufLen_I != l_bufLen_I)
+ rv = 3;
*bufLen_I = l_bufLen_I;
d_n_avail_read_I -= l_bufLen_I;
d_n_avail_write_I += l_bufLen_I;
d_writeBlock->notify_one ();
- return (1);
+ return (rv);
};
void abort () {
diff --git a/gr-audio/lib/osx/osx_sink.cc b/gr-audio/lib/osx/osx_sink.cc
index f027e2e..2e1d32e 100644
--- a/gr-audio/lib/osx/osx_sink.cc
+++ b/gr-audio/lib/osx/osx_sink.cc
@@ -216,14 +216,15 @@ namespace gr {
}
// set the interim buffer size; to work with the GR scheduler,
- // must be at least 16kB. Pick 50 kB since that's plenty yet
+ // must be at least 16kB. Pick 50 kS since that's plenty yet
// not very much.
d_buffer_sample_count = (d_input_sample_rate < 50000.0 ?
50000 : (UInt32)d_input_sample_rate);
#if _OSX_AU_DEBUG_
- std::cerr << "sink(): max # samples = "
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink: max # samples = "
<< d_buffer_sample_count << std::endl;
#endif
@@ -420,7 +421,8 @@ namespace gr {
#if _OSX_AU_DEBUG_
- std::cerr << "audio_osx_sink Parameters:" << std::endl
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink Parameters:" << std::endl
<< " Sample Rate is " << d_input_sample_rate << std::endl
<< " Max # samples to store per channel is "
<< d_buffer_sample_count << std::endl;
@@ -429,6 +431,12 @@ namespace gr {
void osx_sink::teardown()
{
+#if _OSX_AU_DEBUG_
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::teardown: starting"
+ << std::endl;
+#endif
+
OSStatus err = noErr;
// stop the AudioUnit
@@ -491,6 +499,12 @@ namespace gr {
d_using_default_device = false;
d_output_au = 0;
d_output_ad_id = 0;
+
+#if _OSX_AU_DEBUG_
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::teardown: finished"
+ << std::endl;
+#endif
}
bool
@@ -547,7 +561,9 @@ namespace gr {
d_n_user_channels = ninputs;
#if _OSX_AU_DEBUG_
- std::cerr << "chk_topo: Actual # user input channels = "
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::check_topology: "
+ << "Actual # user input channels = "
<< d_n_user_channels << std::endl;
#endif
@@ -643,6 +659,12 @@ namespace gr {
{
if(!is_running() && d_output_au) {
+#if _OSX_AU_DEBUG_
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::start: starting Output AudioUnit."
+ << std::endl;
+#endif
+
// check channels, (re)allocate and reset buffers if/as necessary
check_channels(true);
@@ -655,6 +677,14 @@ namespace gr {
"audio_osx_sink::start");
}
+#if _OSX_AU_DEBUG_
+ else {
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::start: "
+ << "already running." << std::endl;
+ }
+#endif
+
return (true);
}
@@ -663,6 +693,23 @@ namespace gr {
{
if(is_running()) {
+#if _OSX_AU_DEBUG_
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::stop: "
+ << "stopping Output AudioUnit."
+ << std::endl;
+#endif
+
+ // if waiting in ::work, signal to wake up
+ if (d_waiting_for_data) {
+#if _OSX_AU_DEBUG_
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::stop: "
+ << "signaling waiting condition" << std::endl;
+#endif
+ d_cond_data.notify_one();
+ }
+
// stop the audio unit (should never fail)
OSStatus err = AudioOutputUnitStop(d_output_au);
@@ -670,12 +717,25 @@ namespace gr {
(err, "AudioOutputUnitStop",
"audio_osx_sink::stop");
- // abort all buffers
+ // abort and reset all buffers
for(UInt32 nn = 0; nn < d_n_user_channels; ++nn) {
d_buffers[nn]->abort();
+ d_buffers[nn]->reset();
}
+
+ // reset local knowledge of amount of data in queues
+
+ d_queue_sample_count = 0;
+
+ }
+#if _OSX_AU_DEBUG_
+ else {
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::stop: "
+ << "already stopped." << std::endl;
}
+#endif
return(true);
}
@@ -686,8 +746,14 @@ namespace gr {
gr_vector_void_star &output_items)
{
#if _OSX_AU_DEBUG_RENDER_
- std::cerr << ((void*)(pthread_self()))
- << " : audio_osx_sink::work: Starting." << std::endl;
+ {
+ gr::thread::scoped_lock l(d_internal);
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::work: "
+ << "Starting: #OI = "
+ << noutput_items << ", reset = "
+ << (d_do_reset ? "true" : "false") << std::endl;
+ }
#endif
if (d_do_reset) {
if (d_hardware_changed) {
@@ -719,8 +785,12 @@ namespace gr {
else {
#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "audio_osx_sink::work: doing reset."
- << std::endl;
+ {
+ gr::thread::scoped_lock l(d_internal);
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::work: "
+ << "doing reset." << std::endl;
+ }
#endif
GR_LOG_WARN(d_logger, boost::format
@@ -736,16 +806,13 @@ namespace gr {
gr::thread::scoped_lock l(d_internal);
-#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "audio_osx_sink::work: mutex locked."
- << std::endl;
-#endif
-
setup();
start();
#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "audio_osx_sink: returning after reset."
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink: "
+ << "returning 0 after reset."
<< std::endl;
#endif
return(0);
@@ -755,14 +822,16 @@ namespace gr {
gr::thread::scoped_lock l(d_internal);
// take the input data, copy it, and push it to the bottom of
- // the queue mono input are pushed onto queue[0]; stereo input
- // are pushed onto queue[1]. If the number of user/graph
+ // the queue. mono input is pushed onto queue[0]; stereo input
+ // is pushed onto queue[1]. If the number of user/graph
// channels is less than the number of device channels, copy the
// data from the last / highest number channel to remaining
// device channels.
+ // find the maximum amount of buffer space available right now
+
UInt32 l_max_count;
- int diff_count = d_buffer_sample_count - noutput_items;
+ int diff_count = ((int)d_buffer_sample_count) - noutput_items;
if(diff_count < 0) {
l_max_count = 0;
}
@@ -770,35 +839,39 @@ namespace gr {
l_max_count = (UInt32)diff_count;
}
-#if 0
- if(l_max_count < d_queueItemLength->back()) {
- // allow 2 buffers at a time, regardless of length
- l_max_count = d_queueItemLength->back();
- }
-#endif
-
#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "work1: qSC = " << d_queue_sample_count
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::work: "
+ << "qSC = " << d_queue_sample_count
<< ", lMC = "<< l_max_count
- << ", dmSC = " << d_buffer_sample_count
- << ", nOI = " << noutput_items << std::endl;
+ << ", dBSC = " << d_buffer_sample_count
+ << ", #OI = " << noutput_items << std::endl;
#endif
if(d_queue_sample_count > l_max_count) {
- // data coming in too fast; ok_to_block decides what to do
+
+ // data coming in too fast; ok_to_block decides what to do: if
+ // ok to block, then wait until the render callback makes
+ // enough space. If not blocking, detect overflow via writing
+ // data to the circular buffer.
+
if(d_ok_to_block == true) {
// block until there is data to return, or on reset
while(d_queue_sample_count > l_max_count) {
// release control so-as to allow data to be retrieved;
// block until there is data to return
#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "audio_osx_sink::work: waiting." << std::endl;
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::work: "
+ << "waiting." << std::endl;
#endif
d_waiting_for_data = true;
d_cond_data.wait(l);
d_waiting_for_data = false;
#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "audio_osx_sink::work: done waiting." << std::endl;
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::work: "
+ << "done waiting." << std::endl;
#endif
// the condition's 'notify' was called; acquire control to
// keep thread safe
@@ -807,8 +880,9 @@ namespace gr {
// up the next time this method is called.
if (d_do_reset) {
#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "audio_osx_sink::work: "
- "returning for reset." << std::endl;
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::work: "
+ << "returning 0 for reset." << std::endl;
#endif
return(0);
}
@@ -816,7 +890,8 @@ namespace gr {
}
}
- // not blocking case and overflow is handled by the circular buffer
+ // not blocking and overflow is handled by the circular buffer,
+ // or enough data space is available
// add the input frames to the buffers' queue, checking for overflow
@@ -839,23 +914,26 @@ namespace gr {
}
}
+ // did overflow occur?
+
if(res == -1) {
- // data coming in too fast
- // drop oldest buffer
+ // yes: data coming in too fast; drop oldest data.
fputs("aO", stderr);
fflush(stderr);
// set the local number of samples available to the max
d_queue_sample_count = d_buffers[0]->buffer_length_items();
}
else {
- // keep up the local sample count
+ // no: keep up the local sample count
d_queue_sample_count += noutput_items;
}
#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "work2: #OI = "
- << noutput_items << ", #Cnt = "
- << d_queue_sample_count << ", mSC = "
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::work: "
+ << "returning: #OI = "
+ << noutput_items << ", qSC = "
+ << d_queue_sample_count << ", bSS = "
<< d_buffer_sample_count << std::endl;
#endif
@@ -871,50 +949,78 @@ namespace gr {
UInt32 in_number_frames,
AudioBufferList* io_data)
{
+ // NOTE: This is a callback from the OS, so throwing here does
+ // not work; return an error instead when something does not go
+ // as planned.
+
osx_sink* This = reinterpret_cast<osx_sink*>(in_ref_con);
OSStatus err = noErr;
gr::thread::scoped_lock l(This->d_internal);
#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "cb_in: SC = " << This->d_queue_sample_count
- << ", in#F = " << in_number_frames << std::endl;
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::au_output_callback: "
+ << "starting: qSC = "
+ << This->d_queue_sample_count
+ << ", in#F = " << in_number_frames
+ << ", in#C = " << This->d_n_user_channels << std::endl;
#endif
if(This->d_queue_sample_count < in_number_frames) {
- // not enough data to fill request
- err = -1;
+
+ // not enough data to fill request; probably happened on
+ // start-up, where this callback was called before ::work was.
+
+ fputs("aU", stderr);
+ fflush(stderr);
+ err = kAudioUnitErr_Initialized;
+
}
else {
// enough data; remove data from our buffers into the AU's buffers
int nn = This->d_n_user_channels;
-
while(--nn >= 0) {
+
size_t t_n_output_items = in_number_frames;
float* out_buffer = (float*)(io_data->mBuffers[nn].mData);
- This->d_buffers[nn]->dequeue(out_buffer, &t_n_output_items);
- if(t_n_output_items != in_number_frames) {
- throw std::runtime_error
- ("audio_osx_sink::au_output_callback: "
- "number of available items changing "
- "unexpectedly (should never happen).");
+ int rv = This->d_buffers[nn]->dequeue
+ (out_buffer, &t_n_output_items);
+
+ if((rv != 1) || (t_n_output_items != in_number_frames)) {
+
+ std::cerr << "audio_osx_sink::au_output_callback: "
+ << "number of available items changing "
+ << "unexpectedly (should never happen): was "
+ << in_number_frames << " now "
+ << t_n_output_items<< std::endl;
+ err = kAudioUnitErr_TooManyFramesToProcess;
+
}
}
This->d_queue_sample_count -= in_number_frames;
}
-#if _OSX_AU_DEBUG_RENDER_
- std::cerr << "cb_out: SC = "
- << This->d_queue_sample_count << std::endl;
-#endif
-
// signal that data is available, if appropraite
if (This->d_waiting_for_data) {
+#if _OSX_AU_DEBUG_RENDER_
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::au_output_callback: "
+ << "signaling waiting condition" << std::endl;
+#endif
This->d_cond_data.notify_one();
}
+#if _OSX_AU_DEBUG_RENDER_
+ std::cerr << ((void*)(pthread_self()))
+ << " : audio_osx_sink::au_output_callback: "
+ << "returning: qSC = "
+ << This->d_queue_sample_count
+ << ", err = " << err << std::endl;
+#endif
+
return (err);
}
- [Commit-gnuradio] [gnuradio] branch maint updated (1567cbc -> aa4a33d), git, 2014/04/25
- [Commit-gnuradio] [gnuradio] 07/09: blocks: fixed documentation for what the max_XX block does., git, 2014/04/25
- [Commit-gnuradio] [gnuradio] 04/09: runtime: enable thread priority, same as with Linux; fix header comments to this effect, git, 2014/04/25
- [Commit-gnuradio] [gnuradio] 05/09: channels: fixing a minor bug in the flag_fader model., git, 2014/04/25
- [Commit-gnuradio] [gnuradio] 09/09: Merge branch 'maint' of git.gnuradio.org:gnuradio into maint, git, 2014/04/25
- [Commit-gnuradio] [gnuradio] 03/09: audio: osx: rename d_buffer_sample_count -> d_buffer_size_samples; truth in naming!, git, 2014/04/25
- [Commit-gnuradio] [gnuradio] 02/09: whitespace only, git, 2014/04/25
- [Commit-gnuradio] [gnuradio] 01/09: audio: osx audio fixes,
git <=
- [Commit-gnuradio] [gnuradio] 08/09: cmake: fixes expansion of ${pyexe_native} for cross builds with the use of VERBATIM., git, 2014/04/25
- [Commit-gnuradio] [gnuradio] 06/09: docs: fixed typo with logger docs., git, 2014/04/25