void QPulseAudioThread::initialize_callbacks ( QPulseAudioThread * pulseThread ) { pa_operation * op; pa_operation_unref ( pa_context_get_source_info_list ( context, pa_source_info_callback, pulseThread ) ); //pa_operation_unref(pa_context_get_server_info(&c, server_info_callback, this)); //pa_operation_unref(pa_context_get_sink_info_list(&c, sink_info_callback, this)); //pa_operation_unref(pa_context_get_source_info_list(&c, source_info_callback, this)); //pa_operation_unref(pa_context_get_module_info_list(&c, module_info_callback, this)); //pa_operation_unref(pa_context_get_client_info_list(&c, client_info_callback, this)); //pa_operation_unref(pa_context_get_sink_input_info_list(&c, sink_input_info_callback, this)); //pa_operation_unref(pa_context_get_source_output_info_list(&c, source_output_info_callback, this)); //pa_operation_unref(pa_context_get_sample_info_list(&c, sample_info_callback, this)); //pa_context_set_drain pa_context_set_subscribe_callback ( context, subscribe_callback, pulseThread ); if ( op = pa_context_subscribe ( context, ( enum pa_subscription_mask ) PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, NULL, NULL ) ) { pa_operation_unref ( op ); } else { qDebug() << "null op returned on subscribe"; } }
void QPulseAudioEngine::updateDevices() { lock(); // Get default input and output devices pa_operation *operation = pa_context_get_server_info(m_context, serverInfoCallback, this); while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(m_mainLoop); pa_operation_unref(operation); // Get output devices operation = pa_context_get_sink_info_list(m_context, sinkInfoCallback, this); while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(m_mainLoop); pa_operation_unref(operation); // Get input devices operation = pa_context_get_source_info_list(m_context, sourceInfoCallback, this); while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(m_mainLoop); pa_operation_unref(operation); unlock(); // Swap the default output to index 0 m_sinks.removeOne(m_defaultSink); m_sinks.prepend(m_defaultSink); // Swap the default input to index 0 m_sources.removeOne(m_defaultSource); m_sources.prepend(m_defaultSource); }
static void on_pulse_context_state_change(pa_context *pa_context, AudioListContext *context) { gint error; error = pa_context_errno(pa_context); if (error) { g_warning("PulseAudio: error: %s", pa_strerror(error)); } switch (pa_context_get_state(pa_context)) { case PA_CONTEXT_READY: pa_context_get_source_info_list(pa_context, (pa_source_info_cb_t) source_info_iterator, context); break; case PA_CONTEXT_FAILED: g_warning("PulseAudio: failed to connect to daemon"); finish_pa_list(context); break; case PA_CONTEXT_TERMINATED: break; case PA_CONTEXT_UNCONNECTED: break; case PA_CONTEXT_CONNECTING: break; case PA_CONTEXT_AUTHORIZING: break; case PA_CONTEXT_SETTING_NAME: break; default: break; } }
/* * enumerate input/output devices */ static void pulse_enumerate_devices(obs_properties_t props, bool input) { pa_context *c; pa_operation *op; pa_threaded_mainloop *m = pa_threaded_mainloop_new(); struct pulse_enumerate e; e.mainloop = m; e.devices = obs_properties_add_list(props, "device_id", "Device", OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING); e.input = input; pa_threaded_mainloop_start(m); c = pulse_context_create(m); if (pulse_context_connect(m, c) < 0) goto fail; pa_threaded_mainloop_lock(m); op = pa_context_get_source_info_list(c, pulse_source_info, (void *) &e); while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(m); pa_operation_unref(op); pa_threaded_mainloop_unlock(m); pa_context_disconnect(c); fail: pa_context_unref(c); pa_threaded_mainloop_stop(m); pa_threaded_mainloop_free(m); }
static bool set_mic_mute_cb(LSHandle *handle, LSMessage *message, void *user_data) { struct audio_service *service = user_data; const char *payload; jvalue_ref parsed_obj = NULL; struct luna_service_req_data *req; pa_operation *op; if (!service->context_initialized) { luna_service_message_reply_custom_error(handle, message, "Not yet initialized"); return true; } payload = LSMessageGetPayload(message); parsed_obj = luna_service_message_parse_and_validate(payload); if (jis_null(parsed_obj)) { luna_service_message_reply_error_bad_json(handle, message); goto cleanup; } service->mic_mute = luna_service_message_get_boolean(parsed_obj, "micMute", service->mic_mute); req = luna_service_req_data_new(handle, message); req->user_data = service; op = pa_context_get_source_info_list(service->context, mm_sourceinfo_cb, req); pa_operation_unref(op); cleanup: if (!jis_null(parsed_obj)) j_release(&parsed_obj); return true; }
void _cb_state_changed(pa_context *context, void *userdata) { callback_t *callback = (callback_t*)userdata; pa_context_state_t state = pa_context_get_state(context); PACMIXER_LOG("B:server state changed to %d", state); switch(state) { case PA_CONTEXT_READY: pa_context_set_subscribe_callback(context, _cb_event, callback); pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_ALL, NULL, NULL); pa_context_get_sink_input_info_list(context, _cb_sink_input, callback); pa_context_get_sink_info_list(context, _cb_sink, callback); pa_context_get_source_info_list(context, _cb_source, callback); pa_context_get_source_output_info_list(context, _cb_source_output, callback); pa_context_get_card_info_list(context, _cb_card, callback); pa_context_get_server_info(context, _cb_server, callback); ((tstate_callback_func)(callback->state))(callback->self, S_CAME); break; case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: pa_context_unref(context); ((tstate_callback_func)(callback->state))(callback->self, S_GONE); break; default: break; } }
static int pa_get_devicelist(AudioDeviceInfoList& input) { pa_mainloop *pa_ml; pa_mainloop_api *pa_mlapi; pa_operation *pa_op; pa_context *pa_ctx; int state = 0; int pa_ready = 0; pa_ml = pa_mainloop_new(); pa_mlapi = pa_mainloop_get_api(pa_ml); pa_ctx = pa_context_new(pa_mlapi, "USBqemu-devicelist"); pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL); pa_context_set_state_callback(pa_ctx, pa_context_state_cb, &pa_ready); for (;;) { if (pa_ready == 0) { pa_mainloop_iterate(pa_ml, 1, NULL); continue; } // Connection failed if (pa_ready == 2) { pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return -1; } switch (state) { case 0: pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, &input); state++; break; case 1: if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return 0; } break; default: return -1; } pa_mainloop_iterate(pa_ml, 1, NULL); } }
static void cm_sinkinfo_cb(pa_context *context, const pa_sink_info *info, int is_last, void *user_data) { struct luna_service_req_data *req = user_data; struct audio_service *service = req->user_data; pa_sink_port_info *earpiece = NULL, *speaker = NULL, *headphones = NULL; pa_sink_port_info *highest = NULL, *preferred = NULL; pa_operation *op; int i; for (i = 0; i < info->n_ports; i++) { if (!highest || info->ports[i]->priority > highest->priority) { if (info->ports[i]->available != PA_PORT_AVAILABLE_NO) highest = info->ports[i]; } if (!strcmp(info->ports[i]->name, "output-earpiece")) earpiece = info->ports[i]; if (!strcmp(info->ports[i]->name, "output-speaker")) speaker = info->ports[i]; if (!strcmp(info->ports[i]->name, "output-wired_headset") && info->ports[i]->available != PA_PORT_AVAILABLE_NO) headphones = info->ports[i]; if (!strcmp(info->ports[i]->name, "output-wired_headphone") && info->ports[i]->available != PA_PORT_AVAILABLE_NO) headphones = info->ports[i]; } if (is_last && !earpiece) { finish_set_call_mode(false, user_data); return; } if (!earpiece) return; /* Not the right sink */ /* TODO: When on ringtone and headphones are plugged in, people want output through *both* headphones and speaker, but when on call with speaker mode, people want *just* speaker, not including headphones. */ if (service->speaker_mode) preferred = speaker; else if (service->in_call) preferred = headphones ? headphones : earpiece; if (!preferred) preferred = highest; if (preferred && preferred != info->active_port) { op = pa_context_set_sink_port_by_name(service->context, info->name, preferred->name, cm_sink_port_set_cb, req); pa_operation_unref(op); } else { op = pa_context_get_source_info_list(context, cm_sourceinfo_cb, user_data); pa_operation_unref(op); } }
void PulseAudioSystem::query() { bSourceDone=bSinkDone=bServerDone = false; qhInput.clear(); qhOutput.clear(); qhEchoMap.clear(); qhSpecMap.clear(); qhChanMap.clear(); qhInput.insert(QString(), tr("Default Input")); qhOutput.insert(QString(), tr("Default Output")); pa_operation_unref(pa_context_get_server_info(pacContext, server_callback, this)); pa_operation_unref(pa_context_get_sink_info_list(pacContext, sink_callback, this)); pa_operation_unref(pa_context_get_source_info_list(pacContext, source_callback, this)); wakeup(); }
void context_state_cb(pa_context *c, void *userdata) { switch (pa_context_get_state(c)) { case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: { pa_operation *o; if (!(o = pa_context_get_source_info_list(c, source_cb, NULL ))) { show_error(_("pa_context_subscribe() failed")); return; } pa_operation_unref(o); if (!(o = pa_context_get_sink_info_list(c, sink_cb, NULL ))) { show_error(_("pa_context_subscribe() failed")); return; } pa_operation_unref(o); pa_context_set_subscribe_callback(c, subscribe_cb, NULL); if (!(o = pa_context_subscribe(c, (pa_subscription_mask_t) (PA_SUBSCRIPTION_MASK_SINK| PA_SUBSCRIPTION_MASK_SOURCE), NULL, NULL))) { show_error(_("pa_context_subscribe() failed")); return; } pa_operation_unref(o); break; } case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: default: return; } }
static int Open (vlc_object_t *obj) { services_discovery_t *sd = (services_discovery_t *)obj; pa_operation *op; pa_context *ctx; services_discovery_sys_t *sys = malloc (sizeof (*sys)); if (unlikely(sys == NULL)) return VLC_ENOMEM; ctx = vlc_pa_connect (obj, &sys->mainloop); if (ctx == NULL) { free (sys); return VLC_EGENERIC; } sd->p_sys = sys; sd->description = _("Audio capture"); sys->context = ctx; sys->root = NULL; /* Subscribe for source events */ const pa_subscription_mask_t mask = PA_SUBSCRIPTION_MASK_SOURCE; pa_threaded_mainloop_lock (sys->mainloop); pa_context_set_subscribe_callback (ctx, ContextCallback, sd); op = pa_context_subscribe (ctx, mask, NULL, NULL); if (likely(op != NULL)) pa_operation_unref (op); /* Enumerate existing sources */ op = pa_context_get_source_info_list (ctx, SourceCallback, sd); if (likely(op != NULL)) { //while (pa_operation_get_state (op) == PA_OPERATION_RUNNING) // pa_threaded_mainloop_wait (sys->mainloop); pa_operation_unref (op); } pa_threaded_mainloop_unlock (sys->mainloop); return VLC_SUCCESS; /* error: pa_threaded_mainloop_unlock (sys->mainloop); vlc_pa_disconnect (obj, ctx, sys->mainloop); free (sys); return VLC_EGENERIC;*/ }
int_fast32_t pulse_get_source_info_list(pa_source_info_cb_t cb, void* userdata) { if (pulse_context_ready() < 0) return -1; pulse_lock(); pa_operation *op = pa_context_get_source_info_list( pulse_context, cb, userdata); while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) pulse_wait(); pa_operation_unref(op); pulse_unlock(); return 0; }
void processContextState( pa_context* context, void* userData ) { StateData* stateData = static_cast<StateData*>( userData ); pa_context_state_t state = ::pa_context_get_state( context ); switch( state ) { case PA_CONTEXT_READY: { switch( stateData->request ) { case StateData::GET_SINKS: pa_operation_unref( pa_context_get_sink_info_list( context, processSinkInfo, userData ) ); break; case StateData::GET_SOURCES: pa_operation_unref( pa_context_get_source_info_list( context, processSourceInfo, userData ) ); break; case StateData::GET_DEFAULT_SINK_NAME: pa_operation_unref( pa_context_get_server_info( context, processServerInfo, userData ) ); break; case StateData::GET_DEFAULT_SOURCE_NAME: pa_operation_unref( pa_context_get_server_info( context, processServerInfo, userData ) ); break; case StateData::DONE: stateData->mainLoopApi->quit( stateData->mainLoopApi, 0 ); break; case StateData::INVALID: stateData->mainLoopApi->quit( stateData->mainLoopApi, -1 ); break; } } break; case PA_CONTEXT_TERMINATED: stateData->mainLoopApi->quit( stateData->mainLoopApi, 0 ); break; case PA_CONTEXT_FAILED: stateData->mainLoopApi->quit( stateData->mainLoopApi, -1 ); break; default: break; } }
const QStringList *get_source_names(){ if(source_names == NULL){ context_create(); source_names = new QStringList(); finished = false; pa_context_get_source_info_list(context, get_source_info_list_callback, NULL); do{ pa_threaded_mainloop_lock(threaded_main_loop); pa_threaded_mainloop_wait(threaded_main_loop); qDebug("Received signal..."); }while(! finished); pa_threaded_mainloop_unlock(threaded_main_loop); context_stop(); } return source_names; }
void context_state_cb(pa_context *c, void *userdata) { switch (pa_context_get_state(c)) { case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: { printf("func = %s , LINE = %d \n",__func__,__LINE__); pa_operation *o; // set up a callback to tell us about source devices if (!(o = pa_context_get_source_info_list(c, sourcelist_cb, NULL ))) { show_error(_("pa_context_subscribe() failed")); return; } pa_operation_unref(o); // set up a callback to tell us about sink devices if (!(o = pa_context_get_sink_info_list(c, sinklist_cb, NULL ))) { show_error(_("pa_context_subscribe() failed")); return; } pa_operation_unref(o); break; } case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: default: return; } }
JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_pulseaudio_PA_context_1get_1source_1info_1list (JNIEnv *env, jclass clazz, jlong c, jobject cb) { jweak weakCb = cb ? (*env)->NewWeakGlobalRef(env, cb) : NULL; pa_operation *o; if ((*env)->ExceptionCheck(env)) o = NULL; else { o = pa_context_get_source_info_list( (pa_context *) (intptr_t) c, weakCb ? PulseAudio_sourceInfoCallback : NULL, (void *) weakCb); } return (intptr_t) 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) o = pa_context_get_sink_info_list(context, sink_device_callback, loop); else o = pa_context_get_source_info_list(context, source_device_callback, loop); while(pa_operation_get_state(o) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(loop); pa_operation_unref(o); 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); }
// call this while holding the main loop lock static int refresh_devices(struct SoundIoPrivate *si) { struct SoundIo *soundio = &si->pub; struct SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; assert(!sipa->current_devices_info); sipa->current_devices_info = ALLOCATE(struct SoundIoDevicesInfo, 1); if (!sipa->current_devices_info) return SoundIoErrorNoMem; pa_operation *list_sink_op = pa_context_get_sink_info_list(sipa->pulse_context, sink_info_callback, si); pa_operation *list_source_op = pa_context_get_source_info_list(sipa->pulse_context, source_info_callback, si); pa_operation *server_info_op = pa_context_get_server_info(sipa->pulse_context, server_info_callback, si); int err; if ((err = perform_operation(si, list_sink_op))) { return err; } if ((err = perform_operation(si, list_source_op))) { return err; } if ((err = perform_operation(si, server_info_op))) { return err; } if (sipa->device_query_err) { return sipa->device_query_err; } // based on the default sink name, figure out the default output index // if the name doesn't match just pick the first one. if there are no // devices then we need to set it to -1. sipa->current_devices_info->default_output_index = -1; sipa->current_devices_info->default_input_index = -1; if (sipa->current_devices_info->input_devices.length > 0) { sipa->current_devices_info->default_input_index = 0; for (int i = 0; i < sipa->current_devices_info->input_devices.length; i += 1) { struct SoundIoDevice *device = SoundIoListDevicePtr_val_at( &sipa->current_devices_info->input_devices, i); assert(device->aim == SoundIoDeviceAimInput); if (strcmp(device->id, sipa->default_source_name) == 0) { sipa->current_devices_info->default_input_index = i; } } } if (sipa->current_devices_info->output_devices.length > 0) { sipa->current_devices_info->default_output_index = 0; for (int i = 0; i < sipa->current_devices_info->output_devices.length; i += 1) { struct SoundIoDevice *device = SoundIoListDevicePtr_val_at( &sipa->current_devices_info->output_devices, i); assert(device->aim == SoundIoDeviceAimOutput); if (strcmp(device->id, sipa->default_sink_name) == 0) { sipa->current_devices_info->default_output_index = i; } } } soundio_destroy_devices_info(sipa->ready_devices_info); sipa->ready_devices_info = sipa->current_devices_info; sipa->current_devices_info = NULL; pa_threaded_mainloop_signal(sipa->main_loop, 0); soundio->on_events_signal(soundio); return 0; }
PyObject * quisk_pa_sound_devices(PyObject * self, PyObject * args) { // Return a list of PulseAudio device names [pycapt, pyplay] PyObject * pylist, * pycapt, * pyplay; pa_mainloop *pa_names_ml; pa_mainloop_api *pa_names_mlapi; pa_operation *pa_op=NULL; pa_context *pa_names_ctx; int state = 0; if (!PyArg_ParseTuple (args, "")) return NULL; // Each pycapt and pyplay is (dev name, description, alsa name) pylist = PyList_New(0); // list [pycapt, pyplay] pycapt = PyList_New(0); // list of capture devices pyplay = PyList_New(0); // list of play devices PyList_Append(pylist, pycapt); PyList_Append(pylist, pyplay); //printf("Starting name loop\n"); // Create a mainloop API and connection to the default server pa_names_ml = pa_mainloop_new(); pa_names_mlapi = pa_mainloop_get_api(pa_names_ml); pa_names_ctx = pa_context_new(pa_names_mlapi, "DeviceNames"); // This function connects to the pulse server if (pa_context_connect(pa_names_ctx, NULL, 0, NULL) < 0) { if (quisk_sound_state.verbose_pulse) printf("No local daemon to connect to for show_pulse_audio_devices option\n"); return pylist; } // This function defines a callback so the server will tell us it's state. pa_context_set_state_callback(pa_names_ctx, pa_names_state_cb, &state); // Now we'll enter into an infinite loop until we get the data we receive or if there's an error while (state < 10) { switch (state) { case 0: // We can't do anything until PA is ready pa_mainloop_iterate(pa_names_ml, 1, NULL); break; case 1: // This sends an operation to the server. pa_sinklist_info is // our callback function and a pointer to our devicelist will // be passed to the callback. pa_op = pa_context_get_sink_info_list(pa_names_ctx, pa_sinklist_cb, pyplay); // Update state for next iteration through the loop state++; pa_mainloop_iterate(pa_names_ml, 1, NULL); break; case 2: // Now we wait for our operation to complete. When it's // complete our pa_output_devicelist is filled out, and we move // along to the next state if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); // Now we perform another operation to get the source // (input device) list just like before. pa_op = pa_context_get_source_info_list(pa_names_ctx, pa_sourcelist_cb, pycapt); // Update the state so we know what to do next state++; } pa_mainloop_iterate(pa_names_ml, 1, NULL); break; case 3: if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); state = 9; } else pa_mainloop_iterate(pa_names_ml, 1, NULL); break; case 9: // Now we're done, clean up and disconnect and return pa_context_disconnect(pa_names_ctx); pa_context_unref(pa_names_ctx); pa_mainloop_free(pa_names_ml); state = 99; break; } } //printf("Finished with name loop\n"); return pylist; }
void PulseSrc::make_device_description(pa_context* pulse_context) { if (!capture_devices_.empty()) capture_devices_.clear(); pa_operation_unref( pa_context_get_source_info_list(pulse_context, get_source_info_callback, this)); }
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); }
AudioDevPulseAudio::AudioDevPulseAudio(QObject *parent): AudioDev(parent) { this->d = new AudioDevPulseAudioPrivate(this); // Create a threaded main loop for PulseAudio this->d->m_mainLoop = pa_threaded_mainloop_new(); if (!this->d->m_mainLoop) return; // Start main loop. if (pa_threaded_mainloop_start(this->d->m_mainLoop) != 0) { pa_threaded_mainloop_free(this->d->m_mainLoop); this->d->m_mainLoop = nullptr; return; } pa_threaded_mainloop_lock(this->d->m_mainLoop); // Get main loop abstration layer. auto mainLoopApi = pa_threaded_mainloop_get_api(this->d->m_mainLoop); if (!mainLoopApi) { pa_threaded_mainloop_unlock(this->d->m_mainLoop); pa_threaded_mainloop_stop(this->d->m_mainLoop); pa_threaded_mainloop_free(this->d->m_mainLoop); this->d->m_mainLoop = nullptr; return; } // Get a PulseAudio context. this->d->m_context = pa_context_new(mainLoopApi, QCoreApplication::applicationName() .toStdString() .c_str()); if (!this->d->m_context) { pa_threaded_mainloop_unlock(this->d->m_mainLoop); pa_threaded_mainloop_stop(this->d->m_mainLoop); pa_threaded_mainloop_free(this->d->m_mainLoop); this->d->m_mainLoop = nullptr; return; } // We need to set a state callback in order to connect to the server. pa_context_set_state_callback(this->d->m_context, AudioDevPulseAudioPrivate::contextStateCallbackInit, this); // Connect to PulseAudio server. if (pa_context_connect(this->d->m_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr) < 0) { pa_context_unref(this->d->m_context); this->d->m_context = nullptr; pa_threaded_mainloop_unlock(this->d->m_mainLoop); pa_threaded_mainloop_stop(this->d->m_mainLoop); pa_threaded_mainloop_free(this->d->m_mainLoop); this->d->m_mainLoop = nullptr; return; } static const QList<pa_context_state_t> expectedStates = { PA_CONTEXT_READY, PA_CONTEXT_FAILED, PA_CONTEXT_TERMINATED }; pa_context_state_t state; // Wait until the connection to the server is stablished. forever { state = pa_context_get_state(this->d->m_context); if (expectedStates.contains(state)) break; pa_threaded_mainloop_wait(this->d->m_mainLoop); } if (state != PA_CONTEXT_READY) { pa_context_disconnect(this->d->m_context); pa_context_unref(this->d->m_context); this->d->m_context = nullptr; pa_threaded_mainloop_unlock(this->d->m_mainLoop); pa_threaded_mainloop_stop(this->d->m_mainLoop); pa_threaded_mainloop_free(this->d->m_mainLoop); this->d->m_mainLoop = nullptr; return; } // Get server information. auto operation = pa_context_get_server_info(this->d->m_context, AudioDevPulseAudioPrivate::serverInfoCallback, this); while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(this->d->m_mainLoop); pa_operation_unref(operation); // Get sources information. operation = pa_context_get_source_info_list(this->d->m_context, AudioDevPulseAudioPrivate::sourceInfoCallback, this); while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(this->d->m_mainLoop); pa_operation_unref(operation); // Get sinks information. operation = pa_context_get_sink_info_list(this->d->m_context, AudioDevPulseAudioPrivate::sinkInfoCallback, this); while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) pa_threaded_mainloop_wait(this->d->m_mainLoop); pa_operation_unref(operation); pa_context_set_subscribe_callback(this->d->m_context, AudioDevPulseAudioPrivate::deviceUpdateCallback, this); pa_operation_unref(pa_context_subscribe(this->d->m_context, pa_subscription_mask_t(PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE | PA_SUBSCRIPTION_MASK_SERVER), nullptr, this)); pa_threaded_mainloop_unlock(this->d->m_mainLoop); }
static void context_state_callback(pa_context *c, void *userdata) { if ( pa_context_get_state(c) == PA_CONTEXT_READY ) { pa_operation_unref(pa_context_get_source_info_list(c, get_source_info_callback, userdata)); } }
/* * iterate the main loop until all devices are listed * args: * audio_ctx - pointer to audio context * * asserts: * audio_ctx is not null * * returns: error code */ static int pa_get_devicelist(audio_context_t *audio_ctx) { /*assertions*/ assert(audio_ctx != NULL); /* Define our pulse audio loop and connection variables */ pa_mainloop *pa_ml; pa_mainloop_api *pa_mlapi; pa_operation *pa_op = NULL; pa_context *pa_ctx; /* We'll need these state variables to keep track of our requests */ int state = 0; int pa_ready = 0; /* Create a mainloop API and connection to the default server */ pa_ml = pa_mainloop_new(); pa_mlapi = pa_mainloop_get_api(pa_ml); pa_ctx = pa_context_new(pa_mlapi, "getDevices"); /* This function connects to the pulse server */ if(pa_context_connect(pa_ctx, NULL, 0, NULL) < 0) { fprintf(stderr,"AUDIO: PULSE - unable to connect to server: pa_context_connect failed\n"); finish(pa_ctx, pa_ml); return -1; } /* * This function defines a callback so the server will tell us * it's state. * Our callback will wait for the state to be ready. * The callback will modify the variable to 1 so we know when we * have a connection and it's ready. * If there's an error, the callback will set pa_ready to 2 */ pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); /* * Now we'll enter into an infinite loop until we get the data * we receive or if there's an error */ for (;;) { /* * We can't do anything until PA is ready, * so just iterate the mainloop and continue */ if (pa_ready == 0) { pa_mainloop_iterate(pa_ml, 1, NULL); continue; } /* We couldn't get a connection to the server, so exit out */ if (pa_ready == 2) { finish(pa_ctx, pa_ml); return -1; } /* * At this point, we're connected to the server and ready * to make requests */ switch (state) { /* State 0: we haven't done anything yet */ case 0: /* * This sends an operation to the server. * pa_sinklist_cb is our callback function and a pointer * o our devicelist will be passed to the callback * (audio_ctx) The operation ID is stored in the * pa_op variable */ pa_op = pa_context_get_sink_info_list( pa_ctx, pa_sinklist_cb, (void *) audio_ctx); /* Update state for next iteration through the loop */ state++; break; case 1: /* * Now we wait for our operation to complete. * When it's complete our pa_output_devicelist is * filled out, and we move along to the next state */ if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); /* * Now we perform another operation to get the * source(input device) list just like before. * This time we pass a pointer to our input structure */ pa_op = pa_context_get_source_info_list( pa_ctx, pa_sourcelist_cb, (void *) audio_ctx); /* Update the state so we know what to do next */ state++; } break; case 2: if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { /* * Now we're done, * clean up and disconnect and return */ pa_operation_unref(pa_op); finish(pa_ctx, pa_ml); return 0; } break; default: /* We should never see this state */ printf("AUDIO: Pulseaudio in state %d\n", state); return -1; } /* * Iterate the main loop and go again. The second argument is whether * or not the iteration should block until something is ready to be * done. Set it to zero for non-blocking. */ pa_mainloop_iterate(pa_ml, 1, NULL); } return 0; }
PulseAudioWrapper::PulseAudioWrapper(QObject *parent) : QObject(parent), d(new PulseAudioWrapperPrivate(this)) { PulseAudioWrapperPrivate::paMainLoop = pa_threaded_mainloop_new(); pa_threaded_mainloop_start(PulseAudioWrapperPrivate::paMainLoop); PulseAudioWrapperPrivate::paMainLoopApi = pa_threaded_mainloop_get_api(PulseAudioWrapperPrivate::paMainLoop); pa_threaded_mainloop_lock(PulseAudioWrapperPrivate::paMainLoop); PulseAudioWrapperPrivate::paContext = pa_context_new(PulseAudioWrapperPrivate::paMainLoopApi, qApp->applicationName().toUtf8().data()); pa_context_set_state_callback(PulseAudioWrapperPrivate::paContext, &PulseAudioWrapperPrivate::onContextNotify, NULL); pa_context_connect(PulseAudioWrapperPrivate::paContext, NULL, PA_CONTEXT_NOFLAGS, NULL); bool done = false; pa_context_state_t contextState; while (!done) { switch (contextState = pa_context_get_state(d->paContext)) { case PA_CONTEXT_UNCONNECTED: qDebug() << "Context state: PA_CONTEXT_UNCONNECTED"; break; case PA_CONTEXT_CONNECTING: qDebug() << "Context state: PA_CONTEXT_CONNECTING"; break; case PA_CONTEXT_AUTHORIZING: qDebug() << "Context state: PA_CONTEXT_AUTHORIZING"; break; case PA_CONTEXT_SETTING_NAME: qDebug() << "Context state: PA_CONTEXT_SETTING_NAME"; break; case PA_CONTEXT_READY: qDebug() << "Context state: PA_CONTEXT_READY"; done = true; break; case PA_CONTEXT_FAILED: qDebug() << "Context state: PA_CONTEXT_FAILED"; done = true; break; case PA_CONTEXT_TERMINATED: qDebug() << "Context state: PA_CONTEXT_TERMINATED"; done = true; break; } if (!done) pa_threaded_mainloop_wait(PulseAudioWrapperPrivate::paMainLoop); } if (contextState != PA_CONTEXT_READY) throw CallRecorderException("Unable to connect PulseAudio context!"); pa_operation* listCardsOp = pa_context_get_card_info_list(PulseAudioWrapperPrivate::paContext, &PulseAudioWrapperPrivate::onCardInfoList, d.data()); pa_threaded_mainloop_wait(PulseAudioWrapperPrivate::paMainLoop); pa_operation_unref(listCardsOp); pa_operation* listSinksOp = pa_context_get_sink_info_list(PulseAudioWrapperPrivate::paContext, &PulseAudioWrapperPrivate::onSinkInfoList, d.data()); pa_threaded_mainloop_wait(PulseAudioWrapperPrivate::paMainLoop); pa_operation_unref(listSinksOp); pa_operation* listSourcesOp = pa_context_get_source_info_list(PulseAudioWrapperPrivate::paContext, &PulseAudioWrapperPrivate::onSourceInfoList, d.data()); pa_threaded_mainloop_wait(PulseAudioWrapperPrivate::paMainLoop); pa_operation_unref(listSourcesOp); pa_context_set_subscribe_callback(PulseAudioWrapperPrivate::paContext, &PulseAudioWrapperPrivate::onContextSubscription, d.data()); pa_operation* subscriptionOp = pa_context_subscribe(PulseAudioWrapperPrivate::paContext, static_cast< pa_subscription_mask_t >( PA_SUBSCRIPTION_MASK_CARD | PA_SUBSCRIPTION_MASK_SINK | PA_SUBSCRIPTION_MASK_SOURCE), &PulseAudioWrapperPrivate::onContextSubscriptionSuccess, d.data()); pa_threaded_mainloop_wait(PulseAudioWrapperPrivate::paMainLoop); pa_operation_unref(subscriptionOp); pa_threaded_mainloop_unlock(PulseAudioWrapperPrivate::paMainLoop); }
int pa_get_devicelist(pa_devicelist_t *input, pa_devicelist_t *output) { // Define our pulse audio loop and connection variables pa_mainloop *pa_ml; pa_mainloop_api *pa_mlapi; pa_operation *pa_op; pa_context *pa_ctx; // We'll need these state variables to keep track of our requests int state = 0; int pa_ready = 0; // Initialize our device lists memset(input, 0, sizeof(pa_devicelist_t) * 16); memset(output, 0, sizeof(pa_devicelist_t) * 16); // Create a mainloop API and connection to the default server pa_ml = pa_mainloop_new(); pa_mlapi = pa_mainloop_get_api(pa_ml); pa_ctx = pa_context_new(pa_mlapi, "test"); // This function connects to the pulse server pa_context_connect(pa_ctx, NULL, 0, NULL); // This function defines a callback so the server will tell us it's state. // Our callback will wait for the state to be ready. The callback will // modify the variable to 1 so we know when we have a connection and it's // ready. // If there's an error, the callback will set pa_ready to 2 pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); // Now we'll enter into an infinite loop until we get the data we receive // or if there's an error for (;;) { // We can't do anything until PA is ready, so just iterate the mainloop // and continue if (pa_ready == 0) { pa_mainloop_iterate(pa_ml, 1, NULL); continue; } // We couldn't get a connection to the server, so exit out if (pa_ready == 2) { pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return -1; } // At this point, we're connected to the server and ready to make // requests switch (state) { // State 0: we haven't done anything yet case 0: // This sends an operation to the server. pa_sinklist_info is // our callback function and a pointer to our devicelist will // be passed to the callback The operation ID is stored in the // pa_op variable pa_op = pa_context_get_sink_info_list(pa_ctx, pa_sinklist_cb, output ); // Update state for next iteration through the loop state++; break; case 1: // Now we wait for our operation to complete. When it's // complete our pa_output_devicelist is filled out, and we move // along to the next state if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); // Now we perform another operation to get the source // (input device) list just like before. This time we pass // a pointer to our input structure pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, input ); // Update the state so we know what to do next state++; } break; case 2: if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { // Now we're done, clean up and disconnect and return pa_operation_unref(pa_op); pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return 0; } break; default: // We should never see this state fprintf(stderr, "in state %d\n", state); return -1; } // Iterate the main loop and go again. The second argument is whether // or not the iteration should block until something is ready to be // done. Set it to zero for non-blocking. pa_mainloop_iterate(pa_ml, 1, NULL); } }
void Context::contextStateCallback(pa_context *c) { qCDebug(PLASMAPA) << "state callback"; pa_context_state_t state = pa_context_get_state(c); if (state == PA_CONTEXT_READY) { qCDebug(PLASMAPA) << "ready"; // 1. Register for the stream changes (except during probe) if (m_context == c) { pa_context_set_subscribe_callback(c, subscribe_cb, this); if (!PAOperation(pa_context_subscribe(c, (pa_subscription_mask_t) (PA_SUBSCRIPTION_MASK_SINK| PA_SUBSCRIPTION_MASK_SOURCE| PA_SUBSCRIPTION_MASK_CLIENT| PA_SUBSCRIPTION_MASK_SINK_INPUT| PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| PA_SUBSCRIPTION_MASK_CARD| PA_SUBSCRIPTION_MASK_SERVER), nullptr, nullptr))) { qCWarning(PLASMAPA) << "pa_context_subscribe() failed"; return; } } if (!PAOperation(pa_context_get_sink_info_list(c, sink_cb, this))) { qCWarning(PLASMAPA) << "pa_context_get_sink_info_list() failed"; return; } if (!PAOperation(pa_context_get_source_info_list(c, source_cb, this))) { qCWarning(PLASMAPA) << "pa_context_get_source_info_list() failed"; return; } if (!PAOperation(pa_context_get_client_info_list(c, client_cb, this))) { qCWarning(PLASMAPA) << "pa_context_client_info_list() failed"; return; } if (!PAOperation(pa_context_get_card_info_list(c, card_cb, this))) { qCWarning(PLASMAPA) << "pa_context_get_card_info_list() failed"; return; } if (!PAOperation(pa_context_get_sink_input_info_list(c, sink_input_callback, this))) { qCWarning(PLASMAPA) << "pa_context_get_sink_input_info_list() failed"; return; } if (!PAOperation(pa_context_get_source_output_info_list(c, source_output_cb, this))) { qCWarning(PLASMAPA) << "pa_context_get_source_output_info_list() failed"; return; } if (!PAOperation(pa_context_get_server_info(c, server_cb, this))) { qCWarning(PLASMAPA) << "pa_context_get_server_info() failed"; return; } if (PAOperation(pa_ext_stream_restore_read(c, ext_stream_restore_read_cb, this))) { pa_ext_stream_restore_set_subscribe_cb(c, ext_stream_restore_subscribe_cb, this); PAOperation(pa_ext_stream_restore_subscribe(c, 1, nullptr, this)); } else { qCWarning(PLASMAPA) << "Failed to initialize stream_restore extension"; } } else if (!PA_CONTEXT_IS_GOOD(state)) { qCWarning(PLASMAPA) << "context kaput"; if (m_context) { pa_context_unref(m_context); m_context = nullptr; } reset(); QTimer::singleShot(1000, this, &Context::connectToDaemon); } }
static void cm_sink_port_set_cb(pa_context *context, int success, void *user_data) { pa_operation *op; op = pa_context_get_source_info_list(context, cm_sourceinfo_cb, user_data); pa_operation_unref(op); }