static void gst_opensles_src_init (GstOpenSLESSrc * src) { /* Override some default values to fit on the AudioFlinger behaviour of * processing 20ms buffers as minimum buffer size. */ GST_AUDIO_BASE_SRC (src)->buffer_time = 400000; GST_AUDIO_BASE_SRC (src)->latency_time = 20000; }
static guint gst_dshowaudiosrc_read (GstAudioSrc * asrc, gpointer data, guint length, GstClockTime *timestamp) { GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc); guint ret = 0; if (!src->is_running) return -1; if (src->gbarray) { test: if (src->gbarray->len >= length) { g_mutex_lock (&src->gbarray_lock); memcpy (data, src->gbarray->data + (src->gbarray->len - length), length); g_byte_array_remove_range (src->gbarray, src->gbarray->len - length, length); ret = length; g_mutex_unlock (&src->gbarray_lock); } else { if (src->is_running) { Sleep (GST_AUDIO_BASE_SRC(src)->ringbuffer->spec.latency_time / GST_MSECOND / 10); goto test; } } } return ret; }
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 void gst_pulsesrc_init (GstPulseSrc * pulsesrc) { pulsesrc->server = NULL; pulsesrc->device = NULL; pulsesrc->client_name = gst_pulse_client_name (); pulsesrc->device_description = NULL; pulsesrc->context = NULL; pulsesrc->stream = NULL; pulsesrc->stream_connected = FALSE; pulsesrc->source_output_idx = PA_INVALID_INDEX; pulsesrc->read_buffer = NULL; pulsesrc->read_buffer_length = 0; pa_sample_spec_init (&pulsesrc->sample_spec); pulsesrc->operation_success = FALSE; pulsesrc->paused = TRUE; pulsesrc->in_read = FALSE; pulsesrc->volume = DEFAULT_VOLUME; pulsesrc->volume_set = FALSE; pulsesrc->mute = DEFAULT_MUTE; pulsesrc->mute_set = FALSE; pulsesrc->notify = 0; pulsesrc->properties = NULL; pulsesrc->proplist = NULL; pulsesrc->probe = gst_pulseprobe_new (G_OBJECT (pulsesrc), G_OBJECT_GET_CLASS (pulsesrc), PROP_DEVICE, pulsesrc->server, FALSE, TRUE); /* FALSE for sinks, TRUE for sources */ /* this should be the default but it isn't yet */ gst_audio_base_src_set_slave_method (GST_AUDIO_BASE_SRC (pulsesrc), GST_AUDIO_BASE_SRC_SLAVE_SKEW); /* override with a custom clock */ if (GST_AUDIO_BASE_SRC (pulsesrc)->clock) gst_object_unref (GST_AUDIO_BASE_SRC (pulsesrc)->clock); GST_AUDIO_BASE_SRC (pulsesrc)->clock = gst_audio_clock_new ("GstPulseSrcClock", (GstAudioClockGetTimeFunc) gst_pulsesrc_get_time, pulsesrc, NULL); }
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 alsasrc_parse_spec (GstAlsaSrc * alsa, GstAudioRingBufferSpec * spec) { switch (spec->type) { case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW: switch (GST_AUDIO_INFO_FORMAT (&spec->info)) { case GST_AUDIO_FORMAT_U8: alsa->format = SND_PCM_FORMAT_U8; break; case GST_AUDIO_FORMAT_S8: alsa->format = SND_PCM_FORMAT_S8; break; case GST_AUDIO_FORMAT_S16LE: alsa->format = SND_PCM_FORMAT_S16_LE; break; case GST_AUDIO_FORMAT_S16BE: alsa->format = SND_PCM_FORMAT_S16_BE; break; case GST_AUDIO_FORMAT_U16LE: alsa->format = SND_PCM_FORMAT_U16_LE; break; case GST_AUDIO_FORMAT_U16BE: alsa->format = SND_PCM_FORMAT_U16_BE; break; case GST_AUDIO_FORMAT_S24_32LE: alsa->format = SND_PCM_FORMAT_S24_LE; break; case GST_AUDIO_FORMAT_S24_32BE: alsa->format = SND_PCM_FORMAT_S24_BE; break; case GST_AUDIO_FORMAT_U24_32LE: alsa->format = SND_PCM_FORMAT_U24_LE; break; case GST_AUDIO_FORMAT_U24_32BE: alsa->format = SND_PCM_FORMAT_U24_BE; break; case GST_AUDIO_FORMAT_S32LE: alsa->format = SND_PCM_FORMAT_S32_LE; break; case GST_AUDIO_FORMAT_S32BE: alsa->format = SND_PCM_FORMAT_S32_BE; break; case GST_AUDIO_FORMAT_U32LE: alsa->format = SND_PCM_FORMAT_U32_LE; break; case GST_AUDIO_FORMAT_U32BE: alsa->format = SND_PCM_FORMAT_U32_BE; break; case GST_AUDIO_FORMAT_S24LE: alsa->format = SND_PCM_FORMAT_S24_3LE; break; case GST_AUDIO_FORMAT_S24BE: alsa->format = SND_PCM_FORMAT_S24_3BE; break; case GST_AUDIO_FORMAT_U24LE: alsa->format = SND_PCM_FORMAT_U24_3LE; break; case GST_AUDIO_FORMAT_U24BE: alsa->format = SND_PCM_FORMAT_U24_3BE; break; case GST_AUDIO_FORMAT_S20LE: alsa->format = SND_PCM_FORMAT_S20_3LE; break; case GST_AUDIO_FORMAT_S20BE: alsa->format = SND_PCM_FORMAT_S20_3BE; break; case GST_AUDIO_FORMAT_U20LE: alsa->format = SND_PCM_FORMAT_U20_3LE; break; case GST_AUDIO_FORMAT_U20BE: alsa->format = SND_PCM_FORMAT_U20_3BE; break; case GST_AUDIO_FORMAT_S18LE: alsa->format = SND_PCM_FORMAT_S18_3LE; break; case GST_AUDIO_FORMAT_S18BE: alsa->format = SND_PCM_FORMAT_S18_3BE; break; case GST_AUDIO_FORMAT_U18LE: alsa->format = SND_PCM_FORMAT_U18_3LE; break; case GST_AUDIO_FORMAT_U18BE: alsa->format = SND_PCM_FORMAT_U18_3BE; break; case GST_AUDIO_FORMAT_F32LE: alsa->format = SND_PCM_FORMAT_FLOAT_LE; break; case GST_AUDIO_FORMAT_F32BE: alsa->format = SND_PCM_FORMAT_FLOAT_BE; break; case GST_AUDIO_FORMAT_F64LE: alsa->format = SND_PCM_FORMAT_FLOAT64_LE; break; case GST_AUDIO_FORMAT_F64BE: alsa->format = SND_PCM_FORMAT_FLOAT64_BE; break; default: goto error; } break; case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW: alsa->format = SND_PCM_FORMAT_A_LAW; break; case GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW: alsa->format = SND_PCM_FORMAT_MU_LAW; break; default: goto error; } alsa->rate = GST_AUDIO_INFO_RATE (&spec->info); alsa->channels = GST_AUDIO_INFO_CHANNELS (&spec->info); alsa->buffer_time = spec->buffer_time; alsa->period_time = spec->latency_time; alsa->access = SND_PCM_ACCESS_RW_INTERLEAVED; if (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW && alsa->channels < 9) gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC (alsa)->ringbuffer, alsa_position[alsa->channels - 1]); return TRUE; /* ERRORS */ error: { 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; } }
static GstStateChangeReturn gst_pulsesrc_change_state (GstElement * element, GstStateChange transition) { GstStateChangeReturn ret; GstPulseSrc *this = GST_PULSESRC_CAST (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: if (!(this->mainloop = pa_threaded_mainloop_new ())) goto mainloop_failed; if (pa_threaded_mainloop_start (this->mainloop) < 0) { pa_threaded_mainloop_free (this->mainloop); this->mainloop = NULL; goto mainloop_start_failed; } break; case GST_STATE_CHANGE_READY_TO_PAUSED: gst_element_post_message (element, gst_message_new_clock_provide (GST_OBJECT_CAST (element), GST_AUDIO_BASE_SRC (this)->clock, TRUE)); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: /* uncork and start recording */ gst_pulsesrc_play (this); break; case GST_STATE_CHANGE_PLAYING_TO_PAUSED: /* stop recording ASAP by corking */ pa_threaded_mainloop_lock (this->mainloop); GST_DEBUG_OBJECT (this, "corking"); gst_pulsesrc_set_corked (this, TRUE, FALSE); pa_threaded_mainloop_unlock (this->mainloop); break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: /* now make sure we get out of the _read method */ gst_pulsesrc_pause (this); break; case GST_STATE_CHANGE_READY_TO_NULL: if (this->mainloop) pa_threaded_mainloop_stop (this->mainloop); gst_pulsesrc_destroy_context (this); if (this->mainloop) { pa_threaded_mainloop_free (this->mainloop); this->mainloop = NULL; } break; case GST_STATE_CHANGE_PAUSED_TO_READY: /* format_lost is reset in release() in baseaudiosink */ gst_element_post_message (element, gst_message_new_clock_lost (GST_OBJECT_CAST (element), GST_AUDIO_BASE_SRC (this)->clock)); break; default: break; } return ret; /* ERRORS */ mainloop_failed: { GST_ELEMENT_ERROR (this, RESOURCE, FAILED, ("pa_threaded_mainloop_new() failed"), (NULL)); return GST_STATE_CHANGE_FAILURE; } mainloop_start_failed: { GST_ELEMENT_ERROR (this, RESOURCE, FAILED, ("pa_threaded_mainloop_start() failed"), (NULL)); return GST_STATE_CHANGE_FAILURE; } }
static gboolean gst_pulsesrc_prepare (GstAudioSrc * asrc, GstAudioRingBufferSpec * spec) { pa_buffer_attr wanted; const pa_buffer_attr *actual; GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_stream_flags_t flags; pa_operation *o; GstAudioClock *clock; pa_threaded_mainloop_lock (pulsesrc->mainloop); { GstAudioRingBufferSpec s = *spec; const pa_channel_map *m; m = pa_stream_get_channel_map (pulsesrc->stream); gst_pulse_channel_map_to_gst (m, &s); gst_audio_ring_buffer_set_channel_positions (GST_AUDIO_BASE_SRC (pulsesrc)->ringbuffer, s.info.position); } /* enable event notifications */ GST_LOG_OBJECT (pulsesrc, "subscribing to context events"); if (!(o = pa_context_subscribe (pulsesrc->context, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, NULL, NULL))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_context_subscribe() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } pa_operation_unref (o); wanted.maxlength = -1; wanted.tlength = -1; wanted.prebuf = 0; wanted.minreq = -1; wanted.fragsize = spec->segsize; GST_INFO_OBJECT (pulsesrc, "maxlength: %d", wanted.maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d", wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", wanted.prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d", wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d", wanted.fragsize); flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NOT_MONOTONIC | PA_STREAM_ADJUST_LATENCY | PA_STREAM_START_CORKED; if (pulsesrc->mute_set && pulsesrc->mute) flags |= PA_STREAM_START_MUTED; if (pa_stream_connect_record (pulsesrc->stream, pulsesrc->device, &wanted, flags) < 0) { goto connect_failed; } /* our clock will now start from 0 again */ clock = GST_AUDIO_CLOCK (GST_AUDIO_BASE_SRC (pulsesrc)->clock); gst_audio_clock_reset (clock, 0); pulsesrc->corked = TRUE; for (;;) { pa_stream_state_t state; state = pa_stream_get_state (pulsesrc->stream); if (!PA_STREAM_IS_GOOD (state)) goto stream_is_bad; if (state == PA_STREAM_READY) break; /* Wait until the stream is ready */ pa_threaded_mainloop_wait (pulsesrc->mainloop); } pulsesrc->stream_connected = TRUE; /* store the source output index so it can be accessed via a property */ pulsesrc->source_output_idx = pa_stream_get_index (pulsesrc->stream); g_object_notify (G_OBJECT (pulsesrc), "source-output-index"); if (pulsesrc->volume_set) { gst_pulsesrc_set_stream_volume (pulsesrc, pulsesrc->volume); pulsesrc->volume_set = FALSE; } /* get the actual buffering properties now */ actual = pa_stream_get_buffer_attr (pulsesrc->stream); GST_INFO_OBJECT (pulsesrc, "maxlength: %d", actual->maxlength); GST_INFO_OBJECT (pulsesrc, "tlength: %d (wanted: %d)", actual->tlength, wanted.tlength); GST_INFO_OBJECT (pulsesrc, "prebuf: %d", actual->prebuf); GST_INFO_OBJECT (pulsesrc, "minreq: %d (wanted %d)", actual->minreq, wanted.minreq); GST_INFO_OBJECT (pulsesrc, "fragsize: %d (wanted %d)", actual->fragsize, wanted.fragsize); if (actual->fragsize >= wanted.fragsize) { spec->segsize = actual->fragsize; } else { spec->segsize = actual->fragsize * (wanted.fragsize / actual->fragsize); } spec->segtotal = actual->maxlength / spec->segsize; if (!pulsesrc->paused) { GST_DEBUG_OBJECT (pulsesrc, "uncorking because we are playing"); gst_pulsesrc_set_corked (pulsesrc, FALSE, FALSE); } pa_threaded_mainloop_unlock (pulsesrc->mainloop); return TRUE; /* ERRORS */ connect_failed: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } stream_is_bad: { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect stream: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } unlock_and_fail: { gst_pulsesrc_destroy_stream (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return FALSE; } }