QList<DeviceFinder::Device> PulseDeviceFinder::ListDevices() { if (!context_ || pa_context_get_state(context_) != PA_CONTEXT_READY) { return QList<Device>(); } retry: ListDevicesState state; pa_context_get_sink_info_list( context_, &PulseDeviceFinder::GetSinkInfoCallback, &state); forever { if (state.finished) { return state.devices; } switch (pa_context_get_state(context_)) { case PA_CONTEXT_READY: break; case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: // Maybe pulseaudio died. Try reconnecting. if (Reconnect()) { goto retry; } return state.devices; default: return state.devices; } pa_mainloop_iterate(mainloop_, true, nullptr); } }
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; } }
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 m_context_state_cb(pa_context *c, void *user_data) { if (!c) { printf("m_context_state_cb() invalid arguement\n"); return; } pa_operation *pa_op = NULL; 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_context_set_subscribe_callback(c, m_pa_context_subscribe_cb, NULL); pa_op = pa_context_subscribe(c, (pa_subscription_mask_t) (PA_SUBSCRIPTION_MASK_SINK| PA_SUBSCRIPTION_MASK_SOURCE| PA_SUBSCRIPTION_MASK_SINK_INPUT| PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT| PA_SUBSCRIPTION_MASK_CLIENT| PA_SUBSCRIPTION_MASK_SERVER| PA_SUBSCRIPTION_MASK_CARD), NULL, NULL); if (!pa_op) { printf("pa_context_subscribe() failed\n"); return; } pa_operation_unref(pa_op); pa_op = pa_context_get_sink_info_list(c, m_pa_sink_info_cb, NULL); if (!pa_op) { printf("pa_context_get_sink_info_list() failed\n"); return; } pa_operation_unref(pa_op); break; case PA_CONTEXT_FAILED: if (m_pa_ctx) { pa_context_unref(m_pa_ctx); m_pa_ctx = NULL; } printf("Connection failed, attempting reconnect\n"); g_timeout_add_seconds(13, m_connect_to_pulse, NULL); return; case PA_CONTEXT_TERMINATED: default: printf("pa_context terminated\n"); return; } }
int pa_get_devicelist(pa_devicelist_t *output) { pa_mainloop *pa_ml = NULL; pa_mainloop_api *pa_mlapi = NULL; pa_operation *pa_op = NULL; pa_context *pa_ctx = NULL; uint8_t state = 0; int pa_ready = 0; memset(output, 0, sizeof(pa_devicelist_t) * 16); if ( (pa_ml = pa_mainloop_new()) == NULL) return -1; if ( (pa_mlapi = pa_mainloop_get_api(pa_ml)) == NULL ) return -2; if ( (pa_ctx = pa_context_new(pa_mlapi, "test")) == NULL) return -3; pa_context_connect(pa_ctx, NULL, 0, NULL); pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); while (1) { if (pa_ready == 0) { pa_mainloop_iterate(pa_ml, 1, NULL); continue; } 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_sink_info_list(pa_ctx, pa_sinklist_cb, output); 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 get_source_info_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) { if ( is_last ) { pa_operation_unref(pa_context_get_sink_info_list(c, get_sink_info_callback, userdata)); return; } printf("Source: %s - name: %s\n",i->description,i->name); if ( i->monitor_of_sink != PA_INVALID_INDEX ) { printf("[ISMONITOR] of %s\n",i->monitor_of_sink_name); ((MediaRecorder*)userdata)->monitorsources.insert(std::pair<std::string,std::string>(i->monitor_of_sink_name,i->name)); } }
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(); }
/** * Callback to retrieve server infos (mostly, the default sink). */ static void xvd_server_info_callback (pa_context *c, const pa_server_info *info, void *userdata) { pa_operation *op = NULL; if (!c || !userdata) { g_warning ("xvd_server_info_callback: invalid argument"); return; } if (!info) { g_warning("xvd_server_info_callback: No PulseAudio server"); return; } if (info->default_sink_name) { op = pa_context_get_sink_info_by_name (c, info->default_sink_name, xvd_default_sink_info_callback, userdata); if (!op) { g_warning("xvd_server_info_callback: pa_context_get_sink_info_by_name() failed"); return; } pa_operation_unref (op); } else { /* when PulseAudio doesn't set a default sink, look at all of them and hope to find a usable one */ op = pa_context_get_sink_info_list(c, xvd_sink_info_callback, userdata); if (!op) { g_warning("xvd_server_info_callback: pa_context_get_sink_info_list() failed"); return; } pa_operation_unref (op); } }
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; } }
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; } }
static void cm_cardinfo_cb(pa_context *context, const pa_card_info *info, int is_last, void *user_data) { struct luna_service_req_data *req = user_data; struct audio_service *service = req->user_data; pa_card_profile_info *voice_call = NULL, *highest = NULL; const char *name_to_set = NULL; const char *value_to_set = NULL; pa_operation *op; int i; for (i = 0; i < info->n_profiles; i++) { if (!highest || info->profiles[i].priority > highest->priority) highest = &info->profiles[i]; if (!strcmp(info->profiles[i].name, "voicecall")) voice_call = &info->profiles[i]; } if (is_last && !voice_call) { finish_set_call_mode(false, user_data); return; } if (!voice_call) return; /* Not the right card */ if (service->in_call && (voice_call != info->active_profile)) { name_to_set = info->name; value_to_set = voice_call->name; } else if (!service->in_call && (voice_call == info->active_profile)) { name_to_set = info->name; value_to_set = highest->name; } if (name_to_set) { op = pa_context_set_card_profile_by_name(service->context, name_to_set, value_to_set, cm_card_profile_set_cb, req); pa_operation_unref(op); } else { op = pa_context_get_sink_info_list(context, cm_sinkinfo_cb, user_data); pa_operation_unref(op); } }
void CPulseAE::EnumerateOutputDevices(AEDeviceList &devices, bool passthrough) { if (!m_MainLoop || ! m_Context) return; pa_threaded_mainloop_lock(m_MainLoop); SinkInfoStruct sinkStruct; sinkStruct.passthrough = passthrough; sinkStruct.mainloop = m_MainLoop; sinkStruct.list = &devices; CStdString def; def.Format("%s (PulseAudio)",g_localizeStrings.Get(409).c_str()); devices.push_back(AEDevice(def, "pulse:default@default")); WaitForOperation(pa_context_get_sink_info_list(m_Context, SinkInfo, &sinkStruct), m_MainLoop, "EnumerateAudioSinks"); pa_threaded_mainloop_unlock(m_MainLoop); }
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_1sink_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_sink_info_list( (pa_context *) (intptr_t) c, weakCb ? PulseAudio_sinkInfoCallback : 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); }
void CAESinkPULSE::EnumerateDevicesEx(AEDeviceInfoList &list, bool force) { pa_context *context; pa_threaded_mainloop *mainloop; if (!SetupContext(NULL, &context, &mainloop)) { CLog::Log(LOGNOTICE, "PulseAudio might not be running. Context was not created."); return; } pa_threaded_mainloop_lock(mainloop); SinkInfoStruct sinkStruct; sinkStruct.mainloop = mainloop; sinkStruct.list = &list; WaitForOperation(pa_context_get_sink_info_list(context, SinkInfoRequestCallback, &sinkStruct), mainloop, "EnumerateAudioSinks"); pa_threaded_mainloop_unlock(mainloop); if (mainloop) pa_threaded_mainloop_stop(mainloop); if (context) { pa_context_disconnect(context); pa_context_unref(context); context = NULL; } if (mainloop) { pa_threaded_mainloop_free(mainloop); mainloop = NULL; } }
/* * 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; }
static int pulseaudio_open(void) { /* Use PA_CONTEXT_NOAUTOSPAWN to see if a PA server is running. * If not, fail - we're better off using ALSA/OSS. * * Also check for suspended PA - again better using ALSA/OSS in * that case (pa_simple_write just blocks until PA is unsuspended * otherwise). * * TODO: Maybe we should have a force flag to the audio driver * open method, which in the case of PA would spawn a server if * none is running (and also unsuspend?). */ pa_mainloop *mainloop = pa_mainloop_new(); pa_context *c = pa_context_new(pa_mainloop_get_api(mainloop), al_get_app_name()); if (!c) { pa_mainloop_free(mainloop); return 1; } pa_context_connect(c, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); while (1) { /* Don't block or it will hang if there is no server to connect to. */ const int blocking = 0; if (pa_mainloop_iterate(mainloop, blocking, NULL) < 0) { ALLEGRO_ERROR("pa_mainloop_iterate failed\n"); pa_context_disconnect(c); pa_mainloop_free(mainloop); break; } pa_context_state_t s = pa_context_get_state(c); if (s == PA_CONTEXT_READY) { ALLEGRO_DEBUG("PA_CONTEXT_READY\n"); break; } if (s == PA_CONTEXT_FAILED) { ALLEGRO_ERROR("PA_CONTEXT_FAILED\n"); pa_context_disconnect(c); pa_mainloop_free(mainloop); return 1; } } pa_sink_state_t state = 0; pa_operation *op = pa_context_get_sink_info_list(c, sink_info_cb, &state); while (pa_operation_get_state(op) == PA_OPERATION_RUNNING) { pa_mainloop_iterate(mainloop, 1, NULL); } /*if (state == PA_SINK_SUSPENDED) { pa_context_disconnect(c); pa_mainloop_free(mainloop); return 1; }*/ pa_operation_unref(op); pa_context_disconnect(c); pa_context_unref(c); pa_mainloop_free(mainloop); 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; }
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 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); }
int main(int argc, char **argv) { int retval = 0; struct timeval timeout, timeout_def; pa_mainloop * ml = pa_mainloop_new(); pa_mainloop_api * api = pa_mainloop_get_api(ml); pa_context_state_t pa_state; pa_context * context = pa_context_new(api, "pa-mixer"); pa_context_connect(context, NULL, 0, NULL); pa_context_set_state_callback(context, pa_state_changed, &pa_state); /* struct sigaction sigint_handler; sigint_handler.sa_handler = handle_sig_int; sigemptyset(&sigint_handler.sa_mask); sigint_handler.sa_flags = 0; sigaction(SIGINT, &sigint_handler, NULL); */ int init_done = 0; initscr(); keypad(stdscr, TRUE); start_color(); curs_set(0); cbreak(); noecho(); init_pair(1, COLOR_WHITE, COLOR_BLACK); init_pair(2, COLOR_WHITE, COLOR_BLUE); fd_set read_set, test_set; FD_ZERO(&read_set); FD_SET(0, &read_set); timeout_def.tv_sec = 0; timeout_def.tv_usec = 1000; view_init(); while(running) { if(pa_state == PA_CONTEXT_UNCONNECTED) { pa_mainloop_iterate(ml, 1, NULL); continue; } if(pa_state == PA_CONTEXT_FAILED || pa_state == PA_CONTEXT_TERMINATED) { running = 0; retval = -1; } if(pa_state == PA_CONTEXT_READY) { if(!init_done) { pa_context_set_subscribe_callback(context, on_event, NULL); pa_context_subscribe(context, PA_SUBSCRIPTION_MASK_ALL, NULL, NULL); pa_context_get_sink_input_info_list(context, on_sink_input_update, context); pa_context_get_sink_info_list(context, on_sink_update, context); } init_done = 1; } test_set = read_set; timeout = timeout_def; int r = select(1, &test_set, NULL, NULL, &timeout); if(r == 0) { /* timeout */ pa_mainloop_iterate(ml, 0, NULL); } if(FD_ISSET(0, &test_set)) { /* stdin ready */ int key = getch(); switch(key) { case KEY_UP: view_select_prev(); view_show(); break; case KEY_DOWN: view_select_next(); view_show(); break; case KEY_LEFT: change_sel_vol(context, VOL_DOWN); break; case KEY_RIGHT: change_sel_vol(context, VOL_UP); break; case 'n': change_sel_vol(context, VOL_NORM); break; case 'm': change_sel_vol(context, VOL_MUTE); break; case 'q': running = 0; break; case KEY_RESIZE: view_show(); refresh(); break; } } } pa_context_disconnect(context); pa_context_unref(context); pa_mainloop_free(ml); endwin(); return retval; }
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); }
void PulseAudioSinksManager::retrieveSinksInfo() { PaOperation op; op=pa_context_get_sink_info_list(pa_ctx.get(),PulseAudioSinksManager::pulseAudioSinklistCallback,this); }
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); } }
// 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; }
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 PulseSink::make_device_description(pa_context* pulse_context) { devices_.clear(); pa_operation_unref(pa_context_get_sink_info_list(pulse_context, get_sink_info_callback, this)); }
/* The implementation of create_output_device_name_list() is based on the * example code in * http://www.ypass.net/blog/2009/10/ * pulseaudio-an-async-example-to-get-device-lists/ */ mbx_error_code mbx_create_output_device_name_list(char ***dev_names, size_t *n_devs) { pa_mainloop *pa_ml = pa_mainloop_new(); pa_mainloop_api *pa_mlapi = pa_mainloop_get_api(pa_ml); pa_context *pa_ctx = pa_context_new(pa_mlapi, "music box (listing output " "devices)"); pa_operation *pa_op; pa_context_state_t pa_context_state = PA_CONTEXT_UNCONNECTED; int do_iterate = 1; int error = 0; pa_context_connect(pa_ctx, NULL, 0, NULL); /* The state callback will update the state when we are connected to the * PulseAudio server, or if an error occurs. */ pa_context_set_state_callback(pa_ctx, pa_context_state_cb, &pa_context_state); while ( do_iterate ) { switch ( pa_context_state ) { case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: pa_mainloop_iterate(pa_ml, 1, NULL); // we must wait. break; case PA_CONTEXT_READY: do_iterate = 0; break; case PA_CONTEXT_FAILED: mbx_log_error(MBX_LOG_AUDIO_OUTPUT, "Connection to PulseAudio server failed: " "%s", pa_strerror(pa_context_errno(pa_ctx))); error = 1; break; case PA_CONTEXT_TERMINATED: mbx_log_error(MBX_LOG_AUDIO_OUTPUT, "Connection to PulseAudio server " "terminated unexpectedly."); error = 1; break; default: mbx_log_error(MBX_LOG_AUDIO_OUTPUT, "The PulseAudio context has an unexpected " "state: %d", pa_context_state); error = 1; break; } if ( error ) { do_iterate = 0; } } if ( ! error ) { struct list_of_strings result = { NULL, 0, 0 }; pa_op = pa_context_get_sink_info_list(pa_ctx, pa_sinklist_cb, &result); while ( pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING ) { pa_mainloop_iterate(pa_ml, 1, NULL); // wait. } pa_operation_unref(pa_op); *dev_names = result.strings; *n_devs = result.n_strings; } pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return error ? MBX_PULSEAUDIO_ERROR : MBX_SUCCESS; }
static void cm_card_profile_set_cb(pa_context *context, int success, void *user_data) { pa_operation *op; op = pa_context_get_sink_info_list(context, cm_sinkinfo_cb, user_data); pa_operation_unref(op); }