pa_simple* pa_simple_new_proplist( const char *server, const char *name, pa_stream_direction_t dir, const char *dev, const char *stream_name, const pa_sample_spec *ss, const pa_channel_map *map, const pa_buffer_attr *attr, pa_proplist *proplist, int *rerror) { pa_simple *p; int error = PA_ERR_INTERNAL, r; CHECK_VALIDITY_RETURN_ANY(rerror, !server || *server, PA_ERR_INVALID, NULL); CHECK_VALIDITY_RETURN_ANY(rerror, dir == PA_STREAM_PLAYBACK || dir == PA_STREAM_RECORD, PA_ERR_INVALID, NULL); CHECK_VALIDITY_RETURN_ANY(rerror, !dev || *dev, PA_ERR_INVALID, NULL); CHECK_VALIDITY_RETURN_ANY(rerror, ss && pa_sample_spec_valid(ss), PA_ERR_INVALID, NULL); CHECK_VALIDITY_RETURN_ANY(rerror, !map || (pa_channel_map_valid(map) && map->channels == ss->channels), PA_ERR_INVALID, NULL) p = pa_xnew0(pa_simple, 1); p->direction = dir; if (!(p->mainloop = pa_threaded_mainloop_new())) goto fail; if (!(p->context = pa_context_new(pa_threaded_mainloop_get_api(p->mainloop), name))) goto fail; pa_context_set_state_callback(p->context, context_state_cb, p); if (pa_context_connect(p->context, server, 0, NULL) < 0) { error = pa_context_errno(p->context); goto fail; } pa_threaded_mainloop_lock(p->mainloop); if (pa_threaded_mainloop_start(p->mainloop) < 0) goto unlock_and_fail; for (;;) { pa_context_state_t state; state = pa_context_get_state(p->context); if (state == PA_CONTEXT_READY) break; if (!PA_CONTEXT_IS_GOOD(state)) { error = pa_context_errno(p->context); goto unlock_and_fail; } /* Wait until the context is ready */ pa_threaded_mainloop_wait(p->mainloop); } if (!(p->stream = pa_stream_new_with_proplist(p->context, stream_name, ss, map, proplist))) { error = pa_context_errno(p->context); goto unlock_and_fail; } pa_stream_set_state_callback(p->stream, stream_state_cb, p); pa_stream_set_read_callback(p->stream, stream_request_cb, p); pa_stream_set_write_callback(p->stream, stream_request_cb, p); pa_stream_set_latency_update_callback(p->stream, stream_latency_update_cb, p); if (dir == PA_STREAM_PLAYBACK) r = pa_stream_connect_playback(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING |PA_STREAM_ADJUST_LATENCY |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL); else r = pa_stream_connect_record(p->stream, dev, attr, PA_STREAM_INTERPOLATE_TIMING |PA_STREAM_ADJUST_LATENCY |PA_STREAM_AUTO_TIMING_UPDATE |PA_STREAM_START_CORKED); if (r < 0) { error = pa_context_errno(p->context); goto unlock_and_fail; } for (;;) { pa_stream_state_t state; state = pa_stream_get_state(p->stream); if (state == PA_STREAM_READY) break; if (!PA_STREAM_IS_GOOD(state)) { error = pa_context_errno(p->context); goto unlock_and_fail; } /* Wait until the stream is ready */ pa_threaded_mainloop_wait(p->mainloop); } pa_threaded_mainloop_unlock(p->mainloop); return p; unlock_and_fail: pa_threaded_mainloop_unlock(p->mainloop); fail: if (rerror) *rerror = error; pa_simple_free(p); return NULL; }
static int pa_init_boilerplate(struct ao *ao) { struct priv *priv = ao->priv; char *host = priv->cfg_host && priv->cfg_host[0] ? priv->cfg_host : NULL; bool locked = false; pthread_mutex_init(&priv->wakeup_lock, NULL); pthread_cond_init(&priv->wakeup, NULL); if (!(priv->mainloop = pa_threaded_mainloop_new())) { MP_ERR(ao, "Failed to allocate main loop\n"); goto fail; } if (pa_threaded_mainloop_start(priv->mainloop) < 0) goto fail; pa_threaded_mainloop_lock(priv->mainloop); locked = true; if (!(priv->context = pa_context_new(pa_threaded_mainloop_get_api( priv->mainloop), ao->client_name))) { MP_ERR(ao, "Failed to allocate context\n"); goto fail; } MP_VERBOSE(ao, "Library version: %s\n", pa_get_library_version()); MP_VERBOSE(ao, "Proto: %lu\n", (long)pa_context_get_protocol_version(priv->context)); MP_VERBOSE(ao, "Server proto: %lu\n", (long)pa_context_get_server_protocol_version(priv->context)); pa_context_set_state_callback(priv->context, context_state_cb, ao); pa_context_set_subscribe_callback(priv->context, subscribe_cb, ao); if (pa_context_connect(priv->context, host, 0, NULL) < 0) goto fail; /* Wait until the context is ready */ while (1) { int state = pa_context_get_state(priv->context); if (state == PA_CONTEXT_READY) break; if (!PA_CONTEXT_IS_GOOD(state)) goto fail; pa_threaded_mainloop_wait(priv->mainloop); } pa_threaded_mainloop_unlock(priv->mainloop); return 0; fail: if (locked) pa_threaded_mainloop_unlock(priv->mainloop); if (priv->context) { pa_threaded_mainloop_lock(priv->mainloop); if (!(pa_context_errno(priv->context) == PA_ERR_CONNECTIONREFUSED && ao->probing)) GENERIC_ERR_MSG("Init failed"); pa_threaded_mainloop_unlock(priv->mainloop); } uninit(ao); return -1; }
bool AudioOutputPulseAudio::ContextConnect(void) { QString fn_log_tag = "ContextConnect, "; if (pcontext) { VBERROR(fn_log_tag + "context appears to exist, but shouldn't (yet)"); pa_context_unref(pcontext); pcontext = NULL; return false; } pa_proplist *proplist = pa_proplist_new(); if (!proplist) { VBERROR(fn_log_tag + QString("failed to create new proplist")); return false; } pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "MythTV"); pa_proplist_sets(proplist, PA_PROP_APPLICATION_ICON_NAME, "mythtv"); pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "video"); pcontext = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(mainloop), "MythTV", proplist); if (!pcontext) { VBERROR(fn_log_tag + "failed to acquire new context"); return false; } pa_context_set_state_callback(pcontext, ContextStateCallback, this); char *pulse_host = ChooseHost(); int chk = pa_context_connect( pcontext, pulse_host, (pa_context_flags_t)0, NULL); delete[] pulse_host; if (chk < 0) { VBERROR(fn_log_tag + QString("context connect failed: %1") .arg(pa_strerror(pa_context_errno(pcontext)))); return false; } bool connected = false; pa_context_state_t state = pa_context_get_state(pcontext); for (; !connected; state = pa_context_get_state(pcontext)) { switch(state) { case PA_CONTEXT_READY: VBAUDIO(fn_log_tag +"context connection ready"); connected = true; continue; case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: VBERROR(fn_log_tag + QString("context connection failed or terminated: %1") .arg(pa_strerror(pa_context_errno(pcontext)))); return false; default: VBAUDIO(fn_log_tag + "waiting for context connection ready"); pa_threaded_mainloop_wait(mainloop); break; } } pa_operation *op = pa_context_get_server_info(pcontext, ServerInfoCallback, this); if (op) pa_operation_unref(op); else VBERROR(fn_log_tag + "failed to get PulseAudio server info"); return true; }
/** * Initializes the PulseAudio main loop and connects to the PulseAudio server. * @return a PulseAudio context on success, or NULL on error */ pa_context *vlc_pa_connect (vlc_object_t *obj, pa_threaded_mainloop **mlp) { msg_Dbg (obj, "using library version %s", pa_get_library_version ()); msg_Dbg (obj, " (compiled with version %s, protocol %u)", pa_get_headers_version (), PA_PROTOCOL_VERSION); /* Initialize main loop */ pa_threaded_mainloop *mainloop = pa_threaded_mainloop_new (); if (unlikely(mainloop == NULL)) return NULL; if (pa_threaded_mainloop_start (mainloop) < 0) { pa_threaded_mainloop_free (mainloop); return NULL; } /* Fill in context (client) properties */ char *ua = var_InheritString (obj, "user-agent"); pa_proplist *props = pa_proplist_new (); if (likely(props != NULL)) { pa_proplist_sets (props, PA_PROP_APPLICATION_NAME, ua); pa_proplist_sets (props, PA_PROP_APPLICATION_ID, "org.VideoLAN.VLC"); pa_proplist_sets (props, PA_PROP_APPLICATION_VERSION, PACKAGE_VERSION); pa_proplist_sets (props, PA_PROP_APPLICATION_ICON_NAME, PACKAGE_NAME); //pa_proplist_sets (props, PA_PROP_APPLICATION_LANGUAGE, _("C")); pa_proplist_sets (props, PA_PROP_APPLICATION_LANGUAGE, setlocale (LC_MESSAGES, NULL)); pa_proplist_setf (props, PA_PROP_APPLICATION_PROCESS_ID, "%lu", (unsigned long) getpid ()); //pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_BINARY, // PACKAGE_NAME); for (size_t max = sysconf (_SC_GETPW_R_SIZE_MAX), len = max % 1024 + 1024; len < max; len += 1024) { struct passwd pwbuf, *pw; char buf[len]; if (getpwuid_r (getuid (), &pwbuf, buf, sizeof (buf), &pw) == 0 && pw != NULL) pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_USER, pw->pw_name); } for (size_t max = sysconf (_SC_HOST_NAME_MAX), len = max % 1024 + 1024; len < max; len += 1024) { char hostname[len]; if (gethostname (hostname, sizeof (hostname)) == 0) pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_HOST, hostname); } const char *session = getenv ("XDG_SESSION_COOKIE"); if (session != NULL) { pa_proplist_setf (props, PA_PROP_APPLICATION_PROCESS_MACHINE_ID, "%.32s", session); /* XXX: is this valid? */ pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_SESSION_ID, session); } } /* Connect to PulseAudio daemon */ pa_context *ctx; pa_mainloop_api *api; pa_threaded_mainloop_lock (mainloop); api = pa_threaded_mainloop_get_api (mainloop); ctx = pa_context_new_with_proplist (api, ua, props); free (ua); if (props != NULL) pa_proplist_free (props); if (unlikely(ctx == NULL)) goto fail; pa_context_set_state_callback (ctx, context_state_cb, mainloop); pa_context_set_event_callback (ctx, context_event_cb, obj); if (pa_context_connect (ctx, NULL, 0, NULL) < 0 || context_wait (ctx, mainloop)) { vlc_pa_error (obj, "PulseAudio server connection failure", ctx); pa_context_unref (ctx); goto fail; } msg_Dbg (obj, "connected %s to %s as client #%"PRIu32, pa_context_is_local (ctx) ? "locally" : "remotely", pa_context_get_server (ctx), pa_context_get_index (ctx)); msg_Dbg (obj, "using protocol %"PRIu32", server protocol %"PRIu32, pa_context_get_protocol_version (ctx), pa_context_get_server_protocol_version (ctx)); pa_threaded_mainloop_unlock (mainloop); *mlp = mainloop; return ctx; fail: pa_threaded_mainloop_unlock (mainloop); pa_threaded_mainloop_stop (mainloop); pa_threaded_mainloop_free (mainloop); return NULL; }
int force_volume(char* source_name, pa_volume_t desired_volume) { // Create a mainloop pa_mainloop* pa_ml = pa_mainloop_new(); pa_mainloop_api* pa_mlapi = pa_mainloop_get_api(pa_ml); // Establish PA context pa_context* pa_ctx = pa_context_new(pa_mlapi, "uneven"); pa_context_connect(pa_ctx, NULL, 0, NULL); // Set up PA state callback int pa_state = 0; pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_state); // Set up event subscription int state = 0; pa_context_set_subscribe_callback(pa_ctx, source_state_cb, &state); // Prepare loop variables pa_operation* pending_op = NULL; pa_cvolume current_volume = {0, {0}}; int do_update; int i; // Iterate PA mainloop until we're done or the context enters an error state while (done == -1 && pa_state != 2) { pa_mainloop_iterate(pa_ml, 1, NULL); // Can't do anything unless PA is ready if (pa_state == 1) { // Wait for any pending operation to complete if (!pending_op || (pending_op && pa_operation_get_state(pending_op) == PA_OPERATION_DONE)) { if (pending_op) { pa_operation_unref(pending_op); pending_op = NULL; } switch (state) { case 0: // Subscribe to source events pending_op = pa_context_subscribe(pa_ctx, PA_SUBSCRIPTION_MASK_SOURCE, NULL, NULL); state = 2; break; case 1: // Idle break; case 2: // Source change detected, retrive volume information pending_op = pa_context_get_source_info_by_name(pa_ctx, source_name, get_volume_cb, ¤t_volume); state++; break; case 3: // Check channel volumes and reset if required do_update = 0; for (i = 0; i < current_volume.channels; i++) { if (current_volume.values[i] != desired_volume) { do_update = 1; current_volume.values[i] = desired_volume; } } if (do_update) { pending_op = pa_context_set_source_volume_by_name(pa_ctx, source_name, ¤t_volume, NULL, NULL); } state = 1; break; default: fprintf(stderr, "in state %d\n", state); done = 2; } } } } // Clean up pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return done; }
int main(int argc, char *argv[]) { if (argc != 3) { printf("usage: %s property value\n property: pulseaudio sink-input property (ex:application.name)\n value: the value for the wanted property (ex: \"Quod Libet\")\n", argv[0]); return -1; } pa_mainloop* pa_ml; pa_mainloop_api* pa_mlapi; pa_context* pa_ctx; pa_operation* pa_op; 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, "my_context"); pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, 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_sink_input_info_list(pa_ctx, pa_sink_input_info_cb, (void*)argv); state++; break; case 1: if (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) { //printf("PA_OPERATION_RUNNING\n"); } if (pa_operation_get_state(pa_op) == PA_OPERATION_DONE) { // clean 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; } pa_mainloop_iterate(pa_ml, 1, NULL); } printf("we should not be here...\n"); return -1; }
bool Init() { int ret = 0; mPMainLoop = pa_threaded_mainloop_new(); pa_mainloop_api *mlapi = pa_threaded_mainloop_get_api(mPMainLoop); mPContext = pa_context_new (mlapi, "USBqemu-pulse"); ret = pa_context_connect (mPContext, mServer, PA_CONTEXT_NOFLAGS, NULL ); OSDebugOut("pa_context_connect %s\n", pa_strerror(ret)); if (ret != PA_OK) goto error; pa_context_set_state_callback(mPContext, pa_context_state_cb, &mPAready ); pa_threaded_mainloop_start(mPMainLoop); // wait for pa_context_state_cb for(;;) { if(mPAready == 1) break; if(mPAready == 2 || mQuit) goto error; } mStream = pa_stream_new(mPContext, "USBqemu-pulse", &mSSpec, NULL ); pa_stream_set_read_callback(mStream, stream_read_cb, this ); // Sets individual read callback fragsize but recording itself // still "lags" ~1sec (read_cb is called in bursts) without // PA_STREAM_ADJUST_LATENCY pa_buffer_attr buffer_attr; buffer_attr.maxlength = (uint32_t) -1; buffer_attr.tlength = (uint32_t) -1; buffer_attr.prebuf = (uint32_t) -1; buffer_attr.minreq = (uint32_t) -1; buffer_attr.fragsize = pa_usec_to_bytes(mBuffering * 1000, &mSSpec); OSDebugOut("usec_to_bytes %zu\n", buffer_attr.fragsize); ret = pa_stream_connect_record(mStream, mDevice.c_str(), &buffer_attr, PA_STREAM_ADJUST_LATENCY ); OSDebugOut("pa_stream_connect_record %s\n", pa_strerror(ret)); if (ret != PA_OK) goto error; // Setup resampler if (mResampler) mResampler = src_delete(mResampler); mResampler = src_new(SRC_SINC_FASTEST, mSSpec.channels, &ret); if (!mResampler) { OSDebugOut("Failed to create resampler: error %08X\n", ret); goto error; } mLastGetBuffer = hrc::now(); return true; error: Uninit(); return false; }
int soundio_pulseaudio_init(SoundIoPrivate *si) { SoundIo *soundio = &si->pub; SoundIoPulseAudio *sipa = &si->backend_data.pulseaudio; sipa->device_scan_queued = true; sipa->main_loop = pa_threaded_mainloop_new(); if (!sipa->main_loop) { destroy_pa(si); return SoundIoErrorNoMem; } pa_mainloop_api *main_loop_api = pa_threaded_mainloop_get_api(sipa->main_loop); sipa->props = pa_proplist_new(); if (!sipa->props) { destroy_pa(si); return SoundIoErrorNoMem; } sipa->pulse_context = pa_context_new_with_proplist(main_loop_api, soundio->app_name, sipa->props); if (!sipa->pulse_context) { destroy_pa(si); return SoundIoErrorNoMem; } pa_context_set_subscribe_callback(sipa->pulse_context, subscribe_callback, si); pa_context_set_state_callback(sipa->pulse_context, context_state_callback, si); int err = pa_context_connect(sipa->pulse_context, NULL, (pa_context_flags_t)0, NULL); if (err) { destroy_pa(si); return SoundIoErrorInitAudioBackend; } if (pa_threaded_mainloop_start(sipa->main_loop)) { destroy_pa(si); return SoundIoErrorNoMem; } pa_threaded_mainloop_lock(sipa->main_loop); // block until ready while (!sipa->ready_flag) pa_threaded_mainloop_wait(sipa->main_loop); if (sipa->connection_err) { pa_threaded_mainloop_unlock(sipa->main_loop); destroy_pa(si); return sipa->connection_err; } if ((err = subscribe_to_events(si))) { pa_threaded_mainloop_unlock(sipa->main_loop); destroy_pa(si); return err; } pa_threaded_mainloop_unlock(sipa->main_loop); si->destroy = destroy_pa; si->flush_events = flush_events_pa; si->wait_events = wait_events_pa; si->wakeup = wakeup_pa; si->force_device_scan = force_device_scan_pa; si->outstream_open = outstream_open_pa; si->outstream_destroy = outstream_destroy_pa; si->outstream_start = outstream_start_pa; si->outstream_begin_write = outstream_begin_write_pa; si->outstream_end_write = outstream_end_write_pa; si->outstream_clear_buffer = outstream_clear_buffer_pa; si->outstream_pause = outstream_pause_pa; si->outstream_get_latency = outstream_get_latency_pa; si->instream_open = instream_open_pa; si->instream_destroy = instream_destroy_pa; si->instream_start = instream_start_pa; si->instream_begin_read = instream_begin_read_pa; si->instream_end_read = instream_end_read_pa; si->instream_pause = instream_pause_pa; si->instream_get_latency = instream_get_latency_pa; return 0; }
void quisk_start_sound_pulseaudio(struct sound_dev **pCapture, struct sound_dev **pPlayback) { int num_pa_devices = 0; int i; //sorted lists of local and remote devices struct sound_dev *LocalPulseDevices[PA_LIST_SIZE] = {NULL}; struct sound_dev *RemotePulseDevices[PA_LIST_SIZE] = {NULL}; sort_devices(pCapture, LocalPulseDevices, RemotePulseDevices); sort_devices(pPlayback, LocalPulseDevices, RemotePulseDevices); if (!RemotePulseDevices[0] && !LocalPulseDevices[0]) { if (quisk_sound_state.verbose_pulse) printf("No pulseaudio devices to open!\n"); return; //nothing to open. No need to start the mainloop. } // Create a mainloop API pa_ml = pa_threaded_mainloop_new(); pa_mlapi = pa_threaded_mainloop_get_api(pa_ml); assert(pa_signal_init(pa_mlapi) == 0); if (pa_threaded_mainloop_start(pa_ml) < 0) { printf("pa_mainloop_run() failed."); exit(1); } else printf("Pulseaudio threaded mainloop started\n"); pa_threaded_mainloop_lock(pa_ml); if (RemotePulseDevices[0]) { //we've got at least 1 remote device pa_IQ_ctx = pa_context_new(pa_mlapi, "Quisk-remote"); if (pa_context_connect(pa_IQ_ctx, quisk_sound_state.IQ_server, 0, NULL) < 0) printf("Failed to connect to remote Pulseaudio server\n"); pa_context_set_state_callback(pa_IQ_ctx, state_cb, RemotePulseDevices); //send a list of remote devices to open } if (LocalPulseDevices[0]) { //we've got at least 1 local device pa_ctx = pa_context_new(pa_mlapi, "Quisk-local"); if (pa_context_connect(pa_ctx, NULL, 0, NULL) < 0) printf("Failed to connect to local Pulseaudio server\n"); pa_context_set_state_callback(pa_ctx, state_cb, LocalPulseDevices); } pa_threaded_mainloop_unlock(pa_ml); for(i=0; LocalPulseDevices[i]; i++) { num_pa_devices++; } for(i=0; RemotePulseDevices[i]; i++) { num_pa_devices++; } if (quisk_sound_state.verbose_pulse) printf("Waiting for %d streams to start\n", num_pa_devices); while (streams_ready < num_pa_devices); // wait for all the devices to open if (quisk_sound_state.verbose_pulse) printf("All streams started\n"); }
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; }
struct audio_service* audio_service_create() { struct audio_service *service; LSError error; pa_mainloop_api *mainloop_api; char name[100]; service = g_try_new0(struct audio_service, 1); if (!service) return NULL; LSErrorInit(&error); if (!LSRegisterPubPriv("org.webosports.audio", &service->handle, false, &error)) { g_warning("Failed to register the luna service: %s", error.message); LSErrorFree(&error); goto error; } if (!LSRegisterCategory(service->handle, "/", audio_service_methods, NULL, NULL, &error)) { g_warning("Could not register service category: %s", error.message); LSErrorFree(&error); goto error; } if (!LSCategorySetData(service->handle, "/", service, &error)) { g_warning("Could not set daa for service category: %s", error.message); LSErrorFree(&error); goto error; } if (!LSGmainAttach(service->handle, event_loop, &error)) { g_warning("Could not attach service handle to mainloop: %s", error.message); LSErrorFree(&error); goto error; } service->pa_mainloop = pa_glib_mainloop_new(g_main_context_default()); mainloop_api = pa_glib_mainloop_get_api(service->pa_mainloop); snprintf(name, 100, "AudioServiceContext:%i", getpid()); service->context = pa_context_new(mainloop_api, name); service->context_initialized = false; pa_context_set_state_callback(service->context, context_state_cb, service); if (pa_context_connect(service->context, NULL, 0, NULL) < 0) { g_warning("Failed to connect to PulseAudio"); pa_context_unref(service->context); pa_glib_mainloop_free(service->pa_mainloop); goto error; } sample_list = g_slist_alloc(); return service; error: if (service->handle != NULL) { LSUnregister(service->handle, &error); LSErrorFree(&error); } g_free(service); return NULL; }
/***************************************************************************** * Open: open the audio device *****************************************************************************/ static int Open ( vlc_object_t *p_this ) { aout_instance_t *p_aout = (aout_instance_t *)p_this; struct aout_sys_t * p_sys; struct pa_sample_spec ss; const struct pa_buffer_attr *buffer_attr; struct pa_buffer_attr a; struct pa_channel_map map; /* Allocate structures */ p_aout->output.p_sys = p_sys = calloc( 1, sizeof( aout_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; PULSE_DEBUG( "Pulse start initialization"); ss.channels = aout_FormatNbChannels( &p_aout->output.output ); /* Get the input stream channel count */ /* Setup the pulse audio stream based on the input stream count */ switch(ss.channels) { case 8: p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_MIDDLELEFT | AOUT_CHAN_MIDDLERIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; break; case 6: p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE; break; case 4: p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT; break; case 2: p_aout->output.output.i_physical_channels = AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT; break; case 1: p_aout->output.output.i_physical_channels = AOUT_CHAN_CENTER; break; default: msg_Err(p_aout,"Invalid number of channels"); goto fail; } /* Add a quick command line info message */ msg_Dbg(p_aout, "%d audio channels", ss.channels); ss.rate = p_aout->output.output.i_rate; if (HAVE_FPU) { ss.format = PA_SAMPLE_FLOAT32NE; p_aout->output.output.i_format = VLC_CODEC_FL32; } else { ss.format = PA_SAMPLE_S16NE; p_aout->output.output.i_format = VLC_CODEC_S16N; } if (!pa_sample_spec_valid(&ss)) { msg_Err(p_aout,"Invalid sample spec"); goto fail; } /* Reduce overall latency to 200mS to reduce audible clicks * Also pulse minreq and internal buffers are now 20mS which reduces resampling */ a.tlength = pa_bytes_per_second(&ss)/5; a.maxlength = a.tlength * 2; a.prebuf = a.tlength / 2; a.minreq = a.tlength / 10; /* Buffer size is 20mS */ p_sys->buffer_size = a.minreq; /* Initialise the speaker map setup above */ pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); if (!(p_sys->mainloop = pa_threaded_mainloop_new())) { msg_Err(p_aout, "Failed to allocate main loop"); goto fail; } if (!(p_sys->context = pa_context_new(pa_threaded_mainloop_get_api(p_sys->mainloop), _( PULSE_CLIENT_NAME )))) { msg_Err(p_aout, "Failed to allocate context"); goto fail; } pa_context_set_state_callback(p_sys->context, context_state_cb, p_aout); PULSE_DEBUG( "Pulse before context connect"); if (pa_context_connect(p_sys->context, NULL, 0, NULL) < 0) { msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context))); goto fail; } PULSE_DEBUG( "Pulse after context connect"); pa_threaded_mainloop_lock(p_sys->mainloop); if (pa_threaded_mainloop_start(p_sys->mainloop) < 0) { msg_Err(p_aout, "Failed to start main loop"); goto unlock_and_fail; } msg_Dbg(p_aout, "Pulse mainloop started"); /* Wait until the context is ready */ pa_threaded_mainloop_wait(p_sys->mainloop); if (pa_context_get_state(p_sys->context) != PA_CONTEXT_READY) { msg_Dbg(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } if (!(p_sys->stream = pa_stream_new(p_sys->context, "audio stream", &ss, &map))) { msg_Err(p_aout, "Failed to create stream: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } PULSE_DEBUG( "Pulse after new stream"); pa_stream_set_state_callback(p_sys->stream, stream_state_cb, p_aout); pa_stream_set_write_callback(p_sys->stream, stream_request_cb, p_aout); pa_stream_set_latency_update_callback(p_sys->stream, stream_latency_update_cb, p_aout); if (pa_stream_connect_playback(p_sys->stream, NULL, &a, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE|PA_STREAM_ADJUST_LATENCY, NULL, NULL) < 0) { msg_Err(p_aout, "Failed to connect stream: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } PULSE_DEBUG("Pulse stream connect"); /* Wait until the stream is ready */ pa_threaded_mainloop_wait(p_sys->mainloop); msg_Dbg(p_aout,"Pulse stream connected"); if (pa_stream_get_state(p_sys->stream) != PA_STREAM_READY) { msg_Err(p_aout, "Failed to connect to server: %s", pa_strerror(pa_context_errno(p_sys->context))); goto unlock_and_fail; } PULSE_DEBUG("Pulse after stream get status"); pa_threaded_mainloop_unlock(p_sys->mainloop); buffer_attr = pa_stream_get_buffer_attr(p_sys->stream); p_aout->output.i_nb_samples = buffer_attr->minreq / pa_frame_size(&ss); p_aout->output.pf_play = Play; aout_VolumeSoftInit(p_aout); msg_Dbg(p_aout, "Pulse initialized successfully"); { char cmt[PA_CHANNEL_MAP_SNPRINT_MAX], sst[PA_SAMPLE_SPEC_SNPRINT_MAX]; msg_Dbg(p_aout, "Buffer metrics: maxlength=%u, tlength=%u, prebuf=%u, minreq=%u", buffer_attr->maxlength, buffer_attr->tlength, buffer_attr->prebuf, buffer_attr->minreq); msg_Dbg(p_aout, "Using sample spec '%s', channel map '%s'.", pa_sample_spec_snprint(sst, sizeof(sst), pa_stream_get_sample_spec(p_sys->stream)), pa_channel_map_snprint(cmt, sizeof(cmt), pa_stream_get_channel_map(p_sys->stream))); msg_Dbg(p_aout, "Connected to device %s (%u, %ssuspended).", pa_stream_get_device_name(p_sys->stream), pa_stream_get_device_index(p_sys->stream), pa_stream_is_suspended(p_sys->stream) ? "" : "not "); } return VLC_SUCCESS; unlock_and_fail: msg_Dbg(p_aout, "Pulse initialization unlock and fail"); if (p_sys->mainloop) pa_threaded_mainloop_unlock(p_sys->mainloop); fail: msg_Dbg(p_aout, "Pulse initialization failed"); uninit(p_aout); return VLC_EGENERIC; }
static int init(int rate_hz, int channels, int format, int flags) { struct pa_sample_spec ss; struct pa_channel_map map; const struct format_map_s *fmt_map; char *devarg = NULL; char *host = NULL; char *sink = NULL; char *version = pa_get_library_version(); if (ao_subdevice) { devarg = strdup(ao_subdevice); sink = strchr(devarg, ':'); if (sink) *sink++ = 0; if (devarg[0]) host = devarg; } broken_pause = 0; // not sure which versions are affected, assume 0.9.11* to 0.9.14* // known bad: 0.9.14, 0.9.13 // known good: 0.9.9, 0.9.10, 0.9.15 // to test: pause, wait ca. 5 seconds framestep and see if MPlayer hangs somewhen if (strncmp(version, "0.9.1", 5) == 0 && version[5] >= '1' && version[5] <= '4') { mp_msg(MSGT_AO, MSGL_WARN, "[pulse] working around probably broken pause functionality,\n" " see http://www.pulseaudio.org/ticket/440\n"); broken_pause = 1; } ss.channels = channels; ss.rate = rate_hz; ao_data.samplerate = rate_hz; ao_data.channels = channels; fmt_map = format_maps; while (fmt_map->mp_format != format) { if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) { mp_msg(MSGT_AO, MSGL_V, "AO: [pulse] Unsupported format, using default\n"); fmt_map = format_maps; break; } fmt_map++; } ao_data.format = fmt_map->mp_format; ss.format = fmt_map->pa_format; if (!pa_sample_spec_valid(&ss)) { mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Invalid sample spec\n"); goto fail; } pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_ALSA); ao_data.bps = pa_bytes_per_second(&ss); pa_cvolume_reset(&volume, ss.channels); if (!(mainloop = pa_threaded_mainloop_new())) { mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate main loop\n"); goto fail; } if (!(context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), PULSE_CLIENT_NAME))) { mp_msg(MSGT_AO, MSGL_ERR, "AO: [pulse] Failed to allocate context\n"); goto fail; } pa_context_set_state_callback(context, context_state_cb, NULL); if (pa_context_connect(context, host, 0, NULL) < 0) goto fail; pa_threaded_mainloop_lock(mainloop); if (pa_threaded_mainloop_start(mainloop) < 0) goto unlock_and_fail; /* Wait until the context is ready */ pa_threaded_mainloop_wait(mainloop); if (pa_context_get_state(context) != PA_CONTEXT_READY) goto unlock_and_fail; if (!(stream = pa_stream_new(context, "audio stream", &ss, &map))) goto unlock_and_fail; pa_stream_set_state_callback(stream, stream_state_cb, NULL); pa_stream_set_write_callback(stream, stream_request_cb, NULL); pa_stream_set_latency_update_callback(stream, stream_latency_update_cb, NULL); if (pa_stream_connect_playback(stream, sink, NULL, PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE, &volume, NULL) < 0) goto unlock_and_fail; /* Wait until the stream is ready */ pa_threaded_mainloop_wait(mainloop); if (pa_stream_get_state(stream) != PA_STREAM_READY) goto unlock_and_fail; pa_threaded_mainloop_unlock(mainloop); free(devarg); return 1; unlock_and_fail: if (mainloop) pa_threaded_mainloop_unlock(mainloop); fail: if (context) GENERIC_ERR_MSG(context, "Init failed"); free(devarg); uninit(1); return 0; }
void SetupSound (void) { int error_number; // Acquire mainloop /////////////////////////////////////////////////////// device.mainloop = pa_threaded_mainloop_new (); if (device.mainloop == NULL) { fprintf (stderr, "Could not acquire PulseAudio main loop\n"); return; } // Acquire context //////////////////////////////////////////////////////// device.api = pa_threaded_mainloop_get_api (device.mainloop); device.context = pa_context_new (device.api, "PCSX"); pa_context_set_state_callback (device.context, context_state_cb, &device); if (device.context == NULL) { fprintf (stderr, "Could not acquire PulseAudio device context\n"); return; } // Connect to PulseAudio server /////////////////////////////////////////// if (pa_context_connect (device.context, NULL, 0, NULL) < 0) { error_number = pa_context_errno (device.context); fprintf (stderr, "Could not connect to PulseAudio server: %s\n", pa_strerror(error_number)); return; } // Run mainloop until sever context is ready ////////////////////////////// pa_threaded_mainloop_lock (device.mainloop); if (pa_threaded_mainloop_start (device.mainloop) < 0) { fprintf (stderr, "Could not start mainloop\n"); return; } pa_context_state_t context_state; context_state = pa_context_get_state (device.context); while (context_state != PA_CONTEXT_READY) { context_state = pa_context_get_state (device.context); if (! PA_CONTEXT_IS_GOOD (context_state)) { error_number = pa_context_errno (device.context); fprintf (stderr, "Context state is not good: %s\n", pa_strerror (error_number)); return; } else if (context_state == PA_CONTEXT_READY) break; else fprintf (stderr, "PulseAudio context state is %d\n", context_state); pa_threaded_mainloop_wait (device.mainloop); } // Set sample spec //////////////////////////////////////////////////////// device.spec.format = PA_SAMPLE_S16NE; device.spec.channels = 2; device.spec.rate = settings.frequency; pa_buffer_attr buffer_attributes; buffer_attributes.tlength = pa_bytes_per_second (& device.spec) / 5; buffer_attributes.maxlength = buffer_attributes.tlength * 3; buffer_attributes.minreq = buffer_attributes.tlength / 3; buffer_attributes.prebuf = buffer_attributes.tlength; //maxlength = buffer_attributes.maxlength; //fprintf (stderr, "Total space: %u\n", buffer_attributes.maxlength); //fprintf (stderr, "Minimum request size: %u\n", buffer_attributes.minreq); //fprintf (stderr, "Bytes needed before playback: %u\n", buffer_attributes.prebuf); //fprintf (stderr, "Target buffer size: %lu\n", buffer_attributes.tlength); // Acquire new stream using spec ////////////////////////////////////////// device.stream = pa_stream_new (device.context, "PCSX", &device.spec, NULL); if (device.stream == NULL) { error_number = pa_context_errno (device.context); fprintf (stderr, "Could not acquire new PulseAudio stream: %s\n", pa_strerror (error_number)); return; } // Set callbacks for server events //////////////////////////////////////// pa_stream_set_state_callback (device.stream, stream_state_cb, &device); pa_stream_set_write_callback (device.stream, stream_request_cb, &device); pa_stream_set_latency_update_callback (device.stream, stream_latency_update_cb, &device); // Ready stream for playback ////////////////////////////////////////////// pa_stream_flags_t flags = (pa_stream_flags_t) (PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE); //pa_stream_flags_t flags = (pa_stream_flags_t) (PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_EARLY_REQUESTS); if (pa_stream_connect_playback (device.stream, NULL, &buffer_attributes, flags, NULL, NULL) < 0) { pa_context_errno (device.context); fprintf (stderr, "Could not connect for playback: %s\n", pa_strerror (error_number)); return; } // Run mainloop until stream is ready ///////////////////////////////////// pa_stream_state_t stream_state; stream_state = pa_stream_get_state (device.stream); while (stream_state != PA_STREAM_READY) { stream_state = pa_stream_get_state (device.stream); if (stream_state == PA_STREAM_READY) break; else if (! PA_STREAM_IS_GOOD (stream_state)) { error_number = pa_context_errno (device.context); fprintf (stderr, "Stream state is not good: %s\n", pa_strerror (error_number)); return; } else fprintf (stderr, "PulseAudio stream state is %d\n", stream_state); pa_threaded_mainloop_wait (device.mainloop); } pa_threaded_mainloop_unlock (device.mainloop); fprintf (stderr, "PulseAudio should be connected\n"); return; }
static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface) { NOREF(pInterface); LogFlowFuncEnter(); int rc = audioLoadPulseLib(); if (RT_FAILURE(rc)) { LogRel(("PulseAudio: Failed to load the PulseAudio shared library! Error %Rrc\n", rc)); return rc; } bool fLocked = false; do { if (!(g_pMainLoop = pa_threaded_mainloop_new())) { LogRel(("PulseAudio: Failed to allocate main loop: %s\n", pa_strerror(pa_context_errno(g_pContext)))); rc = VERR_NO_MEMORY; break; } if (!(g_pContext = pa_context_new(pa_threaded_mainloop_get_api(g_pMainLoop), "VirtualBox"))) { LogRel(("PulseAudio: Failed to allocate context: %s\n", pa_strerror(pa_context_errno(g_pContext)))); rc = VERR_NO_MEMORY; break; } if (pa_threaded_mainloop_start(g_pMainLoop) < 0) { LogRel(("PulseAudio: Failed to start threaded mainloop: %s\n", pa_strerror(pa_context_errno(g_pContext)))); rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */ break; } pa_context_set_state_callback(g_pContext, drvHostPulseAudioCbCtxState, NULL); pa_threaded_mainloop_lock(g_pMainLoop); fLocked = true; if (pa_context_connect(g_pContext, NULL /* pszServer */, PA_CONTEXT_NOFLAGS, NULL) < 0) { LogRel(("PulseAudio: Failed to connect to server: %s\n", pa_strerror(pa_context_errno(g_pContext)))); rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */ break; } /* Wait until the g_pContext is ready */ for (;;) { pa_context_state_t cstate; pa_threaded_mainloop_wait(g_pMainLoop); cstate = pa_context_get_state(g_pContext); if (cstate == PA_CONTEXT_READY) break; else if ( cstate == PA_CONTEXT_TERMINATED || cstate == PA_CONTEXT_FAILED) { LogRel(("PulseAudio: Failed to initialize context (state %d)\n", cstate)); rc = VERR_GENERAL_FAILURE; /** @todo Find a better rc. */ break; } } pa_threaded_mainloop_unlock(g_pMainLoop); } while (0); if (RT_FAILURE(rc)) { if (g_pMainLoop) { if (fLocked) pa_threaded_mainloop_unlock(g_pMainLoop); if (g_pMainLoop) pa_threaded_mainloop_stop(g_pMainLoop); } if (g_pContext) { pa_context_disconnect(g_pContext); pa_context_unref(g_pContext); g_pContext = NULL; } if (g_pMainLoop) { pa_threaded_mainloop_free(g_pMainLoop); g_pMainLoop = NULL; } } LogFlowFuncLeaveRC(rc); return rc; }
static 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, (pa_context_flags_t)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); } }
/** * ags_pulse_client_open: * @pulse_client: the #AgsPulseClient * @client_name: the client's name * * Open the pulseaudio client's connection and read uuid. * * Since: 2.0.0 */ void ags_pulse_client_open(AgsPulseClient *pulse_client, gchar *client_name) { AgsPulseServer *pulse_server; #ifdef AGS_WITH_PULSE pa_context *context; pa_mainloop *main_loop; pa_mainloop_api *main_loop_api; #else gpointer context; gpointer main_loop; gpointer main_loop_api; #endif gchar *client_uuid; pthread_mutex_t *pulse_server_mutex; pthread_mutex_t *pulse_client_mutex; if(!AGS_IS_PULSE_CLIENT(pulse_client) || client_name == NULL){ return; } /* get pulse client mutex */ pthread_mutex_lock(ags_pulse_client_get_class_mutex()); pulse_client_mutex = pulse_client->obj_mutex; pthread_mutex_unlock(ags_pulse_client_get_class_mutex()); /* check already open */ pthread_mutex_lock(pulse_client_mutex); if(pulse_client->context != NULL){ pthread_mutex_unlock(pulse_client_mutex); g_message("Advanced Gtk+ Sequencer pulseaudio client already open"); return; } pulse_server = (AgsPulseServer *) pulse_client->pulse_server; pthread_mutex_unlock(pulse_client_mutex); g_message("Advanced Gtk+ Sequencer open pulseaudio client"); g_object_set(pulse_client, "client-name", client_name, NULL); /* get pulse server mutex */ pthread_mutex_lock(ags_pulse_server_get_class_mutex()); pulse_server_mutex = pulse_server->obj_mutex; pthread_mutex_unlock(ags_pulse_server_get_class_mutex()); /* get main loop API */ pthread_mutex_lock(pulse_server_mutex); main_loop = pulse_server->main_loop; main_loop_api = pulse_server->main_loop_api; pthread_mutex_unlock(pulse_server_mutex); /* new context */ pthread_mutex_lock(pulse_client_mutex); #ifdef AGS_WITH_PULSE context = pulse_client->context = pa_context_new(main_loop_api, client_name); #else context = pulse_client->context = NULL; #endif pthread_mutex_unlock(pulse_client_mutex); if(context != NULL){ #ifdef AGS_WITH_PULSE pa_context_connect(context, NULL, 0, NULL); pa_context_set_state_callback(context, ags_pulse_client_state_callback, pulse_client); while(!ags_pulse_client_test_flags(pulse_client, AGS_PULSE_CLIENT_READY)){ if(!ags_pulse_client_test_flags(pulse_client, AGS_PULSE_CLIENT_READY)){ pa_mainloop_iterate(main_loop, TRUE, NULL); } } #endif } }
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; /* type for pa_read/_write. passed as userdata to the callbacks */ unsigned long type = 0; 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}, {"passthrough", 0, NULL, ARG_PASSTHROUGH}, {"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}, {"monitor-stream", 1, NULL, ARG_MONITOR_STREAM}, {NULL, 0, NULL, 0} }; setlocale(LC_ALL, ""); #ifdef ENABLE_NLS bindtextdomain(GETTEXT_PACKAGE, PULSE_LOCALEDIR); #endif 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; } else 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_PASSTHROUGH: flags |= PA_STREAM_PASSTHROUGH; break; case ARG_FILE_FORMAT: 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; case ARG_MONITOR_STREAM: if (pa_atou(optarg, &monitor_stream) < 0) { pa_log(_("Failed to parse the argument for --monitor-stream")); goto quit; } break; 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 = pa_open_cloexec(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; } if (file_format <= 0) { char *extension; if (filename && (extension = strrchr(filename, '.'))) file_format = pa_sndfile_format_from_string(extension+1); if (file_format <= 0) file_format = SF_FORMAT_WAV; /* Transparently upgrade classic .wav to wavex for multichannel audio */ if (file_format == SF_FORMAT_WAV && (sample_spec.channels > 2 || (channel_map_set && !(sample_spec.channels == 1 && channel_map.map[0] == PA_CHANNEL_POSITION_MONO) && !(sample_spec.channels == 2 && channel_map.map[0] == PA_CHANNEL_POSITION_LEFT && channel_map.map[1] == PA_CHANNEL_POSITION_RIGHT)))) 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); if (!pa_proplist_contains(proplist, PA_PROP_MEDIA_NAME)) { pa_log(_("Failed to set media name.")); goto quit; } } /* 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) { #ifdef OS_IS_WIN32 /* need to turn on binary mode for stdio io. Windows, meh */ setmode(mode == PLAYBACK ? STDIN_FILENO : STDOUT_FILENO, O_BINARY); #endif 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, &type))) { 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(silence_buffer); pa_xfree(buffer); pa_xfree(server); pa_xfree(device); if (sndfile) sf_close(sndfile); if (proplist) pa_proplist_free(proplist); return ret; }
static DECLCALLBACK(int) drvHostPulseAudioInit(PPDMIHOSTAUDIO pInterface) { AssertPtrReturn(pInterface, VERR_INVALID_POINTER); PDRVHOSTPULSEAUDIO pThis = PDMIHOSTAUDIO_2_DRVHOSTPULSEAUDIO(pInterface); LogFlowFuncEnter(); int rc = audioLoadPulseLib(); if (RT_FAILURE(rc)) { LogRel(("PulseAudio: Failed to load the PulseAudio shared library! Error %Rrc\n", rc)); return rc; } pThis->fLoopWait = false; pThis->pMainLoop = NULL; bool fLocked = false; do { if (!(pThis->pMainLoop = pa_threaded_mainloop_new())) { LogRel(("PulseAudio: Failed to allocate main loop: %s\n", pa_strerror(pa_context_errno(pThis->pContext)))); rc = VERR_NO_MEMORY; break; } if (!(pThis->pContext = pa_context_new(pa_threaded_mainloop_get_api(pThis->pMainLoop), "VirtualBox"))) { LogRel(("PulseAudio: Failed to allocate context: %s\n", pa_strerror(pa_context_errno(pThis->pContext)))); rc = VERR_NO_MEMORY; break; } if (pa_threaded_mainloop_start(pThis->pMainLoop) < 0) { LogRel(("PulseAudio: Failed to start threaded mainloop: %s\n", pa_strerror(pa_context_errno(pThis->pContext)))); rc = VERR_AUDIO_BACKEND_INIT_FAILED; break; } /* Install a global callback to known if something happens to our acquired context. */ pa_context_set_state_callback(pThis->pContext, paContextCbStateChanged, pThis /* pvUserData */); pa_threaded_mainloop_lock(pThis->pMainLoop); fLocked = true; if (pa_context_connect(pThis->pContext, NULL /* pszServer */, PA_CONTEXT_NOFLAGS, NULL) < 0) { LogRel(("PulseAudio: Failed to connect to server: %s\n", pa_strerror(pa_context_errno(pThis->pContext)))); rc = VERR_AUDIO_BACKEND_INIT_FAILED; break; } /* Wait until the pThis->pContext is ready. */ for (;;) { if (!pThis->fLoopWait) pa_threaded_mainloop_wait(pThis->pMainLoop); pThis->fLoopWait = false; pa_context_state_t cstate = pa_context_get_state(pThis->pContext); if (cstate == PA_CONTEXT_READY) break; else if ( cstate == PA_CONTEXT_TERMINATED || cstate == PA_CONTEXT_FAILED) { LogRel(("PulseAudio: Failed to initialize context (state %d)\n", cstate)); rc = VERR_AUDIO_BACKEND_INIT_FAILED; break; } } } while (0); if (fLocked) pa_threaded_mainloop_unlock(pThis->pMainLoop); if (RT_FAILURE(rc)) { if (pThis->pMainLoop) pa_threaded_mainloop_stop(pThis->pMainLoop); if (pThis->pContext) { pa_context_disconnect(pThis->pContext); pa_context_unref(pThis->pContext); pThis->pContext = NULL; } if (pThis->pMainLoop) { pa_threaded_mainloop_free(pThis->pMainLoop); pThis->pMainLoop = NULL; } } LogFlowFuncLeaveRC(rc); return rc; }
/* This is called whenever the context status changes */ static void context_state_callback(pa_context *c, void *userdata) { fail_unless(c != NULL); switch (pa_context_get_state(c)) { case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: break; case PA_CONTEXT_READY: { pa_stream_flags_t flags = PA_STREAM_AUTO_TIMING_UPDATE; pa_buffer_attr attr; static const pa_sample_spec ss = { .format = PA_SAMPLE_S16LE, .rate = 44100, .channels = 2 }; pa_zero(attr); attr.maxlength = (uint32_t) -1; attr.tlength = latency > 0 ? (uint32_t) pa_usec_to_bytes(latency, &ss) : (uint32_t) -1; attr.prebuf = (uint32_t) -1; attr.minreq = (uint32_t) -1; attr.fragsize = (uint32_t) -1; #ifdef INTERPOLATE flags |= PA_STREAM_INTERPOLATE_TIMING; #endif if (latency > 0) flags |= PA_STREAM_ADJUST_LATENCY; pa_log("Connection established"); stream = pa_stream_new(c, "interpol-test", &ss, NULL); fail_unless(stream != NULL); if (playback) { pa_assert_se(pa_stream_connect_playback(stream, NULL, &attr, flags, NULL, NULL) == 0); pa_stream_set_write_callback(stream, stream_write_cb, NULL); } else { pa_assert_se(pa_stream_connect_record(stream, NULL, &attr, flags) == 0); pa_stream_set_read_callback(stream, stream_read_cb, NULL); } pa_stream_set_latency_update_callback(stream, stream_latency_cb, NULL); break; } case PA_CONTEXT_TERMINATED: break; case PA_CONTEXT_FAILED: default: pa_log_error("Context error: %s", pa_strerror(pa_context_errno(c))); ck_abort(); } } START_TEST (interpol_test) { pa_threaded_mainloop* m = NULL; int k; struct timeval start, last_info = { 0, 0 }; pa_usec_t old_t = 0, old_rtc = 0; #ifdef CORK bool corked = false; #endif /* Set up a new main loop */ m = pa_threaded_mainloop_new(); fail_unless(m != NULL); mainloop_api = pa_threaded_mainloop_get_api(m); fail_unless(mainloop_api != NULL); context = pa_context_new(mainloop_api, bname); fail_unless(context != NULL); pa_context_set_state_callback(context, context_state_callback, NULL); fail_unless(pa_context_connect(context, NULL, 0, NULL) >= 0); pa_gettimeofday(&start); fail_unless(pa_threaded_mainloop_start(m) >= 0); /* #ifdef CORK */ for (k = 0; k < 20000; k++) /* #else */ /* for (k = 0; k < 2000; k++) */ /* #endif */ { bool success = false, changed = false; pa_usec_t t, rtc, d; struct timeval now, tv; bool playing = false; pa_threaded_mainloop_lock(m); if (stream) { const pa_timing_info *info; if (pa_stream_get_time(stream, &t) >= 0 && pa_stream_get_latency(stream, &d, NULL) >= 0) success = true; if ((info = pa_stream_get_timing_info(stream))) { if (memcmp(&last_info, &info->timestamp, sizeof(struct timeval))) { changed = true; last_info = info->timestamp; } if (info->playing) playing = true; } } pa_threaded_mainloop_unlock(m); pa_gettimeofday(&now); if (success) { #ifdef CORK bool cork_now; #endif rtc = pa_timeval_diff(&now, &start); pa_log_info("%i\t%llu\t%llu\t%llu\t%llu\t%lli\t%u\t%u\t%llu\t%llu\n", k, (unsigned long long) rtc, (unsigned long long) t, (unsigned long long) (rtc-old_rtc), (unsigned long long) (t-old_t), (signed long long) rtc - (signed long long) t, changed, playing, (unsigned long long) latency, (unsigned long long) d); fflush(stdout); old_t = t; old_rtc = rtc; #ifdef CORK cork_now = (rtc / (2*PA_USEC_PER_SEC)) % 2 == 1; if (corked != cork_now) { pa_threaded_mainloop_lock(m); pa_operation_unref(pa_stream_cork(stream, cork_now, NULL, NULL)); pa_threaded_mainloop_unlock(m); pa_log(cork_now ? "Corking" : "Uncorking"); corked = cork_now; } #endif } /* Spin loop, ugly but normal usleep() is just too badly grained */ tv = now; while (pa_timeval_diff(pa_gettimeofday(&now), &tv) < 1000) pa_thread_yield(); } if (m) pa_threaded_mainloop_stop(m); if (stream) { pa_stream_disconnect(stream); pa_stream_unref(stream); } if (context) { pa_context_disconnect(context); pa_context_unref(context); } if (m) pa_threaded_mainloop_free(m); } END_TEST int main(int argc, char *argv[]) { int failed = 0; Suite *s; TCase *tc; SRunner *sr; if (!getenv("MAKE_CHECK")) pa_log_set_level(PA_LOG_DEBUG); bname = argv[0]; playback = argc <= 1 || !pa_streq(argv[1], "-r"); latency = (argc >= 2 && !pa_streq(argv[1], "-r")) ? atoi(argv[1]) : (argc >= 3 ? atoi(argv[2]) : 0); s = suite_create("Interpol"); tc = tcase_create("interpol"); tcase_add_test(tc, interpol_test); tcase_set_timeout(tc, 5 * 60); suite_add_tcase(s, tc); sr = srunner_create(s); srunner_run_all(sr, CK_NORMAL); failed = srunner_ntests_failed(sr); srunner_free(sr); return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }
int FreeRDPRdpsndDeviceEntry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) { rdpsndDevicePlugin * devplugin; struct pulse_device_data * pulse_data; RD_PLUGIN_DATA * data; int i; devplugin = pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->plugin); if (devplugin == NULL) { LLOGLN(0, ("rdpsnd_pulse: unable to register device.")); return 1; } devplugin->open = rdpsnd_pulse_open; devplugin->format_supported = rdpsnd_pulse_format_supported; devplugin->set_format = rdpsnd_pulse_set_format; devplugin->set_volume = rdpsnd_pulse_set_volume; devplugin->play = rdpsnd_pulse_play; devplugin->close = rdpsnd_pulse_close; devplugin->free = rdpsnd_pulse_free; pulse_data = (struct pulse_device_data *) malloc(sizeof(struct pulse_device_data)); memset(pulse_data, 0, sizeof(struct pulse_device_data)); data = (RD_PLUGIN_DATA *) pEntryPoints->data; if (data && strcmp(data->data[0], "pulse") == 0) { for (i = 1; i < 4 && data->data[i]; i++) { if (i > 1) { strncat(pulse_data->device_name, ":", sizeof(pulse_data->device_name) - strlen(pulse_data->device_name)); } strncat(pulse_data->device_name, (char*)data->data[i], sizeof(pulse_data->device_name) - strlen(pulse_data->device_name)); } } pulse_data->pDecodeImaAdpcm = pEntryPoints->pDecodeImaAdpcm; devplugin->device_data = pulse_data; pulse_data->mainloop = pa_threaded_mainloop_new(); if (!pulse_data->mainloop) { LLOGLN(0, ("rdpsnd_pulse: pa_threaded_mainloop_new failed")); rdpsnd_pulse_free(devplugin); return 1; } pulse_data->context = pa_context_new(pa_threaded_mainloop_get_api(pulse_data->mainloop), "freerdp"); if (!pulse_data->context) { LLOGLN(0, ("rdpsnd_pulse: pa_context_new failed")); rdpsnd_pulse_free(devplugin); return 1; } pa_context_set_state_callback(pulse_data->context, rdpsnd_pulse_context_state_callback, devplugin); if (rdpsnd_pulse_connect(devplugin)) { LLOGLN(0, ("rdpsnd_pulse: rdpsnd_pulse_connect failed")); rdpsnd_pulse_free(devplugin); return 1; } LLOGLN(0, ("rdpsnd_pulse: pulse device '%s' registered.", pulse_data->device_name)); return 0; }
int main(int argc, char **argv) { pa_glib_mainloop *mainloop; pa_mainloop_api *mainloop_api; pa_context *context; GdkWindow *root; int status = EXIT_SUCCESS; int i; gtk_init(&argc, &argv); mainloop = pa_glib_mainloop_new(NULL); if (!mainloop) { fprintf(stderr, "pa_glib_mainloop_new() failed\n"); status = EXIT_FAILURE; goto out; } mainloop_api = pa_glib_mainloop_get_api(mainloop); if (pa_signal_init(mainloop_api) < 0) { fprintf(stderr, "pa_signal_init() failed\n"); status = EXIT_FAILURE; goto mainloop_free; } pa_signal_new(SIGINT, exit_signal_callback, NULL); pa_signal_new(SIGTERM, exit_signal_callback, NULL); context = pa_context_new(mainloop_api, NULL); if (!context) { fprintf(stderr, "pa_context_new() failed\n"); status = EXIT_FAILURE; goto mainloop_free; } pa_context_set_state_callback(context, context_state_callback, NULL); if (pa_context_connect(context, NULL, 0, NULL) < 0) { fprintf(stderr, "pa_context_connect() failed: %s\n", pa_strerror(pa_context_errno(context))); status = EXIT_FAILURE; goto context_unref; } if (!notify_init(APP_NAME)) { fprintf(stderr, "Could not initialize libnotify\n"); status = EXIT_FAILURE; goto context_unref; } notification = notify_notification_new(APP_NAME, NULL, NULL); if (!notification) { fprintf(stderr, "notify_notification_new() failed\n"); status = EXIT_FAILURE; goto notify_uninit; } notify_notification_set_timeout(notification, NOTIFY_EXPIRES_DEFAULT); notify_notification_set_hint_string(notification, "synchronous", "volume"); root = gdk_get_default_root_window(); gdk_window_set_events(root, GDK_KEY_PRESS_MASK); gdk_window_add_filter(root, filter, context); for (i = 0; i < sizeof(keysyms) / sizeof(keysyms[0]); i++) { keycodes[i] = XKeysymToKeycode(GDK_WINDOW_XDISPLAY(root), keysyms[i]); if (!keycodes[i]) { fprintf(stderr, "%s is not mapped on this keyboard\n", XKeysymToString(keysyms[i])); continue; } XGrabKey(GDK_WINDOW_XDISPLAY(root), keycodes[i], AnyModifier, GDK_WINDOW_XID(root), False, GrabModeAsync, GrabModeAsync); } gtk_main(); g_object_unref(G_OBJECT(notification)); notify_uninit: notify_uninit(); context_unref: pa_context_unref(context); mainloop_free: pa_glib_mainloop_free(mainloop); out: return status; }
void PulseAudioPlayer::OpenStream() { if (open) CloseStream(); // Initialise a mainloop //printf("Initialising threaded main loop\n"); mainloop = pa_threaded_mainloop_new(); if (!mainloop) { throw agi::AudioPlayerOpenError("Failed to initialise PulseAudio threaded mainloop object", 0); } //printf("Starting main loop\n"); pa_threaded_mainloop_start(mainloop); // Create context //printf("Creating context\n"); context = pa_context_new(pa_threaded_mainloop_get_api(mainloop), "Aegisub"); if (!context) { pa_threaded_mainloop_free(mainloop); throw agi::AudioPlayerOpenError("Failed to create PulseAudio context", 0); } pa_context_set_state_callback(context, (pa_context_notify_cb_t)pa_context_notify, this); // Connect the context //printf("Connecting context\n"); pa_context_connect(context, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL); // Wait for connection while (true) { context_notify.Wait(); if (cstate == PA_CONTEXT_READY) { break; } else if (cstate == PA_CONTEXT_FAILED) { // eww paerror = pa_context_errno(context); pa_context_unref(context); pa_threaded_mainloop_stop(mainloop); pa_threaded_mainloop_free(mainloop); throw agi::AudioPlayerOpenError(std::string("PulseAudio reported error: ") + pa_strerror(paerror), 0); } // otherwise loop once more } //printf("Context connected\n"); // Set up stream bpf = provider->GetChannels() * provider->GetBytesPerSample(); pa_sample_spec ss; ss.format = PA_SAMPLE_S16LE; // FIXME ss.rate = provider->GetSampleRate(); ss.channels = provider->GetChannels(); pa_channel_map map; pa_channel_map_init_auto(&map, ss.channels, PA_CHANNEL_MAP_DEFAULT); //printf("Creating stream\n"); stream = pa_stream_new(context, "Sound", &ss, &map); if (!stream) { // argh! pa_context_disconnect(context); pa_context_unref(context); pa_threaded_mainloop_stop(mainloop); pa_threaded_mainloop_free(mainloop); throw agi::AudioPlayerOpenError("PulseAudio could not create stream", 0); } pa_stream_set_state_callback(stream, (pa_stream_notify_cb_t)pa_stream_notify, this); pa_stream_set_write_callback(stream, (pa_stream_request_cb_t)pa_stream_write, this); // Connect stream //printf("Connecting playback stream\n"); paerror = pa_stream_connect_playback(stream, NULL, NULL, (pa_stream_flags_t)(PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_NOT_MONOTONOUS|PA_STREAM_AUTO_TIMING_UPDATE), NULL, NULL); if (paerror) { printf("PulseAudio reported error: %s (%d)\n", pa_strerror(paerror), paerror); throw agi::AudioPlayerOpenError(std::string("PulseAudio reported error: ") + pa_strerror(paerror), 0); } while (true) { stream_notify.Wait(); if (sstate == PA_STREAM_READY) { break; } else if (sstate == PA_STREAM_FAILED) { paerror = pa_context_errno(context); printf("PulseAudio player: Stream connection failed: %s (%d)\n", pa_strerror(paerror), paerror); throw agi::AudioPlayerOpenError("PulseAudio player: Something went wrong connecting the stream", 0); } } //printf("Connected playback stream, now playing\n\n"); // Hopefully this marks success //printf("Finished opening PulseAudio\n\n"); open = true; }
static gboolean gst_pulsesrc_open (GstAudioSrc * asrc) { GstPulseSrc *pulsesrc = GST_PULSESRC_CAST (asrc); pa_threaded_mainloop_lock (pulsesrc->mainloop); g_assert (!pulsesrc->context); g_assert (!pulsesrc->stream); GST_DEBUG_OBJECT (pulsesrc, "opening device"); if (!(pulsesrc->context = pa_context_new (pa_threaded_mainloop_get_api (pulsesrc->mainloop), pulsesrc->client_name))) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to create context"), (NULL)); goto unlock_and_fail; } pa_context_set_state_callback (pulsesrc->context, gst_pulsesrc_context_state_cb, pulsesrc); pa_context_set_subscribe_callback (pulsesrc->context, gst_pulsesrc_context_subscribe_cb, pulsesrc); GST_DEBUG_OBJECT (pulsesrc, "connect to server %s", GST_STR_NULL (pulsesrc->server)); if (pa_context_connect (pulsesrc->context, pulsesrc->server, 0, NULL) < 0) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } for (;;) { pa_context_state_t state; state = pa_context_get_state (pulsesrc->context); if (!PA_CONTEXT_IS_GOOD (state)) { GST_ELEMENT_ERROR (pulsesrc, RESOURCE, FAILED, ("Failed to connect: %s", pa_strerror (pa_context_errno (pulsesrc->context))), (NULL)); goto unlock_and_fail; } if (state == PA_CONTEXT_READY) break; /* Wait until the context is ready */ pa_threaded_mainloop_wait (pulsesrc->mainloop); } GST_DEBUG_OBJECT (pulsesrc, "connected"); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return TRUE; /* ERRORS */ unlock_and_fail: { gst_pulsesrc_destroy_context (pulsesrc); pa_threaded_mainloop_unlock (pulsesrc->mainloop); return FALSE; } }
int main(int argc, char **argv) { pa_proplist *proplist = NULL; pa_mainloop *m = NULL; pa_mainloop_api *api = NULL; pa_context *context = NULL; struct context *ctx; struct audio_file *file; int ret; ctx = malloc(sizeof(struct context)); if (!ctx) { errorp("Couldn't allocate async callbacks context"); goto quit; } memset(ctx, 0, sizeof(*ctx)); file = audio_file_new("samples/sample.wav"); if (!file) goto quit; proplist = pa_proplist_new(); if (!proplist) { error("Couldn't create a PulseAudio property list"); goto quit; } pa_proplist_sets(proplist, PA_PROP_APPLICATION_NAME, "malicious-client-kill-server"); m = pa_mainloop_new(); if (!m) { error("Couldn't create PulseAudio mainloop"); goto quit; } api = pa_mainloop_get_api(m); context = pa_context_new_with_proplist(api, NULL, proplist); if (!context) { error("Couldn't create client context"); goto quit; } ctx->file = file; ctx->mainloop_api = api; ctx->context = context; pa_context_set_state_callback(context, context_state_callback, ctx); ret = pa_context_connect(context, NULL, 0, NULL); if (ret < 0) { error ("Couldn't connect to PulseAudio server: %s", pa_strerror(pa_context_errno(context))); goto quit; } pa_mainloop_run(m, &ret); return ret; quit: exit(EXIT_FAILURE); }
static int init(struct ao *ao) { struct pa_sample_spec ss; struct pa_channel_map map; pa_proplist *proplist = NULL; struct priv *priv = ao->priv; char *host = priv->cfg_host && priv->cfg_host[0] ? priv->cfg_host : NULL; char *sink = priv->cfg_sink && priv->cfg_sink[0] ? priv->cfg_sink : NULL; const char *version = pa_get_library_version(); ao->per_application_mixer = true; priv->broken_pause = false; /* not sure which versions are affected, assume 0.9.11* to 0.9.14* * known bad: 0.9.14, 0.9.13 * known good: 0.9.9, 0.9.10, 0.9.15 * To test: pause, wait ca. 5 seconds, framestep and see if MPlayer * hangs somewhen. */ if (strncmp(version, "0.9.1", 5) == 0 && version[5] >= '1' && version[5] <= '4') { MP_WARN(ao, "working around probably broken pause functionality,\n" " see http://www.pulseaudio.org/ticket/440\n"); priv->broken_pause = true; } if (!(priv->mainloop = pa_threaded_mainloop_new())) { MP_ERR(ao, "Failed to allocate main loop\n"); goto fail; } if (!(priv->context = pa_context_new(pa_threaded_mainloop_get_api( priv->mainloop), PULSE_CLIENT_NAME))) { MP_ERR(ao, "Failed to allocate context\n"); goto fail; } pa_context_set_state_callback(priv->context, context_state_cb, ao); if (pa_context_connect(priv->context, host, 0, NULL) < 0) goto fail; pa_threaded_mainloop_lock(priv->mainloop); if (pa_threaded_mainloop_start(priv->mainloop) < 0) goto unlock_and_fail; /* Wait until the context is ready */ pa_threaded_mainloop_wait(priv->mainloop); if (pa_context_get_state(priv->context) != PA_CONTEXT_READY) goto unlock_and_fail; ss.channels = ao->channels.num; ss.rate = ao->samplerate; ao->format = af_fmt_from_planar(ao->format); const struct format_map *fmt_map = format_maps; while (fmt_map->mp_format != ao->format) { if (fmt_map->mp_format == AF_FORMAT_UNKNOWN) { MP_VERBOSE(ao, "Unsupported format, using default\n"); fmt_map = format_maps; break; } fmt_map++; } ao->format = fmt_map->mp_format; ss.format = fmt_map->pa_format; if (!pa_sample_spec_valid(&ss)) { MP_ERR(ao, "Invalid sample spec\n"); goto unlock_and_fail; } if (!select_chmap(ao, &map)) goto unlock_and_fail; if (!(proplist = pa_proplist_new())) { MP_ERR(ao, "Failed to allocate proplist\n"); goto unlock_and_fail; } (void)pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, "video"); if (!(priv->stream = pa_stream_new_with_proplist(priv->context, "audio stream", &ss, &map, proplist))) goto unlock_and_fail; pa_proplist_free(proplist); proplist = NULL; pa_stream_set_state_callback(priv->stream, stream_state_cb, ao); pa_stream_set_write_callback(priv->stream, stream_request_cb, ao); pa_stream_set_latency_update_callback(priv->stream, stream_latency_update_cb, ao); pa_buffer_attr bufattr = { .maxlength = -1, .tlength = pa_usec_to_bytes(1000000, &ss), .prebuf = -1, .minreq = -1, .fragsize = -1, }; if (pa_stream_connect_playback(priv->stream, sink, &bufattr, PA_STREAM_NOT_MONOTONIC, NULL, NULL) < 0) goto unlock_and_fail; /* Wait until the stream is ready */ pa_threaded_mainloop_wait(priv->mainloop); if (pa_stream_get_state(priv->stream) != PA_STREAM_READY) goto unlock_and_fail; pa_threaded_mainloop_unlock(priv->mainloop); return 0; unlock_and_fail: if (priv->mainloop) pa_threaded_mainloop_unlock(priv->mainloop); fail: if (priv->context) { if (!(pa_context_errno(priv->context) == PA_ERR_CONNECTIONREFUSED && ao->probing)) GENERIC_ERR_MSG("Init failed"); } if (proplist) pa_proplist_free(proplist); uninit(ao, true); return -1; } static void cork(struct ao *ao, bool pause) { struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); priv->retval = 0; if (!waitop(priv, pa_stream_cork(priv->stream, pause, success_cb, ao)) || !priv->retval) GENERIC_ERR_MSG("pa_stream_cork() failed"); } // Play the specified data to the pulseaudio server static int play(struct ao *ao, void **data, int samples, int flags) { struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); if (pa_stream_write(priv->stream, data[0], samples * ao->sstride, NULL, 0, PA_SEEK_RELATIVE) < 0) { GENERIC_ERR_MSG("pa_stream_write() failed"); samples = -1; } if (flags & AOPLAY_FINAL_CHUNK) { // Force start in case the stream was too short for prebuf pa_operation *op = pa_stream_trigger(priv->stream, NULL, NULL); pa_operation_unref(op); } pa_threaded_mainloop_unlock(priv->mainloop); return samples; } // Reset the audio stream, i.e. flush the playback buffer on the server side static void reset(struct ao *ao) { // pa_stream_flush() works badly if not corked cork(ao, true); struct priv *priv = ao->priv; pa_threaded_mainloop_lock(priv->mainloop); priv->retval = 0; if (!waitop(priv, pa_stream_flush(priv->stream, success_cb, ao)) || !priv->retval) GENERIC_ERR_MSG("pa_stream_flush() failed"); cork(ao, false); }
int PulseAudio_init(output_PulseAudio *self, PyObject *args, PyObject *kwds) { int sample_rate; int channels; int bits_per_sample; char *stream_name; pa_sample_spec sample_spec; self->mainloop = NULL; self->mainloop_api = NULL; self->context = NULL; self->stream = NULL; if (!PyArg_ParseTuple(args, "iiis", &sample_rate, &channels, &bits_per_sample, &stream_name)) return -1; /*sanity check output parameters*/ if (sample_rate > 0) { sample_spec.rate = sample_rate; } else { PyErr_SetString( PyExc_ValueError, "sample rate must be a postive value"); return -1; } if (channels > 0) { sample_spec.channels = channels; } else { PyErr_SetString( PyExc_ValueError, "channels must be a positive value"); return -1; } /*use .wav-style sample format*/ switch (bits_per_sample) { case 8: sample_spec.format = PA_SAMPLE_U8; break; case 16: sample_spec.format = PA_SAMPLE_S16LE; break; case 24: sample_spec.format = PA_SAMPLE_S24LE; break; default: PyErr_SetString( PyExc_ValueError, "bits-per-sample must be 8, 16 or 24"); return -1; } /*initialize threaded mainloop*/ if ((self->mainloop = pa_threaded_mainloop_new()) == NULL) { PyErr_SetString( PyExc_ValueError, "unable to get new mainloop"); return -1; } /*get abstract API from threaded mainloop*/ if ((self->mainloop_api = pa_threaded_mainloop_get_api(self->mainloop)) == NULL) { PyErr_SetString( PyExc_ValueError, "unable to get mainloop API"); return -1; } /*create new connection context*/ if ((self->context = pa_context_new(self->mainloop_api, stream_name)) == NULL) { PyErr_SetString( PyExc_ValueError, "unable to create PulseAudio connection context"); return -1; } /*setup context change callback*/ pa_context_set_state_callback( self->context, (pa_context_notify_cb_t)context_state_callback, self->mainloop); /*connect the context to default server*/ if (pa_context_connect(self->context, NULL, 0, NULL) < 0) { PyErr_SetString( PyExc_ValueError, "unable to connect context"); return -1; } pa_threaded_mainloop_lock(self->mainloop); if (pa_threaded_mainloop_start(self->mainloop)) { PyErr_SetString( PyExc_ValueError, "unable to start mainloop thread"); goto error; } do { pa_context_state_t state = pa_context_get_state(self->context); if (state == PA_CONTEXT_READY) { break; } else if ((state == PA_CONTEXT_FAILED) || (state == PA_CONTEXT_TERMINATED)) { PyErr_SetString( PyExc_ValueError, "failed to start main loop"); goto error; } else { pa_threaded_mainloop_wait(self->mainloop); } } while (1); /*create new connection stream*/ if ((self->stream = pa_stream_new(self->context, stream_name, &sample_spec, NULL)) == NULL) { PyErr_SetString( PyExc_ValueError, "unable to create PulseAudio connection stream"); goto error; } /*setup stream state change callback*/ pa_stream_set_state_callback( self->stream, (pa_stream_notify_cb_t)stream_state_callback, self->mainloop); /*setup stream write callback*/ pa_stream_set_write_callback( self->stream, (pa_stream_request_cb_t)write_stream_callback, self->mainloop); /*perform connection to PulseAudio server's default output stream*/ if (pa_stream_connect_playback( self->stream, NULL, /*device*/ NULL, /*buffering attributes*/ PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING, /*flags*/ NULL, /*volume*/ NULL /*sync stream*/) < 0) { PyErr_SetString( PyExc_ValueError, "unable to connect for PulseAudio playback"); goto error; } do { pa_stream_state_t state = pa_stream_get_state(self->stream); if (state == PA_STREAM_READY) { break; } else if ((state == PA_STREAM_FAILED) || (state == PA_STREAM_TERMINATED)) { PyErr_SetString(PyExc_ValueError, "failed to connect stream"); goto error; } else { pa_threaded_mainloop_wait(self->mainloop); } } while (1); pa_threaded_mainloop_unlock(self->mainloop); return 0; error: pa_threaded_mainloop_unlock(self->mainloop); return -1; }