Skip to content

Commit 6e0895c

Browse files
committedMar 7, 2014
fix gr-audio osx:
+ use GNU Radio preferences file to set default input and output audio device, if provided; + use gr::logger for all non-debug messages; + case-insensitive string find with desired audio device name; + fixes buffer allocation bug with low sample rates; + allows using a specific (named) audio device, or the default; + handles the case when the selected audio device becomes unavailable (e.g., a USB stick is removed while in use); + if no audio device name is provided, uses the default audio device as found in System Preferences::Sound; + handles the case when the default audio device is in use, and the user changes that audio device in System Preferences::Sound, by internally resetting to use the newly selected audio device; + all non-Apple names are now lower_case, not CamelCase; + move osx_impl functions to gr::audio::osx, and use them correctly; + install osx_impl.h to expose gr::audio::osx functions, but iff OSX audio is enabled.
1 parent ca69ec5 commit 6e0895c

12 files changed

+2648
-1141
lines changed
 

‎gr-audio/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,8 @@ CPACK_COMPONENT("audio_swig"
8686
########################################################################
8787
# Add subdirectories
8888
########################################################################
89-
add_subdirectory(include/gnuradio/audio)
9089
add_subdirectory(lib)
90+
add_subdirectory(include/gnuradio/audio)
9191
add_subdirectory(doc)
9292
if(ENABLE_PYTHON)
9393
add_subdirectory(swig)

‎gr-audio/include/gnuradio/audio/CMakeLists.txt

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2011,2013 Free Software Foundation, Inc.
1+
# Copyright 2011,2013-2014 Free Software Foundation, Inc.
22
#
33
# This file is part of GNU Radio
44
#
@@ -20,10 +20,14 @@
2020
########################################################################
2121
# Install header files
2222
########################################################################
23-
install(FILES
24-
api.h
25-
source.h
26-
sink.h
23+
24+
SET(gr_audio_install_files api.h source.h sink.h)
25+
26+
if(OSX_AUDIO_VALID)
27+
list(APPEND gr_audio_install_files osx_impl.h)
28+
endif(OSX_AUDIO_VALID)
29+
30+
install(FILES ${gr_audio_install_files}
2731
DESTINATION ${GR_INCLUDE_DIR}/gnuradio/audio
2832
COMPONENT "audio_devel"
2933
)
+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/* -*- c++ -*- */
2+
/*
3+
* Copyright 2006, 2013-2014 Free Software Foundation, Inc.
4+
*
5+
* This file is part of GNU Radio.
6+
*
7+
* GNU Radio is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3, or (at your option)
10+
* any later version.
11+
*
12+
* GNU Radio is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with GNU Radio; see the file COPYING. If not, write to
19+
* the Free Software Foundation, Inc., 51 Franklin Street,
20+
* Boston, MA 02110-1301, USA.
21+
*/
22+
23+
#ifndef INCLUDED_AUDIO_OSX_IMPL_H
24+
#define INCLUDED_AUDIO_OSX_IMPL_H
25+
26+
#include <gnuradio/audio/api.h>
27+
28+
#include <iostream>
29+
#include <vector>
30+
31+
#include <string.h>
32+
33+
#include <AudioToolbox/AudioToolbox.h>
34+
#include <AudioUnit/AudioUnit.h>
35+
36+
namespace gr {
37+
namespace audio {
38+
namespace osx {
39+
40+
// Check the version of MacOSX being used
41+
#ifdef __APPLE_CC__
42+
#include <AvailabilityMacros.h>
43+
#ifndef MAC_OS_X_VERSION_10_6
44+
#define MAC_OS_X_VERSION_10_6 1060
45+
#endif
46+
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6
47+
#define GR_USE_OLD_AUDIO_UNIT
48+
#endif
49+
#endif
50+
51+
// helper function to print an ASBD
52+
53+
extern std::ostream& GR_AUDIO_API
54+
operator<<
55+
(std::ostream& s,
56+
const AudioStreamBasicDescription& asbd);
57+
58+
// returns the number of channels for the provided AudioDeviceID,
59+
// input and/or output depending on if the pointer is valid.
60+
61+
extern void GR_AUDIO_API
62+
get_num_channels_for_audio_device_id
63+
(AudioDeviceID ad_id,
64+
UInt32* n_input,
65+
UInt32* n_output);
66+
67+
// search all known audio devices, input or output, for all that
68+
// match the provided device_name string (in part or in whole).
69+
// Returns a vector of all matching IDs, and another of all
70+
// matching names. If the device name is empty, then match all
71+
// input or output devices.
72+
73+
extern void GR_AUDIO_API
74+
find_audio_devices
75+
(const std::string& device_name,
76+
bool is_input,
77+
std::vector < AudioDeviceID >* all_ad_ids,
78+
std::vector < std::string >* all_names);
79+
80+
} /* namespace osx */
81+
} /* namespace audio */
82+
} /* namespace gr */
83+
84+
#endif /* INCLUDED_AUDIO_OSX_IMPL_H */

‎gr-audio/lib/CMakeLists.txt

+9
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,8 @@ CHECK_INCLUDE_FILE_CXX(AudioToolbox/AudioToolbox.h AUDIO_TOOLBOX_H)
106106

107107
if(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H)
108108

109+
set(OSX_AUDIO_VALID 1 CACHE INTERNAL "OSX Audio is valid")
110+
109111
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/osx)
110112
list(APPEND gr_audio_libs
111113
"-framework AudioUnit"
@@ -114,10 +116,17 @@ if(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H)
114116
"-framework Carbon"
115117
)
116118
list(APPEND gr_audio_sources
119+
${CMAKE_CURRENT_SOURCE_DIR}/osx/osx_impl.cc
117120
${CMAKE_CURRENT_SOURCE_DIR}/osx/osx_source.cc
118121
${CMAKE_CURRENT_SOURCE_DIR}/osx/osx_sink.cc
119122
)
120123

124+
list(APPEND gr_audio_confs ${CMAKE_CURRENT_SOURCE_DIR}/osx/gr-audio-osx.conf)
125+
126+
else(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H)
127+
128+
set(OSX_AUDIO_VALID 0 CACHE INTERNAL "OSX Audio is not valid")
129+
121130
endif(AUDIO_UNIT_H AND AUDIO_TOOLBOX_H)
122131

123132
########################################################################

‎gr-audio/lib/osx/gr-audio-osx.conf

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# This file contains system wide configuration data for GNU Radio.
2+
# You may override any setting on a per-user basis by editing
3+
# ~/.gnuradio/config.conf. For OSX audio only, you can use a unique
4+
# subset of the actual device name to set these variables. By this
5+
# default, the OSX audio will use whatever devices are selected in
6+
# System Preferences::Sound for input and output.
7+
8+
[audio_osx]
9+
10+
default_input_device =
11+
default_output_device =

‎gr-audio/lib/osx/osx_common.h

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/* -*- c++ -*- */
2+
/*
3+
* Copyright 2014 Free Software Foundation, Inc.
4+
*
5+
* This file is part of GNU Radio.
6+
*
7+
* GNU Radio is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3, or (at your option)
10+
* any later version.
11+
*
12+
* GNU Radio is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with GNU Radio; see the file COPYING. If not, write to
19+
* the Free Software Foundation, Inc., 51 Franklin Street,
20+
* Boston, MA 02110-1301, USA.
21+
*/
22+
23+
#ifndef INCLUDED_AUDIO_OSX_COMMON_H
24+
#define INCLUDED_AUDIO_OSX_COMMON_H
25+
26+
#include <gnuradio/audio/osx_impl.h>
27+
28+
namespace gr {
29+
namespace audio {
30+
namespace osx {
31+
32+
#define _OSX_AU_DEBUG_ 0
33+
#define _OSX_AU_DEBUG_RENDER_ 0
34+
35+
#define check_error_and_throw(err,what,throw_str) \
36+
if(err) { \
37+
OSStatus error = static_cast<OSStatus>(err); \
38+
char err_str[5]; \
39+
*((UInt32*)err_str) = error; \
40+
err_str[4] = 0; \
41+
GR_LOG_FATAL(d_logger, boost::format(what)); \
42+
GR_LOG_FATAL(d_logger, boost::format(" Error# %u ('%s')") \
43+
% error % err_str); \
44+
GR_LOG_FATAL(d_logger, boost::format(" %s:%d") \
45+
% __FILE__ %__LINE__); \
46+
throw std::runtime_error(throw_str); \
47+
}
48+
49+
#define check_error(err,what) \
50+
if(err) { \
51+
OSStatus error = static_cast<OSStatus>(err); \
52+
char err_str[5]; \
53+
*((UInt32*)err_str) = error; \
54+
err_str[4] = 0; \
55+
GR_LOG_WARN(d_logger, boost::format(what)); \
56+
GR_LOG_WARN(d_logger, boost::format(" Error# %u ('%s')") \
57+
% error % err_str); \
58+
GR_LOG_WARN(d_logger, boost::format(" %s:%d") \
59+
% __FILE__ %__LINE__); \
60+
}
61+
62+
#include <boost/detail/endian.hpp> //BOOST_BIG_ENDIAN
63+
#ifdef BOOST_BIG_ENDIAN
64+
#define GR_PCM_ENDIANNESS kLinearPCMFormatFlagIsBigEndian
65+
#else
66+
#define GR_PCM_ENDIANNESS 0
67+
#endif
68+
69+
} /* namespace osx */
70+
} /* namespace audio */
71+
} /* namespace gr */
72+
73+
#endif /* INCLUDED_AUDIO_OSX_COMMON_H */

‎gr-audio/lib/osx/osx_impl.cc

+313
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
/* -*- c++ -*- */
2+
/*
3+
* Copyright 2014 Free Software Foundation, Inc.
4+
*
5+
* This file is part of GNU Radio.
6+
*
7+
* GNU Radio is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 3, or (at your option)
10+
* any later version.
11+
*
12+
* GNU Radio is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with GNU Radio; see the file COPYING. If not, write to
19+
* the Free Software Foundation, Inc., 51 Franklin Street,
20+
* Boston, MA 02110-1301, USA.
21+
*/
22+
23+
#ifdef HAVE_CONFIG_H
24+
#include "config.h"
25+
#endif
26+
27+
#include "audio_registry.h"
28+
29+
#include <gnuradio/audio/osx_impl.h>
30+
31+
#include <algorithm>
32+
#include <iostream>
33+
#include <locale>
34+
#include <stdexcept>
35+
36+
namespace gr {
37+
namespace audio {
38+
namespace osx {
39+
40+
std::ostream&
41+
operator<<
42+
(std::ostream& s,
43+
const AudioStreamBasicDescription& asbd)
44+
{
45+
char format_id[5];
46+
*((UInt32*)format_id) = asbd.mFormatID;
47+
format_id[4] = 0;
48+
s << " Sample Rate : " << asbd.mSampleRate << std::endl;
49+
s << " Format ID : " << format_id << std::endl;
50+
s << " Format Flags : " << asbd.mFormatFlags << std::endl;
51+
s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
52+
<< " : Is Float" << std::endl;
53+
s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0)
54+
<< " : Is Big Endian" << std::endl;
55+
s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
56+
<< " : Is Signed Integer" << std::endl;
57+
s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsPacked) != 0)
58+
<< " : Is Packed" << std::endl;
59+
s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsAlignedHigh) != 0)
60+
<< " : Is Aligned High" << std::endl;
61+
s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsNonInterleaved) != 0)
62+
<< " : Is Non-Interleaved" << std::endl;
63+
s << " " << ((asbd.mFormatFlags & kAudioFormatFlagIsNonMixable) != 0)
64+
<< " : Is Non-Mixable" << std::endl;
65+
s << " Bytes / Packet : " << asbd.mBytesPerPacket << std::endl;
66+
s << " Frames / Packet : " << asbd.mFramesPerPacket << std::endl;
67+
s << " Bytes / Frame : " << asbd.mBytesPerFrame << std::endl;
68+
s << " Channels / Frame : " << asbd.mChannelsPerFrame << std::endl;
69+
s << " Bits / Channel : " << asbd.mBitsPerChannel;
70+
return(s);
71+
};
72+
73+
static UInt32
74+
_get_num_channels
75+
(AudioDeviceID ad_id,
76+
AudioObjectPropertyScope scope)
77+
{
78+
// retrieve the AudioBufferList associated with this ID using
79+
// the provided scope
80+
81+
UInt32 num_channels = 0;
82+
UInt32 prop_size = 0;
83+
AudioObjectPropertyAddress ao_address = {
84+
kAudioDevicePropertyStreamConfiguration, scope, 0
85+
};
86+
OSStatus err = noErr;
87+
if ((err = AudioObjectGetPropertyDataSize
88+
(ad_id, &ao_address, 0, NULL,
89+
&prop_size)) == noErr) {
90+
boost::scoped_array<AudioBufferList> buf_list
91+
(reinterpret_cast<AudioBufferList*>
92+
(new char[prop_size]));
93+
if ((err = AudioObjectGetPropertyData
94+
(ad_id, &ao_address, 0, NULL,
95+
&prop_size, buf_list.get())) == noErr) {
96+
for (UInt32 mm = 0; mm < buf_list.get()->mNumberBuffers; ++mm) {
97+
num_channels += buf_list.get()->mBuffers[mm].mNumberChannels;
98+
}
99+
}
100+
else {
101+
// assume 2 channels
102+
num_channels = 2;
103+
}
104+
}
105+
else {
106+
// assume 2 channels
107+
num_channels = 2;
108+
}
109+
return(num_channels);
110+
}
111+
112+
// works with both char and wchar_t
113+
template<typename charT>
114+
struct ci_equal {
115+
ci_equal( const std::locale& loc ) : loc_(loc) {}
116+
bool operator()(charT ch1, charT ch2) {
117+
return std::tolower(ch1, loc_) == std::tolower(ch2, loc_);
118+
}
119+
private:
120+
const std::locale& loc_;
121+
};
122+
123+
// find substring (case insensitive)
124+
static std::string::size_type ci_find_substr
125+
(const std::string& str1, const std::string& str2,
126+
const std::locale& loc = std::locale())
127+
{
128+
std::string::const_iterator it = std::search
129+
(str1.begin(), str1.end(),
130+
str2.begin(), str2.end(),
131+
ci_equal<std::string::value_type>(loc));
132+
if (it != str1.end()) {
133+
return(it - str1.begin());
134+
}
135+
// not found
136+
return(std::string::npos);
137+
}
138+
139+
void
140+
get_num_channels_for_audio_device_id
141+
(AudioDeviceID ad_id,
142+
UInt32* n_input,
143+
UInt32* n_output)
144+
{
145+
if (n_input) {
146+
*n_input = _get_num_channels
147+
(ad_id, kAudioDevicePropertyScopeInput);
148+
}
149+
if (n_output) {
150+
*n_output = _get_num_channels
151+
(ad_id, kAudioDevicePropertyScopeOutput);
152+
}
153+
}
154+
155+
void
156+
find_audio_devices
157+
(const std::string& device_name,
158+
bool is_input,
159+
std::vector < AudioDeviceID >* all_ad_ids,
160+
std::vector < std::string >* all_names)
161+
{
162+
if ((!all_ad_ids) && (!all_names)) {
163+
// if nothing is requested, no point in doing anything!
164+
return;
165+
}
166+
167+
OSStatus err = noErr;
168+
169+
// set the default audio device id to "unknown"
170+
171+
AudioDeviceID d_ad_id = kAudioDeviceUnknown;
172+
173+
// retrieve the size of the array of known audio device IDs
174+
175+
UInt32 prop_size = 0;
176+
177+
AudioObjectPropertyAddress ao_address = {
178+
kAudioHardwarePropertyDevices,
179+
kAudioObjectPropertyScopeGlobal,
180+
kAudioObjectPropertyElementMaster
181+
};
182+
183+
if ((err = AudioObjectGetPropertyDataSize
184+
(kAudioObjectSystemObject, &ao_address,
185+
0, NULL, &prop_size)) != noErr) {
186+
#if _OSX_AU_DEBUG_
187+
std::cerr << "audio_osx::find_audio_devices: "
188+
<< "Unable to retrieve number of audio objects: "
189+
<< err << std::endl;
190+
#endif
191+
return;
192+
}
193+
194+
// get the total number of audio devices (input and output)
195+
196+
UInt32 num_devices = prop_size / sizeof(AudioDeviceID);
197+
198+
// retrieve all audio device ids
199+
200+
boost::scoped_array < AudioDeviceID > all_dev_ids
201+
(new AudioDeviceID[num_devices]);
202+
203+
if ((err = AudioObjectGetPropertyData
204+
(kAudioObjectSystemObject, &ao_address,
205+
0, NULL, &prop_size, all_dev_ids.get())) != noErr) {
206+
#if _OSX_AU_DEBUG_
207+
std::cerr << "audio_osx::find_audio_devices: "
208+
<< "Unable to retrieve audio object ids: "
209+
<< err << std::endl;
210+
#endif
211+
return;
212+
}
213+
214+
// success; loop over all retrieved output device ids, retrieving
215+
// the name for each and comparing with the desired name.
216+
217+
std::vector< std::string > valid_names(num_devices);
218+
std::vector< UInt32 > valid_indices(num_devices);
219+
UInt32 num_found_devices = 0;
220+
AudioObjectPropertyScope scope = is_input ?
221+
kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
222+
223+
for (UInt32 nn = 0; nn < num_devices; ++nn) {
224+
225+
// make sure this device has input / output channels (it might
226+
// also have output / input channels, too, but we do not care
227+
// about that here)
228+
229+
AudioDeviceID t_id = all_dev_ids[nn];
230+
231+
if (is_input) {
232+
UInt32 n_input_channels = 0;
233+
get_num_channels_for_audio_device_id
234+
(t_id, &n_input_channels, NULL);
235+
if (n_input_channels == 0) {
236+
// no input channels; must be output device; just continue
237+
// to the next audio device.
238+
continue;
239+
}
240+
} else {
241+
UInt32 n_output_channels = 0;
242+
get_num_channels_for_audio_device_id
243+
(t_id, NULL, &n_output_channels);
244+
if (n_output_channels == 0) {
245+
// no output channels; must be input device; just continue
246+
// to the next audio device.
247+
continue;
248+
}
249+
}
250+
251+
// retrieve the device name; max name length is 64 characters.
252+
253+
prop_size = 65;
254+
char c_name_buf[prop_size];
255+
bzero((void*)c_name_buf, prop_size);
256+
--prop_size;
257+
258+
AudioObjectPropertyAddress ao_address = {
259+
kAudioDevicePropertyDeviceName, scope, 0
260+
};
261+
262+
if ((err = AudioObjectGetPropertyData
263+
(t_id, &ao_address, 0, NULL,
264+
&prop_size, (void*)c_name_buf)) != noErr) {
265+
#if _OSX_AU_DEBUG_
266+
std::cerr << "audio_osx::find_audio_devices: "
267+
<< "Unable to retrieve audio device name #"
268+
<< (nn+1) << ": " << err << std::endl;
269+
#endif
270+
continue;
271+
}
272+
std::string name_buf(c_name_buf);
273+
274+
// compare the retreived name with the desired one, if
275+
// provided; case insensitive.
276+
277+
if (device_name.length() > 0) {
278+
279+
std::string::size_type found =
280+
ci_find_substr(name_buf, device_name);
281+
if (found == std::string::npos) {
282+
// not found; continue to the next ID
283+
continue;
284+
}
285+
}
286+
287+
// store this info
288+
289+
valid_names[nn] = name_buf;
290+
valid_indices[num_found_devices++] = nn;
291+
292+
}
293+
294+
// resize valid function arguments, then copy found values
295+
296+
if (all_ad_ids) {
297+
all_ad_ids->resize(num_found_devices);
298+
for (UInt32 nn = 0; nn < num_found_devices; ++nn) {
299+
(*all_ad_ids)[nn] = all_dev_ids[valid_indices[nn]];
300+
}
301+
}
302+
303+
if (all_names) {
304+
all_names->resize(num_found_devices);
305+
for (UInt32 nn = 0; nn < num_found_devices; ++nn) {
306+
(*all_names)[nn] = valid_names[valid_indices[nn]];
307+
}
308+
}
309+
}
310+
311+
} /* namespace osx */
312+
} /* namespace audio */
313+
} /* namespace gr */

‎gr-audio/lib/osx/osx_impl.h

-78
This file was deleted.

‎gr-audio/lib/osx/osx_sink.cc

+778-237
Large diffs are not rendered by default.

‎gr-audio/lib/osx/osx_sink.h

+84-33
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* -*- c++ -*- */
22
/*
3-
* Copyright 2006-2011,2013 Free Software Foundation, Inc.
3+
* Copyright 2006-2011,2013-2014 Free Software Foundation, Inc.
44
*
55
* This file is part of GNU Radio.
66
*
@@ -24,10 +24,9 @@
2424
#define INCLUDED_AUDIO_OSX_SINK_H
2525

2626
#include <gnuradio/audio/sink.h>
27-
#include <string>
28-
#include <list>
29-
#include <AudioUnit/AudioUnit.h>
30-
#include <circular_buffer.h>
27+
28+
#include "osx_common.h"
29+
#include "circular_buffer.h"
3130

3231
namespace gr {
3332
namespace audio {
@@ -42,44 +41,96 @@ namespace gr {
4241

4342
class osx_sink : public sink
4443
{
45-
Float64 d_sample_rate;
46-
int d_channel_config;
47-
UInt32 d_n_channels;
48-
UInt32 d_queueSampleCount, d_max_sample_count;
49-
bool d_do_block;
50-
gr::thread::mutex* d_internal;
51-
gr::thread::condition_variable* d_cond_data;
52-
circular_buffer<float>** d_buffers;
44+
protected:
45+
46+
Float64 d_input_sample_rate;
47+
UInt32 d_n_user_channels, d_n_dev_channels, d_n_buffer_channels;
48+
UInt32 d_queue_sample_count, d_buffer_sample_count;
49+
bool d_ok_to_block, d_do_reset, d_hardware_changed;
50+
bool d_using_default_device, d_waiting_for_data;
51+
gr::thread::mutex d_internal;
52+
gr::thread::condition_variable d_cond_data;
53+
std::vector < circular_buffer < float > *> d_buffers;
54+
std::string d_desired_name, d_selected_name;
5355

5456
// AudioUnits and Such
55-
AudioUnit d_OutputAU;
57+
58+
AudioUnit d_output_au;
59+
AudioDeviceID d_output_ad_id;
60+
AudioStreamBasicDescription d_stream_format;
5661

5762
public:
58-
osx_sink(int sample_rate = 44100,
59-
const std::string device_name = "2",
60-
bool do_block = true,
61-
int channel_config = -1,
62-
int max_sample_count = -1);
6363

64-
~osx_sink();
64+
osx_sink(int sample_rate,
65+
const std::string& device_name,
66+
bool ok_to_block);
6567

66-
bool IsRunning();
67-
bool start();
68-
bool stop();
68+
inline virtual ~osx_sink() {
69+
teardown();
70+
}
6971

70-
int work(int noutput_items,
71-
gr_vector_const_void_star &input_items,
72-
gr_vector_void_star &output_items);
72+
virtual bool check_topology(int ninputs, int noutputs);
73+
virtual bool start();
74+
virtual bool stop();
75+
76+
virtual int work(int noutput_items,
77+
gr_vector_const_void_star &input_items,
78+
gr_vector_void_star &output_items);
79+
80+
inline void reset(bool hardware_changed) {
81+
d_hardware_changed = hardware_changed;
82+
d_do_reset = true;
83+
}
7384

7485
private:
75-
static OSStatus AUOutputCallback(void *inRefCon,
76-
AudioUnitRenderActionFlags *ioActionFlags,
77-
const AudioTimeStamp *inTimeStamp,
78-
UInt32 inBusNumber,
79-
UInt32 inNumberFrames,
80-
AudioBufferList *ioData);
81-
};
8286

87+
bool is_running();
88+
89+
void setup();
90+
91+
void teardown();
92+
93+
void check_channels(bool force_reset);
94+
95+
static OSStatus au_output_callback
96+
(void* in_ref_con,
97+
AudioUnitRenderActionFlags* io_action_flags,
98+
const AudioTimeStamp* in_time_stamp,
99+
UInt32 in_bus_number,
100+
UInt32 in_number_frames,
101+
AudioBufferList* io_data);
102+
103+
#ifndef GR_USE_OLD_AUDIO_UNIT
104+
105+
// OSX 10.4 and newer
106+
107+
static OSStatus hardware_listener
108+
(AudioObjectID in_object_id,
109+
UInt32 in_num_addresses,
110+
const AudioObjectPropertyAddress in_addresses[],
111+
void* in_client_data);
112+
113+
static OSStatus default_listener
114+
(AudioObjectID in_object_id,
115+
UInt32 in_num_addresses,
116+
const AudioObjectPropertyAddress in_addresses[],
117+
void* in_client_data);
118+
119+
#else
120+
121+
// OSX 10.6 and older; removed as of 10.7
122+
123+
static OSStatus hardware_listener
124+
(AudioHardwarePropertyID in_property_id,
125+
void* in_client_data);
126+
127+
static OSStatus default_listener
128+
(AudioHardwarePropertyID in_property_id,
129+
void* in_client_data);
130+
131+
#endif
132+
133+
};
83134
} /* namespace audio */
84135
} /* namespace gr */
85136

‎gr-audio/lib/osx/osx_source.cc

+1,163-718
Large diffs are not rendered by default.

‎gr-audio/lib/osx/osx_source.h

+123-69
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* -*- c++ -*- */
22
/*
3-
* Copyright 2006-2011,2013 Free Software Foundation, Inc.
3+
* Copyright 2006-2011,2013-2014 Free Software Foundation, Inc.
44
*
55
* This file is part of GNU Radio.
66
*
@@ -24,10 +24,9 @@
2424
#define INCLUDED_AUDIO_OSX_SOURCE_H
2525

2626
#include <gnuradio/audio/source.h>
27-
#include <string>
28-
#include <AudioToolbox/AudioToolbox.h>
29-
#include <AudioUnit/AudioUnit.h>
30-
#include <circular_buffer.h>
27+
28+
#include "osx_common.h"
29+
#include "circular_buffer.h"
3130

3231
namespace gr {
3332
namespace audio {
@@ -41,80 +40,135 @@ namespace gr {
4140
*/
4241
class osx_source : public source
4342
{
44-
Float64 d_deviceSampleRate, d_outputSampleRate;
45-
int d_channel_config;
46-
UInt32 d_inputBufferSizeFrames, d_inputBufferSizeBytes;
47-
UInt32 d_outputBufferSizeFrames, d_outputBufferSizeBytes;
48-
UInt32 d_deviceBufferSizeFrames, d_deviceBufferSizeBytes;
49-
UInt32 d_leadSizeFrames, d_leadSizeBytes;
50-
UInt32 d_trailSizeFrames, d_trailSizeBytes;
51-
UInt32 d_extraBufferSizeFrames, d_extraBufferSizeBytes;
52-
UInt32 d_queueSampleCount, d_max_sample_count;
53-
UInt32 d_n_AvailableInputFrames, d_n_ActualInputFrames;
54-
UInt32 d_n_user_channels, d_n_max_channels, d_n_deviceChannels;
55-
bool d_do_block, d_passThrough, d_waiting_for_data;
56-
gr::thread::mutex* d_internal;
57-
gr::thread::condition_variable* d_cond_data;
58-
circular_buffer<float>** d_buffers;
59-
60-
// AudioUnits and Such
61-
AudioUnit d_InputAU;
62-
AudioBufferList* d_InputBuffer;
63-
AudioBufferList* d_OutputBuffer;
64-
AudioConverterRef d_AudioConverter;
43+
private:
44+
45+
Float64 d_device_sample_rate, d_output_sample_rate;
46+
UInt32 d_input_buffer_size_frames, d_input_buffer_size_bytes;
47+
UInt32 d_output_buffer_size_frames, d_output_buffer_size_bytes;
48+
UInt32 d_device_buffer_size_frames, d_device_buffer_size_bytes;
49+
UInt32 d_lead_size_frames, d_lead_size_bytes;
50+
UInt32 d_trail_size_frames, d_trail_size_bytes;
51+
UInt32 d_extra_buffer_size_frames, d_extra_buffer_size_bytes;
52+
UInt32 d_queue_sample_count, d_buffer_sample_count;
53+
UInt32 d_n_available_input_frames, d_n_actual_input_frames;
54+
UInt32 d_n_user_channels, d_n_dev_channels;
55+
bool d_ok_to_block, d_pass_through;
56+
bool d_waiting_for_data, d_do_reset, d_hardware_changed;
57+
bool d_using_default_device;
58+
gr::thread::mutex d_internal;
59+
gr::thread::condition_variable d_cond_data;
60+
std::vector < circular_buffer<float>* > d_buffers;
61+
std::string d_desired_name, d_selected_name;
62+
63+
// CoreAudio variables
64+
65+
AudioDeviceID d_input_ad_id;
66+
AudioUnit d_input_au;
67+
AudioBufferList* d_input_buffer;
68+
AudioBufferList* d_output_buffer;
69+
AudioConverterRef d_audio_converter;
70+
71+
// d_asbd_device: ASBD of the device that is creating the input
72+
// data stream
73+
74+
AudioStreamBasicDescription d_asbd_device;
75+
76+
// d_asbd_client: ASBD of the client side (output) of the
77+
// hardware device
78+
79+
AudioStreamBasicDescription d_asbd_client;
80+
81+
// d_asbd_user: ASBD of the user's arguments, if an audio
82+
// converter is needed outside that provided by the client side.
83+
84+
AudioStreamBasicDescription d_asbd_user;
6585

6686
public:
67-
osx_source(int sample_rate = 44100,
68-
const std::string device_name = "",
69-
bool do_block = true,
70-
int channel_config = -1,
71-
int max_sample_count = -1);
7287

73-
~osx_source();
88+
osx_source(int sample_rate,
89+
const std::string& device_name,
90+
bool ok_to_block);
91+
92+
virtual inline ~osx_source() {
93+
teardown();
94+
}
7495

75-
bool start();
76-
bool stop();
77-
bool IsRunning();
96+
virtual bool start();
97+
virtual bool stop();
7898

79-
bool check_topology(int ninputs, int noutputs);
99+
virtual bool check_topology(int ninputs, int noutputs);
80100

81-
int work(int noutput_items,
82-
gr_vector_const_void_star &input_items,
83-
gr_vector_void_star &output_items);
101+
virtual int work(int noutput_items,
102+
gr_vector_const_void_star &input_items,
103+
gr_vector_void_star &output_items);
104+
105+
inline void reset(bool hardware_changed) {
106+
d_hardware_changed = hardware_changed;
107+
d_do_reset = true;
108+
}
84109

85110
private:
86-
void SetDefaultInputDeviceAsCurrent();
87-
88-
void AllocAudioBufferList(AudioBufferList** t_ABL,
89-
UInt32 n_channels,
90-
UInt32 inputBufferSizeBytes);
91-
92-
void FreeAudioBufferList(AudioBufferList** t_ABL);
93-
94-
static OSStatus ConverterCallback(AudioConverterRef inAudioConverter,
95-
UInt32* ioNumberDataPackets,
96-
AudioBufferList* ioData,
97-
AudioStreamPacketDescription** outASPD,
98-
void* inUserData);
99-
100-
static OSStatus AUInputCallback(void *inRefCon,
101-
AudioUnitRenderActionFlags *ioActionFlags,
102-
const AudioTimeStamp *inTimeStamp,
103-
UInt32 inBusNumber,
104-
UInt32 inNumberFrames,
105-
AudioBufferList *ioData);
106-
#if _OSX_DO_LISTENERS_
107-
static OSStatus UnitListener(void *inRefCon,
108-
AudioUnit ci,
109-
AudioUnitPropertyID inID,
110-
AudioUnitScope inScope,
111-
AudioUnitElement inElement);
112-
113-
static OSStatus HardwareListener(AudioHardwarePropertyID inPropertyID,
114-
void *inClientData);
111+
112+
bool is_running();
113+
114+
void setup();
115+
116+
void teardown();
117+
118+
void alloc_audio_buffer_list
119+
(AudioBufferList** t_abl,
120+
UInt32 n_channels,
121+
UInt32 input_buffer_size_bytes);
122+
123+
void free_audio_buffer_list
124+
(AudioBufferList** t_abl);
125+
126+
static OSStatus converter_callback
127+
(AudioConverterRef in_audio_converter,
128+
UInt32* io_number_data_packets,
129+
AudioBufferList* io_data,
130+
AudioStreamPacketDescription** out_aspd,
131+
void* in_user_data);
132+
133+
static OSStatus au_input_callback
134+
(void *in_ref_con,
135+
AudioUnitRenderActionFlags *io_action_flags,
136+
const AudioTimeStamp *in_time_stamp,
137+
UInt32 in_bus_number,
138+
UInt32 in_number_frames,
139+
AudioBufferList *io_data);
140+
141+
#ifndef GR_USE_OLD_AUDIO_UNIT
142+
143+
// OSX 10.4 and newer
144+
145+
static OSStatus hardware_listener
146+
(AudioObjectID in_object_id,
147+
UInt32 in_num_addresses,
148+
const AudioObjectPropertyAddress in_addresses[],
149+
void* in_client_data);
150+
151+
static OSStatus default_listener
152+
(AudioObjectID in_object_id,
153+
UInt32 in_num_addresses,
154+
const AudioObjectPropertyAddress in_addresses[],
155+
void* in_client_data);
156+
157+
#else
158+
159+
// OSX 10.6 and older; removed as of 10.7
160+
161+
static OSStatus hardware_listener
162+
(AudioHardwarePropertyID in_property_id,
163+
void* in_client_data);
164+
165+
static OSStatus default_listener
166+
(AudioHardwarePropertyID in_property_id,
167+
void* in_client_data);
168+
115169
#endif
116-
};
117170

171+
};
118172
} /* namespace audio */
119173
} /* namespace gr */
120174

0 commit comments

Comments
 (0)
Please sign in to comment.