/** * Setup a new stream based on the properties of the given audio_buf */ static void stream_setup(pa_audio_mode_t *pam, audio_buf_t *ab) { pa_stream *s; char buf[100]; int flags = 0; #if PA_API_VERSION >= 12 pa_proplist *pl; media_pipe_t *mp = ab->ab_mp; #endif pa_channel_map map; pa_cvolume cv; memset(&pam->ss, 0, sizeof(pa_sample_spec)); pam->ss.format = ab->ab_isfloat ? PA_SAMPLE_FLOAT32NE : PA_SAMPLE_S16NE; pam->ss.rate = ab->ab_samplerate; switch(ab->ab_format) { case AM_FORMAT_PCM_STEREO: pam->ss.channels = 2; pa_channel_map_init_stereo(&map); break; case AM_FORMAT_PCM_5DOT0: pam->ss.channels = 5; pa_channel_map_init(&map); map.channels = 5; map.map[0] = PA_CHANNEL_POSITION_LEFT; map.map[1] = PA_CHANNEL_POSITION_RIGHT; map.map[2] = PA_CHANNEL_POSITION_CENTER; map.map[3] = PA_CHANNEL_POSITION_SIDE_LEFT; map.map[4] = PA_CHANNEL_POSITION_SIDE_RIGHT; break; case AM_FORMAT_PCM_5DOT1: pam->ss.channels = 6; pa_channel_map_init(&map); map.channels = 6; map.map[0] = PA_CHANNEL_POSITION_LEFT; map.map[1] = PA_CHANNEL_POSITION_RIGHT; map.map[2] = PA_CHANNEL_POSITION_CENTER; map.map[3] = PA_CHANNEL_POSITION_LFE; map.map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; map.map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; break; case AM_FORMAT_PCM_7DOT1: pam->ss.channels = 8; pa_channel_map_init(&map); map.channels = 8; map.map[0] = PA_CHANNEL_POSITION_LEFT; map.map[1] = PA_CHANNEL_POSITION_RIGHT; map.map[2] = PA_CHANNEL_POSITION_CENTER; map.map[3] = PA_CHANNEL_POSITION_LFE; map.map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; map.map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; map.map[6] = PA_CHANNEL_POSITION_REAR_LEFT; map.map[7] = PA_CHANNEL_POSITION_REAR_RIGHT; break; case AM_FORMAT_PCM_6DOT1: pam->ss.channels = 7; pa_channel_map_init(&map); map.channels = 7; map.map[0] = PA_CHANNEL_POSITION_LEFT; map.map[1] = PA_CHANNEL_POSITION_RIGHT; map.map[2] = PA_CHANNEL_POSITION_CENTER; map.map[3] = PA_CHANNEL_POSITION_LFE; map.map[4] = PA_CHANNEL_POSITION_SIDE_LEFT; map.map[5] = PA_CHANNEL_POSITION_SIDE_RIGHT; map.map[6] = PA_CHANNEL_POSITION_REAR_CENTER; break; default: abort(); } TRACE(TRACE_DEBUG, "PA", "Created stream %s", pa_sample_spec_snprint(buf, sizeof(buf), &pam->ss)); #if PA_API_VERSION >= 12 pl = pa_proplist_new(); if(mp->mp_flags & MP_VIDEO) pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "video"); else pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "music"); s = pa_stream_new_with_proplist(pam->context, "Showtime playback", &pam->ss, &map, pl); pa_proplist_free(pl); #else s = pa_stream_new(pam->context, "Showtime playback", &pam->ss, &map); #endif pa_stream_set_state_callback(s, stream_state_callback, pam); pa_stream_set_write_callback(s, stream_write_callback, pam); flags |= PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING; memset(&cv, 0, sizeof(cv)); pa_cvolume_set(&cv, pam->ss.channels, pam->mastervol); #if 1 pa_buffer_attr pba = {0}; pba.fragsize = (uint32_t)-1; pba.maxlength = 16 * 1024; pba.minreq = 3 * 1024; pba.prebuf = 8 * 1024; pba.tlength = 12 * 1024; #endif pa_stream_connect_playback(s, NULL, &pba, flags, &cv, NULL); pam->stream = s; pam->cur_rate = ab->ab_samplerate; pam->cur_format = ab->ab_format; pam->cur_isfloat = ab->ab_isfloat; }
void Sounds::reload() { if (m_ctx) { destroy(); } // This can not happen but just in case if (m_loop) { destroy(); } m_loop = pa_threaded_mainloop_new(); pa_proplist *prop = pa_proplist_new(); #ifdef SAILFISH pa_proplist_sets(prop, PA_PROP_MEDIA_ROLE, "event"); #else pa_proplist_sets(prop, PA_PROP_MEDIA_ROLE, MEDIA_ROLE); #endif pa_proplist_sets(prop, PA_PROP_APPLICATION_NAME, qPrintable(QCoreApplication::instance()->applicationName())); #ifdef SAILFISH pa_proplist_sets(prop, PA_PROP_APPLICATION_PROCESS_BINARY, "ngfd"); #endif m_ctx = pa_context_new_with_proplist(pa_threaded_mainloop_get_api(m_loop), NULL, prop); pa_proplist_free(prop); if (!m_ctx) { qmlInfo(this) << "Failed to create pulse audio context"; return; } pa_context_set_state_callback(m_ctx, (pa_context_notify_cb_t)contextStateCallback, m_loop); if (pa_context_connect(m_ctx, NULL, PA_CONTEXT_NOAUTOSPAWN, NULL) < 0) { pa_context_unref(m_ctx); m_ctx = 0; qmlInfo(this) << "Failed to connect to pulse audio"; return; } pa_threaded_mainloop_lock(m_loop); if (pa_threaded_mainloop_start(m_loop) < 0) { pa_threaded_mainloop_unlock(m_loop); pa_context_disconnect(m_ctx); pa_context_unref(m_ctx); m_ctx = 0; qmlInfo(this) << "Failed to start pulse audio loop"; return; } while (true) { bool out = false; switch (pa_context_get_state(m_ctx)) { case PA_CONTEXT_UNCONNECTED: case PA_CONTEXT_CONNECTING: case PA_CONTEXT_AUTHORIZING: case PA_CONTEXT_SETTING_NAME: pa_threaded_mainloop_wait(m_loop); continue; case PA_CONTEXT_READY: out = true; break; case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: pa_threaded_mainloop_unlock(m_loop); pa_context_disconnect(m_ctx); pa_context_unref(m_ctx); m_ctx = 0; qmlInfo(this) << "Failed to connect to pulse audio server"; return; } if (out) { break; } } pa_context_set_state_callback(m_ctx, NULL, NULL); pa_threaded_mainloop_unlock(m_loop); for (QHash<QString, SoundFileInfo *>::const_iterator iter = m_files.begin(); iter != m_files.end(); iter++) { cache(iter.key()); } }
/* Generic sink state change logic. Used by raw_sink and voip_sink */ int voice_sink_set_state(pa_sink *s, pa_sink *other, pa_sink_state_t state) { struct userdata *u; pa_sink *om_sink; pa_sink_assert_ref(s); pa_assert_se(u = s->userdata); if (!other) { pa_log_debug("other sink not initialized or freed"); return 0; } pa_sink_assert_ref(other); om_sink = u->master_sink; if (u->hw_sink_input && PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->hw_sink_input))) { if (pa_sink_input_get_state(u->hw_sink_input) == PA_SINK_INPUT_CORKED) { if (PA_SINK_IS_OPENED(state) || PA_SINK_IS_OPENED(pa_sink_get_state(other)) || pa_atomic_load(&u->cmt_connection.dl_state) == CMT_DL_ACTIVE) { pa_sink_input_cork(u->hw_sink_input, FALSE); pa_log_debug("hw_sink_input uncorked"); } } else { if (state == PA_SINK_SUSPENDED && pa_sink_get_state(other) == PA_SINK_SUSPENDED && pa_atomic_load(&u->cmt_connection.dl_state) != CMT_DL_ACTIVE) { pa_sink_input_cork(u->hw_sink_input, TRUE); pa_log_debug("hw_sink_input corked"); } } } if (om_sink == NULL) { pa_log_info("No master sink, assuming primary mixer tuning.\n"); pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_PRI); } else if (pa_atomic_load(&u->cmt_connection.dl_state) == CMT_DL_ACTIVE || (pa_sink_get_state(u->voip_sink) <= PA_SINK_SUSPENDED && voice_voip_sink_used_by(u))) { if (pa_atomic_load(&u->mixer_state) == PROP_MIXER_TUNING_PRI) { pa_proplist *p = pa_proplist_new(); pa_assert(p); pa_proplist_sets(p, PROP_MIXER_TUNING_MODE, PROP_MIXER_TUNING_ALT_S); pa_sink_update_proplist(om_sink, PA_UPDATE_REPLACE, p); pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_ALT); pa_proplist_free(p); if (u->sidetone_enable) voice_enable_sidetone(u,1); } } else { if (pa_atomic_load(&u->mixer_state) == PROP_MIXER_TUNING_ALT) { pa_proplist *p = pa_proplist_new(); pa_assert(p); pa_proplist_sets(p, PROP_MIXER_TUNING_MODE, PROP_MIXER_TUNING_PRI_S); pa_sink_update_proplist(om_sink, PA_UPDATE_REPLACE, p); pa_atomic_store(&u->mixer_state, PROP_MIXER_TUNING_PRI); pa_proplist_free(p); voice_enable_sidetone(u,0); } } return 0; }
static int pa_audio_start(audio_mode_t *am, audio_fifo_t *af) { pa_audio_mode_t *pam = (pa_audio_mode_t *)am; audio_buf_t *ab = NULL; size_t l, length; int64_t pts; media_pipe_t *mp; int r = 0; pa_threaded_mainloop_lock(mainloop); #if PA_API_VERSION >= 12 pa_proplist *pl = pa_proplist_new(); pa_proplist_sets(pl, PA_PROP_APPLICATION_ID, "com.lonelycoder.hts.showtime"); pa_proplist_sets(pl, PA_PROP_APPLICATION_NAME, "Showtime"); /* Create a new connection context */ pam->context = pa_context_new_with_proplist(api, "Showtime", pl); pa_proplist_free(pl); #else pam->context = pa_context_new(api, "Showtime"); #endif if(pam->context == NULL) { pa_threaded_mainloop_unlock(mainloop); return -1; } pa_context_set_state_callback(pam->context, context_state_callback, pam); /* Connect the context */ if(pa_context_connect(pam->context, NULL, 0, NULL) < 0) { TRACE(TRACE_ERROR, "PA", "pa_context_connect() failed: %s", pa_strerror(pa_context_errno(pam->context))); pa_threaded_mainloop_unlock(mainloop); return -1; } /* Need at least one packet of audio */ /* Subscribe to updates of master volume */ pam->sub_mvol = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_FLOAT, set_mastervol, pam, PROP_TAG_ROOT, prop_mastervol, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); /* Subscribe to updates of master volume mute */ pam->sub_mute = prop_subscribe(PROP_SUB_DIRECT_UPDATE, PROP_TAG_CALLBACK_INT, set_mastermute, pam, PROP_TAG_ROOT, prop_mastermute, PROP_TAG_EXTERNAL_LOCK, mainloop, prop_pa_lockmgr, NULL); while(1) { if(ab == NULL) { pa_threaded_mainloop_unlock(mainloop); ab = af_deq2(af, 1, am); pa_threaded_mainloop_lock(mainloop); if(ab == AF_EXIT) { ab = NULL; break; } } if(pa_context_get_state(pam->context) == PA_CONTEXT_TERMINATED || pa_context_get_state(pam->context) == PA_CONTEXT_FAILED) { r = -1; break; } if(pam->stream != NULL && (pam->cur_format != ab->ab_format || pam->cur_rate != ab->ab_samplerate || pam->cur_isfloat != ab->ab_isfloat)) { stream_destroy(pam); } if(pam->stream == NULL && pa_context_get_state(pam->context) == PA_CONTEXT_READY) { /* Context is ready, but we don't have a stream yet, set it up */ stream_setup(pam, ab); } if(pam->stream == NULL) { pa_threaded_mainloop_wait(mainloop); continue; } switch(pa_stream_get_state(pam->stream)) { case PA_STREAM_UNCONNECTED: case PA_STREAM_CREATING: pa_threaded_mainloop_wait(mainloop); continue; case PA_STREAM_READY: break; case PA_STREAM_TERMINATED: case PA_STREAM_FAILED: pa_stream_unref(pam->stream); pam->stream = NULL; char msg[100]; snprintf(msg, sizeof(msg), "Audio stream disconnected from " "PulseAudio server -- %s.", pa_strerror(pam->stream_error)); mp_flush(ab->ab_mp, 0); mp_enqueue_event(ab->ab_mp, event_create_str(EVENT_INTERNAL_PAUSE, msg)); audio_fifo_purge(af, NULL, NULL); if(ab != NULL) { ab_free(ab); ab = NULL; } continue; } if(ab->ab_flush) { pa_operation *o; o = pa_stream_flush(pam->stream, NULL, NULL); if(o != NULL) pa_operation_unref(o); ab->ab_flush = 0; } l = pa_stream_writable_size(pam->stream); if(l == 0) { pa_threaded_mainloop_wait(mainloop); continue; } length = ab->ab_frames * pa_frame_size(&pam->ss) - ab->ab_tmp; if(l > length) l = length; if((pts = ab->ab_pts) != AV_NOPTS_VALUE && ab->ab_mp != NULL) { int64_t pts; pa_usec_t delay; pts = ab->ab_pts; ab->ab_pts = AV_NOPTS_VALUE; if(!pa_stream_get_latency(pam->stream, &delay, NULL)) { mp = ab->ab_mp; hts_mutex_lock(&mp->mp_clock_mutex); mp->mp_audio_clock = pts - delay; mp->mp_audio_clock_realtime = showtime_get_ts(); mp->mp_audio_clock_epoch = ab->ab_epoch; hts_mutex_unlock(&mp->mp_clock_mutex); } } pa_stream_write(pam->stream, ab->ab_data + ab->ab_tmp, l, NULL, 0LL, PA_SEEK_RELATIVE); ab->ab_tmp += l; assert(ab->ab_tmp <= ab->ab_frames * pa_frame_size(&pam->ss)); if(ab->ab_frames * pa_frame_size(&pam->ss) == ab->ab_tmp) { ab_free(ab); ab = NULL; } } prop_unsubscribe(pam->sub_mvol); prop_unsubscribe(pam->sub_mute); if(pam->stream != NULL) stream_destroy(pam); pa_threaded_mainloop_unlock(mainloop); pa_context_unref(pam->context); if(ab != NULL) { ab_free(ab); ab = NULL; } return r; }
pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) { pa_module *m = NULL; pa_bool_t (*load_once)(void); const char* (*get_deprecated)(void); pa_modinfo *mi; pa_assert(c); pa_assert(name); if (c->disallow_module_loading) goto fail; m = pa_xnew(pa_module, 1); m->name = pa_xstrdup(name); m->argument = pa_xstrdup(argument); m->load_once = FALSE; m->proplist = pa_proplist_new(); if (!(m->dl = lt_dlopenext(name))) { pa_log("Failed to open module \"%s\": %s", name, lt_dlerror()); goto fail; } if ((load_once = (pa_bool_t (*)(void)) pa_load_sym(m->dl, name, PA_SYMBOL_LOAD_ONCE))) { m->load_once = load_once(); if (m->load_once) { pa_module *i; uint32_t idx; /* OK, the module only wants to be loaded once, let's make sure it is */ for (i = pa_idxset_first(c->modules, &idx); i; i = pa_idxset_next(c->modules, &idx)) { if (strcmp(name, i->name) == 0) { pa_log("Module \"%s\" should be loaded once at most. Refusing to load.", name); goto fail; } } } } if ((get_deprecated = (const char* (*) (void)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_DEPRECATE))) { const char *t; if ((t = get_deprecated())) pa_log_warn("%s is deprecated: %s", name, t); } if (!(m->init = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_INIT))) { pa_log("Failed to load module \"%s\": symbol \""PA_SYMBOL_INIT"\" not found.", name); goto fail; } m->done = (void (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_DONE); m->get_n_used = (int (*)(pa_module*_m)) pa_load_sym(m->dl, name, PA_SYMBOL_GET_N_USED); m->userdata = NULL; m->core = c; m->unload_requested = FALSE; if (m->init(m) < 0) { pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : ""); goto fail; } pa_assert_se(pa_idxset_put(c->modules, m, &m->index) >= 0); pa_assert(m->index != PA_IDXSET_INVALID); pa_log_info("Loaded \"%s\" (index: #%u; argument: \"%s\").", m->name, m->index, m->argument ? m->argument : ""); pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_MODULE|PA_SUBSCRIPTION_EVENT_NEW, m->index); if ((mi = pa_modinfo_get_by_handle(m->dl, name))) { if (mi->author && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_AUTHOR)) pa_proplist_sets(m->proplist, PA_PROP_MODULE_AUTHOR, mi->author); if (mi->description && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_DESCRIPTION)) pa_proplist_sets(m->proplist, PA_PROP_MODULE_DESCRIPTION, mi->description); if (mi->version && !pa_proplist_contains(m->proplist, PA_PROP_MODULE_VERSION)) pa_proplist_sets(m->proplist, PA_PROP_MODULE_VERSION, mi->version); pa_modinfo_free(mi); } return m; fail: if (m) { if (m->proplist) pa_proplist_free(m->proplist); pa_xfree(m->argument); pa_xfree(m->name); if (m->dl) lt_dlclose(m->dl); pa_xfree(m); } return NULL; }
AudioStream::AudioStream(pa_context *c, pa_threaded_mainloop *m, const char *desc, int type, unsigned samplrate, const PaDeviceInfos* infos, bool ec) : audiostream_(0), mainloop_(m) { const pa_channel_map channel_map = infos->channel_map; pa_sample_spec sample_spec = { PA_SAMPLE_S16LE, // PA_SAMPLE_FLOAT32LE, samplrate, channel_map.channels }; RING_DBG("%s: trying to create stream with device %s (%dHz, %d channels)", desc, infos->name.c_str(), samplrate, channel_map.channels); assert(pa_sample_spec_valid(&sample_spec)); assert(pa_channel_map_valid(&channel_map)); std::unique_ptr<pa_proplist, decltype(pa_proplist_free)&> pl (pa_proplist_new(), pa_proplist_free); pa_proplist_sets(pl.get(), PA_PROP_FILTER_WANT, "echo-cancel"); audiostream_ = pa_stream_new_with_proplist(c, desc, &sample_spec, &channel_map, ec ? pl.get() : nullptr); if (!audiostream_) { RING_ERR("%s: pa_stream_new() failed : %s" , desc, pa_strerror(pa_context_errno(c))); throw std::runtime_error("Could not create stream\n"); } pa_buffer_attr attributes; attributes.maxlength = pa_usec_to_bytes(160 * PA_USEC_PER_MSEC, &sample_spec); attributes.tlength = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec); attributes.prebuf = 0; attributes.fragsize = pa_usec_to_bytes(80 * PA_USEC_PER_MSEC, &sample_spec); attributes.minreq = (uint32_t) -1; { PulseMainLoopLock lock(mainloop_); const pa_stream_flags_t flags = static_cast<pa_stream_flags_t>(PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE); if (type == PLAYBACK_STREAM || type == RINGTONE_STREAM) { pa_stream_connect_playback(audiostream_, infos->name.empty() ? NULL : infos->name.c_str(), &attributes, flags, NULL, NULL); } else if (type == CAPTURE_STREAM) { pa_stream_connect_record(audiostream_, infos->name.empty() ? NULL : infos->name.c_str(), &attributes, flags); } } pa_stream_set_state_callback(audiostream_, [](pa_stream* s, void* user_data){ static_cast<AudioStream*>(user_data)->stateChanged(s); }, this); pa_stream_set_moved_callback(audiostream_, [](pa_stream* s, void* user_data){ static_cast<AudioStream*>(user_data)->moved(s); }, this); }
static int pulseaudio_audio_reconfig(audio_decoder_t *ad) { decoder_t *d = (decoder_t *)ad; int i; pa_threaded_mainloop_lock(mainloop); if(pulseaudio_make_context_ready()) { pa_threaded_mainloop_unlock(mainloop); return -1; } if(d->s) { pa_stream_disconnect(d->s); pa_stream_unref(d->s); } pa_channel_map map; ad->ad_out_sample_rate = ad->ad_in_sample_rate; d->ss.rate = ad->ad_in_sample_rate; switch(ad->ad_in_sample_format) { case AV_SAMPLE_FMT_S32: case AV_SAMPLE_FMT_S32P: ad->ad_out_sample_format = AV_SAMPLE_FMT_S32; d->ss.format = PA_SAMPLE_S32NE; d->framesize = sizeof(int32_t); break; case AV_SAMPLE_FMT_S16: case AV_SAMPLE_FMT_S16P: ad->ad_out_sample_format = AV_SAMPLE_FMT_S16; d->ss.format = PA_SAMPLE_S16NE; d->framesize = sizeof(int16_t); break; default: ad->ad_out_sample_format = AV_SAMPLE_FMT_FLT; d->ss.format = PA_SAMPLE_FLOAT32NE; d->framesize = sizeof(float); break; } switch(ad->ad_in_channel_layout) { case AV_CH_LAYOUT_MONO: d->ss.channels = 1; ad->ad_out_channel_layout = AV_CH_LAYOUT_MONO; pa_channel_map_init_mono(&map); break; case AV_CH_LAYOUT_STEREO: d->ss.channels = 2; ad->ad_out_channel_layout = AV_CH_LAYOUT_STEREO; pa_channel_map_init_stereo(&map); default: pa_channel_map_init(&map); for(i = 0; i < sizeof(av2pa_map) / sizeof(av2pa_map[0]); i++) { if(ad->ad_in_channel_layout & av2pa_map[i].avmask) { ad->ad_out_channel_layout |= av2pa_map[i].avmask; map.map[map.channels++] = av2pa_map[i].papos; } } d->ss.channels = map.channels; break; } d->framesize *= d->ss.channels; ad->ad_tile_size = pa_context_get_tile_size(ctx, &d->ss) / d->framesize; char buf[100]; char buf2[PA_CHANNEL_MAP_SNPRINT_MAX]; TRACE(TRACE_DEBUG, "PA", "Created stream %s [%s] (tilesize=%d)", pa_sample_spec_snprint(buf, sizeof(buf), &d->ss), pa_channel_map_snprint(buf2, sizeof(buf2), &map), ad->ad_tile_size); #if PA_API_VERSION >= 12 pa_proplist *pl = pa_proplist_new(); media_pipe_t *mp = ad->ad_mp; if(mp->mp_flags & MP_VIDEO) pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "video"); else pa_proplist_sets(pl, PA_PROP_MEDIA_ROLE, "music"); d->s = pa_stream_new_with_proplist(ctx, "Showtime playback", &d->ss, &map, pl); pa_proplist_free(pl); #else d->s = pa_stream_new(ctx, "Showtime playback", &ss, &map); #endif int flags = 0; pa_stream_set_state_callback(d->s, stream_state_callback, d); pa_stream_set_write_callback(d->s, stream_write_callback, d); flags |= PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_INTERPOLATE_TIMING; pa_stream_connect_playback(d->s, NULL, NULL, flags, NULL, NULL); while(1) { switch(pa_stream_get_state(d->s)) { case PA_STREAM_UNCONNECTED: case PA_STREAM_CREATING: pa_threaded_mainloop_wait(mainloop); continue; case PA_STREAM_READY: pa_threaded_mainloop_unlock(mainloop); return 0; case PA_STREAM_TERMINATED: case PA_STREAM_FAILED: pa_threaded_mainloop_unlock(mainloop); return 1; } } }
int soundio_pulseaudio_init(struct SoundIoPrivate *si) { struct SoundIo *soundio = &si->pub; struct 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; }
pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) { pa_context *c; pa_mem_type_t type; pa_assert(mainloop); if (pa_detect_fork()) return NULL; pa_init_i18n(); c = pa_xnew0(pa_context, 1); PA_REFCNT_INIT(c); c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new(); if (name) pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name); #ifdef HAVE_DBUS c->system_bus = c->session_bus = NULL; #endif c->mainloop = mainloop; c->playback_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); c->record_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); c->client_index = PA_INVALID_INDEX; c->use_rtclock = pa_mainloop_is_our_api(mainloop); PA_LLIST_HEAD_INIT(pa_stream, c->streams); PA_LLIST_HEAD_INIT(pa_operation, c->operations); c->error = PA_OK; c->state = PA_CONTEXT_UNCONNECTED; reset_callbacks(c); #ifndef MSG_NOSIGNAL #ifdef SIGPIPE pa_check_signal_is_blocked(SIGPIPE); #endif #endif c->conf = pa_client_conf_new(); pa_client_conf_load(c->conf, true, true); c->srb_template.readfd = -1; c->srb_template.writefd = -1; c->memfd_on_local = (!c->conf->disable_memfd && pa_memfd_is_locally_supported()); type = (c->conf->disable_shm) ? PA_MEM_TYPE_PRIVATE : ((!c->memfd_on_local) ? PA_MEM_TYPE_SHARED_POSIX : PA_MEM_TYPE_SHARED_MEMFD); if (!(c->mempool = pa_mempool_new(type, c->conf->shm_size, true))) { if (!c->conf->disable_shm) { pa_log_warn("Failed to allocate shared memory pool. Falling back to a normal private one."); c->mempool = pa_mempool_new(PA_MEM_TYPE_PRIVATE, c->conf->shm_size, true); } if (!c->mempool) { context_free(c); return NULL; } } return c; }
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); }
void on_set_common(pa_proplist* p, pa_tagstruct* t, pa_core* c) { pa_log_info("on_set_common"); const char* attribute = pa_proplist_gets(p, PROPLIST_KEY_ATTRIBUTE); if (!attribute) { pa_log_error("on_set_common: attribute not found!"); return; } if (!strcmp(attribute, PROPLIST_VALUE_GET_INFO)) { const char* str_device = pa_proplist_gets(p, PROPLIST_KEY_DEVICE); if (!str_device) { pa_log_error("on_set_common device not specific!"); return; } int device_id = atoi(str_device); pa_sink* sink = NULL; pa_source* source = NULL; sink = find_sink(c, device_id); if (!sink) { source = find_source(c, device_id); } if (!sink && !source) { pa_log_error("do not find any sink or source of device %d", device_id); return; } int n_used = 0; if (sink) { n_used = pa_module_get_n_used(sink->module); } else { n_used = pa_module_get_n_used(source->module); } char value[32]; snprintf(value, sizeof(value), "%d", n_used); pa_proplist* replyp = pa_proplist_new(); pa_proplist_sets(replyp, PROPLIST_KEY_VALUE, value); pa_tagstruct_put_proplist(t, replyp); pa_proplist_free(replyp); } else if (!strcmp(attribute, PROPLIST_VALUE_REMOTE_SINK)) { #ifdef HAVE_WEB_SOCKET extern void start_web_socket(); start_web_socket(); #endif on_set_debug(c, p, EAUDIO_STREAM_DEVICE_VIRTUALOUPUT_REMOTE, NULL); } else if (!strcmp(attribute, PROPLIST_VALUE_FILE_SINK)) { const char* str_path = pa_proplist_gets(p, PROPLIST_VALUE_PATH); char args[64] = { 0 }; if (str_path) { snprintf(args, sizeof(args), "path=%s", str_path); } on_set_debug(c, p, EAUDIO_STREAM_DEVICE_VIRTUALOUPUT_FILE, str_path ? args : NULL); } else if (!strcmp(attribute, PROPLIST_VALUE_ALSA_BUFFER)) { const char* str_device = pa_proplist_gets(p, PROPLIST_KEY_DEVICE); if (!str_device) { pa_log_error("on_set_common alsa-buffer device not specific!"); return; } int device = atoi(str_device); pa_sink* s = find_sink(c, device); if (!s) { pa_log_error("sink not found %d", device); return; } pa_usec_t left_to_play = pa_sink_get_left_to_play(s); pa_proplist* replyp = pa_proplist_new(); pa_proplist_set(replyp, PROPLIST_KEY_COMMAND_RESULT, &left_to_play, sizeof(left_to_play)); pa_tagstruct_put_proplist(t, replyp); pa_proplist_free(replyp); } else if (!strcmp(attribute, PROPLIST_VALUE_STOP_TEST)) { pthread_t tid_stop; int err = pthread_create(&tid_stop, NULL, stop_thread, NULL); if (err != 0) { pa_log_error("can't create thread: %s\n", strerror(err)); return; } } #ifdef HAVE_WEB_SOCKET else if (!strcmp(attribute, "web-start")) { extern void start_web_socket(); start_web_socket(); } else if (!strcmp(attribute, "web-stop")) { extern void stop_web_socket(); stop_web_socket(); } #endif }
static int init(struct ao *ao) { pa_proplist *proplist = NULL; pa_format_info *format = NULL; struct priv *priv = ao->priv; char *sink = priv->cfg_sink && priv->cfg_sink[0] ? priv->cfg_sink : ao->device; if (pa_init_boilerplate(ao) < 0) return -1; pa_threaded_mainloop_lock(priv->mainloop); 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_ICON_NAME, ao->client_name); if (!(format = pa_format_info_new())) goto unlock_and_fail; if (!set_format(ao, format)) { ao->channels = (struct mp_chmap) MP_CHMAP_INIT_STEREO; ao->samplerate = 48000; ao->format = AF_FORMAT_FLOAT; if (!set_format(ao, format)) { MP_ERR(ao, "Invalid audio format\n"); goto unlock_and_fail; } } if (!(priv->stream = pa_stream_new_extended(priv->context, "audio stream", &format, 1, proplist))) goto unlock_and_fail; pa_format_info_free(format); format = NULL; 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); int buf_size = af_fmt_seconds_to_bytes(ao->format, priv->cfg_buffer / 1000.0, ao->channels.num, ao->samplerate); pa_buffer_attr bufattr = { .maxlength = -1, .tlength = buf_size > 0 ? buf_size : (uint32_t)-1, .prebuf = -1, .minreq = -1, .fragsize = -1, }; int flags = PA_STREAM_NOT_MONOTONIC; if (!priv->cfg_latency_hacks) flags |= PA_STREAM_INTERPOLATE_TIMING|PA_STREAM_AUTO_TIMING_UPDATE; if (pa_stream_connect_playback(priv->stream, sink, &bufattr, flags, NULL, NULL) < 0) goto unlock_and_fail; /* Wait until the stream is ready */ while (1) { int state = pa_stream_get_state(priv->stream); if (state == PA_STREAM_READY) break; if (!PA_STREAM_IS_GOOD(state)) goto unlock_and_fail; pa_threaded_mainloop_wait(priv->mainloop); } if (pa_stream_is_suspended(priv->stream)) { MP_ERR(ao, "The stream is suspended. Bailing out.\n"); goto unlock_and_fail; } pa_threaded_mainloop_unlock(priv->mainloop); return 0; unlock_and_fail: pa_threaded_mainloop_unlock(priv->mainloop); if (format) pa_format_info_free(format); if (proplist) pa_proplist_free(proplist); uninit(ao); 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 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); }
void Sounds::cache(const QString& id) { SoundFileInfo *info = m_files[id]; if (!info) { return; } if (info->path().isEmpty()) { return; } if (!m_ctx) { return; } FileReader h(info->path()); pa_sample_spec *spec = h.sampleSpec(); if (!spec) { qmlInfo(this) << "Failed to get a sample spec"; return; } if (!pa_sample_spec_valid(spec)) { qmlInfo(this) << "Failed to get a valid sample spec"; return; } // First we set the file duration info->setDuration(pa_bytes_to_usec(h.size(), spec)); pa_proplist *prop = pa_proplist_new(); pa_proplist_sets(prop, PA_PROP_MEDIA_ROLE, "event"); #ifdef SAILFISH pa_proplist_sets(prop, PA_PROP_MEDIA_NAME, "camera-event"); #else pa_proplist_sets(prop, PA_PROP_MEDIA_NAME, qPrintable(id)); #endif pa_proplist_sets(prop, PA_PROP_EVENT_ID, qPrintable(id)); pa_proplist_sets(prop, PA_PROP_MEDIA_FILENAME, qPrintable(info->path())); #ifdef SAILFISH pa_proplist_sets(prop, PA_PROP_APPLICATION_PROCESS_BINARY, "ngfd"); pa_stream *stream = pa_stream_new_with_proplist(m_ctx, "camera-event", spec, NULL, prop); #else pa_stream *stream = pa_stream_new_with_proplist(m_ctx, qPrintable(id), spec, NULL, prop); #endif pa_proplist_free(prop); if (!stream) { qmlInfo(this) << "Failed to create a pulse audio stream"; return; } pa_stream_set_state_callback(stream, (pa_stream_notify_cb_t)streamStateCallback, m_loop); pa_stream_set_write_callback(stream, (pa_stream_request_cb_t)streamRequestCallback, &h); pa_threaded_mainloop_lock(m_loop); if (pa_stream_connect_upload(stream, h.size()) < 0) { pa_stream_unref(stream); pa_threaded_mainloop_unlock(m_loop); qmlInfo(this) << "Failed to connect pulse audio stream"; return; } while (true) { bool out = false; switch (pa_stream_get_state(stream)) { case PA_STREAM_FAILED: qmlInfo(this) << "Failed to connect our stream to pulse audio " << pa_strerror(pa_context_errno(m_ctx)); pa_stream_disconnect(stream); pa_stream_unref(stream); pa_threaded_mainloop_unlock(m_loop); return; case PA_STREAM_TERMINATED: pa_threaded_mainloop_unlock(m_loop); out = true; break; case PA_STREAM_READY: case PA_STREAM_UNCONNECTED: case PA_STREAM_CREATING: pa_threaded_mainloop_wait(m_loop); continue; } if (out) { break; } } pa_stream_unref(stream); }
JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_pulseaudio_PA_proplist_1new (JNIEnv *env, jclass clazz) { return (intptr_t) pa_proplist_new(); }
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 (0 == pa_ready) { pa_mainloop_iterate(pa_ml, 1, NULL); continue; } if (2 == pa_ready) { pa_context_disconnect(pa_ctx); pa_context_unref(pa_ctx); pa_mainloop_free(pa_ml); return -1; } switch (state) { case 0: if (pa_context_get_server_protocol_version (pa_ctx) < 13) { return -1; } printf("server version: %d\n", pa_context_get_server_protocol_version(pa_ctx)); pa_stream *s = NULL; pa_proplist *proplist; pa_buffer_attr attr; pa_sample_spec ss; int res; char dev_name[40]; // pa_sample_spec ss.channels = 1; ss.format = PA_SAMPLE_FLOAT32; ss.rate = 25; // pa_buffer_attr memset(&attr, 0, sizeof(attr)); attr.fragsize = sizeof(float); attr.maxlength = (uint32_t) -1; // pa_proplist proplist = pa_proplist_new (); pa_proplist_sets (proplist, PA_PROP_APPLICATION_ID, "deepin.sound"); // create new stream if (!(s = pa_stream_new_with_proplist(pa_ctx, "Peak detect", &ss, NULL, proplist))) { fprintf(stderr, "pa_stream_new error\n"); return -2; } pa_proplist_free(proplist); /*pa_stream_set_monitor_stream(s, 26);*/ pa_stream_set_read_callback(s, on_monitor_read_callback, NULL); pa_stream_set_suspended_callback(s, on_monitor_suspended_callback, NULL); res = pa_stream_connect_record(s, NULL, &attr, (pa_stream_flags_t) (PA_STREAM_DONT_MOVE |PA_STREAM_PEAK_DETECT |PA_STREAM_ADJUST_LATENCY)); if (res < 0) { fprintf(stderr, "Failed to connect monitoring stream\n"); return -3; } state++; break; case 1: usleep(100); break; case 2: return 0; break; default: return -1; } pa_mainloop_iterate(pa_ml, 1, NULL); } return 0; }
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; }
pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) { pa_context *c; pa_assert(mainloop); if (pa_detect_fork()) return NULL; pa_init_i18n(); c = pa_xnew0(pa_context, 1); PA_REFCNT_INIT(c); c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new(); if (name) pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name); #ifdef HAVE_DBUS c->system_bus = c->session_bus = NULL; #endif c->mainloop = mainloop; c->playback_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); c->record_streams = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func); c->client_index = PA_INVALID_INDEX; c->use_rtclock = pa_mainloop_is_our_api(mainloop); PA_LLIST_HEAD_INIT(pa_stream, c->streams); PA_LLIST_HEAD_INIT(pa_operation, c->operations); c->error = PA_OK; c->state = PA_CONTEXT_UNCONNECTED; reset_callbacks(c); #ifndef MSG_NOSIGNAL #ifdef SIGPIPE pa_check_signal_is_blocked(SIGPIPE); #endif #endif c->conf = pa_client_conf_new(); pa_client_conf_load(c->conf, NULL); #ifdef HAVE_X11 pa_client_conf_from_x11(c->conf, NULL); #endif pa_client_conf_env(c->conf); if (!(c->mempool = pa_mempool_new(!c->conf->disable_shm, c->conf->shm_size))) { if (!c->conf->disable_shm) c->mempool = pa_mempool_new(FALSE, c->conf->shm_size); if (!c->mempool) { context_free(c); return NULL; } } return c; }
bool AudioOutputPulseAudio::ConnectPlaybackStream(void) { QString fn_log_tag = "ConnectPlaybackStream, "; 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_MEDIA_ROLE, "video"); pstream = pa_stream_new_with_proplist(pcontext, "MythTV playback", &sample_spec, &channel_map, proplist); if (!pstream) { VBERROR("failed to create new playback stream"); return false; } pa_stream_set_state_callback(pstream, StreamStateCallback, this); pa_stream_set_write_callback(pstream, WriteCallback, this); pa_stream_set_overflow_callback(pstream, BufferFlowCallback, (char*)"over"); pa_stream_set_underflow_callback(pstream, BufferFlowCallback, (char*)"under"); if (set_initial_vol) { int volume = gCoreContext->GetNumSetting("MasterMixerVolume", 80); pa_cvolume_set(&volume_control, channels, (float)volume * (float)PA_VOLUME_NORM / 100.0f); } else pa_cvolume_reset(&volume_control, channels); fragment_size = (samplerate * 25 * output_bytes_per_frame) / 1000; buffer_settings.maxlength = (uint32_t)-1; buffer_settings.tlength = fragment_size * 4; buffer_settings.prebuf = (uint32_t)-1; buffer_settings.minreq = (uint32_t)-1; int flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_NO_REMIX_CHANNELS; pa_stream_connect_playback(pstream, NULL, &buffer_settings, (pa_stream_flags_t)flags, NULL, NULL); pa_context_state_t cstate; pa_stream_state_t sstate; bool connected = false, failed = false; while (!(connected || failed)) { switch (cstate = pa_context_get_state(pcontext)) { case PA_CONTEXT_FAILED: case PA_CONTEXT_TERMINATED: VBERROR(QString("context is stuffed, %1") .arg(pa_strerror(pa_context_errno(pcontext)))); failed = true; break; default: switch (sstate = pa_stream_get_state(pstream)) { case PA_STREAM_READY: connected = true; break; case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: VBERROR(QString("stream failed or was terminated, " "context state %1, stream state %2") .arg(cstate).arg(sstate)); failed = true; break; default: pa_threaded_mainloop_wait(mainloop); break; } } } const pa_buffer_attr *buf_attr = pa_stream_get_buffer_attr(pstream); fragment_size = buf_attr->tlength >> 2; soundcard_buffer_size = buf_attr->maxlength; VBAUDIO(QString("fragment size %1, soundcard buffer size %2") .arg(fragment_size).arg(soundcard_buffer_size)); return (connected && !failed); }
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; }
int pa_scache_play_item(pa_core *c, const char *name, pa_sink *sink, pa_volume_t volume, pa_proplist *p, uint32_t *sink_input_idx) { pa_scache_entry *e; pa_cvolume r; pa_proplist *merged; pa_bool_t pass_volume; pa_assert(c); pa_assert(name); pa_assert(sink); if (!(e = pa_namereg_get(c, name, PA_NAMEREG_SAMPLE))) return -1; merged = pa_proplist_new(); pa_proplist_sets(merged, PA_PROP_MEDIA_NAME, name); pa_proplist_sets(merged, PA_PROP_EVENT_ID, name); if (e->lazy && !e->memchunk.memblock) { pa_channel_map old_channel_map = e->channel_map; if (pa_sound_file_load(c->mempool, e->filename, &e->sample_spec, &e->channel_map, &e->memchunk, merged) < 0) goto fail; pa_subscription_post(c, PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE|PA_SUBSCRIPTION_EVENT_CHANGE, e->index); if (e->volume_is_set) { if (pa_cvolume_valid(&e->volume)) pa_cvolume_remap(&e->volume, &old_channel_map, &e->channel_map); else pa_cvolume_reset(&e->volume, e->sample_spec.channels); } } if (!e->memchunk.memblock) goto fail; pa_log_debug("Playing sample \"%s\" on \"%s\"", name, sink->name); pass_volume = TRUE; if (e->volume_is_set && volume != PA_VOLUME_INVALID) { pa_cvolume_set(&r, e->sample_spec.channels, volume); pa_sw_cvolume_multiply(&r, &r, &e->volume); } else if (e->volume_is_set) r = e->volume; else if (volume != PA_VOLUME_INVALID) pa_cvolume_set(&r, e->sample_spec.channels, volume); else pass_volume = FALSE; pa_proplist_update(merged, PA_UPDATE_REPLACE, e->proplist); if (p) pa_proplist_update(merged, PA_UPDATE_REPLACE, p); if (pa_play_memchunk(sink, &e->sample_spec, &e->channel_map, &e->memchunk, pass_volume ? &r : NULL, merged, PA_SINK_INPUT_NO_CREATE_ON_SUSPEND|PA_SINK_INPUT_KILL_ON_SUSPEND, sink_input_idx) < 0) goto fail; pa_proplist_free(merged); if (e->lazy) time(&e->last_used_time); return 0; fail: pa_proplist_free(merged); return -1; }
/** * 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) { if (pw != NULL) pa_proplist_sets (props, PA_PROP_APPLICATION_PROCESS_USER, pw->pw_name); break; } } 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); break; } } 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); 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; }
void voice_sink_proplist_update(struct userdata *u, pa_sink *s) { pa_sink *master_sink; const char *mode; const char *accessory_hwid; pa_proplist *p; char *hash_str; unsigned int hash; const char *file; char fname[256]; size_t nbytes; const void *data; master_sink = voice_get_original_master_sink(u); ENTER(); if (!master_sink) { pa_log_warn("Original master sink not found, parameters not loaded."); return; } if (!pa_proplist_get(s->proplist, "x-maemo.aep.trace-func", &data, &nbytes)) memcpy(&u->trace_func, data, sizeof(u->trace_func)); mode = pa_proplist_gets(s->proplist, PA_NOKIA_PROP_AUDIO_MODE); accessory_hwid = pa_proplist_gets(s->proplist, PA_NOKIA_PROP_AUDIO_ACCESSORY_HWID); if (!accessory_hwid || !mode) return; if (master_sink != s) { p = pa_proplist_new(); pa_proplist_sets(p, PA_NOKIA_PROP_AUDIO_MODE, mode); pa_proplist_sets(p, PA_NOKIA_PROP_AUDIO_ACCESSORY_HWID, accessory_hwid); pa_proplist_update(master_sink->proplist, PA_UPDATE_REPLACE, p); pa_proplist_free(p); } hash_str = pa_sprintf_malloc("%s%s", mode, accessory_hwid); hash = pa_idxset_string_hash_func(hash_str); pa_xfree(hash_str); if (hash == u->mode_accessory_hwid_hash && !voice_pa_proplist_get_bool(master_sink->proplist, "x-maemo.tuning")) return; u->mode_accessory_hwid_hash = hash; file = pa_proplist_gets(master_sink->proplist, "x-maemo.file"); if (!file) file = "/var/lib/pulse-nokia/%s%s.parameters"; pa_snprintf(fname, sizeof(fname), file, mode); pa_log_debug("Loading tuning parameters from file: %s",fname); p = pa_nokia_proplist_from_file(fname); if (!pa_proplist_contains(p, "x-maemo.aep") ) { pa_log_warn("Parameter file not valid: %s", fname); pa_proplist_free(p); return; } u->btmono = FALSE; if (!strcmp(mode, "ihf")) aep_runtime_switch[3] = 'i'; else if (!strcmp(mode, "hs")) aep_runtime_switch[3] = 't'; else if (!strcmp(mode, "btmono")) { aep_runtime_switch[3] = 't'; u->btmono = TRUE; } else if (!strcmp(mode, "hp")) aep_runtime_switch[3] = 'p'; else if (!strcmp(mode, "lineout")) aep_runtime_switch[3] = 'f'; else aep_runtime_switch[3] = 't'; if (master_sink == s) pa_proplist_update(master_sink->proplist, PA_UPDATE_REPLACE, p); else pa_sink_update_proplist(master_sink, PA_UPDATE_REPLACE, p); pa_proplist_free(p); voice_update_parameters(u); return; }