diff options
author | Jonny Lamb <jonny.lamb@collabora.co.uk> | 2011-08-17 22:55:32 +0800 |
---|---|---|
committer | Jonny Lamb <jonny.lamb@collabora.co.uk> | 2011-08-18 22:59:11 +0800 |
commit | cd40005a5e9608fa8e1295b8606788af38100dba (patch) | |
tree | 082c70811946d78b2b80fe2bfe7066376557b782 /src/empathy-audio-src.c | |
parent | 956bfcb33c33452f4ce958ae0a7112efb5ccf4a9 (diff) | |
download | gsoc2013-empathy-cd40005a5e9608fa8e1295b8606788af38100dba.tar gsoc2013-empathy-cd40005a5e9608fa8e1295b8606788af38100dba.tar.gz gsoc2013-empathy-cd40005a5e9608fa8e1295b8606788af38100dba.tar.bz2 gsoc2013-empathy-cd40005a5e9608fa8e1295b8606788af38100dba.tar.lz gsoc2013-empathy-cd40005a5e9608fa8e1295b8606788af38100dba.tar.xz gsoc2013-empathy-cd40005a5e9608fa8e1295b8606788af38100dba.tar.zst gsoc2013-empathy-cd40005a5e9608fa8e1295b8606788af38100dba.zip |
mic-monitor: move the PA-specific stuff from audio-src to here
Sorry for another big commit.
Signed-off-by: Jonny Lamb <jonny.lamb@collabora.co.uk>
Diffstat (limited to 'src/empathy-audio-src.c')
-rw-r--r-- | src/empathy-audio-src.c | 396 |
1 files changed, 56 insertions, 340 deletions
diff --git a/src/empathy-audio-src.c b/src/empathy-audio-src.c index 8f7a0599f..0b19b868a 100644 --- a/src/empathy-audio-src.c +++ b/src/empathy-audio-src.c @@ -22,15 +22,13 @@ #include <stdio.h> #include <stdlib.h> -#include <pulse/pulseaudio.h> -#include <pulse/glib-mainloop.h> - #include <libempathy/empathy-utils.h> #include <libempathy-gtk/empathy-call-utils.h> #include "empathy-audio-src.h" #include "src-marshal.h" +#include "empathy-mic-monitor.h" #define DEBUG_FLAG EMPATHY_DEBUG_VOIP #include <libempathy/empathy-debug.h> @@ -42,8 +40,6 @@ enum { PEAK_LEVEL_CHANGED, RMS_LEVEL_CHANGED, - MICROPHONE_ADDED, - MICROPHONE_REMOVED, LAST_SIGNAL }; @@ -66,9 +62,7 @@ struct _EmpathyGstAudioSrcPrivate GstElement *volume; GstElement *level; - pa_glib_mainloop *loop; - pa_context *context; - GQueue *operations; + EmpathyMicMonitor *mic_monitor; /* 0 if not known yet */ guint source_output_idx; @@ -98,261 +92,54 @@ empathy_audio_src_supports_changing_mic (EmpathyGstAudioSrc *self) "source-output-index") != NULL); } -typedef void (*OperationFunc) (EmpathyGstAudioSrc *, GSimpleAsyncResult *); - -typedef struct -{ - OperationFunc func; - GSimpleAsyncResult *result; -} Operation; - -static Operation * -operation_new (OperationFunc func, - GSimpleAsyncResult *result) -{ - Operation *o = g_slice_new0 (Operation); - - o->func = func; - o->result = result; - - return o; -} - -static void -operation_free (Operation *o, - gboolean cancelled) -{ - if (cancelled) - { - g_simple_async_result_set_error (o->result, - G_IO_ERROR, G_IO_ERROR_CANCELLED, - "The audio source was disposed"); - g_simple_async_result_complete (o->result); - g_object_unref (o->result); - } - - g_slice_free (Operation, o); -} - static void -operation_get_microphones_free (gpointer data) -{ - GQueue *queue = data; - GList *l; - - for (l = queue->head; l != NULL; l = l->next) - { - EmpathyAudioSrcMicrophone *mic = l->data; - - g_free (mic->name); - g_free (mic->description); - g_slice_free (EmpathyAudioSrcMicrophone, mic); - } - - g_queue_free (queue); -} - -static void -operation_get_microphones_cb (pa_context *context, - const pa_source_info *info, - int eol, - void *userdata) -{ - GSimpleAsyncResult *result = userdata; - EmpathyAudioSrcMicrophone *mic; - GQueue *queue; - - if (eol) - { - g_simple_async_result_complete (result); - g_object_unref (result); - return; - } - - mic = g_slice_new0 (EmpathyAudioSrcMicrophone); - mic->index = info->index; - mic->name = g_strdup (info->name); - mic->description = g_strdup (info->description); - mic->is_monitor = (info->monitor_of_sink != PA_INVALID_INDEX); - - /* add it to the queue */ - queue = g_simple_async_result_get_op_res_gpointer (result); - g_queue_push_tail (queue, mic); -} - -static void -operation_get_microphones (EmpathyGstAudioSrc *self, - GSimpleAsyncResult *result) -{ - EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); - - g_assert_cmpuint (pa_context_get_state (priv->context), ==, PA_CONTEXT_READY); - - g_simple_async_result_set_op_res_gpointer (result, g_queue_new (), - operation_get_microphones_free); - - pa_context_get_source_info_list (priv->context, - operation_get_microphones_cb, result); -} - -static void -operation_change_microphone_cb (pa_context *context, - int success, - void *userdata) -{ - GSimpleAsyncResult *result = userdata; - - if (!success) - { - g_simple_async_result_set_error (result, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed to change microphone. Reason unknown."); - } - - g_simple_async_result_complete (result); - g_object_unref (result); -} - -static void -operation_change_microphone (EmpathyGstAudioSrc *self, - GSimpleAsyncResult *result) -{ - EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); - guint source_output_idx, microphone; - - g_object_get (priv->src, "source-output-index", &source_output_idx, NULL); - - g_assert_cmpuint (pa_context_get_state (priv->context), ==, PA_CONTEXT_READY); - g_assert_cmpuint (source_output_idx, !=, PA_INVALID_INDEX); - - microphone = GPOINTER_TO_UINT ( - g_simple_async_result_get_op_res_gpointer (result)); - - pa_context_move_source_output_by_index (priv->context, source_output_idx, microphone, - operation_change_microphone_cb, result); -} - -static void -operations_run (EmpathyGstAudioSrc *self) +empathy_audio_src_microphone_changed_cb (EmpathyMicMonitor *monitor, + guint source_output_idx, + guint source_idx, + gpointer user_data) { + EmpathyGstAudioSrc *self = user_data; EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); - pa_context_state_t state = pa_context_get_state (priv->context); - GList *l; - - if (state != PA_CONTEXT_READY) - return; - - for (l = priv->operations->head; l != NULL; l = l->next) - { - Operation *o = l->data; + guint audio_src_idx = PA_INVALID_INDEX; - o->func (self, o->result); - - operation_free (o, FALSE); - } + g_object_get (priv->src, "source-output-index", &audio_src_idx, NULL); - g_queue_clear (priv->operations); -} - -static void -empathy_audio_src_source_output_info_cb (pa_context *context, - const pa_source_output_info *info, - int eol, - void *userdata) -{ - EmpathyGstAudioSrc *self = userdata; - EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); - - if (eol) + if (source_output_idx == PA_INVALID_INDEX + || source_output_idx != audio_src_idx) return; - /* There should only be one call here. */ - - if (priv->source_idx == info->source) + if (priv->source_idx == source_idx) return; - priv->source_idx = info->source; + priv->source_idx = source_idx; g_object_notify (G_OBJECT (self), "microphone"); } static void -empathy_audio_src_source_info_cb (pa_context *context, - const pa_source_info *info, - int eol, - void *userdata) -{ - EmpathyGstAudioSrc *self = userdata; - gboolean is_monitor; - - if (eol) - return; - - is_monitor = (info->monitor_of_sink != PA_INVALID_INDEX); - - g_signal_emit (self, signals[MICROPHONE_ADDED], 0, - info->index, info->name, info->description, is_monitor); -} - -static void -empathy_audio_src_pa_event_cb (pa_context *context, - pa_subscription_event_type_t type, - uint32_t idx, - void *userdata) +empathy_audio_src_get_current_mic_cb (GObject *source_object, + GAsyncResult *result, + gpointer user_data) { - EmpathyGstAudioSrc *self = userdata; + EmpathyMicMonitor *monitor = EMPATHY_MIC_MONITOR (source_object); + EmpathyGstAudioSrc *self = user_data; EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); + guint source_idx; + GError *error = NULL; - if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT - && (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE - && idx == priv->source_output_idx) - { - /* Microphone in the source output has changed */ - pa_context_get_source_output_info (context, idx, - empathy_audio_src_source_output_info_cb, self); - } - else if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE - && (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) - { - /* A mic has been removed */ - g_signal_emit (self, signals[MICROPHONE_REMOVED], 0, idx); - } - else if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE - && (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW) + source_idx = empathy_mic_monitor_get_current_mic_finish (monitor, result, &error); + + if (error != NULL) { - /* A mic has been plugged in */ - pa_context_get_source_info_by_index (context, idx, - empathy_audio_src_source_info_cb, self); + DEBUG ("Failed to get current mic: %s", error->message); + g_clear_error (&error); + return; } -} - -static void -empathy_audio_src_pa_subscribe_cb (pa_context *context, - int success, - void *userdata) -{ - if (!success) - DEBUG ("Failed to subscribe to PulseAudio events"); -} -static void -empathy_audio_src_pa_state_change_cb (pa_context *context, - void *userdata) -{ - EmpathyGstAudioSrc *self = userdata; - EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self); - pa_context_state_t state = pa_context_get_state (priv->context); + if (priv->source_idx == source_idx) + return; - if (state == PA_CONTEXT_READY) - { - /* Listen to pulseaudio events so we know when sources are - * added and when the microphone is changed. */ - pa_context_set_subscribe_callback (priv->context, - empathy_audio_src_pa_event_cb, self); - pa_context_subscribe (priv->context, - PA_SUBSCRIPTION_MASK_SOURCE | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, - empathy_audio_src_pa_subscribe_cb, NULL); - - operations_run (self); - } + priv->source_idx = source_idx; + g_object_notify (G_OBJECT (self), "microphone"); } static void @@ -374,8 +161,8 @@ empathy_audio_src_source_output_index_notify (GObject *object, /* It's actually changed. */ priv->source_output_idx = source_output_idx; - pa_context_get_source_output_info (priv->context, source_output_idx, - empathy_audio_src_source_output_info_cb, self); + empathy_mic_monitor_get_current_mic_async (priv->mic_monitor, + source_output_idx, empathy_audio_src_get_current_mic_cb, self); } static GstElement * @@ -442,12 +229,6 @@ empathy_audio_src_init (EmpathyGstAudioSrc *obj) gst_object_unref (G_OBJECT (src)); - /* PulseAudio stuff: We need to create a dummy pa_glib_mainloop* so - * Pulse can use the mainloop that GTK has created for us. */ - priv->loop = pa_glib_mainloop_new (NULL); - priv->context = pa_context_new (pa_glib_mainloop_get_api (priv->loop), - "EmpathyAudioSrc"); - /* Listen to changes to GstPulseSrc:source-output-index so we know when * it's no longer PA_INVALID_INDEX (starting for the first time) or if it * changes (READY->NULL->READY...) */ @@ -455,13 +236,11 @@ empathy_audio_src_init (EmpathyGstAudioSrc *obj) G_CALLBACK (empathy_audio_src_source_output_index_notify), obj); - /* Finally listen for state changes so we know when we've - * connected. */ - pa_context_set_state_callback (priv->context, - empathy_audio_src_pa_state_change_cb, obj); - pa_context_connect (priv->context, NULL, 0, NULL); + priv->mic_monitor = empathy_mic_monitor_new (); + g_signal_connect (priv->mic_monitor, "microphone-changed", + G_CALLBACK (empathy_audio_src_microphone_changed_cb), obj); - priv->operations = g_queue_new (); + priv->source_idx = PA_INVALID_INDEX; } static void empathy_audio_src_dispose (GObject *object); @@ -565,7 +344,6 @@ empathy_audio_src_class_init (EmpathyGstAudioSrcClass G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_property (object_class, PROP_RMS_LEVEL, param_spec); - signals[RMS_LEVEL_CHANGED] = g_signal_new ("rms-level-changed", G_TYPE_FROM_CLASS (empathy_audio_src_class), G_SIGNAL_RUN_LAST, @@ -573,22 +351,6 @@ empathy_audio_src_class_init (EmpathyGstAudioSrcClass NULL, NULL, g_cclosure_marshal_VOID__DOUBLE, G_TYPE_NONE, 1, G_TYPE_DOUBLE); - - signals[MICROPHONE_ADDED] = g_signal_new ("microphone-added", - G_TYPE_FROM_CLASS (empathy_audio_src_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - _src_marshal_VOID__UINT_STRING_STRING_BOOLEAN, - G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); - - signals[MICROPHONE_REMOVED] = g_signal_new ("microphone-removed", - G_TYPE_FROM_CLASS (empathy_audio_src_class), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); } void @@ -607,13 +369,7 @@ empathy_audio_src_dispose (GObject *object) priv->idle_id = 0; - if (priv->context != NULL) - pa_context_unref (priv->context); - priv->context = NULL; - - if (priv->loop != NULL) - pa_glib_mainloop_free (priv->loop); - priv->loop = NULL; + tp_clear_object (&priv->mic_monitor); /* release any references held by the object here */ @@ -630,10 +386,6 @@ empathy_audio_src_finalize (GObject *object) /* free any data held directly by the object here */ g_mutex_free (priv->lock); - g_queue_foreach (priv->operations, (GFunc) operation_free, - GUINT_TO_POINTER (TRUE)); - g_queue_free (priv->operations); - G_OBJECT_CLASS (empathy_audio_src_parent_class)->finalize (object); } @@ -761,61 +513,31 @@ empathy_audio_src_get_volume (EmpathyGstAudioSrc *src) return volume; } -void -empathy_audio_src_get_microphones_async (EmpathyGstAudioSrc *src, - GAsyncReadyCallback callback, - gpointer user_data) +guint +empathy_audio_src_get_microphone (EmpathyGstAudioSrc *src) { EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src); - Operation *operation; - GSimpleAsyncResult *simple; - - simple = g_simple_async_result_new (G_OBJECT (src), callback, user_data, - empathy_audio_src_get_microphones_async); - - /* If we can't change mic let's not pretend we can by returning the - * list of available mics. */ - if (!empathy_audio_src_supports_changing_mic (src)) - { - g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED, - "pulsesrc is not new enough to support changing microphone"); - g_simple_async_result_complete_in_idle (simple); - g_object_unref (simple); - return; - } - operation = operation_new (operation_get_microphones, simple); - g_queue_push_tail (priv->operations, operation); - - /* gogogogo */ - operations_run (src); + return priv->source_idx; } -const GList * -empathy_audio_src_get_microphones_finish (EmpathyGstAudioSrc *src, +static void +empathy_audio_src_change_microphone_cb (GObject *source_object, GAsyncResult *result, - GError **error) + gpointer user_data) { - GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); - GQueue *queue; - - if (g_simple_async_result_propagate_error (simple, error)) - return NULL; - - g_return_val_if_fail (g_simple_async_result_is_valid (result, - G_OBJECT (src), empathy_audio_src_get_microphones_async), - NULL); - - queue = g_simple_async_result_get_op_res_gpointer (simple); - return queue->head; -} + EmpathyMicMonitor *monitor = EMPATHY_MIC_MONITOR (source_object); + GSimpleAsyncResult *simple = user_data; + GError *error = NULL; -guint -empathy_audio_src_get_microphone (EmpathyGstAudioSrc *src) -{ - EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src); + if (!empathy_mic_monitor_change_microphone_finish (monitor, + result, &error)) + { + g_simple_async_result_take_error (simple, error); + } - return priv->source_idx; + g_simple_async_result_complete (simple); + g_object_unref (simple); } void @@ -827,7 +549,6 @@ empathy_audio_src_change_microphone_async (EmpathyGstAudioSrc *src, EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src); guint source_output_idx; GSimpleAsyncResult *simple; - Operation *operation; simple = g_simple_async_result_new (G_OBJECT (src), callback, user_data, empathy_audio_src_change_microphone_async); @@ -852,14 +573,9 @@ empathy_audio_src_change_microphone_async (EmpathyGstAudioSrc *src, return; } - g_simple_async_result_set_op_res_gpointer (simple, - GUINT_TO_POINTER (microphone), NULL); - - operation = operation_new (operation_change_microphone, simple); - g_queue_push_tail (priv->operations, operation); - - /* gogogogo */ - operations_run (src); + empathy_mic_monitor_change_microphone_async (priv->mic_monitor, + source_output_idx, microphone, empathy_audio_src_change_microphone_cb, + simple); } gboolean |