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_internal = new mld_mutex ();
158 if (d_internal == NULL)
159 CheckErrorAndThrow (errno, "new mld_mutex (internal)",
160 "audio_osx_source::audio_osx_source");
162 d_cond_data = new mld_condition ();
163 if (d_cond_data == NULL)
164 CheckErrorAndThrow (errno, "new mld_condition (data)",
165 "audio_osx_source::audio_osx_source");
167 // initialize the AU for output
169 err = AudioUnitInitialize (d_OutputAU);
170 CheckErrorAndThrow (err, "AudioUnitInitialize",
171 "audio_osx_sink::audio_osx_sink");
174 fprintf (stderr, "audio_osx_sink Parameters:\n");
175 fprintf (stderr, " Sample Rate is %g\n", d_sample_rate);
176 fprintf (stderr, " Number of Channels is %ld\n", d_n_channels);
177 fprintf (stderr, " Max # samples to store per channel is %ld",
182 bool audio_osx_sink::IsRunning ()
184 UInt32 AURunning = 0, AUSize = sizeof (UInt32);
186 OSStatus err = AudioUnitGetProperty (d_OutputAU,
187 kAudioOutputUnitProperty_IsRunning,
188 kAudioUnitScope_Global,
192 CheckErrorAndThrow (err, "AudioUnitGetProperty IsRunning",
193 "audio_osx_sink::IsRunning");
198 bool audio_osx_sink::start ()
200 if (! IsRunning ()) {
201 OSStatus err = AudioOutputUnitStart (d_OutputAU);
202 CheckErrorAndThrow (err, "AudioOutputUnitStart", "audio_osx_sink::start");
208 bool audio_osx_sink::stop ()
211 OSStatus err = AudioOutputUnitStop (d_OutputAU);
212 CheckErrorAndThrow (err, "AudioOutputUnitStop", "audio_osx_sink::stop");
214 for (UInt32 n = 0; n < d_n_channels; n++) {
215 d_buffers[n]->abort ();
222 audio_osx_sink::~audio_osx_sink ()
224 // stop and close the AudioUnit
226 AudioUnitUninitialize (d_OutputAU);
227 CloseComponent (d_OutputAU);
229 // empty and delete the queues
230 for (UInt32 n = 0; n < d_n_channels; n++) {
237 // close and delete control stuff
243 audio_osx_make_sink (int sampling_freq,
244 const std::string dev,
247 int max_sample_count)
249 return audio_osx_sink_sptr (new audio_osx_sink (sampling_freq,
257 audio_osx_sink::work (int noutput_items,
258 gr_vector_const_void_star &input_items,
259 gr_vector_void_star &output_items)
263 /* take the input data, copy it, and push it to the bottom of the queue
264 mono input are pushed onto queue[0];
265 stereo input are pushed onto queue[1].
266 Start the AudioUnit if necessary. */
269 int diff_count = d_max_sample_count - noutput_items;
273 l_max_count = (UInt32) diff_count;
276 if (l_max_count < d_queueItemLength->back()) {
277 // allow 2 buffers at a time, regardless of length
278 l_max_count = d_queueItemLength->back();
283 fprintf (stderr, "work1: qSC = %ld, lMC = %ld, dmSC = %ld, nOI = %d\n",
284 d_queueSampleCount, l_max_count, d_max_sample_count, noutput_items);
287 if (d_queueSampleCount > l_max_count) {
288 // data coming in too fast; do_block decides what to do
289 if (d_do_block == true) {
290 // block until there is data to return
291 while (d_queueSampleCount > l_max_count) {
292 // release control so-as to allow data to be retrieved
294 // block until there is data to return
295 d_cond_data->wait ();
296 // the condition's signal() was called; acquire control
297 // to keep thread safe
302 // not blocking case and overflow is handled by the circular buffer
304 // add the input frames to the buffers' queue, checking for overflow
308 float* inBuffer = (float*) input_items[0];
309 const UInt32 l_size = input_items.size();
310 for (l_counter = 0; l_counter < l_size; l_counter++) {
311 inBuffer = (float*) input_items[l_counter];
312 int l_res = d_buffers[l_counter]->enqueue (inBuffer,
317 while (l_counter < d_n_channels) {
318 // for extra channels, copy the last input's data
319 int l_res = d_buffers[l_counter++]->enqueue (inBuffer,
326 // data coming in too fast
327 // drop oldest buffer
328 fputs ("oX", stderr);
330 // set the local number of samples available to the max
331 d_queueSampleCount = d_buffers[0]->buffer_length_items ();
333 // keep up the local sample count
334 d_queueSampleCount += noutput_items;
338 fprintf (stderr, "work2: #OI = %4d, #Cnt = %4ld, mSC = %ld\n",
339 noutput_items, d_queueSampleCount, d_max_sample_count);
342 // release control to allow for other processing parts to run
345 return (noutput_items);
348 OSStatus audio_osx_sink::AUOutputCallback
350 AudioUnitRenderActionFlags *ioActionFlags,
351 const AudioTimeStamp *inTimeStamp,
353 UInt32 inNumberFrames,
354 AudioBufferList *ioData)
356 audio_osx_sink* This = (audio_osx_sink*) inRefCon;
357 OSStatus err = noErr;
359 This->d_internal->wait ();
362 fprintf (stderr, "cb_in: SC = %4ld, in#F = %4ld\n",
363 This->d_queueSampleCount, inNumberFrames);
366 if (This->d_queueSampleCount < inNumberFrames) {
367 // not enough data to fill request
370 // enough data; remove data from our buffers into the AU's buffers
371 int l_counter = This->d_n_channels;
373 while (--l_counter >= 0) {
374 UInt32 t_n_output_items = inNumberFrames;
375 float* outBuffer = (float*) ioData->mBuffers[l_counter].mData;
376 This->d_buffers[l_counter]->dequeue (outBuffer, &t_n_output_items);
377 if (t_n_output_items != inNumberFrames) {
378 throw std::runtime_error ("audio_osx_sink::AUOutputCallback(): "
379 "number of available items changing "
384 This->d_queueSampleCount -= inNumberFrames;
388 fprintf (stderr, "cb_out: SC = %4ld\n", This->d_queueSampleCount);
391 // signal that data is available
392 This->d_cond_data->signal ();
394 // release control to allow for other processing parts to run
395 This->d_internal->post ();