Imported Upstream version 3.2.2
[debian/gnuradio] / gr-audio-portaudio / src / audio_portaudio_source.cc
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 he 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_portaudio_source.h>
28 #include <gr_io_signature.h>
29 #include <gr_prefs.h>
30 #include <stdio.h>
31 #include <iostream>
32 #include <unistd.h>
33 #include <stdexcept>
34 #include <gri_portaudio.h>
35 #include <gnuradio/omnithread.h>
36 #include <string.h>
37
38 #define LOGGING 0               // define to 0 or 1
39
40 #define SAMPLE_FORMAT           paFloat32
41 typedef float sample_t;
42
43 // Number of portaudio buffers in the ringbuffer
44 static const unsigned int N_BUFFERS = 4;
45
46 static std::string 
47 default_device_name ()
48 {
49   return gr_prefs::singleton()->get_string("audio_portaudio", "default_input_device", "");
50 }
51
52 void
53 audio_portaudio_source::create_ringbuffer(void)
54 {
55   int bufsize_samples = d_portaudio_buffer_size_frames * d_input_parameters.channelCount;
56   
57   if (d_verbose)
58     fprintf(stderr, "ring buffer size  = %d frames\n",
59             N_BUFFERS*bufsize_samples/d_input_parameters.channelCount);
60
61   // FYI, the buffer indicies are in units of samples.
62   d_writer = gr_make_buffer(N_BUFFERS * bufsize_samples, sizeof(sample_t));
63   d_reader = gr_buffer_add_reader(d_writer, 0);
64 }
65
66 /*
67  * This routine will be called by the PortAudio engine when audio is needed.
68  * It may called at interrupt level on some machines so don't do anything
69  * that could mess up the system like calling malloc() or free().
70  *
71  * Our job is to copy framesPerBuffer frames from inputBuffer.
72  */
73 int
74 portaudio_source_callback (const void *inputBuffer,
75                            void *outputBuffer,
76                            unsigned long framesPerBuffer,
77                            const PaStreamCallbackTimeInfo* timeInfo,
78                            PaStreamCallbackFlags statusFlags,
79                            void *arg)
80 {
81   audio_portaudio_source *self = (audio_portaudio_source *)arg;
82   int nchan = self->d_input_parameters.channelCount;
83   int nframes_to_copy = framesPerBuffer;
84   int nframes_room = self->d_writer->space_available() / nchan;
85
86   if (nframes_to_copy <= nframes_room){  // We've got room for the data ..
87     if (LOGGING)
88       self->d_log->printf("PAsrc  cb: f/b = %4ld\n", framesPerBuffer);
89
90     // copy from input buffer to ringbuffer
91     memcpy(self->d_writer->write_pointer(),
92            inputBuffer,
93            nframes_to_copy * nchan * sizeof(sample_t));
94     self->d_writer->update_write_pointer(nframes_to_copy * nchan);
95          
96     // Tell the source thread there is new data in the ringbuffer.
97     self->d_ringbuffer_ready.post();
98     return paContinue;
99   }
100
101   else {                        // overrun
102     if (LOGGING)
103       self->d_log->printf("PAsrc  cb: f/b = %4ld OVERRUN\n", framesPerBuffer);
104
105     self->d_noverruns++;
106     ::write(2, "aO", 2);        // FIXME change to non-blocking call
107
108 #if 0
109     // copy any frames that will fit
110     memcpy(self->d_writer->write_pointer(),
111            inputBuffer,
112            nframes_room * nchan * sizeof(sample_t));
113     self->d_writer->update_write_pointer(nframes_room * nchan);
114 #endif   
115
116     self->d_ringbuffer_ready.post();  // Tell the sink to get going!
117     return paContinue;
118   }
119 }
120
121
122 // ----------------------------------------------------------------
123
124 audio_portaudio_source_sptr
125 audio_portaudio_make_source (int sampling_rate, const std::string dev, bool ok_to_block)
126 {
127   return audio_portaudio_source_sptr (new audio_portaudio_source (sampling_rate,
128                                                                   dev, ok_to_block));
129 }
130
131 audio_portaudio_source::audio_portaudio_source(int sampling_rate,
132                                                const std::string device_name,
133                                                bool ok_to_block)
134   : gr_sync_block ("audio_portaudio_source",
135                    gr_make_io_signature(0, 0, 0),
136                    gr_make_io_signature(0, 0, 0)),
137     d_sampling_rate(sampling_rate),
138     d_device_name(device_name.empty() ? default_device_name() : device_name),
139     d_ok_to_block(ok_to_block),
140     d_verbose(gr_prefs::singleton()->get_bool("audio_portaudio", "verbose", false)),
141     d_portaudio_buffer_size_frames(0),
142     d_stream(0),
143     d_ringbuffer_ready(1, 1),           // binary semaphore
144     d_noverruns(0)
145 {
146   memset(&d_input_parameters, 0, sizeof(d_input_parameters));
147   if (LOGGING)
148     d_log = gri_logger::singleton();
149
150   PaError             err;
151   int                 i, numDevices;
152   PaDeviceIndex       device = 0;
153   const PaDeviceInfo *deviceInfo = NULL;
154
155
156   err = Pa_Initialize();
157   if (err != paNoError) {
158     bail ("Initialize failed", err);
159   }
160
161   if (d_verbose)
162     gri_print_devices();
163
164   numDevices = Pa_GetDeviceCount();
165   if (numDevices < 0)
166     bail("Pa Device count failed", 0);
167   if (numDevices == 0)
168     bail("no devices available", 0);
169
170   if (d_device_name.empty()) 
171   {
172     // FIXME Get smarter about picking something
173     device = Pa_GetDefaultInputDevice();
174     deviceInfo = Pa_GetDeviceInfo(device);
175     fprintf(stderr,"%s is the chosen device using %s as the host\n",
176             deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name);
177   }
178   else
179   {
180     bool found = false;
181     
182     for (i=0;i<numDevices;i++) {
183       deviceInfo = Pa_GetDeviceInfo( i );
184       fprintf(stderr,"Testing device name: %s",deviceInfo->name);
185       if (deviceInfo->maxInputChannels <= 0) {
186         fprintf(stderr,"\n");
187         continue;
188       }
189       if (strstr(deviceInfo->name, d_device_name.c_str())){
190         fprintf(stderr,"  Chosen!\n");
191         device = i;
192         fprintf(stderr,"%s using %s as the host\n",d_device_name.c_str(),
193                 Pa_GetHostApiInfo(deviceInfo->hostApi)->name), fflush(stderr);
194         found = true;
195         deviceInfo = Pa_GetDeviceInfo(device);
196         i = numDevices;         // force loop exit
197       }
198       else
199         fprintf(stderr,"\n"),fflush(stderr);
200     }
201
202     if (!found){
203       bail("Failed to find specified device name", 0);
204     }
205   }
206
207
208   d_input_parameters.device = device;
209   d_input_parameters.channelCount     = deviceInfo->maxInputChannels;
210   d_input_parameters.sampleFormat     = SAMPLE_FORMAT;
211   d_input_parameters.suggestedLatency = deviceInfo->defaultLowInputLatency;
212   d_input_parameters.hostApiSpecificStreamInfo = NULL;
213
214   // We fill in the real channelCount in check_topology when we know
215   // how many inputs are connected to us.
216
217   // Now that we know the maximum number of channels (allegedly)
218   // supported by the h/w, we can compute a reasonable output
219   // signature.  The portaudio specs say that they'll accept any
220   // number of channels from 1 to max.
221   set_output_signature(gr_make_io_signature(1, deviceInfo->maxInputChannels,
222                                             sizeof (sample_t)));
223 }
224
225
226 bool
227 audio_portaudio_source::check_topology (int ninputs, int noutputs)
228 {
229   PaError err;
230
231   if (Pa_IsStreamActive(d_stream))
232   {
233       Pa_CloseStream(d_stream);
234       d_stream = 0;
235       d_reader.reset();         // boost::shared_ptr for d_reader = 0
236       d_writer.reset();         // boost::shared_ptr for d_write = 0
237   }
238
239   d_input_parameters.channelCount = noutputs;   // # of channels we're really using
240
241 #if 1
242   d_portaudio_buffer_size_frames = (int)(0.0213333333  * d_sampling_rate + 0.5);  // Force 512 frame buffers at 48000
243   fprintf(stderr, "Latency = %8.5f, requested sampling_rate = %g\n", // Force latency to 21.3333333.. ms
244           0.0213333333, (double)d_sampling_rate);
245 #endif
246   err = Pa_OpenStream(&d_stream,
247                       &d_input_parameters,
248                       NULL,                     // No output
249                       d_sampling_rate,
250                       d_portaudio_buffer_size_frames,
251                       paClipOff,
252                       &portaudio_source_callback,
253                       (void*)this);
254
255   if (err != paNoError) {
256     output_error_msg ("OpenStream failed", err);
257     return false;
258   }
259
260 #if 0  
261   const PaStreamInfo *psi = Pa_GetStreamInfo(d_stream);
262
263   d_portaudio_buffer_size_frames = (int)(d_input_parameters.suggestedLatency  * psi->sampleRate);
264   fprintf(stderr, "Latency = %7.4f, psi->sampleRate = %g\n",
265           d_input_parameters.suggestedLatency, psi->sampleRate);
266 #endif
267
268   fprintf(stderr, "d_portaudio_buffer_size_frames = %d\n", d_portaudio_buffer_size_frames);
269
270   assert(d_portaudio_buffer_size_frames != 0);
271
272   create_ringbuffer();
273
274   err = Pa_StartStream(d_stream);
275   if (err != paNoError) {
276     output_error_msg ("StartStream failed", err);
277     return false;
278   }
279
280   return true;
281 }
282
283 audio_portaudio_source::~audio_portaudio_source ()
284 {
285   Pa_StopStream(d_stream);      // wait for output to drain
286   Pa_CloseStream(d_stream);
287   Pa_Terminate();
288 }
289
290 int
291 audio_portaudio_source::work (int noutput_items,
292                               gr_vector_const_void_star &input_items,
293                               gr_vector_void_star &output_items)
294 {
295   float **out = (float **) &output_items[0];
296   const unsigned nchan = d_input_parameters.channelCount; // # of channels == samples/frame
297
298   int k;
299   for (k = 0; k < noutput_items; ){
300
301     int nframes = d_reader->items_available() / nchan;  // # of frames in ringbuffer
302     if (nframes == 0){          // no data right now...
303       if (k > 0)                // If we've produced anything so far, return that
304         return k;
305
306       if (d_ok_to_block){
307         d_ringbuffer_ready.wait();      // block here, then try again
308         continue;
309       }
310
311       assert(k == 0);
312
313       // There's no data and we're not allowed to block.
314       // (A USRP is most likely controlling the pacing through the pipeline.)
315       // This is an underun.  The scheduler wouldn't have called us if it
316       // had anything better to do.  Thus we really need to produce some amount
317       // of "fill".
318       //
319       // There are lots of options for comfort noise, etc.
320       // FIXME We'll fill with zeros for now.  Yes, it will "click"...
321
322       // Fill with some frames of zeros
323       int nf = std::min(noutput_items - k, (int) d_portaudio_buffer_size_frames);
324       for (int i = 0; i < nf; i++){
325         for (unsigned int c = 0; c < nchan; c++){
326           out[c][k + i] = 0;
327         }
328       }
329       k += nf;
330       return k;
331     }
332
333     // We can read the smaller of the request and what's in the buffer.
334     int nf = std::min(noutput_items - k, nframes);
335
336     const float *p = (const float *) d_reader->read_pointer();
337     for (int i = 0; i < nf; i++){
338       for (unsigned int c = 0; c < nchan; c++){
339         out[c][k + i] = *p++;
340       }
341     }
342     d_reader->update_read_pointer(nf * nchan);
343     k += nf;
344   }
345
346   return k;  // tell how many we actually did
347 }
348
349 void
350 audio_portaudio_source::output_error_msg (const char *msg, int err)
351 {
352   fprintf (stderr, "audio_portaudio_source[%s]: %s: %s\n",
353            d_device_name.c_str (), msg, Pa_GetErrorText(err));
354 }
355
356 void
357 audio_portaudio_source::bail (const char *msg, int err) throw (std::runtime_error)
358 {
359   output_error_msg (msg, err);
360   throw std::runtime_error ("audio_portaudio_source");
361 }