/* -*- c++ -*- */
/*
- * Copyright 2006 Free Software Foundation, Inc.
+ * Copyright 2006,2010 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* GNU Radio is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
+ * the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* GNU Radio is distributed in he hope that it will be useful,
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
- * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include <unistd.h>
#include <stdexcept>
#include <gri_portaudio.h>
-#include <omnithread.h>
+#include <string.h>
-#define LOGGING 0 // define to 0 or 1
+//#define LOGGING 0 // define to 0 or 1
#define SAMPLE_FORMAT paFloat32
typedef float sample_t;
int nframes_room = self->d_writer->space_available() / nchan;
if (nframes_to_copy <= nframes_room){ // We've got room for the data ..
- if (LOGGING)
- self->d_log->printf("PAsrc cb: f/b = %4ld\n", framesPerBuffer);
+ //if (LOGGING)
+ // self->d_log->printf("PAsrc cb: f/b = %4ld\n", framesPerBuffer);
// copy from input buffer to ringbuffer
- memcpy(self->d_writer->write_pointer(),
- inputBuffer,
- nframes_to_copy * nchan * sizeof(sample_t));
- self->d_writer->update_write_pointer(nframes_to_copy * nchan);
+ {
+ gruel::scoped_lock(d_ringbuffer_mutex);
+
+ memcpy(self->d_writer->write_pointer(),
+ inputBuffer,
+ nframes_to_copy * nchan * sizeof(sample_t));
+ self->d_writer->update_write_pointer(nframes_to_copy * nchan);
- // Tell the source thread there is new data in the ringbuffer.
- self->d_ringbuffer_ready.post();
+ // Tell the source thread there is new data in the ringbuffer.
+ self->d_ringbuffer_ready = true;
+ }
+
+ self->d_ringbuffer_cond.notify_one();
return paContinue;
}
else { // overrun
- if (LOGGING)
- self->d_log->printf("PAsrc cb: f/b = %4ld OVERRUN\n", framesPerBuffer);
-
self->d_noverruns++;
- ::write(2, "aU", 2); // FIXME change to non-blocking call
-
-#if 0
- // copy any frames that will fit
- memcpy(self->d_writer->write_pointer(),
- inputBuffer,
- nframes_room * nchan * sizeof(sample_t));
- self->d_writer->update_write_pointer(nframes_room * nchan);
-#endif
+ ssize_t r = ::write(2, "aO", 2); // FIXME change to non-blocking call
+ if(r == -1) {
+ perror("audio_portaudio_source::portaudio_source_callback write error to stderr.");
+ }
- self->d_ringbuffer_ready.post(); // Tell the sink to get going!
+ self->d_ringbuffer_ready = false;
+ self->d_ringbuffer_cond.notify_one(); // Tell the sink to get going!
return paContinue;
}
}
audio_portaudio_source_sptr
audio_portaudio_make_source (int sampling_rate, const std::string dev, bool ok_to_block)
{
- return audio_portaudio_source_sptr (new audio_portaudio_source (sampling_rate,
+ return gnuradio::get_initial_sptr(new audio_portaudio_source (sampling_rate,
dev, ok_to_block));
}
d_verbose(gr_prefs::singleton()->get_bool("audio_portaudio", "verbose", false)),
d_portaudio_buffer_size_frames(0),
d_stream(0),
- d_ringbuffer_ready(1, 1), // binary semaphore
+ d_ringbuffer_mutex(),
+ d_ringbuffer_cond(),
+ d_ringbuffer_ready(false),
d_noverruns(0)
{
memset(&d_input_parameters, 0, sizeof(d_input_parameters));
- if (LOGGING)
- d_log = gri_logger::singleton();
+ //if (LOGGING)
+ // d_log = gri_logger::singleton();
PaError err;
int i, numDevices;
for (i=0;i<numDevices;i++) {
deviceInfo = Pa_GetDeviceInfo( i );
fprintf(stderr,"Testing device name: %s",deviceInfo->name);
+ if (deviceInfo->maxInputChannels <= 0) {
+ fprintf(stderr,"\n");
+ continue;
+ }
if (strstr(deviceInfo->name, d_device_name.c_str())){
fprintf(stderr," Chosen!\n");
- device = gri_pa_find_device_by_name(deviceInfo->name);
+ device = i;
fprintf(stderr,"%s using %s as the host\n",d_device_name.c_str(),
Pa_GetHostApiInfo(deviceInfo->hostApi)->name), fflush(stderr);
found = true;
deviceInfo = Pa_GetDeviceInfo(device);
i = numDevices; // force loop exit
}
- fprintf(stderr,"\n"),fflush(stderr);
+ else
+ fprintf(stderr,"\n"),fflush(stderr);
}
if (!found){
if (k > 0) // If we've produced anything so far, return that
return k;
- if (d_ok_to_block){
- d_ringbuffer_ready.wait(); // block here, then try again
+ if (d_ok_to_block) {
+ gruel:: scoped_lock guard(d_ringbuffer_mutex);
+ while (d_ringbuffer_ready == false)
+ d_ringbuffer_cond.wait(guard); // block here, then try again
continue;
}
-
+
assert(k == 0);
// There's no data and we're not allowed to block.
// FIXME We'll fill with zeros for now. Yes, it will "click"...
// Fill with some frames of zeros
- int nf = std::min(noutput_items - k, (int) d_portaudio_buffer_size_frames);
- for (int i = 0; i < nf; i++){
- for (unsigned int c = 0; c < nchan; c++){
- out[c][k + i] = 0;
+ {
+ gruel::scoped_lock guard(d_ringbuffer_mutex);
+
+ int nf = std::min(noutput_items - k, (int) d_portaudio_buffer_size_frames);
+ for (int i = 0; i < nf; i++){
+ for (unsigned int c = 0; c < nchan; c++){
+ out[c][k + i] = 0;
+ }
}
+ k += nf;
+
+ d_ringbuffer_ready = false;
+ return k;
}
- k += nf;
- return k;
}
// We can read the smaller of the request and what's in the buffer.
- int nf = std::min(noutput_items - k, nframes);
+ {
+ gruel::scoped_lock guard(d_ringbuffer_mutex);
- const float *p = (const float *) d_reader->read_pointer();
- for (int i = 0; i < nf; i++){
- for (unsigned int c = 0; c < nchan; c++){
- out[c][k + i] = *p++;
+ int nf = std::min(noutput_items - k, nframes);
+
+ const float *p = (const float *) d_reader->read_pointer();
+ for (int i = 0; i < nf; i++){
+ for (unsigned int c = 0; c < nchan; c++){
+ out[c][k + i] = *p++;
+ }
}
+ d_reader->update_read_pointer(nf * nchan);
+ k += nf;
+ d_ringbuffer_ready = false;
}
- d_reader->update_read_pointer(nf * nchan);
- k += nf;
}
return k; // tell how many we actually did