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; }
bool PulseHandler::Init(void) { if (m_initialised) return m_valid; m_initialised = true; // Initialse our connection to the server m_loop = pa_mainloop_new(); if (!m_loop) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get PulseAudio mainloop"); return m_valid; } pa_mainloop_api *api = pa_mainloop_get_api(m_loop); if (!api) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to get PulseAudio api"); return m_valid; } if (pa_signal_init(api) != 0) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to initialise signaling"); return m_valid; } const char *client = "mythtv"; m_ctx = pa_context_new(api, client); if (!m_ctx) { LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to create context"); return m_valid; } // remember which thread created this object for later sanity debugging m_thread = QThread::currentThread(); // we set the callback, connect and then run the main loop 'by hand' // until we've successfully connected (or not) pa_context_set_state_callback(m_ctx, StatusCallback, this); pa_context_connect(m_ctx, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); int ret = 0; int tries = 0; while ((tries++ < 100) && !IS_READY(m_ctx_state)) { pa_mainloop_iterate(m_loop, 0, &ret); usleep(10000); } if (PA_CONTEXT_READY != m_ctx_state) { LOG(VB_GENERAL, LOG_ERR, LOC + "Context not ready after 1000ms"); return m_valid; } LOG(VB_AUDIO, LOG_INFO, LOC + "Initialised handler"); m_valid = true; return m_valid; }
int main(int argc, char *argv[]) { // Define our pulse audio loop and connection variables pa_mainloop *pa_ml; pa_mainloop_api *pa_mlapi; pa_operation *pa_op; pa_time_event *time_event; // Create a mainloop API and connection to the default server pa_ml = pa_mainloop_new(); pa_mlapi = pa_mainloop_get_api(pa_ml); context = pa_context_new(pa_mlapi, "Device list"); // This function connects to the pulse server pa_context_connect(context, NULL, 0, NULL); // This function defines a callback so the server will tell us its state. pa_context_set_state_callback(context, context_state_cb, NULL); if (pa_mainloop_run(pa_ml, &ret) < 0) { printf("pa_mainloop_run() failed."); exit(1); } }
void vis::PulseAudioSource::populate_default_source_name() { #ifdef _ENABLE_PULSE pa_mainloop_api *mainloop_api; pa_context *pulseaudio_context; // Create a mainloop API and connection to the default server m_pulseaudio_mainloop = pa_mainloop_new(); mainloop_api = pa_mainloop_get_api(m_pulseaudio_mainloop); pulseaudio_context = pa_context_new(mainloop_api, "vis device list"); // This function connects to the pulse server pa_context_connect(pulseaudio_context, nullptr, PA_CONTEXT_NOFLAGS, nullptr); // This function defines a callback so the server will tell us its state. pa_context_set_state_callback(pulseaudio_context, pulseaudio_context_state_callback, reinterpret_cast<void *>(this)); int ret; if (pa_mainloop_run(m_pulseaudio_mainloop, &ret) < 0) { VIS_LOG(vis::LogLevel::ERROR, "Could not open pulseaudio mainloop to " "find default device name: %d", ret); } #endif }
bool PulseDeviceFinder::Reconnect() { if (context_) { pa_context_disconnect(context_); pa_context_unref(context_); } context_ = pa_context_new(pa_mainloop_get_api(mainloop_), "Clementine device finder"); if (!context_) { qLog(Warning) << "Failed to create pulseaudio context"; return false; } if (pa_context_connect(context_, nullptr, PA_CONTEXT_NOFLAGS, nullptr) < 0) { qLog(Warning) << "Failed to connect pulseaudio context"; return false; } // Wait for the context to be connected. forever { const pa_context_state state = pa_context_get_state(context_); if (state == PA_CONTEXT_FAILED || state == PA_CONTEXT_TERMINATED) { qLog(Warning) << "Connection to pulseaudio failed"; return false; } if (state == PA_CONTEXT_READY) { return true; } pa_mainloop_iterate(mainloop_, true, nullptr); } }
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; }
/* * Initialize pulseAudio */ static int init_pa(recorder_context_t *rctx) { pa_mainloop_api *pa_mlapi; pa_proplist *ctx_properties = pa_proplist_new(); pa_proplist *stream_properties = pa_proplist_new(); int retval = 0; rctx->pa_ml = pa_mainloop_new(); pa_mlapi = pa_mainloop_get_api(rctx->pa_ml); rctx->pa_ctx = pa_context_new_with_proplist(pa_mlapi, "NoApp recorder", ctx_properties); pa_context_connect(rctx->pa_ctx, NULL, 0, NULL); rctx->pa_ready = 0; pa_context_set_state_callback(rctx->pa_ctx, pa_state_cb, rctx); while (rctx->pa_ready == 0){ pa_mainloop_iterate(rctx->pa_ml, 1, NULL); } if (rctx->pa_ready == 2){ retval = -1; goto exit; } rctx->recording_stream = pa_stream_new_with_proplist(rctx->pa_ctx, "NoApp recorder", &rctx->pa_ss, NULL, stream_properties); retval = pa_stream_connect_record(rctx->recording_stream, NULL, NULL, 0); if (retval < 0){ Log(LOG_ERR, "pa_stream_connect_playback failed\n"); goto exit; } exit: return retval; }
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); } }
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; }
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); } }
bool PulseAudio::PulseInit() { m_pa_error = 0; m_pa_connected = 0; // create pulseaudio main loop and context // also register the async state callback which is called when the connection to the pa server has changed m_pa_ml = pa_mainloop_new(); m_pa_mlapi = pa_mainloop_get_api(m_pa_ml); m_pa_ctx = pa_context_new(m_pa_mlapi, "dolphin-emu"); m_pa_error = pa_context_connect(m_pa_ctx, nullptr, PA_CONTEXT_NOFLAGS, nullptr); pa_context_set_state_callback(m_pa_ctx, StateCallback, this); // wait until we're connected to the pulseaudio server while (m_pa_connected == 0 && m_pa_error >= 0) m_pa_error = pa_mainloop_iterate(m_pa_ml, 1, nullptr); if (m_pa_connected == 2 || m_pa_error < 0) { ERROR_LOG(AUDIO, "PulseAudio failed to initialize: %s", pa_strerror(m_pa_error)); return false; } // create a new audio stream with our sample format // also connect the callbacks for this stream pa_sample_spec ss; ss.format = PA_SAMPLE_S16LE; ss.channels = 2; ss.rate = m_mixer->GetSampleRate(); m_pa_s = pa_stream_new(m_pa_ctx, "Playback", &ss, nullptr); pa_stream_set_write_callback(m_pa_s, WriteCallback, this); pa_stream_set_underflow_callback(m_pa_s, UnderflowCallback, this); // connect this audio stream to the default audio playback // limit buffersize to reduce latency m_pa_ba.fragsize = -1; m_pa_ba.maxlength = -1; // max buffer, so also max latency m_pa_ba.minreq = -1; // don't read every byte, try to group them _a bit_ m_pa_ba.prebuf = -1; // start as early as possible m_pa_ba.tlength = BUFFER_SIZE; // designed latency, only change this flag for low latency output pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE); m_pa_error = pa_stream_connect_playback(m_pa_s, nullptr, &m_pa_ba, flags, nullptr, nullptr); if (m_pa_error < 0) { ERROR_LOG(AUDIO, "PulseAudio failed to initialize: %s", pa_strerror(m_pa_error)); return false; } INFO_LOG(AUDIO, "Pulse successfully initialized"); return true; }
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; }
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 int create_mainloop(client_t *c) { if (!c->glib) { c->pa = pa_mainloop_new(); c->ml = mrp_mainloop_pulse_get(pa_mainloop_get_api(c->pa)); } else { c->gml = g_main_loop_new(NULL, FALSE); c->ml = mrp_mainloop_glib_get(c->gml); } if (c->ml != NULL) return TRUE; else return FALSE; }
int main(int argc, char *argv[]) { struct stat st; off_t size; ssize_t nread; // We'll need these state variables to keep track of our requests int state = 0; int pa_ready = 0; if (argc != 2) { fprintf(stderr, "Usage: %s file\n", argv[0]); exit(1); } // slurp the whole file into buffer if ((fdin = open(argv[1], O_RDONLY)) == -1) { perror("open"); exit(1); } // Create a mainloop API and connection to the default server mainloop = pa_mainloop_new(); mainloop_api = pa_mainloop_get_api(mainloop); context = pa_context_new(mainloop_api, "test"); // This function connects to the pulse server pa_context_connect(context, NULL, 0, NULL); printf("Connecting\n"); // 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(context, state_cb, &pa_ready); if (pa_mainloop_run(mainloop, &ret) < 0) { printf("pa_mainloop_run() failed."); exit(1); // goto quit } }
/** * Pulsaudio init */ static void pa_init () { int r; int i; if (!pa_sample_spec_valid (&sample_spec)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Wrong Spec\n")); } /* set up main record loop */ if (!(m = pa_mainloop_new ())) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_mainloop_new() failed.\n")); } mainloop_api = pa_mainloop_get_api (m); /* listen to signals */ r = pa_signal_init (mainloop_api); GNUNET_assert (r == 0); pa_signal_new (SIGINT, &exit_signal_callback, NULL); pa_signal_new (SIGTERM, &exit_signal_callback, NULL); /* connect to the main pulseaudio context */ if (!(context = pa_context_new (mainloop_api, "GNUNET VoIP"))) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_context_new() failed.\n")); } pa_context_set_state_callback (context, &context_state_callback, NULL); if (pa_context_connect (context, NULL, 0, NULL) < 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_context_connect() failed: %s\n"), pa_strerror (pa_context_errno (context))); } if (pa_mainloop_run (m, &i) < 0) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("pa_mainloop_run() failed.\n")); } }
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 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 ); }
/* * Create a new pulse audio main loop and connect to the server * * Returns a negative value on error */ static int pulse_connect(struct pulse_data *data) { data->mainloop = pa_mainloop_new(); if (!data->mainloop) { blog(LOG_ERROR, "pulse-input: Unable to create main loop"); return -1; } data->context = pa_context_new_with_proplist( pa_mainloop_get_api(data->mainloop), "OBS Studio", data->props); if (!data->context) { blog(LOG_ERROR, "pulse-input: Unable to create context"); return -1; } int status = pa_context_connect( data->context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); if (status < 0) { blog(LOG_ERROR, "pulse-input: Unable to connect! Status: %d", status); return -1; } // wait until connected for (;;) { pulse_iterate(data); pa_context_state_t state = pa_context_get_state(data->context); if (state == PA_CONTEXT_READY) { blog(LOG_DEBUG, "pulse-input: Context ready"); break; } if (!PA_CONTEXT_IS_GOOD(state)) { blog(LOG_ERROR, "pulse-input: Context connect failed"); return -1; } } return 0; }
int pulse_init(struct pulseaudio_t *pulse) { enum pa_context_state state = PA_CONTEXT_CONNECTING; pulse->mainloop = pa_mainloop_new(); pulse->cxt = pa_context_new(pa_mainloop_get_api(pulse->mainloop), "pavol"); pulse->default_sink = NULL; pulse->muted = 0; pulse->volume = 0; pa_context_set_state_callback(pulse->cxt, pulse_connect_state_cb, &state); pa_context_connect(pulse->cxt, NULL, PA_CONTEXT_NOFLAGS, NULL); while (state != PA_CONTEXT_READY && state != PA_CONTEXT_FAILED) pa_mainloop_iterate(pulse->mainloop, 1, NULL); if (state != PA_CONTEXT_READY) { fprintf(stderr, "failed to connect to pulse daemon: %s\n", pa_strerror(pa_context_errno(pulse->cxt))); return 1; } return 0; }
/* 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 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 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); } }
pa_mainloop_api* pa_threaded_mainloop_get_api(pa_threaded_mainloop*m) { pa_assert(m); return pa_mainloop_get_api(m->real_mainloop); }
MediaRecorder::MediaRecorder(const char * outfile,int width, int height) { audiofailed = false; /* INIT SOUND RECORDING */ debug_samples_out = fopen("audiosamples.s16","wb"); audio_samples_written = 0; pa_context* pactx; pa_mainloop * m = pa_mainloop_new(); m_api = pa_mainloop_get_api(m); pactx = pa_context_new(m_api,"Rec1"); if ( pa_context_connect(pactx,NULL,(pa_context_flags_t)0,NULL) < 0 ) printf("Cannot connect to pulseaudio\n"); int ret; pa_context_set_state_callback(pactx, context_state_callback, this); pa_mainloop_run(m,&ret); std::cout << "Use source: " << monitorsources[defaultsink] << std::endl; static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; pa_context_disconnect(pactx); int error; s = pa_simple_new(NULL,"GLCAP Record",PA_STREAM_RECORD,monitorsources[defaultsink].c_str(), "record", &ss, NULL,NULL , &error); if ( !s ) { printf("Cannot create pa_simple\n"); } run = true; ready = false; firstframe = true; this->width = width; this->height = height; pthread_mutex_init(&encode_mutex,NULL); pthread_mutex_init(&sound_buffer_lock,NULL); pthread_cond_init(&encode_cond,NULL); pthread_create(&encode_thread,NULL,(void*(*)(void*))&MediaRecorder::EncodingThread,this); av_log_set_level(AV_LOG_DEBUG); outCtx = avformat_alloc_context(); outCtx->oformat = av_guess_format(NULL, outfile, NULL); snprintf(outCtx->filename, sizeof(outCtx->filename), "%s", outfile); codec = avcodec_find_encoder(AV_CODEC_ID_MPEG4); acodec = avcodec_find_encoder(AV_CODEC_ID_MP2); ctx = avcodec_alloc_context3(codec); actx = avcodec_alloc_context3(acodec); avcodec_get_context_defaults3(actx,acodec); avcodec_get_context_defaults3(ctx,codec); ctx->width = width; ctx->height = height; ctx->bit_rate = 6000*1000; std::cout << ctx->time_base.den << " " << ctx->time_base.num << std::endl; ctx->time_base.den = TIMEBASE; ctx->time_base.num = 1; ctx->thread_count = 4; ctx->qmin = 2; ctx->qmax = 31; ctx->b_sensitivity = 100; ctx->gop_size = 1; ctx->me_method = 1; ctx->global_quality = 100; ctx->lowres = 0; ctx->bit_rate_tolerance = 200000; actx->sample_fmt = AV_SAMPLE_FMT_S16; actx->sample_rate = 44100; actx->channels = 2; actx->time_base.den = 44100; actx->time_base.num = 1; actx->bit_rate = 128000; actx->frame_size = 8192; actx->channel_layout = 3; /* ctx->compression_level = 0; ctx->trellis = 0; ctx->gop_size = 1; /* emit one intra frame every ten frames */ /*ctx->me_pre_cmp = 0; ctx->me_cmp = 0; ctx->me_sub_cmp = 0; ctx->mb_cmp = 2; ctx->pre_dia_size = 0; ctx->dia_size = 1; ctx->quantizer_noise_shaping = 0; // qns=0 ctx->noise_reduction = 0; // nr=0 ctx->mb_decision = 0; // mbd=0 ("realtime" encoding) ctx->flags &= ~CODEC_FLAG_QPEL; ctx->flags &= ~CODEC_FLAG_4MV; ctx->trellis = 0; ctx->flags &= ~CODEC_FLAG_CBP_RD; ctx->flags &= ~CODEC_FLAG_QP_RD; ctx->flags &= ~CODEC_FLAG_MV0;*/ //ctx->s ctx->pix_fmt = PIX_FMT_YUV420P; if (avcodec_open2(ctx, codec, NULL) < 0) { fprintf(stderr, "Could not open codec\n"); } if (avcodec_open2(actx, acodec, NULL) < 0) { fprintf(stderr, "Could not open audio codec\n"); audiofailed = true; } printf("frame_size: %d\n",actx->frame_size); pthread_create(&record_sound_thread,NULL,(void*(*)(void*))&MediaRecorder::RecordingThread,this); AVStream* s = av_new_stream(outCtx,0); s->codec = ctx; s->r_frame_rate.den = TIMEBASE; s->r_frame_rate.num = 1; if (!audiofailed ) { AVStream* as = av_new_stream(outCtx,1); as->codec = actx; as->r_frame_rate.den = 44100; as->r_frame_rate.num = 1; } picture = alloc_picture(PIX_FMT_YUV420P, ctx->width, ctx->height); if (!picture) { fprintf(stderr, "Could not allocate picture\n"); exit(1); } tmp_picture = NULL; tmp_picture = alloc_picture(PIX_FMT_RGBA, ctx->width, ctx->height); if (!tmp_picture) { fprintf(stderr, "Could not allocate temporary picture\n"); exit(1); } img_convert_ctx = sws_getContext(ctx->width, ctx->height, PIX_FMT_RGBA, ctx->width, ctx->height, PIX_FMT_YUV420P, SWS_FAST_BILINEAR , NULL, NULL, NULL); if (img_convert_ctx == NULL) { fprintf(stderr, "Cannot initialize the conversion context\n"); exit(1); } av_dump_format(outCtx, 0, outfile, 1); avio_open2(&outCtx->pb, outfile, AVIO_FLAG_WRITE,NULL,NULL); avformat_write_header(outCtx,NULL); } MediaRecorder::~MediaRecorder() { run = false; ready = false; pthread_cond_broadcast(&encode_cond); printf("Joining thread..\n"); pthread_join(encode_thread,NULL); printf("Joining recording thread..\n"); pthread_join(record_sound_thread,NULL); printf("Done\n"); av_write_trailer(outCtx); av_free(picture); avformat_free_context(outCtx); pa_simple_free(s); fclose(debug_samples_out); } int fcount = 0; void MediaRecorder::AppendFrame(float time, int width, int height, char* data) { if ( !ready ) return ; printf("AppendFrame\n"); this->time = getcurrenttime2(); if ( firstframe ) { starttime = getcurrenttime2(); firstframe = false; } this->height = height; this->width = width; m_data = data; ready = false; pthread_cond_broadcast(&encode_cond); /*int i = 0; unsigned int numpixels = width * height; unsigned int ui = numpixels; unsigned int vi = numpixels + numpixels / 4; for ( int j = 0; j < height; j++ ) { for ( int k = 0; k < width; k++ ) { int sR = data[i*4+0]; int sG = data[i*4+1]; int sB = data[i*4+2]; picture->data[0][i] = ( (66*sR + 129*sG + 25*sB + 128) >> 8) + 16; if (0 == j%2 && 0 == k%2) { picture->data[0][ui++] = ( (-38*sR - 74*sG + 112*sB + 128) >> 8) + 128; picture->data[0][vi++] = ( (112*sR - 94*sG - 18*sB + 128) >> 8) + 128; } i++; } }*/ // printf("End flip %f\n",(float)getcurrenttime2()); //memcpy(tmp_picture->data[0],data,width*height*4); } void MediaRecorder::EncodingThread() { while ( run ) { printf("Encode thread ready\n"); ready = true; pthread_cond_wait(&encode_cond,&encode_mutex); if (!run) { printf("Encoding finished\n"); break; } for ( int y = 0; y < height; y++ ) { /*for ( int x = 0; x < width; x++ ) {*/ char r,g,b; int oldindex = (y*width); int newindex = ((height-1-y)*width); memcpy(&tmp_picture->data[0][(newindex)*4],&m_data[oldindex*4],width*4); /* r = data[oldindex*4+0]; g = data[oldindex*4+1]; b = data[oldindex*4+2]; tmp_picture->data[0][(newindex)*4+0] = r; tmp_picture->data[0][(newindex)*4+1] = g; tmp_picture->data[0][(newindex)*4+2] = b; */ // } } sws_scale(img_convert_ctx,tmp_picture->data,tmp_picture->linesize,0,height,picture->data,picture->linesize); AVPacket p; av_init_packet(&p); p.data = NULL; p.size = 0; picture->pts = int64_t((time-starttime)*TIMEBASE); uint64_t vpts = picture->pts; // picture->pts = time*30.0; int got_frame; printf("%p %p\n",ctx, picture); if(avcodec_encode_video2(ctx, &p, picture, &got_frame) < 0) return; if(got_frame) { // outContainer is "mp4" p.pts = vpts; p.dts = AV_NOPTS_VALUE; av_write_frame(outCtx, &p); av_free_packet(&p); } //sleep(1); printf("End enc frame %f, pts %lld\n",(float)getcurrenttime2(),picture->pts); AVFrame * aframe = avcodec_alloc_frame(); bool unlocked = false; while ( sound_buffers.size() > 0 ) { uint64_t apts = audio_samples_written; /* if ( apts > vpts ) break;*/ pthread_mutex_lock(&sound_buffer_lock); short * buf = sound_buffers.front(); sound_buffers.pop_front(); pthread_mutex_unlock(&sound_buffer_lock); if (!audiofailed ) { unlocked = true; aframe->nb_samples = actx->frame_size; aframe->channel_layout = actx->channel_layout; aframe->format = AV_SAMPLE_FMT_S16; aframe->channels = actx->channels; avcodec_fill_audio_frame(aframe,actx->channels,AV_SAMPLE_FMT_S16,(char*)buf,actx->frame_size*2*2,0); // avcodec_fill_audio_frame(aframe,actx->channels,actx->sample_fmt,(char*)buf,actx->frame_size*2,0); printf("sound_buffers.size() = %d\n",sound_buffers.size()); av_init_packet(&p); p.data = NULL; p.size = 0; avcodec_encode_audio2(actx,&p,aframe,&got_frame); if ( got_frame ) { p.stream_index = 1; p.flags |= AV_PKT_FLAG_KEY; av_write_frame(outCtx,&p); av_free_packet(&p); } audio_samples_written += actx->frame_size;//samples/2 each channel } //printf("Consumed 1024 samples\n"); delete[] buf; } /* if ( !unlocked ) pthread_mutex_unlock(&sound_buffer_lock);*/ avcodec_free_frame(&aframe); } } bool MediaRecorder::isReady() { return ready; }
struct pulse_conn_t *pulse_conn_open(const char *name, amp_audio_f func, void *arg, const struct pulse_conf_t *conf) { int err; unsigned int i; pthread_attr_t attr; struct sched_param param; struct pulse_conn_t *conn; conn = malloc(sizeof(struct pulse_conn_t)); conn->quit = 0; conn->width = (conf->in > conf->out) ? conf->in : conf->out; conn->lat = conf->rate * (conf->lat / 1000.0f); conn->conf = *conf; conn->func = func; conn->arg = arg; conn->rd = 0; conn->wr = conn->lat; conn->startup = 2; conn->reset[0] = conn->reset[1] = 1; conn->nrd = conn->nwr = conf->rate; //printf("width: %u\n", conn->width); conn->buf = malloc(conn->width * sizeof(void *)); for(i = 0; i < conn->width; i++) memset(conn->buf[i] = malloc(2 * conn->lat * sizeof(float)), 0x00, 2 * conn->lat * sizeof(float)); if(pipe(conn->pipe) < 0) fprintf(stderr, "Cannot create pipe."), exit(1); conn->loop = pa_mainloop_new(); conn->api = pa_mainloop_get_api(conn->loop); pa_mainloop_set_poll_func(conn->loop, conn_poll, conn); conn->context = pa_context_new(conn->api, name); pa_context_set_state_callback(conn->context, conn_state, conn); pa_context_connect(conn->context, NULL, 0, NULL); err = pthread_attr_init(&attr); if(err != 0) fprintf(stderr, "Failed to initialize thread attributes. %s.", strerror(err)), exit(1); err = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); if(err != 0) fprintf(stderr, "Failed to set schedular inheritance. %s.", strerror(err)), exit(1); err = pthread_attr_setschedpolicy(&attr, SCHED_FIFO); if(err != 0) fprintf(stderr, "Failed to set schedular policy. %s.", strerror(err)), exit(1); param.sched_priority = 99; err = pthread_attr_setschedparam(&attr, ¶m); if(err != 0) fprintf(stderr, "Failed to set schedular parameter. %s.", strerror(err)), exit(1); err = pthread_create(&conn->thread, &attr, conn_thread, conn); if(err != 0) { err = pthread_create(&conn->thread, NULL, conn_thread, conn); if(err != 0) fprintf(stderr, "Failed to start thread. %s.", strerror(err)), exit(1); } pthread_attr_destroy(&attr); if(err != 0) fprintf(stderr, "Failed to destroy thread attributes. %s.", strerror(err)), exit(1); return conn; }
int PulseAudioDriver::setup(bool capture, bool playback, const QString& ) { PENTER; sample_spec.rate = frame_rate; sample_spec.channels = 2; sample_spec.format = PA_SAMPLE_FLOAT32NE; assert(pa_sample_spec_valid(&sample_spec)); if (channel_map_set && channel_map.channels != sample_spec.channels) { fprintf(stderr, "Channel map doesn't match file.\n"); return -1; } /* Set up a new main loop */ if (!(mainloop = pa_mainloop_new())) { fprintf(stderr, "pa_mainloop_new() failed.\n"); return -1; } mainloop_api = pa_mainloop_get_api(mainloop); int r = pa_signal_init(mainloop_api); assert(r == 0); /* Create a new connection context */ if (!(context = pa_context_new(mainloop_api, "Traverso"))) { fprintf(stderr, "pa_context_new() failed.\n"); return -1; } pa_context_set_state_callback(context, context_state_callback, this); /* Connect the context */ pa_context_connect(context, "", (pa_context_flags_t)0, NULL); int ret; /* Run the main loop */ // if (pa_mainloop_run(mainloop, &ret) < 0) { // fprintf(stderr, "pa_mainloop_run() failed.\n"); // return -1; // } AudioChannel* audiochannel; int port_flags; char buf[32]; // TODO use the found maxchannel count for the playback stream, instead of assuming 2 !! for (int chn = 0; chn < 2; chn++) { snprintf (buf, sizeof(buf) - 1, "playback_%d", chn+1); audiochannel = device->register_playback_channel(buf, "32 bit float audio", port_flags, frames_per_cycle, chn); audiochannel->set_latency( frames_per_cycle + capture_frame_latency ); playbackChannels.append(audiochannel); } // TODO use the found maxchannel count for the capture stream, instead of assuming 0 !! for (int chn = 0; chn < 2; chn++) { snprintf (buf, sizeof(buf) - 1, "capture_%d", chn+1); audiochannel = device->register_capture_channel(buf, "32 bit float audio", port_flags, frames_per_cycle, chn); audiochannel->set_latency( frames_per_cycle + capture_frame_latency ); captureChannels.append(audiochannel); } return 1; }
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; }