static gboolean gst_alsasrc_open (GstAudioSrc * asrc) { GstAlsaSrc *alsa; gint err; alsa = GST_ALSA_SRC (asrc); CHECK (snd_pcm_open (&alsa->handle, alsa->device, SND_PCM_STREAM_CAPTURE, (alsa->driver_timestamps) ? 0 : SND_PCM_NONBLOCK), open_error); return TRUE; /* ERRORS */ open_error: { if (err == -EBUSY) { GST_ELEMENT_ERROR (alsa, RESOURCE, BUSY, (_("Could not open audio device for recording. " "Device is being used by another application.")), ("Device '%s' is busy", alsa->device)); } else { GST_ELEMENT_ERROR (alsa, RESOURCE, OPEN_READ, (_("Could not open audio device for recording.")), ("Recording open error on device '%s': %s", alsa->device, snd_strerror (err))); } return FALSE; } }
static void gst_alsasrc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstAlsaSrc *src; src = GST_ALSA_SRC (object); switch (prop_id) { case PROP_DEVICE: g_value_set_string (value, src->device); break; case PROP_DEVICE_NAME: g_value_take_string (value, gst_alsa_find_device_name (GST_OBJECT_CAST (src), src->device, src->handle, SND_PCM_STREAM_CAPTURE)); break; case PROP_CARD_NAME: g_value_take_string (value, gst_alsa_find_card_name (GST_OBJECT_CAST (src), src->device, SND_PCM_STREAM_CAPTURE)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void gst_alsasrc_reset (GstAudioSrc * asrc) { GstAlsaSrc *alsa; gint err; alsa = GST_ALSA_SRC (asrc); GST_ALSA_SRC_LOCK (asrc); GST_DEBUG_OBJECT (alsa, "drop"); CHECK (snd_pcm_drop (alsa->handle), drop_error); GST_DEBUG_OBJECT (alsa, "prepare"); CHECK (snd_pcm_prepare (alsa->handle), prepare_error); GST_DEBUG_OBJECT (alsa, "reset done"); GST_ALSA_SRC_UNLOCK (asrc); return; /* ERRORS */ drop_error: { GST_ERROR_OBJECT (alsa, "alsa-reset: pcm drop error: %s", snd_strerror (err)); GST_ALSA_SRC_UNLOCK (asrc); return; } prepare_error: { GST_ERROR_OBJECT (alsa, "alsa-reset: pcm prepare error: %s", snd_strerror (err)); GST_ALSA_SRC_UNLOCK (asrc); return; } }
static GstStateChangeReturn gst_alsasrc_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstAudioBaseSrc *src = GST_AUDIO_BASE_SRC (element); GstAlsaSrc *alsa = GST_ALSA_SRC (element); GstClock *clk; switch (transition) { /* show the compiler that we care */ case GST_STATE_CHANGE_NULL_TO_READY: case GST_STATE_CHANGE_READY_TO_PAUSED: case GST_STATE_CHANGE_PLAYING_TO_PAUSED: case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_READY_TO_NULL: break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: clk = src->clock; alsa->driver_timestamps = FALSE; if (GST_IS_SYSTEM_CLOCK (clk)) { gint clocktype; g_object_get (clk, "clock-type", &clocktype, NULL); if (clocktype == GST_CLOCK_TYPE_MONOTONIC) { GST_INFO ("Using driver timestamps !"); alsa->driver_timestamps = TRUE; } } break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); return ret; }
static guint gst_alsasrc_read (GstAudioSrc * asrc, gpointer data, guint length, GstClockTime * timestamp) { GstAlsaSrc *alsa; gint err; gint cptr; guint8 *ptr = data; alsa = GST_ALSA_SRC (asrc); cptr = length / alsa->bpf; GST_ALSA_SRC_LOCK (asrc); while (cptr > 0) { GST_DELAY_SRC_LOCK (asrc); err = snd_pcm_readi (alsa->handle, ptr, cptr); GST_DELAY_SRC_UNLOCK (asrc); if (err < 0) { if (err == -EAGAIN) { GST_DEBUG_OBJECT (asrc, "Read error: %s", snd_strerror (err)); continue; } else if (err == -ENODEV) { goto device_disappeared; } else if (xrun_recovery (alsa, alsa->handle, err) < 0) { goto read_error; } continue; } ptr += snd_pcm_frames_to_bytes (alsa->handle, err); cptr -= err; } GST_ALSA_SRC_UNLOCK (asrc); /* if driver timestamps are enabled we need to return this here */ if (alsa->driver_timestamps && timestamp) *timestamp = gst_alsasrc_get_timestamp (alsa); return length - (cptr * alsa->bpf); read_error: { GST_ALSA_SRC_UNLOCK (asrc); return length; /* skip one period */ } device_disappeared: { GST_ELEMENT_ERROR (asrc, RESOURCE, READ, (_("Error recording from audio device. " "The device has been disconnected.")), (NULL)); GST_ALSA_SRC_UNLOCK (asrc); return (guint) - 1; } }
static void gst_alsasrc_finalize (GObject * object) { GstAlsaSrc *src = GST_ALSA_SRC (object); g_free (src->device); g_mutex_free (src->alsa_lock); G_OBJECT_CLASS (parent_class)->finalize (object); }
static gboolean gst_alsasrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { GstAlsaSrc *alsa; gint err; alsa = GST_ALSA_SRC (asrc); if (!alsasrc_parse_spec (alsa, spec)) goto spec_parse; CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block); CHECK (set_hwparams (alsa), hw_params_failed); CHECK (set_swparams (alsa), sw_params_failed); CHECK (snd_pcm_prepare (alsa->handle), prepare_failed); alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info); spec->segsize = alsa->period_size * alsa->bpf; spec->segtotal = alsa->buffer_size / alsa->period_size; return TRUE; /* ERRORS */ spec_parse: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Error parsing spec")); return FALSE; } non_block: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Could not set device to blocking: %s", snd_strerror (err))); return FALSE; } hw_params_failed: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Setting of hwparams failed: %s", snd_strerror (err))); return FALSE; } sw_params_failed: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Setting of swparams failed: %s", snd_strerror (err))); return FALSE; } prepare_failed: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Prepare failed: %s", snd_strerror (err))); return FALSE; } }
static gboolean gst_alsasrc_close (GstAudioSrc * asrc) { GstAlsaSrc *alsa = GST_ALSA_SRC (asrc); snd_pcm_close (alsa->handle); alsa->handle = NULL; gst_caps_replace (&alsa->cached_caps, NULL); return TRUE; }
static GstCaps * gst_alsasrc_getcaps (GstBaseSrc * bsrc, GstCaps * filter) { GstElementClass *element_class; GstPadTemplate *pad_template; GstAlsaSrc *src; GstCaps *caps, *templ_caps; src = GST_ALSA_SRC (bsrc); if (src->handle == NULL) { GST_DEBUG_OBJECT (src, "device not open, using template caps"); return GST_BASE_SRC_CLASS (parent_class)->get_caps (bsrc, filter); } if (src->cached_caps) { GST_LOG_OBJECT (src, "Returning cached caps"); if (filter) return gst_caps_intersect_full (filter, src->cached_caps, GST_CAPS_INTERSECT_FIRST); else return gst_caps_ref (src->cached_caps); } element_class = GST_ELEMENT_GET_CLASS (src); pad_template = gst_element_class_get_pad_template (element_class, "src"); g_return_val_if_fail (pad_template != NULL, NULL); templ_caps = gst_pad_template_get_caps (pad_template); GST_INFO_OBJECT (src, "template caps %" GST_PTR_FORMAT, templ_caps); caps = gst_alsa_probe_supported_formats (GST_OBJECT (src), src->device, src->handle, templ_caps); gst_caps_unref (templ_caps); if (caps) { src->cached_caps = gst_caps_ref (caps); } GST_INFO_OBJECT (src, "returning caps %" GST_PTR_FORMAT, caps); if (filter) { GstCaps *intersection; intersection = gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); gst_caps_unref (caps); return intersection; } else { return caps; } }
static gboolean gst_alsasrc_unprepare (GstAudioSrc * asrc) { GstAlsaSrc *alsa; alsa = GST_ALSA_SRC (asrc); snd_pcm_drop (alsa->handle); snd_pcm_hw_free (alsa->handle); snd_pcm_nonblock (alsa->handle, 1); return TRUE; }
static guint gst_alsasrc_delay (GstAudioSrc * asrc) { GstAlsaSrc *alsa; snd_pcm_sframes_t delay; int res; alsa = GST_ALSA_SRC (asrc); res = snd_pcm_delay (alsa->handle, &delay); if (G_UNLIKELY (res < 0)) { GST_DEBUG_OBJECT (alsa, "snd_pcm_delay returned %d", res); delay = 0; } return CLAMP (delay, 0, alsa->buffer_size); }
static void gst_alsasrc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstAlsaSrc *src; src = GST_ALSA_SRC (object); switch (prop_id) { case PROP_DEVICE: g_free (src->device); src->device = g_value_dup_string (value); if (src->device == NULL) { src->device = g_strdup (DEFAULT_PROP_DEVICE); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_alsasrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { GstAlsaSrc *alsa; gint err; alsa = GST_ALSA_SRC (asrc); if (!alsasrc_parse_spec (alsa, spec)) goto spec_parse; CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block); CHECK (set_hwparams (alsa), hw_params_failed); CHECK (set_swparams (alsa), sw_params_failed); CHECK (snd_pcm_prepare (alsa->handle), prepare_failed); alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info); spec->segsize = alsa->period_size * alsa->bpf; spec->segtotal = alsa->buffer_size / alsa->period_size; { snd_output_t *out_buf = NULL; char *msg = NULL; snd_output_buffer_open (&out_buf); snd_pcm_dump_hw_setup (alsa->handle, out_buf); snd_output_buffer_string (out_buf, &msg); GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg); snd_output_close (out_buf); snd_output_buffer_open (&out_buf); snd_pcm_dump_sw_setup (alsa->handle, out_buf); snd_output_buffer_string (out_buf, &msg); GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg); snd_output_close (out_buf); } #ifdef SND_CHMAP_API_VERSION if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW && alsa->channels < 9) { snd_pcm_chmap_t *chmap = snd_pcm_get_chmap (alsa->handle); if (chmap && chmap->channels == alsa->channels) { GstAudioChannelPosition pos[8]; if (alsa_chmap_to_channel_positions (chmap, pos)) gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC (alsa)->ringbuffer, pos); } free (chmap); } #endif /* SND_CHMAP_API_VERSION */ return TRUE; /* ERRORS */ spec_parse: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Error parsing spec")); return FALSE; } non_block: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Could not set device to blocking: %s", snd_strerror (err))); return FALSE; } hw_params_failed: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Setting of hwparams failed: %s", snd_strerror (err))); return FALSE; } sw_params_failed: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Setting of swparams failed: %s", snd_strerror (err))); return FALSE; } prepare_failed: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Prepare failed: %s", snd_strerror (err))); return FALSE; } }
static gboolean gst_alsasrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { GstAlsaSrc *alsa; gint err; alsa = GST_ALSA_SRC (asrc); if (!alsasrc_parse_spec (alsa, spec)) goto spec_parse; CHECK (snd_pcm_nonblock (alsa->handle, 0), non_block); CHECK (set_hwparams (alsa), hw_params_failed); CHECK (set_swparams (alsa), sw_params_failed); CHECK (snd_pcm_prepare (alsa->handle), prepare_failed); alsa->bpf = GST_AUDIO_INFO_BPF (&spec->info); spec->segsize = alsa->period_size * alsa->bpf; spec->segtotal = alsa->buffer_size / alsa->period_size; { snd_output_t *out_buf = NULL; char *msg = NULL; snd_output_buffer_open (&out_buf); snd_pcm_dump_hw_setup (alsa->handle, out_buf); snd_output_buffer_string (out_buf, &msg); GST_DEBUG_OBJECT (alsa, "Hardware setup: \n%s", msg); snd_output_close (out_buf); snd_output_buffer_open (&out_buf); snd_pcm_dump_sw_setup (alsa->handle, out_buf); snd_output_buffer_string (out_buf, &msg); GST_DEBUG_OBJECT (alsa, "Software setup: \n%s", msg); snd_output_close (out_buf); } #ifdef SND_CHMAP_API_VERSION alsa_detect_channels_mapping (GST_OBJECT (alsa), alsa->handle, spec, alsa->channels, GST_AUDIO_BASE_SRC (alsa)->ringbuffer); #endif /* SND_CHMAP_API_VERSION */ return TRUE; /* ERRORS */ spec_parse: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Error parsing spec")); return FALSE; } non_block: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Could not set device to blocking: %s", snd_strerror (err))); return FALSE; } hw_params_failed: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Setting of hwparams failed: %s", snd_strerror (err))); return FALSE; } sw_params_failed: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Setting of swparams failed: %s", snd_strerror (err))); return FALSE; } prepare_failed: { GST_ELEMENT_ERROR (alsa, RESOURCE, SETTINGS, (NULL), ("Prepare failed: %s", snd_strerror (err))); return FALSE; } }