void AudioDriverPulseAudio::detect_channels(bool capture) { pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map); String device = capture ? capture_device_name : device_name; if (device == "Default") { // Get the default output device name pa_status = 0; pa_operation *pa_op = pa_context_get_server_info(pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)this); if (pa_op) { while (pa_status == 0) { int ret = pa_mainloop_iterate(pa_ml, 1, NULL); if (ret < 0) { ERR_PRINT("pa_mainloop_iterate error"); } } pa_operation_unref(pa_op); } else { ERR_PRINT("pa_context_get_server_info error"); } } char dev[1024]; if (device == "Default") { strcpy(dev, capture ? capture_default_device.utf8().get_data() : default_device.utf8().get_data()); } else { strcpy(dev, device.utf8().get_data()); } // Now using the device name get the amount of channels pa_status = 0; pa_operation *pa_op; if (capture) { pa_op = pa_context_get_source_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_source_info_cb, (void *)this); } else { pa_op = pa_context_get_sink_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_sink_info_cb, (void *)this); } if (pa_op) { while (pa_status == 0) { int ret = pa_mainloop_iterate(pa_ml, 1, NULL); if (ret < 0) { ERR_PRINT("pa_mainloop_iterate error"); } } pa_operation_unref(pa_op); } else { if (capture) { ERR_PRINT("pa_context_get_source_info_by_name error"); } else { ERR_PRINT("pa_context_get_sink_info_by_name error"); } } }
static void toggle_mic_mute(pa_context *c) { pa_operation *o; o = pa_context_get_source_info_by_name(c, "@DEFAULT_SOURCE@", source_toggle_mute_callback, NULL); if (!o) { fprintf(stderr, "Operation failed: %s\n", pa_strerror(pa_context_errno(c))); return; } pa_operation_unref(o); }
static gchar * gst_pulsesrc_device_description (GstPulseSrc * pulsesrc) { pa_operation *o = NULL; gchar *t; if (!pulsesrc->mainloop) goto no_mainloop; pa_threaded_mainloop_lock (pulsesrc->mainloop); if (!(o = pa_context_get_source_info_by_name (pulsesrc->context, pulsesrc->device, gst_pulsesrc_source_info_cb, pulsesrc))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("pa_stream_get_source_info() failed: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock; } while (pa_operation_get_state (o) == PA_OPERATION_RUNNING) { if (gst_pulsesrc_is_dead (pulsesrc, FALSE)) goto unlock; pa_threaded_mainloop_wait (pulsesrc->mainloop); } unlock: if (o) pa_operation_unref (o); t = g_strdup (pulsesrc->device_description); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return t; no_mainloop: { GST_DEBUG_OBJECT (pulsesrc, "have no mainloop"); return NULL; } }
int_fast32_t pulse_get_source_info(pa_source_info_cb_t cb, const char *name, void *userdata) { if (pulse_context_ready() < 0) return -1; pulse_lock(); pa_operation *op = pa_context_get_source_info_by_name( pulse_context, name, cb, userdata); while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) pulse_wait(); pa_operation_unref(op); pulse_unlock(); return 0; }
static int pulse_update_volume(snd_ctl_pulse_t * ctl) { int err; pa_operation *o; assert(ctl); if (!ctl->p) return -EBADFD; err = pulse_check_connection(ctl->p); if (err < 0) return err; o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->sink, sink_info_cb, ctl); if (o) { err = pulse_wait_operation(ctl->p, o); pa_operation_unref(o); } else err = -EIO; if (err < 0) return err; o = pa_context_get_source_info_by_name(ctl->p->context, ctl->source, source_info_cb, ctl); if (o) { err = pulse_wait_operation(ctl->p, o); pa_operation_unref(o); } else err = -EIO; if (err < 0) return err; return 0; }
static void event_cb(pa_context * c, pa_subscription_event_type_t t, uint32_t index, void *userdata) { snd_ctl_pulse_t *ctl = (snd_ctl_pulse_t *) userdata; pa_operation *o; assert(ctl); if (!ctl->p || !ctl->p->mainloop || !ctl->p->context) return; o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->sink, sink_info_cb, ctl); if (o) pa_operation_unref(o); o = pa_context_get_source_info_by_name(ctl->p->context, ctl->source, source_info_cb, ctl); if (o) pa_operation_unref(o); }
static void probe_devices(ALboolean capture) { pa_threaded_mainloop *loop; if(capture == AL_FALSE) allDevNameMap = malloc(sizeof(DevMap) * 1); else allCaptureDevNameMap = malloc(sizeof(DevMap) * 1); if((loop=pa_threaded_mainloop_new()) && pa_threaded_mainloop_start(loop) >= 0) { pa_context *context; pa_threaded_mainloop_lock(loop); context = connect_context(loop, AL_FALSE); if(context) { pa_operation *o; if(capture == AL_FALSE) { pa_stream_flags_t flags; pa_sample_spec spec; pa_stream *stream; flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE; spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; spec.channels = 2; stream = connect_playback_stream(NULL, loop, context, flags, NULL, &spec, NULL); if(stream) { o = pa_context_get_sink_info_by_name(context, pa_stream_get_device_name(stream), sink_device_callback, loop); WAIT_FOR_OPERATION(o, loop); pa_stream_disconnect(stream); pa_stream_unref(stream); stream = NULL; } o = pa_context_get_sink_info_list(context, sink_device_callback, loop); } else { pa_stream_flags_t flags; pa_sample_spec spec; pa_stream *stream; flags = PA_STREAM_FIX_FORMAT | PA_STREAM_FIX_RATE | PA_STREAM_FIX_CHANNELS | PA_STREAM_DONT_MOVE; spec.format = PA_SAMPLE_S16NE; spec.rate = 44100; spec.channels = 1; stream = connect_record_stream(NULL, loop, context, flags, NULL, &spec, NULL); if(stream) { o = pa_context_get_source_info_by_name(context, pa_stream_get_device_name(stream), source_device_callback, loop); WAIT_FOR_OPERATION(o, loop); pa_stream_disconnect(stream); pa_stream_unref(stream); stream = NULL; } o = pa_context_get_source_info_list(context, source_device_callback, loop); } WAIT_FOR_OPERATION(o, loop); pa_context_disconnect(context); pa_context_unref(context); } pa_threaded_mainloop_unlock(loop); pa_threaded_mainloop_stop(loop); } if(loop) pa_threaded_mainloop_free(loop); }
static ALCenum pulse_open_capture(ALCdevice *device, const ALCchar *device_name) { const char *pulse_name = NULL; pa_stream_flags_t flags = 0; pa_channel_map chanmap; pulse_data *data; pa_operation *o; ALuint samples; if(device_name) { ALuint i; if(!allCaptureDevNameMap) probe_devices(AL_TRUE); for(i = 0;i < numCaptureDevNames;i++) { if(strcmp(device_name, allCaptureDevNameMap[i].name) == 0) { pulse_name = allCaptureDevNameMap[i].device_name; break; } } if(i == numCaptureDevNames) return ALC_INVALID_VALUE; } if(pulse_open(device) == ALC_FALSE) return ALC_INVALID_VALUE; data = device->ExtraData; pa_threaded_mainloop_lock(data->loop); data->spec.rate = device->Frequency; data->spec.channels = ChannelsFromDevFmt(device->FmtChans); switch(device->FmtType) { case DevFmtUByte: data->spec.format = PA_SAMPLE_U8; break; case DevFmtShort: data->spec.format = PA_SAMPLE_S16NE; break; case DevFmtInt: data->spec.format = PA_SAMPLE_S32NE; break; case DevFmtFloat: data->spec.format = PA_SAMPLE_FLOAT32NE; break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: ERR("%s capture samples not supported\n", DevFmtTypeString(device->FmtType)); pa_threaded_mainloop_unlock(data->loop); goto fail; } if(pa_sample_spec_valid(&data->spec) == 0) { ERR("Invalid sample format\n"); pa_threaded_mainloop_unlock(data->loop); goto fail; } if(!pa_channel_map_init_auto(&chanmap, data->spec.channels, PA_CHANNEL_MAP_WAVEEX)) { ERR("Couldn't build map for channel count (%d)!\n", data->spec.channels); pa_threaded_mainloop_unlock(data->loop); goto fail; } samples = device->UpdateSize * device->NumUpdates; samples = maxu(samples, 100 * device->Frequency / 1000); data->attr.minreq = -1; data->attr.prebuf = -1; data->attr.maxlength = samples * pa_frame_size(&data->spec); data->attr.tlength = -1; data->attr.fragsize = minu(samples, 50*device->Frequency/1000) * pa_frame_size(&data->spec); flags |= PA_STREAM_DONT_MOVE; flags |= PA_STREAM_START_CORKED|PA_STREAM_ADJUST_LATENCY; data->stream = connect_record_stream(pulse_name, data->loop, data->context, flags, &data->attr, &data->spec, &chanmap); if(!data->stream) { pa_threaded_mainloop_unlock(data->loop); goto fail; } pa_stream_set_state_callback(data->stream, stream_state_callback2, device); data->device_name = strdup(pa_stream_get_device_name(data->stream)); o = pa_context_get_source_info_by_name(data->context, data->device_name, source_name_callback, device); WAIT_FOR_OPERATION(o, data->loop); pa_threaded_mainloop_unlock(data->loop); return ALC_NO_ERROR; fail: pulse_close(device); return ALC_INVALID_VALUE; }
static gboolean gst_pulsemixer_ctrl_open (GstPulseMixerCtrl * c) { int e; gchar *name = gst_pulse_client_name (); pa_operation *o = NULL; g_assert (c); c->mainloop = pa_threaded_mainloop_new (); g_assert (c->mainloop); e = pa_threaded_mainloop_start (c->mainloop); g_assert (e == 0); pa_threaded_mainloop_lock (c->mainloop); if (!(c->context = pa_context_new (pa_threaded_mainloop_get_api (c->mainloop), name))) { GST_WARNING_OBJECT (c->object, "Failed to create context"); goto unlock_and_fail; } pa_context_set_state_callback (c->context, gst_pulsemixer_ctrl_context_state_cb, c); pa_context_set_subscribe_callback (c->context, gst_pulsemixer_ctrl_subscribe_cb, c); if (pa_context_connect (c->context, c->server, 0, NULL) < 0) { GST_WARNING_OBJECT (c->object, "Failed to connect context: %s", pa_strerror (pa_context_errno (c->context))); goto unlock_and_fail; } /* Wait until the context is ready */ pa_threaded_mainloop_wait (c->mainloop); if (pa_context_get_state (c->context) != PA_CONTEXT_READY) { GST_WARNING_OBJECT (c->object, "Failed to connect context: %s", pa_strerror (pa_context_errno (c->context))); goto unlock_and_fail; } /* Subscribe to events */ if (!(o = pa_context_subscribe (c->context, PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE, gst_pulsemixer_ctrl_success_cb, c))) { GST_WARNING_OBJECT (c->object, "Failed to subscribe to events: %s", pa_strerror (pa_context_errno (c->context))); goto unlock_and_fail; } c->operation_success = 0; while (pa_operation_get_state (o) != PA_OPERATION_DONE) { pa_threaded_mainloop_wait (c->mainloop); CHECK_DEAD_GOTO (c, unlock_and_fail); } if (!c->operation_success) { GST_WARNING_OBJECT (c->object, "Failed to subscribe to events: %s", pa_strerror (pa_context_errno (c->context))); goto unlock_and_fail; } pa_operation_unref (o); o = NULL; /* Get sink info */ if (c->type == GST_PULSEMIXER_UNKNOWN || c->type == GST_PULSEMIXER_SINK) { if (!(o = pa_context_get_sink_info_by_name (c->context, c->device, gst_pulsemixer_ctrl_sink_info_cb, c))) { GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s", pa_strerror (pa_context_errno (c->context))); goto unlock_and_fail; } c->operation_success = 0; while (pa_operation_get_state (o) != PA_OPERATION_DONE) { pa_threaded_mainloop_wait (c->mainloop); CHECK_DEAD_GOTO (c, unlock_and_fail); } pa_operation_unref (o); o = NULL; if (!c->operation_success && (c->type == GST_PULSEMIXER_SINK || pa_context_errno (c->context) != PA_ERR_NOENTITY)) { GST_WARNING_OBJECT (c->object, "Failed to get sink info: %s", pa_strerror (pa_context_errno (c->context))); goto unlock_and_fail; } } if (c->type == GST_PULSEMIXER_UNKNOWN || c->type == GST_PULSEMIXER_SOURCE) { if (!(o = pa_context_get_source_info_by_name (c->context, c->device, gst_pulsemixer_ctrl_source_info_cb, c))) { GST_WARNING_OBJECT (c->object, "Failed to get source info: %s", pa_strerror (pa_context_errno (c->context))); goto unlock_and_fail; } c->operation_success = 0; while (pa_operation_get_state (o) != PA_OPERATION_DONE) { pa_threaded_mainloop_wait (c->mainloop); CHECK_DEAD_GOTO (c, unlock_and_fail); } pa_operation_unref (o); o = NULL; if (!c->operation_success) { GST_WARNING_OBJECT (c->object, "Failed to get source info: %s", pa_strerror (pa_context_errno (c->context))); goto unlock_and_fail; } } g_assert (c->type != GST_PULSEMIXER_UNKNOWN); c->track = gst_pulsemixer_track_new (c); c->tracklist = g_list_append (c->tracklist, c->track); pa_threaded_mainloop_unlock (c->mainloop); g_free (name); return TRUE; unlock_and_fail: if (o) pa_operation_unref (o); if (c->mainloop) pa_threaded_mainloop_unlock (c->mainloop); g_free (name); return FALSE; }
int force_volume(char* source_name, pa_volume_t desired_volume) { // Create a mainloop pa_mainloop* pa_ml = pa_mainloop_new(); pa_mainloop_api* pa_mlapi = pa_mainloop_get_api(pa_ml); // Establish PA context pa_context* pa_ctx = pa_context_new(pa_mlapi, "uneven"); pa_context_connect(pa_ctx, NULL, 0, NULL); // Set up PA state callback int pa_state = 0; pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_state); // Set up event subscription int state = 0; pa_context_set_subscribe_callback(pa_ctx, source_state_cb, &state); // Prepare loop variables pa_operation* pending_op = NULL; pa_cvolume current_volume = {0, {0}}; int do_update; int i; // Iterate PA mainloop until we're done or the context enters an error state while (done == -1 && pa_state != 2) { pa_mainloop_iterate(pa_ml, 1, NULL); // Can't do anything unless PA is ready if (pa_state == 1) { // Wait for any pending operation to complete if (!pending_op || (pending_op && pa_operation_get_state(pending_op) == PA_OPERATION_DONE)) { if (pending_op) { pa_operation_unref(pending_op); pending_op = NULL; } switch (state) { case 0: // Subscribe to source events pending_op = pa_context_subscribe(pa_ctx, PA_SUBSCRIPTION_MASK_SOURCE, NULL, NULL); state = 2; break; case 1: // Idle break; case 2: // Source change detected, retrive volume information pending_op = pa_context_get_source_info_by_name(pa_ctx, source_name, get_volume_cb, ¤t_volume); state++; break; case 3: // Check channel volumes and reset if required do_update = 0; for (i = 0; i < current_volume.channels; i++) { if (current_volume.values[i] != desired_volume) { do_update = 1; current_volume.values[i] = desired_volume; } } if (do_update) { pending_op = pa_context_set_source_volume_by_name(pa_ctx, source_name, ¤t_volume, NULL, NULL); } state = 1; break; default: fprintf(stderr, "in state %d\n", state); done = 2; } } } } // Clean up pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return done; }