[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Commit-gnuradio] r4154 - gnuradio/branches/developers/brickle/jack/gr-a
From: |
brickle |
Subject: |
[Commit-gnuradio] r4154 - gnuradio/branches/developers/brickle/jack/gr-audio-jack/src |
Date: |
Tue, 19 Dec 2006 17:27:23 -0700 (MST) |
Author: brickle
Date: 2006-12-19 17:27:23 -0700 (Tue, 19 Dec 2006)
New Revision: 4154
Modified:
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_mgr.cc
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_mgr.h
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_source.cc
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_source.h
Log:
What's more-or-less done so far of the "new" jack stuff.
Modified:
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_mgr.cc
===================================================================
---
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_mgr.cc
2006-12-19 22:54:23 UTC (rev 4153)
+++
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_mgr.cc
2006-12-20 00:27:23 UTC (rev 4154)
@@ -30,15 +30,219 @@
static boost::weak_ptr<audio_jack_mgr> s_singleton;
+//------------------------------------------------------------------------
+// main jack callback here
+//------------------------------------------------------------------------
+static int
+_jack_duplex_callback(int nframes, void *arg)
+{
+ audio_jack_mgr *self = (audio_jack_mgr *) arg;
+ jack_info_t *in_info = self->d_jack_input;
+ jack_info_t *out_info = self->d_jack_output;
+
+ char *port_buffer;
+ size_t nbytes = nframes * sizeof(float);
+
+ // handle pending output (from sinks, to jack)
+
+ for (int i = 0; i < MAX_JACK_PORTS; i++) {
+ if (!out_info[i].used)
+ continue;
+ port_buffer = jack_port_get_buffer(out_info[i].port, nframes);
+ if (jack_ringbuffer_read_space(out_info[i].ring_buffer) >= nbytes)
+ jack_ringbuffer_read(out_info[i].ring_buffer,
+ port_buffer,
+ nbytes);
+ else
+ memset(port_buffer, 0, nbytes);
+ }
+
+ // handle pending input (from jack, to sources)
+
+ for (int i = 0; i < MAX_JACK_PORTS; i++) {
+ if (!in_info[i].used)
+ continue;
+ port_buffer = jack_port_get_buffer(in_info[i].port, nframes);
+ if (jack_ringbuffer_write_space(in_info[i].ring_buffer) >= nbytes)
+ jack_ringbuffer_write(self->d_jack>output[i].ring_buffer,
+ port_buffer,
+ nbytes);
+ else
+ ::write(2, "aO", 2); // That's all for now
+ }
+
+ // trip sinks
+
+ for (int i = 0; i < MAX_JACK_PORTS; i++)
+ if (out_info[i].used)
+ out_info[i].semaphore.post();
+
+ // trip sources
+
+ for (int i = 0; i < MAX_JACK_PORTS; i++)
+ if (in_info[i].used)
+ in_info[i].semaphore.post();
+}
+
+// minor callbacks
+
+static void
+_jack_shutdown_callback(void *arg) {
+ std::cerr << "audio_jack_mgr: shutdown callback fired\n";
+}
+
+static void
+_jack_xrun_callback(void *arg) {
+ std::cerr << "audio_jack_mgr: xrun callback fired\n";
+}
+
+//------------------------------------------------------------------------
+//------------------------------------------------------------------------
+
+int
+audio_jack_mgr::audio_jack_mgr_register_source(const std::string name,
+ jack_ringbuffer_t *rb_ptr,
+ omni_semaphore *sem_ptr)
+{
+ int i;
+
+ for (i = 0; i < JACK_MAX_PORTS; i++)
+ if (!d_jack_input[i].used)
+ break;
+
+ if (i >= JACK_MAX_PORTS) {
+ std::cerr << "audio_jack_mgr: out of source slots\n";
+ ::exit(1);
+ }
+
+ d_jack_input[i].port = jack_port_register(d_client,
+ name,
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsInput,
+ 0);
+
+ d_jack_input[i].ring_buffer = rb_ptr;
+ d_jack_input[i].semaphore = sem_ptr;
+
+ return i;
+}
+
+bool
+audio_jack_mgr::audio_jack_mgr_unregister_source(int id)
+{
+ if (id < 0 || id >= JACK_MAX_PORTS) {
+ std::cerr << "audio_jack_mgr: trying to unregister source id out of
range\n";
+ return false;
+ }
+
+ if (!d_jack_input[id].used) {
+ std::cerr << "audio_jack_mgr: trying to unregister source id not used\n";
+ return false;
+ }
+ d_jack_input[id].used = false;
+
+ jack_port_unregister(d_jack_input[id].port);
+ d_jack_input[id].ring_buffer = NULL;
+ d_jack_input[id].semaphore = NULL;
+
+ return true;
+}
+
+int
+audio_jack_mgr::audio_jack_mgr_register_sink(const std::string name,
+ jack_ringbuffer_t *rb_ptr,
+ omni_semaphore *sem_ptr)
+{
+ int i;
+
+ for (i = 0; i < JACK_MAX_PORTS; i++)
+ if (!d_jack_output[i].used)
+ break;
+
+ if (i >= JACK_MAX_PORTS) {
+ std::cerr << "audio_jack_mgr: out of sink slots\n";
+ ::exit(1);
+ }
+
+ d_jack_output[i].port = jack_port_register(d_client,
+ name,
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput,
+ 0);
+
+ d_jack_output[i].ring_buffer = rb_ptr;
+ d_jack_output[i].semaphore = sem_ptr;
+
+ return i;
+ return true;
+}
+
+bool
+audio_jack_mgr::audio_jack_mgr_unregister_sink(int id)
+{
+ if (id < 0 || id >= JACK_MAX_PORTS) {
+ std::cerr << "audio_jack_mgr: trying to unregister sink id out of range\n";
+ return false;
+ }
+
+ if (!d_jack_output[id].used) {
+ std::cerr << "audio_jack_mgr: trying to unregister source id not used\n";
+ return false;
+ }
+ d_jack_output[id].used = false;
+
+ jack_port_unregister(d_jack_output[id].port);
+ d_jack_output[id].ring_buffer = NULL;
+ d_jack_output[id].semaphore = NULL;
+
+ return true;
+}
+
audio_jack_mgr::audio_jack_mgr(int sample_rate, const std::string name)
- : d_sample_rate(sample_rate), d_name(name)
+ : d_sample_rate(sample_rate), d_name(name), d_running(false)
{
+ if (!(d_client = jack_client_new(d_name))) {
+ std::cerr << "audio_jack_mgr: Can't create client. Is jack running?\n";
+ ::exit(1);
+ }
+
+ jack_set_process_callback(d_client,
+ (void *) _jack_duplex_callback,
+ (void *) this);
+
+ jack_on_shutdown(d_client, (void *) _jack_shutdown_callback, 0);
+ jack_set_xrun_callback(d_client, (void *) _jack_xrun_callback, 0);
+
+ d_sample_rate = (int) jack_get_sample_rate(d_client);
+ d_buffer_size = jack_get_buffer_size(d_client);
+
+ for (int i = 0; i < MAX_JACK_PORTS; i++) {
+ d_jack_input[i].used = false;
+ d_jack_output[i].used = false;
+ }
+
+ if (jack_client_activate(d_client)) {
+ std::cerr << "audio_jack_mgr: cannot activate jack client (though created
OK)\n";
+ ::exit(1);
+ }
+
+ d_running = true;
+
std::cerr << "audio_jack_mgr: constructor called\n";
}
audio_jack_mgr::~audio_jack_mgr()
{
+ for (int i = 0; i < JACK_MAX_PORTS; i++)
+ if (d_jack_input[i].used)
+ audio_jack_mgr::audio_jack_mgr_unregister_source(i);
+ for (int i = 0; i < JACK_MAX_PORTS; i++)
+ if (d_jack_output[i].used)
+ audio_jack_mgr::audio_jack_mgr_unregister_sink(i);
+
+ jack_client_close(d_client);
+
std::cerr << "audio_jack_mgr: destructor called\n";
}
@@ -59,3 +263,4 @@
s_singleton = r;
return r;
}
+
Modified:
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_mgr.h
===================================================================
---
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_mgr.h
2006-12-19 22:54:23 UTC (rev 4153)
+++
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_mgr.h
2006-12-20 00:27:23 UTC (rev 4154)
@@ -25,6 +25,21 @@
#include <boost/shared_ptr.hpp>
#include <string>
+#include <omnithread.h>
+
+#include <jack/jack.h>
+#include <jack/ringbuffer.h>
+
+#define MAX_JACK_PORTS 16
+
+typedef
+struct _jack_info {
+ bool used;
+ jack_port_t *port;
+ jack_ringbuffer_t *ring_buffer;
+ omni_semaphore *semaphore;
+} jack_info_t;
+
class audio_jack_mgr;
typedef boost::shared_ptr<audio_jack_mgr> audio_jack_mgr_sptr;
@@ -32,14 +47,37 @@
* \brief class that coordinates all GNU Radio access to jack
*/
class audio_jack_mgr {
- int d_sample_rate;
std::string d_name;
+ jack_client_t d_client;
+ bool d_running;
+
+ int d_sample_rate;
+ int d_buffer_size;
+
+ jack_info_t d_jack_input[MAX_JACK_PORTS]; // sources
+ jack_info_t d_jack_output[MAX_JACK_PORTS]; // sinks
+
+
audio_jack_mgr (int sample_rate, const std::string name);
public:
~audio_jack_mgr ();
+ int
+ audio_jack_mgr_register_source(const std::string name,
+ jack_ringbuffer_t *rb_ptr,
+ omni_semaphore *sem_ptr);
+ bool
+ audio_jack_mgr_unregister_source(int id);
+
+ int
+ audio_jack_mgr_register_sink(const std::string name,
+ jack_ringbuffer_t *rb_ptr,
+ omni_semaphore *sem_ptr);
+ bool
+ audio_jack_mgr_unregister_sink(int id);
+
/*!
* \brief return single instance, create if required
*/
Modified:
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_source.cc
===================================================================
---
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_source.cc
2006-12-19 22:54:23 UTC (rev 4153)
+++
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_source.cc
2006-12-20 00:27:23 UTC (rev 4154)
@@ -32,13 +32,10 @@
#include <stdexcept>
#include <gri_jack.h>
-#ifndef NO_PTHREAD
-#include <pthread.h>
-#endif
+#include <audio_jack_mgr.h>
typedef jack_default_audio_sample_t sample_t;
-
// Number of jack buffers in the ringbuffer
// TODO: make it to match at least the quantity of items passed to work()
static const unsigned int N_BUFFERS = 16;
@@ -49,42 +46,6 @@
return gr_prefs::singleton()->get_string("audio_jack",
"default_input_device", "gr_source");
}
-
-int
-jack_source_process (jack_nframes_t nframes, void *arg)
-{
- audio_jack_source *self = (audio_jack_source *)arg;
- unsigned int write_size = nframes*sizeof(sample_t);
-
- if (jack_ringbuffer_write_space (self->d_ringbuffer) < write_size) {
- self->d_noverruns++;
- // FIXME: move this fputs out, we shouldn't use blocking calls in process()
- fputs ("jO", stderr);
- return 0;
- }
-
- char *buffer = (char *) jack_port_get_buffer (self->d_jack_input_port,
nframes);
-
- jack_ringbuffer_write (self->d_ringbuffer, buffer, write_size);
-
-#ifndef NO_PTHREAD
- // Tell the source thread there is data in the ringbuffer.
- // If it is already running, the lock will not be available.
- // We can't wait here in the process() thread, but we don't
- // need to signal in that case, because the source thread will
- // check for data availability.
-
- if (pthread_mutex_trylock (&self->d_jack_process_lock) == 0) {
- pthread_cond_signal (&self->d_ringbuffer_ready);
- pthread_mutex_unlock (&self->d_jack_process_lock);
- }
-#endif
-
- return 0;
-}
-
-// ----------------------------------------------------------------
-
audio_jack_source_sptr
audio_jack_make_source (int sampling_rate, const std::string dev, bool
ok_to_block)
{
@@ -104,10 +65,9 @@
d_ringbuffer (0),
d_noverruns (0)
{
-#ifndef NO_PTHREAD
- pthread_cond_init(&d_ringbuffer_ready, NULL);;
+
+ pthread_cond_init(&d_ringbuffer_ready, NULL);
pthread_mutex_init(&d_jack_process_lock, NULL);
-#endif
// try to become a client of the JACK server
if ((d_jack_client = jack_client_new (d_device_name.c_str ())) == 0) {
@@ -130,7 +90,6 @@
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
-
d_jack_buffer_size = jack_get_buffer_size (d_jack_client);
set_output_multiple (d_jack_buffer_size);
@@ -170,6 +129,65 @@
}
int
+audio_portaudio_source::work (int noutput_items,
+ gr_vector_const_void_star &input_items,
+ gr_vector_void_star &output_items)
+{
+ float **out = (float **) &output_items[0];
+ const unsigned nchan = d_input_parameters.channelCount; // # of channels ==
samples/frame
+
+ int k;
+ for (k = 0; k < noutput_items; ){
+
+ int nframes = d_reader->items_available() / nchan; // # of frames in
ringbuffer
+ if (nframes == 0){ // no data right now...
+ 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
+ continue;
+ }
+
+ assert(k == 0);
+
+ // There's no data and we're not allowed to block.
+ // (A USRP is most likely controlling the pacing through the pipeline.)
+ // This is an underun. The scheduler wouldn't have called us if it
+ // had anything better to do. Thus we really need to produce some amount
+ // of "fill".
+ //
+ // There are lots of options for comfort noise, etc.
+ // 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;
+ }
+ }
+ 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);
+
+ 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;
+ }
+
+ return k; // tell how many we actually did
+}
+
+int
audio_jack_source::work (int noutput_items,
gr_vector_const_void_star &input_items,
gr_vector_void_star &output_items)
@@ -185,12 +203,6 @@
while (work_size > 0) {
unsigned int read_space; // bytes
-#ifdef NO_PTHREAD
- while ((read_space=jack_ringbuffer_read_space (d_ringbuffer)) <
- d_jack_buffer_size*sizeof(sample_t)) {
-
usleep(1000000*((d_jack_buffer_size-read_space/sizeof(sample_t))/d_sampling_rate));
- }
-#else
// JACK actually requires POSIX
pthread_mutex_lock (&d_jack_process_lock);
@@ -201,7 +213,6 @@
pthread_cond_wait (&d_ringbuffer_ready, &d_jack_process_lock);
}
pthread_mutex_unlock (&d_jack_process_lock);
-#endif
read_space -= read_space%(d_jack_buffer_size*sizeof(sample_t));
read_size = std::min(read_space, (unsigned int)work_size);
Modified:
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_source.h
===================================================================
---
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_source.h
2006-12-19 22:54:23 UTC (rev 4153)
+++
gnuradio/branches/developers/brickle/jack/gr-audio-jack/src/audio_jack_source.h
2006-12-20 00:27:23 UTC (rev 4154)
@@ -24,6 +24,7 @@
#include <gr_sync_block.h>
#include <string>
+#include <omnithread.h>
#include <jack/jack.h>
#include <jack/ringbuffer.h>
#include <stdexcept>
@@ -54,7 +55,9 @@
*/
class audio_jack_source : public gr_sync_block {
friend audio_jack_source_sptr
- audio_jack_make_source (int sampling_rate, const std::string device_name,
bool ok_to_block);
+ audio_jack_make_source (int sampling_rate,
+ const std::string device_name,
+ bool ok_to_block);
friend int jack_source_process (jack_nframes_t nframes, void *arg);
@@ -67,20 +70,22 @@
std::string d_device_name;
bool d_ok_to_block;
- jack_client_t *d_jack_client;
- jack_port_t *d_jack_input_port;
jack_ringbuffer_t *d_ringbuffer;
jack_nframes_t d_jack_buffer_size;
- pthread_cond_t d_ringbuffer_ready;
- pthread_mutex_t d_jack_process_lock;
+ omni_semaphore d_ringbuffer_ready;
+
+ // our position in the manager's table of sources/ports
+
+ int d_mgr_id;
+
// random stats
+
int d_noverruns; // count of overruns
void output_error_msg (const char *msg, int err);
void bail (const char *msg, int err) throw (std::runtime_error);
-
protected:
audio_jack_source (int sampling_rate, const std::string device_name, bool
ok_to_block);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Commit-gnuradio] r4154 - gnuradio/branches/developers/brickle/jack/gr-audio-jack/src,
brickle <=