static void gst_jack_audio_src_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object); switch (prop_id) { case PROP_CLIENT_NAME: g_value_set_string (value, src->client_name); break; case PROP_CONNECT: g_value_set_enum (value, src->connect); break; case PROP_SERVER: g_value_set_string (value, src->server); break; case PROP_CLIENT: g_value_set_boxed (value, src->jclient); break; case PROP_TRANSPORT: g_value_set_flags (value, src->transport); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_jack_audio_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object); switch (prop_id) { case PROP_CLIENT_NAME: g_free (src->client_name); src->client_name = g_value_dup_string (value); break; case PROP_CONNECT: src->connect = g_value_get_enum (value); break; case PROP_SERVER: g_free (src->server); src->server = g_value_dup_string (value); break; case PROP_CLIENT: if (GST_STATE (src) == GST_STATE_NULL || GST_STATE (src) == GST_STATE_READY) { src->jclient = g_value_get_boxed (value); } break; case PROP_TRANSPORT: src->transport = g_value_get_flags (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
/* function is called with LOCK */ static gboolean gst_jack_ring_buffer_release (GstRingBuffer * buf) { GstJackAudioSrc *src; GstJackRingBuffer *abuf; gint res; abuf = GST_JACK_RING_BUFFER_CAST (buf); src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); GST_DEBUG_OBJECT (src, "release"); if ((res = gst_jack_audio_client_set_active (src->client, FALSE))) { /* we only warn, this means the server is probably shut down and the client * is gone anyway. */ GST_ELEMENT_WARNING (src, RESOURCE, CLOSE, (NULL), ("Could not deactivate Jack client (%d)", res)); } abuf->channels = -1; abuf->buffer_size = -1; abuf->sample_rate = -1; /* free the buffer */ gst_buffer_unref (buf->data); buf->data = NULL; return TRUE; }
static guint gst_jack_ring_buffer_delay (GstRingBuffer * buf) { GstJackAudioSrc *src; guint i, res = 0; #ifdef HAVE_JACK_0_120_2 jack_latency_range_t range; #else guint latency; #endif jack_client_t *client; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); client = gst_jack_audio_client_get_client (src->client); for (i = 0; i < src->port_count; i++) { #ifdef HAVE_JACK_0_120_2 jack_port_get_latency_range (src->ports[i], JackCaptureLatency, &range); if (range.max > res) res = range.max; #else latency = jack_port_get_total_latency (client, src->ports[i]); if (latency > res) res = latency; #endif } GST_DEBUG_OBJECT (src, "delay %u", res); return res; }
static void gst_jack_audio_src_dispose (GObject * object) { GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object); gst_caps_replace (&src->caps, NULL); G_OBJECT_CLASS (parent_class)->dispose (object); }
static GstCaps * gst_jack_audio_src_getcaps (GstBaseSrc * bsrc) { GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (bsrc); const char **ports; gint min, max; gint rate; jack_client_t *client; if (src->client == NULL) goto no_client; client = gst_jack_audio_client_get_client (src->client); if (src->connect == GST_JACK_CONNECT_AUTO) { /* get a port count, this is the number of channels we can automatically * connect. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); max = 0; if (ports != NULL) { for (; ports[max]; max++); free (ports); } else max = 0; } else { /* we allow any number of pads, something else is going to connect the * pads. */ max = G_MAXINT; } min = MIN (1, max); rate = jack_get_sample_rate (client); GST_DEBUG_OBJECT (src, "got %d-%d ports, samplerate: %d", min, max, rate); if (!src->caps) { src->caps = gst_caps_new_simple ("audio/x-raw-float", "endianness", G_TYPE_INT, G_BYTE_ORDER, "width", G_TYPE_INT, 32, "rate", G_TYPE_INT, rate, "channels", GST_TYPE_INT_RANGE, min, max, NULL); } GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, src->caps); return gst_caps_ref (src->caps); /* ERRORS */ no_client: { GST_DEBUG_OBJECT (src, "device not open, using template caps"); /* base class will get template caps for us when we return NULL */ return NULL; } }
static gboolean gst_jack_ring_buffer_stop (GstRingBuffer * buf) { GstJackAudioSrc *src; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); GST_DEBUG_OBJECT (src, "stop"); return TRUE; }
static void jack_shutdown_cb (void *arg) { GstJackAudioSrc *src; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg)); GST_DEBUG_OBJECT (src, "shutdown"); GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (NULL), ("Jack server shutdown")); }
/* this is the callback of jack. This should be RT-safe. * Writes samples from the jack input port's buffer to the gst ring buffer. */ static int jack_process_cb (jack_nframes_t nframes, void *arg) { GstJackAudioSrc *src; GstRingBuffer *buf; GstJackRingBuffer *abuf; gint len, givenLen; guint8 *writeptr, *dataStart; gint writeseg; gint channels, i, j; sample_t **buffers, *data; buf = GST_RING_BUFFER_CAST (arg); abuf = GST_JACK_RING_BUFFER_CAST (arg); src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); channels = buf->spec.channels; len = sizeof (sample_t) * nframes * channels; /* alloc pointers to samples */ buffers = g_alloca (sizeof (sample_t *) * channels); data = g_alloca (len); /* get input buffers */ for (i = 0; i < channels; i++) buffers[i] = (sample_t *) jack_port_get_buffer (src->ports[i], nframes); //writeptr = data; dataStart = (guint8 *) data; /* the samples in the jack input buffers have to be interleaved into the * ringbuffer */ for (i = 0; i < nframes; ++i) for (j = 0; j < channels; ++j) *data++ = buffers[j][i]; if (gst_ring_buffer_prepare_read (buf, &writeseg, &writeptr, &givenLen)) { memcpy (writeptr, (char *) dataStart, givenLen); GST_DEBUG ("copy %d frames: %p, %d bytes, %d channels", nframes, writeptr, len / channels, channels); /* clear written samples in the ringbuffer */ // gst_ring_buffer_clear(buf, 0); /* we wrote one segment */ gst_ring_buffer_advance (buf, 1); } return 0; }
/* this is the callback of jack. This should be RT-safe. * Writes samples from the jack input port's buffer to the gst ring buffer. */ static int jack_process_cb (jack_nframes_t nframes, void *arg) { GstJackAudioSrc *src; GstRingBuffer *buf; gint len; guint8 *writeptr; gint writeseg; gint channels, i, j, flen; sample_t *data; buf = GST_RING_BUFFER_CAST (arg); src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); channels = buf->spec.channels; /* get input buffers */ for (i = 0; i < channels; i++) src->buffers[i] = (sample_t *) jack_port_get_buffer (src->ports[i], nframes); if (gst_ring_buffer_prepare_read (buf, &writeseg, &writeptr, &len)) { flen = len / channels; /* the number of samples must be exactly the segment size */ if (nframes * sizeof (sample_t) != flen) goto wrong_size; /* the samples in the jack input buffers have to be interleaved into the * ringbuffer */ data = (sample_t *) writeptr; for (i = 0; i < nframes; ++i) for (j = 0; j < channels; ++j) *data++ = src->buffers[j][i]; GST_DEBUG ("copy %d frames: %p, %d bytes, %d channels", nframes, writeptr, len / channels, channels); /* we wrote one segment */ gst_ring_buffer_advance (buf, 1); } return 0; /* ERRORS */ wrong_size: { GST_ERROR_OBJECT (src, "nbytes (%d) != flen (%d)", (gint) (nframes * sizeof (sample_t)), flen); return 1; } }
static void gst_jack_audio_src_dispose (GObject * object) { GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object); gst_caps_replace (&src->caps, NULL); if (src->client_name != NULL) { g_free (src->client_name); src->client_name = NULL; } G_OBJECT_CLASS (parent_class)->dispose (object); }
/* close the connection with the server */ static gboolean gst_jack_ring_buffer_close_device (GstRingBuffer * buf) { GstJackAudioSrc *src; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); GST_DEBUG_OBJECT (src, "close"); gst_jack_audio_src_free_channels (src); gst_jack_audio_client_free (src->client); src->client = NULL; return TRUE; }
/* the _open_device method should make a connection with the server */ static gboolean gst_jack_ring_buffer_open_device (GstRingBuffer * buf) { GstJackAudioSrc *src; jack_status_t status = 0; const gchar *name; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); GST_DEBUG_OBJECT (src, "open"); if (src->client_name) { name = src->client_name; } else { name = g_get_application_name (); } if (!name) name = "GStreamer"; src->client = gst_jack_audio_client_new (name, src->server, src->jclient, GST_JACK_CLIENT_SOURCE, jack_shutdown_cb, jack_process_cb, jack_buffer_size_cb, jack_sample_rate_cb, buf, &status); if (src->client == NULL) goto could_not_open; GST_DEBUG_OBJECT (src, "opened"); return TRUE; /* ERRORS */ could_not_open: { if (status & (JackServerFailed | JackFailure)) { GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, (_("Jack server not found")), ("Cannot connect to the Jack server (status %d)", status)); } else { GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ, (NULL), ("Jack client open error (status %d)", status)); } return FALSE; } }
static gboolean gst_jack_ring_buffer_stop (GstRingBuffer * buf) { GstJackAudioSrc *src; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); GST_DEBUG_OBJECT (src, "stop"); if (src->transport & GST_JACK_TRANSPORT_MASTER) { jack_client_t *client; client = gst_jack_audio_client_get_client (src->client); jack_transport_stop (client); } return TRUE; }
static void gst_jack_audio_src_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstJackAudioSrc *src = GST_JACK_AUDIO_SRC (object); switch (prop_id) { case PROP_CONNECT: src->connect = g_value_get_enum (value); break; case PROP_SERVER: g_free (src->server); src->server = g_value_dup_string (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static guint gst_jack_ring_buffer_delay (GstRingBuffer * buf) { GstJackAudioSrc *src; guint i, res = 0; jack_latency_range_t range; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); for (i = 0; i < src->port_count; i++) { jack_port_get_latency_range (src->ports[i], JackCaptureLatency, &range); if (range.max > res) res = range.max; } GST_DEBUG_OBJECT (src, "delay %u", res); return res; }
static guint gst_jack_ring_buffer_delay (GstRingBuffer * buf) { GstJackAudioSrc *src; guint i, res = 0, latency; jack_client_t *client; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); client = gst_jack_audio_client_get_client (src->client); for (i = 0; i < src->port_count; i++) { latency = jack_port_get_total_latency (client, src->ports[i]); if (latency > res) res = latency; } GST_DEBUG_OBJECT (src, "delay %u", res); return res; }
/* we error out */ static int jack_buffer_size_cb (jack_nframes_t nframes, void *arg) { GstJackAudioSrc *src; GstJackRingBuffer *abuf; abuf = GST_JACK_RING_BUFFER_CAST (arg); src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (arg)); if (abuf->buffer_size != -1 && abuf->buffer_size != nframes) goto not_supported; return 0; /* ERRORS */ not_supported: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Jack changed the buffer size, which is not supported")); return 1; } }
/* allocate a buffer and setup resources to process the audio samples of * the format as specified in @spec. * * We allocate N jack ports, one for each channel. If we are asked to * automatically make a connection with physical ports, we connect as many * ports as there are physical ports, leaving leftover ports unconnected. * * It is assumed that samplerate and number of channels are acceptable since our * getcaps method will always provide correct values. If unacceptable caps are * received for some reason, we fail here. */ static gboolean gst_jack_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec) { GstJackAudioSrc *src; GstJackRingBuffer *abuf; const char **ports; gint sample_rate, buffer_size; gint i, channels, res; jack_client_t *client; src = GST_JACK_AUDIO_SRC (GST_OBJECT_PARENT (buf)); abuf = GST_JACK_RING_BUFFER_CAST (buf); GST_DEBUG_OBJECT (src, "acquire"); client = gst_jack_audio_client_get_client (src->client); /* sample rate must be that of the server */ sample_rate = jack_get_sample_rate (client); if (sample_rate != spec->rate) goto wrong_samplerate; channels = spec->channels; if (!gst_jack_audio_src_allocate_channels (src, channels)) goto out_of_ports; buffer_size = jack_get_buffer_size (client); /* the segment size in bytes, this is large enough to hold a buffer of 32bit floats * for all channels */ spec->segsize = buffer_size * sizeof (gfloat) * channels; spec->latency_time = gst_util_uint64_scale (spec->segsize, (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample); /* segtotal based on buffer-time latency */ spec->segtotal = spec->buffer_time / spec->latency_time; GST_DEBUG_OBJECT (src, "segsize %d, segtotal %d", spec->segsize, spec->segtotal); /* allocate the ringbuffer memory now */ buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize); memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data)); if ((res = gst_jack_audio_client_set_active (src->client, TRUE))) goto could_not_activate; /* if we need to automatically connect the ports, do so now. We must do this * after activating the client. */ if (src->connect == GST_JACK_CONNECT_AUTO) { /* find all the physical output ports. A physical output port is a port * associated with a hardware device. Someone needs connect to a physical * port in order to capture something. */ ports = jack_get_ports (client, NULL, NULL, JackPortIsPhysical | JackPortIsOutput); if (ports == NULL) { /* no ports? fine then we don't do anything except for posting a warning * message. */ GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL), ("No physical output ports found, leaving ports unconnected")); goto done; } for (i = 0; i < channels; i++) { /* stop when all output ports are exhausted */ if (ports[i] == NULL) { /* post a warning that we could not connect all ports */ GST_ELEMENT_WARNING (src, RESOURCE, NOT_FOUND, (NULL), ("No more physical ports, leaving some ports unconnected")); break; } GST_DEBUG_OBJECT (src, "try connecting to %s", jack_port_name (src->ports[i])); /* connect the physical port to a port */ res = jack_connect (client, ports[i], jack_port_name (src->ports[i])); g_print ("connecting to %s\n", jack_port_name (src->ports[i])); if (res != 0 && res != EEXIST) goto cannot_connect; } free (ports); } done: abuf->sample_rate = sample_rate; abuf->buffer_size = buffer_size; abuf->channels = spec->channels; return TRUE; /* ERRORS */ wrong_samplerate: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Wrong samplerate, server is running at %d and we received %d", sample_rate, spec->rate)); return FALSE; } out_of_ports: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Cannot allocate more Jack ports")); return FALSE; } could_not_activate: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Could not activate client (%d:%s)", res, g_strerror (res))); return FALSE; } cannot_connect: { GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL), ("Could not connect input ports to physical ports (%d:%s)", res, g_strerror (res))); free (ports); return FALSE; } }