Error AudioDriverPulseAudio::init() { active = false; thread_exited = false; exit_thread = false; mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); pa_ml = pa_mainloop_new(); ERR_FAIL_COND_V(pa_ml == NULL, ERR_CANT_OPEN); pa_ctx = pa_context_new(pa_mainloop_get_api(pa_ml), "Godot"); ERR_FAIL_COND_V(pa_ctx == NULL, ERR_CANT_OPEN); pa_ready = 0; pa_context_set_state_callback(pa_ctx, pa_state_cb, (void *)this); int ret = pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL); if (ret < 0) { if (pa_ctx) { pa_context_unref(pa_ctx); pa_ctx = NULL; } if (pa_ml) { pa_mainloop_free(pa_ml); pa_ml = NULL; } return ERR_CANT_OPEN; } while (pa_ready == 0) { pa_mainloop_iterate(pa_ml, 1, NULL); } if (pa_ready < 0) { if (pa_ctx) { pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_ctx = NULL; } if (pa_ml) { pa_mainloop_free(pa_ml); pa_ml = NULL; } return ERR_CANT_OPEN; } Error err = init_device(); if (err == OK) { mutex = Mutex::create(); thread = Thread::create(AudioDriverPulseAudio::thread_func, this); } return OK; }
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); } }
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); } }
int main(int argc, const char *argv[]) { pa_mainloop *pa_ml = NULL; pa_mainloop_api *pa_mlapi = NULL; pa_operation *pa_op = NULL; pa_context *pa_ctx = NULL; int pa_ready = 0; int state = 0; pa_ml = pa_mainloop_new(); pa_mlapi = pa_mainloop_get_api(pa_ml); pa_ctx = pa_context_new(pa_mlapi, "deepin"); pa_context_connect(pa_ctx, NULL, 0, NULL); pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); for (;;) { 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_source_output_info_list(pa_ctx, pa_source_output_cb, NULL); 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: fprintf(stderr, "in state %d\n", state); return -1; } pa_mainloop_iterate(pa_ml, 1, NULL); } return 0; }
int PulseAudioDriver::thread_body() { m_main_loop = pa_mainloop_new(); pa_mainloop_api* api = pa_mainloop_get_api(m_main_loop); pa_io_event* ioev = api->io_new(api, m_pipe[0], PA_IO_EVENT_INPUT, pipe_callback, this); m_ctx = pa_context_new(api, "Hydrogen"); pa_context_set_state_callback(m_ctx, ctx_state_callback, this); pa_context_connect(m_ctx, 0, pa_context_flags_t(0), 0); int retval; pa_mainloop_run(m_main_loop, &retval); if (m_stream) { pa_stream_set_state_callback(m_stream, 0, 0); pa_stream_set_write_callback(m_stream, 0, 0); pa_stream_unref(m_stream); m_stream = 0; } api->io_free(ioev); pa_context_unref(m_ctx); pa_mainloop_free(m_main_loop); return retval; }
/* * clean up and disconnect * args: * pa_ctx - pointer to pulse context * pa_ml - pointer to pulse mainloop * * asserts: * none * * returns: * none */ static void finish(pa_context *pa_ctx, pa_mainloop *pa_ml) { /* clean up and disconnect */ pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); }
void pulse_conn_close(struct pulse_conn_t *conn) { int err; unsigned int i; uint8_t cmd; cmd = 1; err = write(conn->pipe[1], &cmd, 1); if(err < 0) fprintf(stderr, "Failed to write to descriptor. %s.", strerror(errno)), exit(1); pthread_join(conn->thread, NULL); pa_context_disconnect(conn->context); pa_context_unref(conn->context); pa_mainloop_free(conn->loop); for(i = 0; i < conn->width; i++) free(conn->buf[i]); free(conn->buf); close(conn->pipe[0]); close(conn->pipe[1]); free(conn); }
int main(int argc, char *argv[]) { pa_mainloop *m; m = pa_mainloop_new(); assert(m); pa_cpu_limit_init(pa_mainloop_get_api(m)); time(&start); #ifdef TEST2 pa_signal_init(pa_mainloop_get_api(m)); pa_signal_new(SIGUSR1, func, NULL); raise(SIGUSR1); pa_mainloop_run(m, NULL); pa_signal_done(); #else for (;;) { time_t now; time(&now); if ((now - start) >= 30) { fprintf(stderr, "Test failed\n"); break; } } #endif pa_cpu_limit_done(); pa_mainloop_free(m); return 0; }
void pulse_deinit(struct pulseaudio_t *pulse) { enum pa_context_state state = PA_CONTEXT_CONNECTING; pa_context_set_state_callback(pulse->cxt, pulse_connect_state_cb, &state); pa_context_disconnect(pulse->cxt); pa_mainloop_free(pulse->mainloop); free(pulse->default_sink); }
PulseDeviceFinder::~PulseDeviceFinder() { if (context_) { pa_context_disconnect(context_); pa_context_unref(context_); } if (mainloop_) { pa_mainloop_free(mainloop_); } }
/* * Disconnect from the pulse audio server and destroy the main loop */ static void pulse_disconnect(struct pulse_data *data) { if (data->context) { pa_context_disconnect(data->context); pa_context_unref(data->context); } if (data->mainloop) pa_mainloop_free(data->mainloop); }
bool PulseAudio::init(bool) { 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, "MuseScore"); if (pa_context_connect(pa_ctx, NULL, pa_context_flags_t(0), NULL) != 0) qDebug("PulseAudio Context Connect Failed with Error: %s", pa_strerror(pa_context_errno(pa_ctx))); int pa_ready = 0; pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); while (pa_ready == 0) pa_mainloop_iterate(pa_ml, 1, NULL); if (pa_ready == 2) return false; ss.rate = _sampleRate; ss.channels = 2; ss.format = PA_SAMPLE_FLOAT32LE; pa_stream* playstream = pa_stream_new(pa_ctx, "Playback", &ss, NULL); if (!playstream) { qDebug("pa_stream_new failed"); return false; } pa_stream_set_write_callback(playstream, paCallback, this); bufattr.fragsize = (uint32_t)-1; bufattr.maxlength = FRAMES * 2 * sizeof(float); bufattr.minreq = FRAMES * 1 * sizeof(float); // pa_usec_to_bytes(0, &ss); bufattr.prebuf = (uint32_t)-1; bufattr.tlength = bufattr.maxlength; int r = pa_stream_connect_playback(playstream, NULL, &bufattr, pa_stream_flags_t(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL); if (r < 0) { // Old pulse audio servers don't like the ADJUST_LATENCY flag, so retry without that r = pa_stream_connect_playback(playstream, NULL, &bufattr, pa_stream_flags_t(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL); } if (r < 0) { qDebug("pa_stream_connect_playback failed"); pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); pa_ml = 0; return false; } return true; }
int main(int argc, char *argv[]) { pa_mainloop_api *a; pa_io_event *ioe; pa_time_event *te; struct timeval tv; #ifdef GLIB_MAIN_LOOP pa_glib_mainloop *g; glib_main_loop = g_main_loop_new(NULL, FALSE); assert(glib_main_loop); g = pa_glib_mainloop_new(NULL); assert(g); a = pa_glib_mainloop_get_api(g); assert(a); #else /* GLIB_MAIN_LOOP */ pa_mainloop *m; m = pa_mainloop_new(); assert(m); a = pa_mainloop_get_api(m); assert(a); #endif /* GLIB_MAIN_LOOP */ ioe = a->io_new(a, 0, PA_IO_EVENT_INPUT, iocb, NULL); assert(ioe); de = a->defer_new(a, dcb, NULL); assert(de); te = a->time_new(a, pa_timeval_rtstore(&tv, pa_rtclock_now() + 2 * PA_USEC_PER_SEC, TRUE), tcb, NULL); #if defined(GLIB_MAIN_LOOP) g_main_loop_run(glib_main_loop); #else pa_mainloop_run(m, NULL); #endif a->time_free(te); a->defer_free(de); a->io_free(ioe); #ifdef GLIB_MAIN_LOOP pa_glib_mainloop_free(g); g_main_loop_unref(glib_main_loop); #else pa_mainloop_free(m); #endif return 0; }
PulseAudioDriver::~PulseAudioDriver( ) { PENTER; if (stream) pa_stream_unref(stream); if (context) pa_context_unref(context); if (mainloop) { pa_signal_done(); pa_mainloop_free(mainloop); } }
APULSE_EXPORT void pa_threaded_mainloop_free(pa_threaded_mainloop *m) { trace_info_f("F %s m=%p\n", __func__, m); if (m->running) pa_threaded_mainloop_stop(m); pthread_mutex_destroy(&m->lock); pthread_cond_destroy(&m->cond); pa_mainloop_free(m->m); free(m); }
bool PulseAudio::init(bool) { 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, "MuseScore"); if (pa_context_connect(pa_ctx, NULL, pa_context_flags_t(0), NULL) != 0) { qDebug("PulseAudio Context Connect Failed with Error: %s", pa_strerror(pa_context_errno(pa_ctx))); return false; } int pa_ready = 0; pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); while (pa_ready == 0) pa_mainloop_iterate(pa_ml, 1, NULL); if (pa_ready == 2) return false; ss.rate = _sampleRate; ss.channels = 2; ss.format = PA_SAMPLE_FLOAT32LE; pa_stream* playstream = pa_stream_new(pa_ctx, "Playback", &ss, NULL); if (!playstream) { qDebug("pa_stream_new failed: %s", pa_strerror(pa_context_errno(pa_ctx))); return false; } pa_stream_set_write_callback(playstream, paCallback, this); bufattr.fragsize = (uint32_t)-1; bufattr.maxlength = FRAMES * 2 * sizeof(float); bufattr.minreq = FRAMES * 1 * sizeof(float); // pa_usec_to_bytes(0, &ss); bufattr.prebuf = (uint32_t)-1; bufattr.tlength = bufattr.maxlength; int r = pa_stream_connect_playback(playstream, nullptr, &bufattr, PA_STREAM_NOFLAGS, nullptr, nullptr); if (r < 0) { qDebug("pa_stream_connect_playback failed"); pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); pa_ml = 0; return false; } return true; }
static void destroy_client(client_t *c) { if (c != NULL) { mrp_debug("destroying client"); if (c->ml != NULL) mrp_mainloop_destroy(c->ml); if (c->pa != NULL) pa_mainloop_free(c->pa); if (c->gml != NULL) g_main_loop_unref(c->gml); mrp_free(c); } }
/** Destroy libao driver */ static void uninit(int immed) { if (stream) { if (!immed && pa_stream_get_state(stream) == PA_STREAM_READY) wait_for_operation(pa_stream_drain(stream, NULL, NULL)); pa_stream_unref(stream); stream = NULL; } if (context) { pa_context_unref(context); context = NULL; } if (mainloop) { pa_mainloop_free(mainloop); mainloop = NULL; } }
PulseHandler::~PulseHandler(void) { // TODO - do we need to drain the context?? LOG(VB_AUDIO, LOG_INFO, LOC + "Destroying PulseAudio handler"); // is this correct? if (m_ctx) { pa_context_disconnect(m_ctx); pa_context_unref(m_ctx); } if (m_loop) { pa_signal_done(); pa_mainloop_free(m_loop); } }
void pa_threaded_mainloop_free(pa_threaded_mainloop* m) { pa_assert(m); /* Make sure that this function is not called from the helper thread */ pa_assert((m->thread && !pa_thread_is_running(m->thread)) || !in_worker(m)); pa_threaded_mainloop_stop(m); if (m->thread) pa_thread_free(m->thread); pa_mainloop_free(m->real_mainloop); pa_mutex_free(m->mutex); pa_cond_free(m->cond); pa_cond_free(m->accept_cond); pa_xfree(m->name); pa_xfree(m); }
int main(int argc, char *argv[]) { pa_mainloop* m = NULL; int i, ret = 0; for (i = 0; i < SAMPLE_HZ; i++) data[i] = (float) sin(((double) i/SAMPLE_HZ)*2*M_PI*SINE_HZ)/2; for (i = 0; i < NSTREAMS; i++) streams[i] = NULL; /* Set up a new main loop */ m = pa_mainloop_new(); assert(m); mainloop_api = pa_mainloop_get_api(m); context = pa_context_new(mainloop_api, argv[0]); assert(context); pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ if (pa_context_connect(context, NULL, 0, NULL) < 0) { fprintf(stderr, "pa_context_connect() failed.\n"); goto quit; } if (pa_mainloop_run(m, &ret) < 0) fprintf(stderr, "pa_mainloop_run() failed.\n"); quit: pa_context_unref(context); for (i = 0; i < NSTREAMS; i++) if (streams[i]) pa_stream_unref(streams[i]); pa_mainloop_free(m); return ret; }
void pa__done(pa_module *m) { struct userdata *u; pa_assert(m); if (!(u = m->userdata)) return; if (u->sink) pa_sink_unlink(u->sink); if (u->thread) { pa_asyncmsgq_send(u->thread_mq->inq, NULL, PA_MESSAGE_SHUTDOWN, NULL, 0, NULL); pa_thread_free(u->thread); } if (u->thread_mq) { pa_thread_mq_done(u->thread_mq); pa_xfree(u->thread_mq); } if (u->thread_mainloop) pa_mainloop_free(u->thread_mainloop); if (u->cookie_file) pa_xfree(u->cookie_file); if (u->remote_sink_name) pa_xfree(u->remote_sink_name); if (u->remote_server) pa_xfree(u->remote_server); if (u->sink) pa_sink_unref(u->sink); if(u->transcode.encoding != -1) pa_transcode_free(&u->transcode); pa_xfree(u); }
void executeRequest( StateData* stateData ) { // Create mainloop pa_mainloop* mainLoop = pa_mainloop_new(); // Create mainloop API pa_mainloop_api* mainLoopApi = pa_mainloop_get_api( mainLoop ); // Create context pa_context* context = pa_context_new( mainLoopApi, "cinder-requests" ); // Set context state callback stateData->mainLoopApi = mainLoopApi; pa_context_set_state_callback( context, processContextState, static_cast<void*>( stateData ) ); // Connect context if( pa_context_connect( context, nullptr, PA_CONTEXT_NOFLAGS, nullptr ) >= 0 ) { // Run mainloop int result = 0; if( pa_mainloop_run( mainLoop, &result ) < 0 ) { // Handle error } } pa_context_unref( context ); pa_mainloop_free( mainLoop ); }
int stop_recording(recorder_context_t *rctx, bool restart) { int retval = 0; Log(LOG_INFO, "Stopping recorder.\n"); #ifdef DEBUG fclose(threshold_file); #endif fclose(rctx->recording_file); fclose(rctx->length_file); pa_mainloop_quit(rctx->pa_ml, retval); pa_stream_disconnect(rctx->recording_stream); pa_stream_unref(rctx->recording_stream); pa_context_disconnect(rctx->pa_ctx); pa_context_unref(rctx->pa_ctx); pa_mainloop_free(rctx->pa_ml); if (!restart){ free(rctx); } Log(LOG_INFO, "DONE.\n"); return retval; }
void kradpulse_destroy(krad_pulse_t *kradpulse) { kradpulse->shutdown = 1; pthread_join(kradpulse->loop_thread, NULL); // clean up and disconnect pa_context_disconnect(kradpulse->pa_ctx); pa_context_unref(kradpulse->pa_ctx); pa_mainloop_free(kradpulse->pa_ml); free(kradpulse->samples[0]); free(kradpulse->samples[1]); free(kradpulse->interleaved_samples); free(kradpulse->capture_samples[0]); free(kradpulse->capture_samples[1]); free(kradpulse->capture_interleaved_samples); free(kradpulse); }
/* 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; }
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); } }
int set_active_port(pa_devicelist_t device, pa_portlist_t port) { pa_mainloop *pa_ml; pa_mainloop_api *pa_mlapi; pa_operation *pa_op; pa_context *pa_ctx; int pa_ready = 0; int state = 0; pa_ml = pa_mainloop_new(); pa_mlapi = pa_mainloop_get_api(pa_ml); pa_ctx = pa_context_new(pa_mlapi, "test"); pa_context_connect(pa_ctx, NULL, 0, NULL); pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); pa_device_port_t dev_port_set; dev_port_set.device = device; dev_port_set.port = port; pa_clientlist_t clientlist[30]; int i = 0; 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; } switch(state) { case 0: // Set source or sink switch(device.type) { case JOAPA_SOURCE: pa_op = pa_context_set_source_port_by_index( pa_ctx, device.index, port.name, set_active_port_cb, &dev_port_set); break; case JOAPA_SINK: pa_op = pa_context_set_sink_port_by_index( pa_ctx, device.index, port.name, set_active_port_cb, &dev_port_set); break; } state++; break; case 1: // get clients using a source or sink if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); switch(device.type) { case JOAPA_SOURCE: pa_op = pa_context_get_source_output_info_list(pa_ctx, pa_source_info_cb, &clientlist); break; case JOAPA_SINK: pa_op = pa_context_get_sink_input_info_list(pa_ctx, pa_sink_info_cb, &clientlist); break; } state++; } break; case 2: // move the clients to the new source or sink if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); if(!clientlist[i].initialized) { pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return 0; } //printf("CLIENT: %d\n", clientlist[i].index); switch(device.type) { case JOAPA_SOURCE: pa_op = pa_context_move_source_output_by_index( pa_ctx, clientlist[i].index, device.index, set_active_port_cb, NULL); break; case JOAPA_SINK: pa_op = pa_context_move_sink_input_by_index( pa_ctx, clientlist[i].index, device.index, set_active_port_cb, NULL); break; } i++; } break; default: fprintf(stderr, "in state %d\n", state); return -1; } pa_mainloop_iterate(pa_ml, 1, NULL); } }
int main(int argc, char *argv[]) { pa_mainloop* m = NULL; int ret = 1, c; char *bn, *server = NULL; pa_time_event *time_event = NULL; const char *filename = NULL; static const struct option long_options[] = { {"record", 0, NULL, 'r'}, {"playback", 0, NULL, 'p'}, {"device", 1, NULL, 'd'}, {"server", 1, NULL, 's'}, {"client-name", 1, NULL, 'n'}, {"stream-name", 1, NULL, ARG_STREAM_NAME}, {"version", 0, NULL, ARG_VERSION}, {"help", 0, NULL, 'h'}, {"verbose", 0, NULL, 'v'}, {"volume", 1, NULL, ARG_VOLUME}, {"rate", 1, NULL, ARG_SAMPLERATE}, {"format", 1, NULL, ARG_SAMPLEFORMAT}, {"channels", 1, NULL, ARG_CHANNELS}, {"channel-map", 1, NULL, ARG_CHANNELMAP}, {"fix-format", 0, NULL, ARG_FIX_FORMAT}, {"fix-rate", 0, NULL, ARG_FIX_RATE}, {"fix-channels", 0, NULL, ARG_FIX_CHANNELS}, {"no-remap", 0, NULL, ARG_NO_REMAP}, {"no-remix", 0, NULL, ARG_NO_REMIX}, {"latency", 1, NULL, ARG_LATENCY}, {"process-time", 1, NULL, ARG_PROCESS_TIME}, {"property", 1, NULL, ARG_PROPERTY}, {"raw", 0, NULL, ARG_RAW}, {"file-format", 2, NULL, ARG_FILE_FORMAT}, {"list-file-formats", 0, NULL, ARG_LIST_FILE_FORMATS}, {"latency-msec", 1, NULL, ARG_LATENCY_MSEC}, {"process-time-msec", 1, NULL, ARG_PROCESS_TIME_MSEC}, {NULL, 0, NULL, 0} }; setlocale(LC_ALL, ""); bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); bn = pa_path_get_filename(argv[0]); if (strstr(bn, "play")) { mode = PLAYBACK; raw = FALSE; } else if (strstr(bn, "record")) { mode = RECORD; raw = FALSE; } else if (strstr(bn, "cat")) { mode = PLAYBACK; raw = TRUE; } if (strstr(bn, "rec") || strstr(bn, "mon")) { mode = RECORD; raw = TRUE; } proplist = pa_proplist_new(); while ((c = getopt_long(argc, argv, "rpd:s:n:hv", long_options, NULL)) != -1) { switch (c) { case 'h' : help(bn); ret = 0; goto quit; case ARG_VERSION: printf(_("pacat %s\n" "Compiled with libpulse %s\n" "Linked with libpulse %s\n"), PACKAGE_VERSION, pa_get_headers_version(), pa_get_library_version()); ret = 0; goto quit; case 'r': mode = RECORD; break; case 'p': mode = PLAYBACK; break; case 'd': pa_xfree(device); device = pa_xstrdup(optarg); break; case 's': pa_xfree(server); server = pa_xstrdup(optarg); break; case 'n': { char *t; if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t) < 0) { pa_log(_("Invalid client name '%s'"), t ? t : optarg); pa_xfree(t); goto quit; } pa_xfree(t); break; } case ARG_STREAM_NAME: { char *t; if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t) < 0) { pa_log(_("Invalid stream name '%s'"), t ? t : optarg); pa_xfree(t); goto quit; } pa_xfree(t); break; } case 'v': verbose = 1; break; case ARG_VOLUME: { int v = atoi(optarg); volume = v < 0 ? 0U : (pa_volume_t) v; volume_is_set = TRUE; break; } case ARG_CHANNELS: sample_spec.channels = (uint8_t) atoi(optarg); sample_spec_set = TRUE; break; case ARG_SAMPLEFORMAT: sample_spec.format = pa_parse_sample_format(optarg); sample_spec_set = TRUE; break; case ARG_SAMPLERATE: sample_spec.rate = (uint32_t) atoi(optarg); sample_spec_set = TRUE; break; case ARG_CHANNELMAP: if (!pa_channel_map_parse(&channel_map, optarg)) { pa_log(_("Invalid channel map '%s'"), optarg); goto quit; } channel_map_set = TRUE; break; case ARG_FIX_CHANNELS: flags |= PA_STREAM_FIX_CHANNELS; break; case ARG_FIX_RATE: flags |= PA_STREAM_FIX_RATE; break; case ARG_FIX_FORMAT: flags |= PA_STREAM_FIX_FORMAT; break; case ARG_NO_REMIX: flags |= PA_STREAM_NO_REMIX_CHANNELS; break; case ARG_NO_REMAP: flags |= PA_STREAM_NO_REMAP_CHANNELS; break; case ARG_LATENCY: if (((latency = (size_t) atoi(optarg))) <= 0) { pa_log(_("Invalid latency specification '%s'"), optarg); goto quit; } break; case ARG_PROCESS_TIME: if (((process_time = (size_t) atoi(optarg))) <= 0) { pa_log(_("Invalid process time specification '%s'"), optarg); goto quit; } break; case ARG_LATENCY_MSEC: if (((latency_msec = (int32_t) atoi(optarg))) <= 0) { pa_log(_("Invalid latency specification '%s'"), optarg); goto quit; } break; case ARG_PROCESS_TIME_MSEC: if (((process_time_msec = (int32_t) atoi(optarg))) <= 0) { pa_log(_("Invalid process time specification '%s'"), optarg); goto quit; } break; case ARG_PROPERTY: { char *t; if (!(t = pa_locale_to_utf8(optarg)) || pa_proplist_setp(proplist, t) < 0) { pa_xfree(t); pa_log(_("Invalid property '%s'"), optarg); goto quit; } pa_xfree(t); break; } case ARG_RAW: raw = TRUE; break; case ARG_FILE_FORMAT: raw = FALSE; if (optarg) { if ((file_format = pa_sndfile_format_from_string(optarg)) < 0) { pa_log(_("Unknown file format %s."), optarg); goto quit; } } raw = FALSE; break; case ARG_LIST_FILE_FORMATS: pa_sndfile_dump_formats(); ret = 0; goto quit; default: goto quit; } } if (!pa_sample_spec_valid(&sample_spec)) { pa_log(_("Invalid sample specification")); goto quit; } if (optind+1 == argc) { int fd; filename = argv[optind]; if ((fd = open(argv[optind], mode == PLAYBACK ? O_RDONLY : O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { pa_log(_("open(): %s"), strerror(errno)); goto quit; } if (dup2(fd, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO) < 0) { pa_log(_("dup2(): %s"), strerror(errno)); goto quit; } pa_close(fd); } else if (optind+1 <= argc) { pa_log(_("Too many arguments.")); goto quit; } if (!raw) { SF_INFO sfi; pa_zero(sfi); if (mode == RECORD) { /* This might patch up the sample spec */ if (pa_sndfile_write_sample_spec(&sfi, &sample_spec) < 0) { pa_log(_("Failed to generate sample specification for file.")); goto quit; } /* Transparently upgrade classic .wav to wavex for multichannel audio */ if (file_format <= 0) { if ((sample_spec.channels == 2 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_LEFT && channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT))) || (sample_spec.channels == 1 && (!channel_map_set || (channel_map.map[0] == PA_CHANNEL_POSITION_MONO)))) file_format = SF_FORMAT_WAV; else file_format = SF_FORMAT_WAVEX; } sfi.format |= file_format; } if (!(sndfile = sf_open_fd(mode == RECORD ? STDOUT_FILENO : STDIN_FILENO, mode == RECORD ? SFM_WRITE : SFM_READ, &sfi, 0))) { pa_log(_("Failed to open audio file.")); goto quit; } if (mode == PLAYBACK) { if (sample_spec_set) pa_log(_("Warning: specified sample specification will be overwritten with specification from file.")); if (pa_sndfile_read_sample_spec(sndfile, &sample_spec) < 0) { pa_log(_("Failed to determine sample specification from file.")); goto quit; } sample_spec_set = TRUE; if (!channel_map_set) { /* Allow the user to overwrite the channel map on the command line */ if (pa_sndfile_read_channel_map(sndfile, &channel_map) < 0) { if (sample_spec.channels > 2) pa_log(_("Warning: Failed to determine channel map from file.")); } else channel_map_set = TRUE; } } } if (!channel_map_set) pa_channel_map_init_extend(&channel_map, sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); if (!pa_channel_map_compatible(&channel_map, &sample_spec)) { pa_log(_("Channel map doesn't match sample specification")); goto quit; } if (!raw) { pa_proplist *sfp; if (mode == PLAYBACK) readf_function = pa_sndfile_readf_function(&sample_spec); else { if (pa_sndfile_write_channel_map(sndfile, &channel_map) < 0) pa_log(_("Warning: failed to write channel map to file.")); writef_function = pa_sndfile_writef_function(&sample_spec); } /* Fill in libsndfile prop list data */ sfp = pa_proplist_new(); pa_sndfile_init_proplist(sndfile, sfp); pa_proplist_update(proplist, PA_UPDATE_MERGE, sfp); pa_proplist_free(sfp); } if (verbose) { char tss[PA_SAMPLE_SPEC_SNPRINT_MAX], tcm[PA_CHANNEL_MAP_SNPRINT_MAX]; pa_log(_("Opening a %s stream with sample specification '%s' and channel map '%s'."), mode == RECORD ? _("recording") : _("playback"), pa_sample_spec_snprint(tss, sizeof(tss), &sample_spec), pa_channel_map_snprint(tcm, sizeof(tcm), &channel_map)); } /* Fill in client name if none was set */ if (!pa_proplist_contains(proplist, PA_PROP_APPLICATION_NAME)) { char *t; if ((t = pa_locale_to_utf8(bn))) { pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, t); pa_xfree(t); } } /* Fill in media name if none was set */ if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) { const char *t; if ((t = filename) || (t = pa_proplist_gets(proplist, PA_PROP_APPLICATION_NAME))) pa_proplist_sets(proplist, PA_PROP_MEDIA_NAME, t); } /* Set up a new main loop */ if (!(m = pa_mainloop_new())) { pa_log(_("pa_mainloop_new() failed.")); goto quit; } mainloop_api = pa_mainloop_get_api(m); pa_assert_se(pa_signal_init(mainloop_api) == 0); pa_signal_new(SIGINT, exit_signal_callback, NULL); pa_signal_new(SIGTERM, exit_signal_callback, NULL); #ifdef SIGUSR1 pa_signal_new(SIGUSR1, sigusr1_signal_callback, NULL); #endif pa_disable_sigpipe(); if (raw) { if (!(stdio_event = mainloop_api->io_new(mainloop_api, mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, mode == PLAYBACK ? PA_IO_EVENT_INPUT : PA_IO_EVENT_OUTPUT, mode == PLAYBACK ? stdin_callback : stdout_callback, NULL))) { pa_log(_("io_new() failed.")); goto quit; } } /* Create a new connection context */ if (!(context = pa_context_new_with_proplist(mainloop_api, NULL, proplist))) { pa_log(_("pa_context_new() failed.")); goto quit; } pa_context_set_state_callback(context, context_state_callback, NULL); /* Connect the context */ if (pa_context_connect(context, server, 0, NULL) < 0) { pa_log(_("pa_context_connect() failed: %s"), pa_strerror(pa_context_errno(context))); goto quit; } if (verbose) { if (!(time_event = pa_context_rttime_new(context, pa_rtclock_now() + TIME_EVENT_USEC, time_event_callback, NULL))) { pa_log(_("pa_context_rttime_new() failed.")); goto quit; } } /* Run the main loop */ if (pa_mainloop_run(m, &ret) < 0) { pa_log(_("pa_mainloop_run() failed.")); goto quit; } quit: if (stream) pa_stream_unref(stream); if (context) pa_context_unref(context); if (stdio_event) { pa_assert(mainloop_api); mainloop_api->io_free(stdio_event); } if (time_event) { pa_assert(mainloop_api); mainloop_api->time_free(time_event); } if (m) { pa_signal_done(); pa_mainloop_free(m); } pa_xfree(buffer); pa_xfree(server); pa_xfree(device); if (sndfile) sf_close(sndfile); if (proplist) pa_proplist_free(proplist); return ret; }
int main(int argc, char *const *argv) { static const char *context_name = "i3blocks-pulse-volume"; static const char *usage_str = "Usage: %s [-h] [-d] [-s INDEX] [-m FUNC]\n" "Options:\n" " -s INDEX: pulseaudio sink index on which to wait for " "changes (default: 0)\n" " -m FUNC : function used to compute the displayed volume value\n" " in there are multiple channels (eg. left/right):\n" " * avg: use average volume of all channels (default)\n" " * min: use minimum volume of all channels\n" " * max: use maximum volume of all channels\n" " -d : use decibel notation instead of 0-100 percentage; " "the sink may\n" " not support this feature\n"; options_t options; options.calculator = pa_cvolume_avg; options.use_decibel = 0; options.observed_index = 0; sink_info_data_t sink_info_data; sink_info_data.sink_ready = 0; sink_info_data.sink_changed = 0; pa_mainloop *pa_ml = NULL; pa_mainloop_api *pa_ml_api = NULL; pa_operation *pa_op = NULL; pa_context *pa_ctx = NULL; enum state_t state = FIRST_SINK_INFO; int pa_ready = CONN_WAIT; int opt; while ((opt = getopt(argc, argv, "m:s:dh")) != -1) { if (opt == 'm') { if (strcmp(optarg, "min") == 0) { options.calculator = pa_cvolume_min; } else if (strcmp(optarg, "max") == 0) { options.calculator = pa_cvolume_max; } else if (strcmp(optarg, "avg") == 0) { options.calculator = pa_cvolume_avg; } else { fprintf(stderr, usage_str, argv[0]); return 1; } } else if (opt == 's') { // Parse observed sink index errno = 0; char *endptr; uint32_t *oind = &options.observed_index; *oind = strtoul(optarg, &endptr, 10); if ((errno == ERANGE) || (errno != 0 && *oind == 0) || endptr == optarg) { fprintf(stderr, "%s: invalid sink index: %s\n", argv[0], optarg); fprintf(stderr, usage_str, argv[0]); return 1; } } else if (opt == 'd') { options.use_decibel = 1; } else if (opt == 'h') { fprintf(stderr, usage_str, argv[0]); return 0; } else { fprintf(stderr, usage_str, argv[0]); return 1; } } // Needed to filter out sink in callbacks sink_info_data.observed_index = options.observed_index; if ((pa_ml = pa_mainloop_new()) == NULL) { fprintf(stderr, "error: failed to allocate pulseaudio mainloop.\n"); return 2; } if ((pa_ml_api = pa_mainloop_get_api(pa_ml)) == NULL) { fprintf(stderr, "error: failed to allocate pulseaudio mainloop API.\n"); return 3; } if ((pa_ctx = pa_context_new(pa_ml_api, context_name)) == NULL) { fprintf(stderr, "error: failed to allocate pulseaudio context.\n"); return 4; } if (pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFAIL, NULL) < 0) { fprintf(stderr, "error: failed to connect to pulseaudio context: %s\n", pa_strerror(pa_context_errno(pa_ctx))); return 5; } pa_context_set_state_callback(pa_ctx, state_cb, &pa_ready); pa_context_set_subscribe_callback(pa_ctx, subscribe_cb, &sink_info_data); while (1) { if (pa_ready == CONN_WAIT) { pa_mainloop_iterate(pa_ml, 1, NULL); continue; } if (pa_ready == CONN_FAILED) { pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); fprintf(stderr, "error: failed to connect to pulseaudio context.\n"); return 6; } // Main loop automaton switch (state) { case FIRST_SINK_INFO: // First run pa_op = pa_context_get_sink_info_by_index(pa_ctx, options.observed_index, sink_info_cb, &sink_info_data); state = SUBSCRIBE; break; case SUBSCRIBE: if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); if (!sink_info_data.sink_ready) { fprintf(stderr, "error: sink %u does not exist.\n", options.observed_index); pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return 7; } if (options.use_decibel && !sink_info_data.sink.can_decibel) { fprintf(stderr, "error: sink %u does not support decibel; " "try without `-d`.\n", options.observed_index); pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return 8; } // Show volume once at start show_volume(&sink_info_data.sink, &options); // Subsequent runs: wait for changes pa_op = pa_context_subscribe(pa_ctx, PA_SUBSCRIPTION_MASK_SINK, NULL, &sink_info_data); state = SUBSCRIBED; } break; case SUBSCRIBED: if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); state = WAIT_FOR_CHANGE; } break; case WAIT_FOR_CHANGE: if (sink_info_data.sink_changed) { sink_info_data.sink_changed = 0; pa_op = pa_context_get_sink_info_by_index(pa_ctx, options.observed_index, sink_info_cb, &sink_info_data); state = SHOW_CHANGE; } break; case SHOW_CHANGE: if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { pa_operation_unref(pa_op); show_volume(&sink_info_data.sink, &options); state = WAIT_FOR_CHANGE; } break; default: return 7; } pa_mainloop_iterate(pa_ml, 1, NULL); } }