3
* Copyright 2006 Free Software Foundation, Inc.
5
* This file is part of GNU Radio.
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)
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.
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.
27
#define _USE_OMNI_THREADS_
29
#include <audio_osx_sink.h>
30
#include <gr_io_signature.h>
32
#include <audio_osx.h>
34
#define _OSX_AU_DEBUG_ 0
36
audio_osx_sink::audio_osx_sink (int sample_rate,
37
const std::string device_name,
41
: gr_sync_block ("audio_osx_sink",
42
gr_make_io_signature (0, 0, 0),
43
gr_make_io_signature (0, 0, 0)),
44
d_sample_rate (0.0), d_channel_config (0), d_n_channels (0),
45
d_queueSampleCount (0), d_max_sample_count (0),
46
d_do_block (do_block), d_internal (0), d_cond_data (0),
49
if (sample_rate <= 0) {
50
fprintf (stderr, "Invalid Sample Rate: %d\n", sample_rate);
51
throw std::invalid_argument ("audio_osx_sink::audio_osx_sink");
53
d_sample_rate = (Float64) sample_rate;
55
if (channel_config <= 0 & channel_config != -1) {
56
fprintf (stderr, "Invalid Channel Config: %d\n", channel_config);
57
throw std::invalid_argument ("audio_osx_sink::audio_osx_sink");
58
} else if (channel_config == -1) {
59
// no user input; try "device name" instead
60
int l_n_channels = (int) strtol (device_name.data(), (char **)NULL, 10);
61
if (l_n_channels == 0 & errno) {
62
fprintf (stderr, "Error Converting Device Name: %d\n", errno);
63
throw std::invalid_argument ("audio_osx_sink::audio_osx_sink");
65
if (l_n_channels <= 0)
68
channel_config = l_n_channels;
71
d_n_channels = d_channel_config = channel_config;
73
// set the input signature
75
set_input_signature (gr_make_io_signature (1, d_n_channels, sizeof (float)));
77
// check that the max # of samples to store is valid
79
if (max_sample_count == -1)
80
max_sample_count = sample_rate;
81
else if (max_sample_count <= 0) {
82
fprintf (stderr, "Invalid Max Sample Count: %d\n", max_sample_count);
83
throw std::invalid_argument ("audio_osx_sink::audio_osx_sink");
86
d_max_sample_count = max_sample_count;
88
// allocate the output circular buffer(s), one per channel
90
d_buffers = (circular_buffer<float>**) new
91
circular_buffer<float>* [d_n_channels];
92
UInt32 n_alloc = (UInt32) ceil ((double) d_max_sample_count);
93
for (UInt32 n = 0; n < d_n_channels; n++) {
94
d_buffers[n] = new circular_buffer<float> (n_alloc, false, false);
97
// create the default AudioUnit for output
100
// Open the default output unit
101
ComponentDescription desc;
102
desc.componentType = kAudioUnitType_Output;
103
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
104
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
105
desc.componentFlags = 0;
106
desc.componentFlagsMask = 0;
108
Component comp = FindNextComponent (NULL, &desc);
110
fprintf (stderr, "FindNextComponent Error\n");
111
throw std::runtime_error ("audio_osx_sink::audio_osx_sink");
114
err = OpenAComponent (comp, &d_OutputAU);
115
CheckErrorAndThrow (err, "OpenAComponent", "audio_osx_sink::audio_osx_sink");
117
// Set up a callback function to generate output to the output unit
119
AURenderCallbackStruct input;
120
input.inputProc = (AURenderCallback)(audio_osx_sink::AUOutputCallback);
121
input.inputProcRefCon = this;
123
err = AudioUnitSetProperty (d_OutputAU,
124
kAudioUnitProperty_SetRenderCallback,
125
kAudioUnitScope_Input,
129
CheckErrorAndThrow (err, "AudioUnitSetProperty Render Callback", "audio_osx_sink::audio_osx_sink");
131
// tell the Output Unit what format data will be supplied to it
132
// so that it handles any format conversions
134
AudioStreamBasicDescription streamFormat;
135
streamFormat.mSampleRate = (Float64)(sample_rate);
136
streamFormat.mFormatID = kAudioFormatLinearPCM;
137
streamFormat.mFormatFlags = (kLinearPCMFormatFlagIsFloat |
139
kLinearPCMFormatFlagIsPacked |
140
kAudioFormatFlagIsNonInterleaved);
141
streamFormat.mBytesPerPacket = 4;
142
streamFormat.mFramesPerPacket = 1;
143
streamFormat.mBytesPerFrame = 4;
144
streamFormat.mChannelsPerFrame = d_n_channels;
145
streamFormat.mBitsPerChannel = 32;
147
err = AudioUnitSetProperty (d_OutputAU,
148
kAudioUnitProperty_StreamFormat,
149
kAudioUnitScope_Input,
152
sizeof (AudioStreamBasicDescription));
153
CheckErrorAndThrow (err, "AudioUnitSetProperty StreamFormat", "audio_osx_sink::audio_osx_sink");
155
// create the stuff to regulate I/O
157
d_cond_data = new mld_condition ();
158
if (d_cond_data == NULL)
159
CheckErrorAndThrow (errno, "new mld_condition (data)",
160
"audio_osx_source::audio_osx_source");
161
d_internal = d_cond_data->mutex ();
163
// initialize the AU for output
165
err = AudioUnitInitialize (d_OutputAU);
166
CheckErrorAndThrow (err, "AudioUnitInitialize",
167
"audio_osx_sink::audio_osx_sink");
170
fprintf (stderr, "audio_osx_sink Parameters:\n");
171
fprintf (stderr, " Sample Rate is %g\n", d_sample_rate);
172
fprintf (stderr, " Number of Channels is %ld\n", d_n_channels);
173
fprintf (stderr, " Max # samples to store per channel is %ld",
178
bool audio_osx_sink::IsRunning ()
180
UInt32 AURunning = 0, AUSize = sizeof (UInt32);
182
OSStatus err = AudioUnitGetProperty (d_OutputAU,
183
kAudioOutputUnitProperty_IsRunning,
184
kAudioUnitScope_Global,
188
CheckErrorAndThrow (err, "AudioUnitGetProperty IsRunning",
189
"audio_osx_sink::IsRunning");
194
bool audio_osx_sink::start ()
196
if (! IsRunning ()) {
197
OSStatus err = AudioOutputUnitStart (d_OutputAU);
198
CheckErrorAndThrow (err, "AudioOutputUnitStart", "audio_osx_sink::start");
204
bool audio_osx_sink::stop ()
207
OSStatus err = AudioOutputUnitStop (d_OutputAU);
208
CheckErrorAndThrow (err, "AudioOutputUnitStop", "audio_osx_sink::stop");
210
for (UInt32 n = 0; n < d_n_channels; n++) {
211
d_buffers[n]->abort ();
218
audio_osx_sink::~audio_osx_sink ()
220
// stop and close the AudioUnit
222
AudioUnitUninitialize (d_OutputAU);
223
CloseComponent (d_OutputAU);
225
// empty and delete the queues
226
for (UInt32 n = 0; n < d_n_channels; n++) {
233
// close and delete control stuff
238
audio_osx_make_sink (int sampling_freq,
239
const std::string dev,
242
int max_sample_count)
244
return audio_osx_sink_sptr (new audio_osx_sink (sampling_freq,
252
audio_osx_sink::work (int noutput_items,
253
gr_vector_const_void_star &input_items,
254
gr_vector_void_star &output_items)
258
/* take the input data, copy it, and push it to the bottom of the queue
259
mono input are pushed onto queue[0];
260
stereo input are pushed onto queue[1].
261
Start the AudioUnit if necessary. */
264
int diff_count = d_max_sample_count - noutput_items;
268
l_max_count = (UInt32) diff_count;
271
if (l_max_count < d_queueItemLength->back()) {
272
// allow 2 buffers at a time, regardless of length
273
l_max_count = d_queueItemLength->back();
278
fprintf (stderr, "work1: qSC = %ld, lMC = %ld, dmSC = %ld, nOI = %d\n",
279
d_queueSampleCount, l_max_count, d_max_sample_count, noutput_items);
282
if (d_queueSampleCount > l_max_count) {
283
// data coming in too fast; do_block decides what to do
284
if (d_do_block == true) {
285
// block until there is data to return
286
while (d_queueSampleCount > l_max_count) {
287
// release control so-as to allow data to be retrieved;
288
// block until there is data to return
289
d_cond_data->wait ();
290
// the condition's signal() was called; acquire control
291
// to keep thread safe
295
// not blocking case and overflow is handled by the circular buffer
297
// add the input frames to the buffers' queue, checking for overflow
301
float* inBuffer = (float*) input_items[0];
302
const UInt32 l_size = input_items.size();
303
for (l_counter = 0; l_counter < l_size; l_counter++) {
304
inBuffer = (float*) input_items[l_counter];
305
int l_res = d_buffers[l_counter]->enqueue (inBuffer,
310
while (l_counter < d_n_channels) {
311
// for extra channels, copy the last input's data
312
int l_res = d_buffers[l_counter++]->enqueue (inBuffer,
319
// data coming in too fast
320
// drop oldest buffer
321
fputs ("oX", stderr);
323
// set the local number of samples available to the max
324
d_queueSampleCount = d_buffers[0]->buffer_length_items ();
326
// keep up the local sample count
327
d_queueSampleCount += noutput_items;
331
fprintf (stderr, "work2: #OI = %4d, #Cnt = %4ld, mSC = %ld\n",
332
noutput_items, d_queueSampleCount, d_max_sample_count);
335
// release control to allow for other processing parts to run
336
d_internal->unlock ();
338
return (noutput_items);
341
OSStatus audio_osx_sink::AUOutputCallback
343
AudioUnitRenderActionFlags *ioActionFlags,
344
const AudioTimeStamp *inTimeStamp,
346
UInt32 inNumberFrames,
347
AudioBufferList *ioData)
349
audio_osx_sink* This = (audio_osx_sink*) inRefCon;
350
OSStatus err = noErr;
352
This->d_internal->lock ();
355
fprintf (stderr, "cb_in: SC = %4ld, in#F = %4ld\n",
356
This->d_queueSampleCount, inNumberFrames);
359
if (This->d_queueSampleCount < inNumberFrames) {
360
// not enough data to fill request
363
// enough data; remove data from our buffers into the AU's buffers
364
int l_counter = This->d_n_channels;
366
while (--l_counter >= 0) {
367
UInt32 t_n_output_items = inNumberFrames;
368
float* outBuffer = (float*) ioData->mBuffers[l_counter].mData;
369
This->d_buffers[l_counter]->dequeue (outBuffer, &t_n_output_items);
370
if (t_n_output_items != inNumberFrames) {
371
throw std::runtime_error ("audio_osx_sink::AUOutputCallback(): "
372
"number of available items changing "
377
This->d_queueSampleCount -= inNumberFrames;
381
fprintf (stderr, "cb_out: SC = %4ld\n", This->d_queueSampleCount);
384
// signal that data is available
385
This->d_cond_data->signal ();
387
// release control to allow for other processing parts to run
388
This->d_internal->unlock ();