2 * empathy-gst-audio-src.c - Source for EmpathyGstAudioSrc
3 * Copyright (C) 2008 Collabora Ltd.
4 * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <pulse/pulseaudio.h>
26 #include <pulse/glib-mainloop.h>
28 #include <libempathy/empathy-utils.h>
29 #include <libempathy-gtk/empathy-call-utils.h>
31 #include "empathy-audio-src.h"
33 #include "src-marshal.h"
35 #define DEBUG_FLAG EMPATHY_DEBUG_VOIP
36 #include <libempathy/empathy-debug.h>
38 G_DEFINE_TYPE(EmpathyGstAudioSrc, empathy_audio_src, GST_TYPE_BIN)
50 static guint signals[LAST_SIGNAL] = {0};
59 /* private structure */
60 typedef struct _EmpathyGstAudioSrcPrivate EmpathyGstAudioSrcPrivate;
62 struct _EmpathyGstAudioSrcPrivate
64 gboolean dispose_has_run;
69 pa_glib_mainloop *loop;
73 /* 0 if not known yet */
74 guint source_output_idx;
75 /* G_MAXUINT if not known yet */
85 #define EMPATHY_GST_AUDIO_SRC_GET_PRIVATE(o) \
86 (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_GST_AUDIO_SRC, \
87 EmpathyGstAudioSrcPrivate))
90 empathy_audio_src_supports_changing_mic (EmpathyGstAudioSrc *self)
92 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
93 GObjectClass *object_class;
95 object_class = G_OBJECT_GET_CLASS (priv->src);
97 return (g_object_class_find_property (object_class,
98 "source-output-index") != NULL);
101 typedef void (*OperationFunc) (EmpathyGstAudioSrc *, GSimpleAsyncResult *);
106 GSimpleAsyncResult *result;
110 operation_new (OperationFunc func,
111 GSimpleAsyncResult *result)
113 Operation *o = g_slice_new0 (Operation);
122 operation_free (Operation *o,
127 g_simple_async_result_set_error (o->result,
128 G_IO_ERROR, G_IO_ERROR_CANCELLED,
129 "The audio source was disposed");
130 g_simple_async_result_complete (o->result);
131 g_object_unref (o->result);
134 g_slice_free (Operation, o);
138 operation_get_microphones_free (gpointer data)
140 GQueue *queue = data;
143 for (l = queue->head; l != NULL; l = l->next)
145 EmpathyAudioSrcMicrophone *mic = l->data;
148 g_free (mic->description);
149 g_slice_free (EmpathyAudioSrcMicrophone, mic);
152 g_queue_free (queue);
156 operation_get_microphones_cb (pa_context *context,
157 const pa_source_info *info,
161 GSimpleAsyncResult *result = userdata;
162 EmpathyAudioSrcMicrophone *mic;
167 g_simple_async_result_complete (result);
168 g_object_unref (result);
172 mic = g_slice_new0 (EmpathyAudioSrcMicrophone);
173 mic->index = info->index;
174 mic->name = g_strdup (info->name);
175 mic->description = g_strdup (info->description);
176 mic->is_monitor = (info->monitor_of_sink != PA_INVALID_INDEX);
178 /* add it to the queue */
179 queue = g_simple_async_result_get_op_res_gpointer (result);
180 g_queue_push_tail (queue, mic);
184 operation_get_microphones (EmpathyGstAudioSrc *self,
185 GSimpleAsyncResult *result)
187 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
189 g_assert_cmpuint (pa_context_get_state (priv->context), ==, PA_CONTEXT_READY);
191 g_simple_async_result_set_op_res_gpointer (result, g_queue_new (),
192 operation_get_microphones_free);
194 pa_context_get_source_info_list (priv->context,
195 operation_get_microphones_cb, result);
199 operation_change_microphone_cb (pa_context *context,
203 GSimpleAsyncResult *result = userdata;
207 g_simple_async_result_set_error (result, G_IO_ERROR, G_IO_ERROR_FAILED,
208 "Failed to change microphone. Reason unknown.");
211 g_simple_async_result_complete (result);
212 g_object_unref (result);
216 operation_change_microphone (EmpathyGstAudioSrc *self,
217 GSimpleAsyncResult *result)
219 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
220 guint source_output_idx, microphone;
222 g_object_get (priv->src, "source-output-index", &source_output_idx, NULL);
224 g_assert_cmpuint (pa_context_get_state (priv->context), ==, PA_CONTEXT_READY);
225 g_assert_cmpuint (source_output_idx, !=, PA_INVALID_INDEX);
227 microphone = GPOINTER_TO_UINT (
228 g_simple_async_result_get_op_res_gpointer (result));
230 pa_context_move_source_output_by_index (priv->context, source_output_idx, microphone,
231 operation_change_microphone_cb, result);
235 operations_run (EmpathyGstAudioSrc *self)
237 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
238 pa_context_state_t state = pa_context_get_state (priv->context);
241 if (state != PA_CONTEXT_READY)
244 for (l = priv->operations->head; l != NULL; l = l->next)
246 Operation *o = l->data;
248 o->func (self, o->result);
250 operation_free (o, FALSE);
253 g_queue_clear (priv->operations);
257 empathy_audio_src_source_output_info_cb (pa_context *context,
258 const pa_source_output_info *info,
262 EmpathyGstAudioSrc *self = userdata;
263 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
268 /* There should only be one call here. */
270 if (priv->source_idx == info->source)
273 priv->source_idx = info->source;
274 g_object_notify (G_OBJECT (self), "microphone");
278 empathy_audio_src_source_info_cb (pa_context *context,
279 const pa_source_info *info,
283 EmpathyGstAudioSrc *self = userdata;
289 is_monitor = (info->monitor_of_sink != PA_INVALID_INDEX);
291 g_signal_emit (self, signals[MICROPHONE_ADDED], 0,
292 info->index, info->name, info->description, is_monitor);
296 empathy_audio_src_pa_event_cb (pa_context *context,
297 pa_subscription_event_type_t type,
301 EmpathyGstAudioSrc *self = userdata;
302 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
304 if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT
305 && (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE
306 && idx == priv->source_output_idx)
308 /* Microphone in the source output has changed */
309 pa_context_get_source_output_info (context, idx,
310 empathy_audio_src_source_output_info_cb, self);
312 else if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE
313 && (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE)
315 /* A mic has been removed */
316 g_signal_emit (self, signals[MICROPHONE_REMOVED], 0, idx);
318 else if ((type & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE
319 && (type & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_NEW)
321 /* A mic has been plugged in */
322 pa_context_get_source_info_by_index (context, idx,
323 empathy_audio_src_source_info_cb, self);
328 empathy_audio_src_pa_subscribe_cb (pa_context *context,
333 DEBUG ("Failed to subscribe to PulseAudio events");
337 empathy_audio_src_pa_state_change_cb (pa_context *context,
340 EmpathyGstAudioSrc *self = userdata;
341 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
342 pa_context_state_t state = pa_context_get_state (priv->context);
344 if (state == PA_CONTEXT_READY)
346 /* Listen to pulseaudio events so we know when sources are
347 * added and when the microphone is changed. */
348 pa_context_set_subscribe_callback (priv->context,
349 empathy_audio_src_pa_event_cb, self);
350 pa_context_subscribe (priv->context,
351 PA_SUBSCRIPTION_MASK_SOURCE | PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT,
352 empathy_audio_src_pa_subscribe_cb, NULL);
354 operations_run (self);
359 empathy_audio_src_source_output_index_notify (GObject *object,
361 EmpathyGstAudioSrc *self)
363 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
364 guint source_output_idx = PA_INVALID_INDEX;
366 g_object_get (priv->src, "source-output-index", &source_output_idx, NULL);
368 if (source_output_idx == PA_INVALID_INDEX)
371 if (priv->source_output_idx == source_output_idx)
374 /* It's actually changed. */
375 priv->source_output_idx = source_output_idx;
377 pa_context_get_source_output_info (priv->context, source_output_idx,
378 empathy_audio_src_source_output_info_cb, self);
385 const gchar *description;
387 description = g_getenv ("EMPATHY_AUDIO_SRC");
389 if (description != NULL)
391 GError *error = NULL;
393 src = gst_parse_bin_from_description (description, TRUE, &error);
396 DEBUG ("Failed to create bin %s: %s", description, error->message);
397 g_error_free (error);
403 /* Use pulsesrc as default */
404 src = gst_element_factory_make ("pulsesrc", NULL);
408 empathy_call_set_stream_properties (src);
414 empathy_audio_src_init (EmpathyGstAudioSrc *obj)
416 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (obj);
419 priv->peak_level = -G_MAXDOUBLE;
420 priv->lock = g_mutex_new ();
422 priv->src = create_src ();
423 if (priv->src == NULL)
426 gst_bin_add (GST_BIN (obj), priv->src);
428 priv->volume = gst_element_factory_make ("volume", NULL);
429 g_object_ref (priv->volume);
431 gst_bin_add (GST_BIN (obj), priv->volume);
432 gst_element_link (priv->src, priv->volume);
434 priv->level = gst_element_factory_make ("level", NULL);
435 gst_bin_add (GST_BIN (obj), priv->level);
436 gst_element_link (priv->volume, priv->level);
438 src = gst_element_get_static_pad (priv->level, "src");
440 ghost = gst_ghost_pad_new ("src", src);
441 gst_element_add_pad (GST_ELEMENT (obj), ghost);
443 gst_object_unref (G_OBJECT (src));
445 /* PulseAudio stuff: We need to create a dummy pa_glib_mainloop* so
446 * Pulse can use the mainloop that GTK has created for us. */
447 priv->loop = pa_glib_mainloop_new (NULL);
448 priv->context = pa_context_new (pa_glib_mainloop_get_api (priv->loop),
451 /* Listen to changes to GstPulseSrc:source-output-index so we know when
452 * it's no longer PA_INVALID_INDEX (starting for the first time) or if it
453 * changes (READY->NULL->READY...) */
454 g_signal_connect (priv->src, "notify::source-output-index",
455 G_CALLBACK (empathy_audio_src_source_output_index_notify),
458 /* Finally listen for state changes so we know when we've
460 pa_context_set_state_callback (priv->context,
461 empathy_audio_src_pa_state_change_cb, obj);
462 pa_context_connect (priv->context, NULL, 0, NULL);
464 priv->operations = g_queue_new ();
467 static void empathy_audio_src_dispose (GObject *object);
468 static void empathy_audio_src_finalize (GObject *object);
469 static void empathy_audio_src_handle_message (GstBin *bin,
470 GstMessage *message);
472 static gboolean empathy_audio_src_levels_updated (gpointer user_data);
475 empathy_audio_src_set_property (GObject *object,
476 guint property_id, const GValue *value, GParamSpec *pspec)
481 empathy_audio_src_set_volume (EMPATHY_GST_AUDIO_SRC (object),
482 g_value_get_double (value));
485 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
490 empathy_audio_src_get_property (GObject *object,
491 guint property_id, GValue *value, GParamSpec *pspec)
493 EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (object);
494 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
499 g_value_set_double (value,
500 empathy_audio_src_get_volume (self));
502 case PROP_PEAK_LEVEL:
503 g_mutex_lock (priv->lock);
504 g_value_set_double (value, priv->peak_level);
505 g_mutex_unlock (priv->lock);
508 g_mutex_lock (priv->lock);
509 g_value_set_double (value, priv->rms_level);
510 g_mutex_unlock (priv->lock);
512 case PROP_MICROPHONE:
513 g_value_set_uint (value, priv->source_idx);
516 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
521 empathy_audio_src_class_init (EmpathyGstAudioSrcClass
522 *empathy_audio_src_class)
524 GObjectClass *object_class = G_OBJECT_CLASS (empathy_audio_src_class);
525 GstBinClass *gstbin_class = GST_BIN_CLASS (empathy_audio_src_class);
526 GParamSpec *param_spec;
528 g_type_class_add_private (empathy_audio_src_class,
529 sizeof (EmpathyGstAudioSrcPrivate));
531 object_class->dispose = empathy_audio_src_dispose;
532 object_class->finalize = empathy_audio_src_finalize;
534 object_class->set_property = empathy_audio_src_set_property;
535 object_class->get_property = empathy_audio_src_get_property;
537 gstbin_class->handle_message =
538 GST_DEBUG_FUNCPTR (empathy_audio_src_handle_message);
540 param_spec = g_param_spec_double ("volume", "Volume", "volume contol",
542 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
543 g_object_class_install_property (object_class, PROP_VOLUME, param_spec);
545 param_spec = g_param_spec_double ("peak-level", "peak level", "peak level",
546 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
547 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
548 g_object_class_install_property (object_class, PROP_PEAK_LEVEL, param_spec);
550 param_spec = g_param_spec_uint ("microphone", "microphone", "microphone",
551 0, G_MAXUINT, G_MAXUINT,
552 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
553 g_object_class_install_property (object_class, PROP_MICROPHONE, param_spec);
555 signals[PEAK_LEVEL_CHANGED] = g_signal_new ("peak-level-changed",
556 G_TYPE_FROM_CLASS (empathy_audio_src_class),
560 g_cclosure_marshal_VOID__DOUBLE,
561 G_TYPE_NONE, 1, G_TYPE_DOUBLE);
563 param_spec = g_param_spec_double ("rms-level", "RMS level", "RMS level",
564 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
565 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
566 g_object_class_install_property (object_class, PROP_RMS_LEVEL, param_spec);
569 signals[RMS_LEVEL_CHANGED] = g_signal_new ("rms-level-changed",
570 G_TYPE_FROM_CLASS (empathy_audio_src_class),
574 g_cclosure_marshal_VOID__DOUBLE,
575 G_TYPE_NONE, 1, G_TYPE_DOUBLE);
577 signals[MICROPHONE_ADDED] = g_signal_new ("microphone-added",
578 G_TYPE_FROM_CLASS (empathy_audio_src_class),
582 _src_marshal_VOID__UINT_STRING_STRING_BOOLEAN,
583 G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN);
585 signals[MICROPHONE_REMOVED] = g_signal_new ("microphone-removed",
586 G_TYPE_FROM_CLASS (empathy_audio_src_class),
590 g_cclosure_marshal_VOID__UINT,
591 G_TYPE_NONE, 1, G_TYPE_UINT);
595 empathy_audio_src_dispose (GObject *object)
597 EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (object);
598 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
600 if (priv->dispose_has_run)
603 priv->dispose_has_run = TRUE;
605 if (priv->idle_id != 0)
606 g_source_remove (priv->idle_id);
610 if (priv->context != NULL)
611 pa_context_unref (priv->context);
612 priv->context = NULL;
614 if (priv->loop != NULL)
615 pa_glib_mainloop_free (priv->loop);
618 /* release any references held by the object here */
620 if (G_OBJECT_CLASS (empathy_audio_src_parent_class)->dispose)
621 G_OBJECT_CLASS (empathy_audio_src_parent_class)->dispose (object);
625 empathy_audio_src_finalize (GObject *object)
627 EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (object);
628 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
630 /* free any data held directly by the object here */
631 g_mutex_free (priv->lock);
633 g_queue_foreach (priv->operations, (GFunc) operation_free,
634 GUINT_TO_POINTER (TRUE));
635 g_queue_free (priv->operations);
637 G_OBJECT_CLASS (empathy_audio_src_parent_class)->finalize (object);
641 empathy_audio_src_levels_updated (gpointer user_data)
643 EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (user_data);
644 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
646 g_mutex_lock (priv->lock);
648 g_signal_emit (self, signals[PEAK_LEVEL_CHANGED], 0, priv->peak_level);
649 g_signal_emit (self, signals[RMS_LEVEL_CHANGED], 0, priv->rms_level);
652 g_mutex_unlock (priv->lock);
658 empathy_audio_src_handle_message (GstBin *bin, GstMessage *message)
660 EmpathyGstAudioSrc *self = EMPATHY_GST_AUDIO_SRC (bin);
661 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (self);
663 if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ELEMENT &&
664 GST_MESSAGE_SRC (message) == GST_OBJECT (priv->level))
666 const GstStructure *s;
670 gdouble peak = -G_MAXDOUBLE;
671 gdouble rms = -G_MAXDOUBLE;
673 s = gst_message_get_structure (message);
674 name = gst_structure_get_name (s);
676 if (g_strcmp0 ("level", name) != 0)
679 list = gst_structure_get_value (s, "peak");
680 len = gst_value_list_get_size (list);
682 for (i =0 ; i < len; i++)
687 value = gst_value_list_get_value (list, i);
688 db = g_value_get_double (value);
689 peak = MAX (db, peak);
692 list = gst_structure_get_value (s, "rms");
693 len = gst_value_list_get_size (list);
695 for (i =0 ; i < len; i++)
700 value = gst_value_list_get_value (list, i);
701 db = g_value_get_double (value);
705 g_mutex_lock (priv->lock);
707 priv->peak_level = peak;
708 priv->rms_level = rms;
709 if (priv->idle_id == 0)
710 priv->idle_id = g_idle_add (empathy_audio_src_levels_updated, self);
712 g_mutex_unlock (priv->lock);
716 GST_BIN_CLASS (empathy_audio_src_parent_class)->handle_message (bin,
721 empathy_audio_src_new (void)
723 static gboolean registered = FALSE;
726 if (!gst_element_register (NULL, "empathyaudiosrc",
727 GST_RANK_NONE, EMPATHY_TYPE_GST_AUDIO_SRC))
731 return gst_element_factory_make ("empathyaudiosrc", NULL);
735 empathy_audio_src_set_volume (EmpathyGstAudioSrc *src, gdouble volume)
737 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src);
739 GParamSpecDouble *pspec_double;
741 pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (priv->volume),
744 g_assert (pspec != NULL);
746 pspec_double = G_PARAM_SPEC_DOUBLE (pspec);
748 volume = CLAMP (volume, pspec_double->minimum, pspec_double->maximum);
750 g_object_set (G_OBJECT (priv->volume), "volume", volume, NULL);
754 empathy_audio_src_get_volume (EmpathyGstAudioSrc *src)
756 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src);
759 g_object_get (G_OBJECT (priv->volume), "volume", &volume, NULL);
765 empathy_audio_src_get_microphones_async (EmpathyGstAudioSrc *src,
766 GAsyncReadyCallback callback,
769 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src);
770 Operation *operation;
771 GSimpleAsyncResult *simple;
773 simple = g_simple_async_result_new (G_OBJECT (src), callback, user_data,
774 empathy_audio_src_get_microphones_async);
776 /* If we can't change mic let's not pretend we can by returning the
777 * list of available mics. */
778 if (!empathy_audio_src_supports_changing_mic (src))
780 g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
781 "pulsesrc is not new enough to support changing microphone");
782 g_simple_async_result_complete_in_idle (simple);
783 g_object_unref (simple);
787 operation = operation_new (operation_get_microphones, simple);
788 g_queue_push_tail (priv->operations, operation);
791 operations_run (src);
795 empathy_audio_src_get_microphones_finish (EmpathyGstAudioSrc *src,
796 GAsyncResult *result,
799 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
802 if (g_simple_async_result_propagate_error (simple, error))
805 g_return_val_if_fail (g_simple_async_result_is_valid (result,
806 G_OBJECT (src), empathy_audio_src_get_microphones_async),
809 queue = g_simple_async_result_get_op_res_gpointer (simple);
814 empathy_audio_src_get_microphone (EmpathyGstAudioSrc *src)
816 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src);
818 return priv->source_idx;
822 empathy_audio_src_change_microphone_async (EmpathyGstAudioSrc *src,
824 GAsyncReadyCallback callback,
827 EmpathyGstAudioSrcPrivate *priv = EMPATHY_GST_AUDIO_SRC_GET_PRIVATE (src);
828 guint source_output_idx;
829 GSimpleAsyncResult *simple;
830 Operation *operation;
832 simple = g_simple_async_result_new (G_OBJECT (src), callback, user_data,
833 empathy_audio_src_change_microphone_async);
835 if (!empathy_audio_src_supports_changing_mic (src))
837 g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
838 "pulsesrc is not new enough to support changing microphone");
839 g_simple_async_result_complete_in_idle (simple);
840 g_object_unref (simple);
844 g_object_get (priv->src, "source-output-index", &source_output_idx, NULL);
846 if (source_output_idx == PA_INVALID_INDEX)
848 g_simple_async_result_set_error (simple, G_IO_ERROR, G_IO_ERROR_FAILED,
849 "pulsesrc is not yet PLAYING");
850 g_simple_async_result_complete_in_idle (simple);
851 g_object_unref (simple);
855 g_simple_async_result_set_op_res_gpointer (simple,
856 GUINT_TO_POINTER (microphone), NULL);
858 operation = operation_new (operation_change_microphone, simple);
859 g_queue_push_tail (priv->operations, operation);
862 operations_run (src);
866 empathy_audio_src_change_microphone_finish (EmpathyGstAudioSrc *src,
867 GAsyncResult *result,
870 empathy_implement_finish_void (src,
871 empathy_audio_src_change_microphone_async);