commit-gnuradio
[Top][All Lists]
Advanced

[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);
 





reply via email to

[Prev in Thread] Current Thread [Next in Thread]