~ubuntu-branches/ubuntu/trusty/gnuradio/trusty-updates

« back to all changes in this revision

Viewing changes to gr-audio-osx/src/audio_osx_sink.cc

  • Committer: Package Import Robot
  • Author(s): A. Maitland Bottoms
  • Date: 2012-02-26 21:26:16 UTC
  • mfrom: (1.1.4)
  • Revision ID: package-import@ubuntu.com-20120226212616-vsfkbi1158xshdql
Tags: 3.5.1-1
* new upstream version, re-packaged from scratch with modern tools
    closes: #642716, #645332, #394849, #616832, #590048, #642580,
    #647018, #557050, #559640, #631863
* CMake build

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- c++ -*- */
2
 
/*
3
 
 * Copyright 2006 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
 
#define _USE_OMNI_THREADS_
28
 
 
29
 
#include <audio_osx_sink.h>
30
 
#include <gr_io_signature.h>
31
 
#include <stdexcept>
32
 
#include <audio_osx.h>
33
 
 
34
 
#define _OSX_AU_DEBUG_ 0
35
 
 
36
 
audio_osx_sink::audio_osx_sink (int sample_rate,
37
 
                                const std::string device_name,
38
 
                                bool do_block,
39
 
                                int channel_config,
40
 
                                int max_sample_count)
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),
47
 
    d_OutputAU (0)
48
 
{
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");
52
 
  } else
53
 
    d_sample_rate = (Float64) sample_rate;
54
 
 
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");
64
 
    }
65
 
    if (l_n_channels <= 0)
66
 
      channel_config = 2;
67
 
    else
68
 
      channel_config = l_n_channels;
69
 
  }
70
 
 
71
 
  d_n_channels = d_channel_config = channel_config;
72
 
 
73
 
// set the input signature
74
 
 
75
 
  set_input_signature (gr_make_io_signature (1, d_n_channels, sizeof (float)));
76
 
 
77
 
// check that the max # of samples to store is valid
78
 
 
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");
84
 
  }
85
 
 
86
 
  d_max_sample_count = max_sample_count;
87
 
 
88
 
// allocate the output circular buffer(s), one per channel
89
 
 
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);
95
 
  }
96
 
 
97
 
// create the default AudioUnit for output
98
 
  OSStatus err = noErr;
99
 
 
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;
107
 
 
108
 
  Component comp = FindNextComponent (NULL, &desc);
109
 
  if (comp == NULL) {
110
 
    fprintf (stderr, "FindNextComponent Error\n");
111
 
    throw std::runtime_error ("audio_osx_sink::audio_osx_sink");
112
 
  }
113
 
 
114
 
  err = OpenAComponent (comp, &d_OutputAU);
115
 
  CheckErrorAndThrow (err, "OpenAComponent", "audio_osx_sink::audio_osx_sink");
116
 
 
117
 
// Set up a callback function to generate output to the output unit
118
 
 
119
 
  AURenderCallbackStruct input;
120
 
  input.inputProc = (AURenderCallback)(audio_osx_sink::AUOutputCallback);
121
 
  input.inputProcRefCon = this;
122
 
 
123
 
  err = AudioUnitSetProperty (d_OutputAU,
124
 
                              kAudioUnitProperty_SetRenderCallback, 
125
 
                              kAudioUnitScope_Input,
126
 
                              0, 
127
 
                              &input, 
128
 
                              sizeof (input));
129
 
  CheckErrorAndThrow (err, "AudioUnitSetProperty Render Callback", "audio_osx_sink::audio_osx_sink");
130
 
 
131
 
// tell the Output Unit what format data will be supplied to it
132
 
// so that it handles any format conversions
133
 
 
134
 
  AudioStreamBasicDescription streamFormat;
135
 
  streamFormat.mSampleRate = (Float64)(sample_rate);
136
 
  streamFormat.mFormatID = kAudioFormatLinearPCM;
137
 
  streamFormat.mFormatFlags = (kLinearPCMFormatFlagIsFloat |
138
 
                               GR_PCM_ENDIANNESS |
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;
146
 
 
147
 
  err = AudioUnitSetProperty (d_OutputAU,
148
 
                              kAudioUnitProperty_StreamFormat,
149
 
                              kAudioUnitScope_Input,
150
 
                              0,
151
 
                              &streamFormat,
152
 
                              sizeof (AudioStreamBasicDescription));
153
 
  CheckErrorAndThrow (err, "AudioUnitSetProperty StreamFormat", "audio_osx_sink::audio_osx_sink");
154
 
 
155
 
// create the stuff to regulate I/O
156
 
 
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 ();
162
 
 
163
 
// initialize the AU for output
164
 
 
165
 
  err = AudioUnitInitialize (d_OutputAU);
166
 
  CheckErrorAndThrow (err, "AudioUnitInitialize",
167
 
                      "audio_osx_sink::audio_osx_sink");
168
 
 
169
 
#if _OSX_AU_DEBUG_
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",
174
 
           d_max_sample_count);
175
 
#endif
176
 
}
177
 
 
178
 
bool audio_osx_sink::IsRunning ()
179
 
{
180
 
  UInt32 AURunning = 0, AUSize = sizeof (UInt32);
181
 
 
182
 
  OSStatus err = AudioUnitGetProperty (d_OutputAU,
183
 
                                       kAudioOutputUnitProperty_IsRunning,
184
 
                                       kAudioUnitScope_Global,
185
 
                                       0,
186
 
                                       &AURunning,
187
 
                                       &AUSize);
188
 
  CheckErrorAndThrow (err, "AudioUnitGetProperty IsRunning",
189
 
                      "audio_osx_sink::IsRunning");
190
 
 
191
 
  return (AURunning);
192
 
}
193
 
 
194
 
bool audio_osx_sink::start ()
195
 
{
196
 
  if (! IsRunning ()) {
197
 
    OSStatus err = AudioOutputUnitStart (d_OutputAU);
198
 
    CheckErrorAndThrow (err, "AudioOutputUnitStart", "audio_osx_sink::start");
199
 
  }
200
 
 
201
 
  return (true);
202
 
}
203
 
 
204
 
bool audio_osx_sink::stop ()
205
 
{
206
 
  if (IsRunning ()) {
207
 
    OSStatus err = AudioOutputUnitStop (d_OutputAU);
208
 
    CheckErrorAndThrow (err, "AudioOutputUnitStop", "audio_osx_sink::stop");
209
 
 
210
 
    for (UInt32 n = 0; n < d_n_channels; n++) {
211
 
      d_buffers[n]->abort ();
212
 
    }
213
 
  }
214
 
 
215
 
  return (true);
216
 
}
217
 
 
218
 
audio_osx_sink::~audio_osx_sink ()
219
 
{
220
 
// stop and close the AudioUnit
221
 
  stop ();
222
 
  AudioUnitUninitialize (d_OutputAU);
223
 
  CloseComponent (d_OutputAU);
224
 
 
225
 
// empty and delete the queues
226
 
  for (UInt32 n = 0; n < d_n_channels; n++) {
227
 
    delete d_buffers[n];
228
 
    d_buffers[n] = 0;
229
 
  }
230
 
  delete [] d_buffers;
231
 
  d_buffers = 0;
232
 
 
233
 
// close and delete control stuff
234
 
  delete d_cond_data;
235
 
}
236
 
 
237
 
audio_osx_sink_sptr
238
 
audio_osx_make_sink (int sampling_freq,
239
 
                     const std::string dev,
240
 
                     bool do_block,
241
 
                     int channel_config,
242
 
                     int max_sample_count)
243
 
{
244
 
  return audio_osx_sink_sptr (new audio_osx_sink (sampling_freq,
245
 
                                                  dev,
246
 
                                                  do_block,
247
 
                                                  channel_config,
248
 
                                                  max_sample_count));
249
 
}
250
 
 
251
 
int
252
 
audio_osx_sink::work (int noutput_items,
253
 
                      gr_vector_const_void_star &input_items,
254
 
                      gr_vector_void_star &output_items)
255
 
{
256
 
  d_internal->lock ();
257
 
 
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. */
262
 
 
263
 
  UInt32 l_max_count;
264
 
  int diff_count = d_max_sample_count - noutput_items;
265
 
  if (diff_count < 0)
266
 
    l_max_count = 0;
267
 
  else
268
 
    l_max_count = (UInt32) diff_count;
269
 
 
270
 
#if 0
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();
274
 
  }
275
 
#endif
276
 
 
277
 
#if _OSX_AU_DEBUG_
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);
280
 
#endif
281
 
 
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
292
 
      }
293
 
    }
294
 
  }
295
 
// not blocking case and overflow is handled by the circular buffer
296
 
 
297
 
// add the input frames to the buffers' queue, checking for overflow
298
 
 
299
 
  UInt32 l_counter;
300
 
  int res = 0;
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,
306
 
                                               noutput_items);
307
 
    if (l_res == -1)
308
 
      res = -1;
309
 
  }
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,
313
 
                                                 noutput_items);
314
 
    if (l_res == -1)
315
 
      res = -1;
316
 
  }
317
 
 
318
 
  if (res == -1) {
319
 
// data coming in too fast
320
 
// drop oldest buffer
321
 
    fputs ("oX", stderr);
322
 
    fflush (stderr);
323
 
// set the local number of samples available to the max
324
 
    d_queueSampleCount = d_buffers[0]->buffer_length_items ();
325
 
  } else {
326
 
// keep up the local sample count
327
 
    d_queueSampleCount += noutput_items;
328
 
  }
329
 
 
330
 
#if _OSX_AU_DEBUG_
331
 
  fprintf (stderr, "work2: #OI = %4d, #Cnt = %4ld, mSC = %ld\n",
332
 
           noutput_items, d_queueSampleCount, d_max_sample_count);
333
 
#endif
334
 
 
335
 
// release control to allow for other processing parts to run
336
 
  d_internal->unlock ();
337
 
 
338
 
  return (noutput_items);
339
 
}
340
 
 
341
 
OSStatus audio_osx_sink::AUOutputCallback
342
 
(void *inRefCon, 
343
 
 AudioUnitRenderActionFlags *ioActionFlags, 
344
 
 const AudioTimeStamp *inTimeStamp, 
345
 
 UInt32 inBusNumber, 
346
 
 UInt32 inNumberFrames, 
347
 
 AudioBufferList *ioData)
348
 
{
349
 
  audio_osx_sink* This = (audio_osx_sink*) inRefCon;
350
 
  OSStatus err = noErr;
351
 
 
352
 
  This->d_internal->lock ();
353
 
 
354
 
#if _OSX_AU_DEBUG_
355
 
  fprintf (stderr, "cb_in: SC = %4ld, in#F = %4ld\n",
356
 
           This->d_queueSampleCount, inNumberFrames);
357
 
#endif
358
 
 
359
 
  if (This->d_queueSampleCount < inNumberFrames) {
360
 
// not enough data to fill request
361
 
    err = -1;
362
 
  } else {
363
 
// enough data; remove data from our buffers into the AU's buffers
364
 
    int l_counter = This->d_n_channels;
365
 
 
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 "
373
 
                                  "unexpectedly.\n");
374
 
      }
375
 
    }
376
 
 
377
 
    This->d_queueSampleCount -= inNumberFrames;
378
 
  }
379
 
 
380
 
#if _OSX_AU_DEBUG_
381
 
  fprintf (stderr, "cb_out: SC = %4ld\n", This->d_queueSampleCount);
382
 
#endif
383
 
 
384
 
// signal that data is available
385
 
  This->d_cond_data->signal ();
386
 
 
387
 
// release control to allow for other processing parts to run
388
 
  This->d_internal->unlock ();
389
 
 
390
 
  return (err);
391
 
}