void change_sel_vol(pa_context * c, vol_change_t vol_change) { view_entry_t view_entry = view_selected_item(); if(view_entry.type == VIEW_SINK) { sink_t * sink = (sink_t *) view_entry.ref; if(sink != NULL) { /* averge all channel volumes of local copy */ pa_volume_t vol; vol = pa_cvolume_avg(&sink->volume); vol = modify_volume(vol, vol_change); pa_cvolume_set(&sink->volume, sink->volume.channels, vol); pa_context_set_sink_volume_by_index(c, sink->index, &sink->volume, NULL, NULL); } } if(view_entry.type == VIEW_SINK_INPUT) { sink_input_t * sink_input = (sink_input_t *) view_entry.ref; if(sink_input != NULL) { /* averge all channel volumes of local copy */ pa_volume_t vol; vol = pa_cvolume_avg(&sink_input->volume); vol = modify_volume(vol, vol_change); pa_cvolume_set(&sink_input->volume, sink_input->volume.channels, vol); pa_context_set_sink_input_volume(c, sink_input->index, &sink_input->volume, NULL, NULL); } } }
static void handle_sink_input_fixate(struct userdata *u, pa_sink_input_new_data *sinp_data) { struct pa_policy_group *group = NULL; const char *sinp_name; int group_volume; pa_cvolume group_limit; uint32_t flags; pa_assert(u); pa_assert(sinp_data); pa_assert_se((group = get_group(u, NULL, sinp_data->proplist, &flags))); sinp_name = sink_input_ext_get_name(sinp_data->proplist); group_volume = group->flags & PA_POLICY_GROUP_FLAG_LIMIT_VOLUME; /* Set volume factor in sink_input_fixate() so that we have our target sink and * channel_map defined properly. */ if (group_volume && !group->mutebyrt && group->limit > 0 && group->limit < PA_VOLUME_NORM) { pa_log_debug("set stream '%s'/'%s' volume factor to %d", group->name, sinp_name, (group->limit * 100) / PA_VOLUME_NORM); pa_cvolume_set(&group_limit, sinp_data->channel_map.channels, group->limit); pa_sink_input_new_data_add_volume_factor(sinp_data, sinp_name, &group_limit); } }
void CPulseAEStream::SetVolume(float volume) { if (!m_Initialized) return; if (!pa_threaded_mainloop_in_thread(m_MainLoop)) pa_threaded_mainloop_lock(m_MainLoop); if (volume > 0.f) { m_Volume = volume; pa_volume_t paVolume = pa_sw_volume_from_linear((double)(m_Volume * m_MaxVolume)); pa_cvolume_set(&m_ChVolume, m_SampleSpec.channels, paVolume); } else pa_cvolume_mute(&m_ChVolume,m_SampleSpec.channels); pa_operation *op = pa_context_set_sink_input_volume(m_Context, pa_stream_get_index(m_Stream), &m_ChVolume, NULL, NULL); if (op == NULL) CLog::Log(LOGERROR, "PulseAudio: Failed to set volume"); else pa_operation_unref(op); if (!pa_threaded_mainloop_in_thread(m_MainLoop)) pa_threaded_mainloop_unlock(m_MainLoop); }
static void sink_set_volume_cb(pa_sink *s) { struct userdata *u = s->userdata; pa_cvolume hw; pa_volume_t v; char t[PA_CVOLUME_SNPRINT_VERBOSE_MAX]; pa_assert(u); /* If we're muted we don't need to do anything */ if (s->muted) return; /* Calculate the max volume of all channels. We'll use this as our (single) volume on the APEX device and emulate any variation in channel volumes in software */ v = pa_cvolume_max(&s->real_volume); /* Create a pa_cvolume version of our single value */ pa_cvolume_set(&hw, s->sample_spec.channels, v); /* Perform any software manipulation of the volume needed */ pa_sw_cvolume_divide(&s->soft_volume, &s->real_volume, &hw); pa_log_debug("Requested volume: %s", pa_cvolume_snprint_verbose(t, sizeof(t), &s->real_volume, &s->channel_map, false)); pa_log_debug("Got hardware volume: %s", pa_cvolume_snprint_verbose(t, sizeof(t), &hw, &s->channel_map, false)); pa_log_debug("Calculated software volume: %s", pa_cvolume_snprint_verbose(t, sizeof(t), &s->soft_volume, &s->channel_map, true)); /* Any necessary software volume manipulation is done so set our hw volume (or v as a single value) on the device */ pa_raop_client_set_volume(u->raop, v); }
void PulseOutput::volume(FXfloat v) { if (pulse_context && stream) { pulsevolume = (pa_volume_t)(v*PA_VOLUME_NORM); pa_cvolume cvol; pa_cvolume_set(&cvol,af.channels,pulsevolume); pa_operation* operation = pa_context_set_sink_input_volume(pulse_context,pa_stream_get_index(stream),&cvol,nullptr,nullptr); pa_operation_unref(operation); } }
void PulseAudioInput::SetGain(long m_gain) { pa_cvolume v; v.values[0] = pa_sw_volume_from_linear(m_gain); pa_cvolume_set(&v, 2, v.values[0]); // pa_volume_t gain = pa_sw_volume_from_linear(m_gain); // pa_cvolume_set(mp_vol, 1, gain); return; }
void pulse_set_default_sink_volume(struct pulseaudio_t *pulse, pa_volume_t volume) { pa_operation *op; pa_cvolume_set(&(pulse->cvolume), 2, volume); op = pa_context_set_sink_volume_by_name(pulse->cxt, pulse->default_sink, &(pulse->cvolume), NULL, pulse); pulse_async_wait(pulse, op); pa_operation_unref(op); }
static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) { struct userdata *u = PA_SOURCE(o)->userdata; int err; audio_info_t info; switch (code) { case PA_SOURCE_MESSAGE_GET_LATENCY: { pa_usec_t r = 0; if (u->fd) { err = ioctl(u->fd, AUDIO_GETINFO, &info); pa_assert(err >= 0); r += pa_bytes_to_usec(info.record.samples * u->frame_size, &PA_SOURCE(o)->sample_spec); r -= pa_bytes_to_usec(u->read_bytes, &PA_SOURCE(o)->sample_spec); } *((pa_usec_t*) data) = r; return 0; } case PA_SOURCE_MESSAGE_SET_VOLUME: if (u->fd >= 0) { AUDIO_INITINFO(&info); info.record.gain = pa_cvolume_avg((pa_cvolume*) data) * AUDIO_MAX_GAIN / PA_VOLUME_NORM; assert(info.record.gain <= AUDIO_MAX_GAIN); if (ioctl(u->fd, AUDIO_SETINFO, &info) < 0) { if (errno == EINVAL) pa_log("AUDIO_SETINFO: Unsupported volume."); else pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); } else { return 0; } } break; case PA_SOURCE_MESSAGE_GET_VOLUME: if (u->fd >= 0) { err = ioctl(u->fd, AUDIO_GETINFO, &info); pa_assert(err >= 0); pa_cvolume_set((pa_cvolume*) data, ((pa_cvolume*) data)->channels, info.record.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); return 0; } break; } return pa_source_process_msg(o, code, data, offset, chunk); }
int sa_stream_set_volume_abs(sa_stream_t *s, float vol) { pa_cvolume cv; if (s == NULL || s->stream == NULL) { return SA_ERROR_NO_INIT; } pa_cvolume_set(&cv, s->sample_spec.channels, pa_sw_volume_from_dB(vol)); return SA_SUCCESS; }
JNIEXPORT jlong JNICALL Java_org_jitsi_impl_neomedia_pulseaudio_PA_cvolume_1set (JNIEnv *env, jclass clazz, jlong cv, jint channels, jint v) { return (intptr_t) pa_cvolume_set( (pa_cvolume *) (intptr_t) cv, (unsigned) channels, (pa_volume_t) v); }
static void set_volume(struct audio_service *service, int new_volume, void *user_data) { pa_cvolume volume; pa_operation *op; service->new_volume = new_volume; pa_cvolume_set(&volume, 1, (service->new_volume * (double) (PA_VOLUME_NORM / 100))); op = pa_context_set_sink_volume_by_name(service->context, service->default_sink_name, &volume, set_volume_success_cb, user_data); pa_operation_unref(op); }
static void set_from_pa_map (GvcChannelMap *map, const pa_channel_map *pa_map) { g_assert (pa_channel_map_valid(pa_map)); map->priv->can_balance = pa_channel_map_can_balance (pa_map); map->priv->can_fade = pa_channel_map_can_fade (pa_map); map->priv->pa_map = *pa_map; pa_cvolume_set(&map->priv->pa_volume, pa_map->channels, PA_VOLUME_NORM); }
static void source_get_volume(pa_source *s) { struct userdata *u; audio_info_t info; pa_assert_se(u = s->userdata); if (u->fd >= 0) { if (ioctl(u->fd, AUDIO_GETINFO, &info) < 0) pa_log("AUDIO_SETINFO: %s", pa_cstrerror(errno)); else pa_cvolume_set(&s->real_volume, s->sample_spec.channels, info.play.gain * PA_VOLUME_NORM / AUDIO_MAX_GAIN); } }
void CAESinkPULSE::UpdateInternalVolume(const pa_cvolume* nVol) { if (!nVol) return; pa_volume_t o_vol = pa_cvolume_avg(&m_Volume); pa_volume_t n_vol = pa_cvolume_avg(nVol); if (o_vol != n_vol) { pa_cvolume_set(&m_Volume, m_Channels, n_vol); m_volume_needs_update = true; } }
static int control(int cmd, void *arg) { switch (cmd) { case AOCONTROL_GET_VOLUME: { ao_control_vol_t *vol = arg; uint32_t devidx = pa_stream_get_index(stream); pa_threaded_mainloop_lock(mainloop); if (!waitop(pa_context_get_sink_input_info(context, devidx, info_func, NULL))) { GENERIC_ERR_MSG(context, "pa_stream_get_sink_input_info() failed"); return CONTROL_ERROR; } if (volume.channels != 2) vol->left = vol->right = pa_cvolume_avg(&volume)*100/PA_VOLUME_NORM; else { vol->left = volume.values[0]*100/PA_VOLUME_NORM; vol->right = volume.values[1]*100/PA_VOLUME_NORM; } return CONTROL_OK; } case AOCONTROL_SET_VOLUME: { const ao_control_vol_t *vol = arg; pa_operation *o; if (volume.channels != 2) pa_cvolume_set(&volume, volume.channels, (pa_volume_t)vol->left*PA_VOLUME_NORM/100); else { volume.values[0] = (pa_volume_t)vol->left*PA_VOLUME_NORM/100; volume.values[1] = (pa_volume_t)vol->right*PA_VOLUME_NORM/100; } pa_threaded_mainloop_lock(mainloop); o = pa_context_set_sink_input_volume(context, pa_stream_get_index(stream), &volume, NULL, NULL); if (!o) { pa_threaded_mainloop_unlock(mainloop); GENERIC_ERR_MSG(context, "pa_context_set_sink_input_volume() failed"); return CONTROL_ERROR; } /* We don't wait for completion here */ pa_operation_unref(o); pa_threaded_mainloop_unlock(mainloop); return CONTROL_OK; } default: return CONTROL_UNKNOWN; } }
int pa_simple_set_volume(pa_simple *p, int volume, int *rerror) { pa_operation *o = NULL; pa_stream *s = NULL; uint32_t idx; pa_cvolume cv; pa_volume_t v; pa_assert(p); CHECK_VALIDITY_RETURN_ANY(rerror, p->direction == PA_STREAM_PLAYBACK, PA_ERR_BADSTATE, -1); CHECK_VALIDITY_RETURN_ANY(rerror, volume >= 0, PA_ERR_INVALID, -1); CHECK_VALIDITY_RETURN_ANY(rerror, volume <= 65535, PA_ERR_INVALID, -1); pa_threaded_mainloop_lock(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); CHECK_SUCCESS_GOTO(p, rerror, ((idx = pa_stream_get_index (p->stream)) != PA_INVALID_INDEX), unlock_and_fail); s = p->stream; pa_assert(s); pa_cvolume_set(&cv, s->sample_spec.channels, volume); o = pa_context_set_sink_input_volume (p->context, idx, &cv, success_context_cb, p); CHECK_SUCCESS_GOTO(p, rerror, o, unlock_and_fail); p->operation_success = 0; while (pa_operation_get_state(o) == PA_OPERATION_RUNNING) { pa_threaded_mainloop_wait(p->mainloop); CHECK_DEAD_GOTO(p, rerror, unlock_and_fail); } CHECK_SUCCESS_GOTO(p, rerror, p->operation_success, unlock_and_fail); pa_operation_unref(o); pa_threaded_mainloop_unlock(p->mainloop); return 0; unlock_and_fail: if (o) { pa_operation_cancel(o); pa_operation_unref(o); } pa_threaded_mainloop_unlock(p->mainloop); return -1; }
pa_cvolume* pa_cvolume_scale(pa_cvolume *v, pa_volume_t max) { unsigned c; pa_volume_t t = 0; pa_assert(v); pa_return_val_if_fail(pa_cvolume_valid(v), NULL); pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); t = pa_cvolume_max(v); if (t <= PA_VOLUME_MUTED) return pa_cvolume_set(v, v->channels, max); for (c = 0; c < v->channels; c++) v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); return v; }
int xmms_pulse_backend_volume_set (xmms_pulse *p, unsigned int vol) { pa_operation *o; pa_cvolume cvol; int idx, res = 0; if (p == NULL) { return FALSE; } pa_threaded_mainloop_lock (p->mainloop); if (p->stream != NULL) { pa_cvolume_set (&cvol, p->sample_spec.channels, PA_VOLUME_NORM * vol / 100); idx = pa_stream_get_index (p->stream); o = pa_context_set_sink_input_volume (p->context, idx, &cvol, volume_set_cb, &res); if (o) { /* wait for result to land */ while (pa_operation_get_state (o) != PA_OPERATION_DONE) { pa_threaded_mainloop_wait (p->mainloop); } pa_operation_unref (o); /* The cb set res to 1 or 0 depending on success */ if (res) { p->volume = vol; } } } pa_threaded_mainloop_unlock (p->mainloop); return res; }
/** * Volume adjusted (from within showtime), send update to PA * * Lock for PA mainloop is already held */ static void set_mastervol(void *opaque, float value) { pa_audio_mode_t *pam = opaque; pa_operation *o; pa_cvolume cv; pam->mastervol = pa_sw_volume_from_dB(value); if(pam->stream == NULL || pa_stream_get_state(pam->stream) != PA_STREAM_READY) return; memset(&cv, 0, sizeof(cv)); pa_cvolume_set(&cv, pam->ss.channels, pam->mastervol); o = pa_context_set_sink_input_volume(pam->context, pa_stream_get_index(pam->stream), &cv, NULL, NULL); if(o != NULL) pa_operation_unref(o); }
pa_cvolume* pa_cvolume_scale_mask(pa_cvolume *v, pa_volume_t max, pa_channel_map *cm, pa_channel_position_mask_t mask) { unsigned c; pa_volume_t t = 0; pa_assert(v); pa_return_val_if_fail(PA_VOLUME_IS_VALID(max), NULL); if (!cm) return pa_cvolume_scale(v, max); pa_return_val_if_fail(pa_cvolume_compatible_with_channel_map(v, cm), NULL); t = pa_cvolume_max_mask(v, cm, mask); if (t <= PA_VOLUME_MUTED) return pa_cvolume_set(v, v->channels, max); for (c = 0; c < v->channels; c++) v->values[c] = (pa_volume_t) PA_CLAMP_VOLUME(((uint64_t) v->values[c] * (uint64_t) max) / (uint64_t) t); return v; }
void CAESinkPULSE::SetVolume(float volume) { if (m_IsAllocated && !m_passthrough) { pa_threaded_mainloop_lock(m_MainLoop); // clamp possibly too large / low values float per_cent_volume = std::max(0.0f, std::min(volume, 1.0f)); if (m_volume_needs_update) { m_volume_needs_update = false; pa_volume_t n_vol = pa_cvolume_avg(&m_Volume); n_vol = std::min(n_vol, PA_VOLUME_NORM); per_cent_volume = (float) n_vol / PA_VOLUME_NORM; // only update internal volume pa_threaded_mainloop_unlock(m_MainLoop); g_application.SetVolume(per_cent_volume, false); return; } pa_volume_t pavolume = per_cent_volume * PA_VOLUME_NORM; unsigned int sink_input_idx = pa_stream_get_index(m_Stream); if ( pavolume <= 0 ) pa_cvolume_mute(&m_Volume, m_Channels); else pa_cvolume_set(&m_Volume, m_Channels, pavolume); pa_operation *op = pa_context_set_sink_input_volume(m_Context, sink_input_idx, &m_Volume, NULL, NULL); if (op == NULL) CLog::Log(LOGERROR, "PulseAudio: Failed to set volume"); else pa_operation_unref(op); pa_threaded_mainloop_unlock(m_MainLoop); } }
void PaObject::set_volume(float perc) { if (pa_set_volume != nullptr) { pa_threaded_mainloop_lock(pulse.pa_ml); int vol = (PA_VOLUME_NORM * perc); pa_cvolume cvol; pa_cvolume_init(&cvol); pa_cvolume_set(&cvol, channels, vol); pa_operation *o = pa_set_volume( pulse.pa_ctx, index, &cvol, NULL, NULL ); pa_operation_unref(o); pa_threaded_mainloop_unlock(pulse.pa_ml); } }
bool CPulseAESound::Initialize() { /* we dont re-init the wav loader in PA as PA handles the samplerate */ if (!m_wavLoader.IsValid()) return false; m_sampleSpec.format = PA_SAMPLE_FLOAT32NE; m_sampleSpec.rate = m_wavLoader.GetSampleRate(); m_sampleSpec.channels = m_wavLoader.GetChannelLayout().Count(); if (!pa_sample_spec_valid(&m_sampleSpec)) { CLog::Log(LOGERROR, "CPulseAESound::Initialize - Invalid sample spec"); return false; } struct pa_channel_map map; map.channels = m_sampleSpec.channels; switch (map.channels) { case 1: map.map[0] = PA_CHANNEL_POSITION_MONO; break; case 2: map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; break; default: CLog::Log(LOGERROR, "CPulseAESound::Initialize - We do not yet support multichannel sounds"); return false; } m_maxVolume = CAEFactory::GetEngine()->GetVolume(); m_volume = 1.0f; pa_volume_t paVolume = pa_sw_volume_from_linear((double)(m_volume * m_maxVolume)); pa_cvolume_set(&m_chVolume, m_sampleSpec.channels, paVolume); pa_threaded_mainloop_lock(m_mainLoop); if ((m_stream = pa_stream_new(m_context, m_pulseName.c_str(), &m_sampleSpec, &map)) == NULL) { CLog::Log(LOGERROR, "CPulseAESound::Initialize - Could not create a stream"); pa_threaded_mainloop_unlock(m_mainLoop); return false; } pa_stream_set_state_callback(m_stream, CPulseAESound::StreamStateCallback, this); pa_stream_set_write_callback(m_stream, CPulseAESound::StreamWriteCallback, this); if (pa_stream_connect_upload(m_stream, m_wavLoader.GetFrameCount() * pa_frame_size(&m_sampleSpec)) != 0) { CLog::Log(LOGERROR, "CPulseAESound::Initialize - Could not initialize the stream"); pa_stream_disconnect(m_stream); m_stream = NULL; pa_threaded_mainloop_unlock(m_mainLoop); return false; } /* check if the stream failed */ if (pa_stream_get_state(m_stream) == PA_STREAM_FAILED) { CLog::Log(LOGERROR, "CPulseAESound::Initialize - Waited for the stream but it failed"); pa_stream_disconnect(m_stream); m_stream = NULL; pa_threaded_mainloop_unlock(m_mainLoop); return false; } pa_threaded_mainloop_unlock(m_mainLoop); return true; }
static int control(struct ao *ao, enum aocontrol cmd, void *arg) { struct priv *priv = ao->priv; switch (cmd) { case AOCONTROL_GET_MUTE: case AOCONTROL_GET_VOLUME: { uint32_t devidx = pa_stream_get_index(priv->stream); pa_threaded_mainloop_lock(priv->mainloop); if (!waitop(priv, pa_context_get_sink_input_info(priv->context, devidx, info_func, ao))) { GENERIC_ERR_MSG(priv->context, "pa_stream_get_sink_input_info() failed"); return CONTROL_ERROR; } // Warning: some information in pi might be unaccessible, because // we naively copied the struct, without updating pointers etc. // Pointers might point to invalid data, accessors might fail. if (cmd == AOCONTROL_GET_VOLUME) { ao_control_vol_t *vol = arg; if (priv->pi.volume.channels != 2) vol->left = vol->right = pa_cvolume_avg(&priv->pi.volume) * 100 / PA_VOLUME_NORM; else { vol->left = priv->pi.volume.values[0] * 100 / PA_VOLUME_NORM; vol->right = priv->pi.volume.values[1] * 100 / PA_VOLUME_NORM; } } else if (cmd == AOCONTROL_GET_MUTE) { bool *mute = arg; *mute = priv->pi.mute; } return CONTROL_OK; } case AOCONTROL_SET_MUTE: case AOCONTROL_SET_VOLUME: { pa_operation *o; pa_threaded_mainloop_lock(priv->mainloop); uint32_t stream_index = pa_stream_get_index(priv->stream); if (cmd == AOCONTROL_SET_VOLUME) { const ao_control_vol_t *vol = arg; struct pa_cvolume volume; pa_cvolume_reset(&volume, ao->channels); if (volume.channels != 2) pa_cvolume_set(&volume, volume.channels, vol->left * PA_VOLUME_NORM / 100); else { volume.values[0] = vol->left * PA_VOLUME_NORM / 100; volume.values[1] = vol->right * PA_VOLUME_NORM / 100; } o = pa_context_set_sink_input_volume(priv->context, stream_index, &volume, NULL, NULL); if (!o) { pa_threaded_mainloop_unlock(priv->mainloop); GENERIC_ERR_MSG(priv->context, "pa_context_set_sink_input_volume() failed"); return CONTROL_ERROR; } } else if (cmd == AOCONTROL_SET_MUTE) { const bool *mute = arg; o = pa_context_set_sink_input_mute(priv->context, stream_index, *mute, NULL, NULL); if (!o) { pa_threaded_mainloop_unlock(priv->mainloop); GENERIC_ERR_MSG(priv->context, "pa_context_set_sink_input_mute() failed"); return CONTROL_ERROR; } } else abort(); /* We don't wait for completion here */ pa_operation_unref(o); pa_threaded_mainloop_unlock(priv->mainloop); return CONTROL_OK; } default: return CONTROL_UNKNOWN; } }
/* This is called whenever the context status changes */ static void context_state_callback(pa_context *c, void *userdata) { pa_assert(c); 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_buffer_attr buffer_attr; pa_assert(c); pa_assert(!stream); if (verbose) pa_log(_("Connection established.%s"), CLEAR_LINE); if (!(stream = pa_stream_new_with_proplist(c, NULL, &sample_spec, &channel_map, proplist))) { pa_log(_("pa_stream_new() failed: %s"), pa_strerror(pa_context_errno(c))); goto fail; } pa_stream_set_state_callback(stream, stream_state_callback, NULL); pa_stream_set_write_callback(stream, stream_write_callback, NULL); pa_stream_set_read_callback(stream, stream_read_callback, NULL); pa_stream_set_suspended_callback(stream, stream_suspended_callback, NULL); pa_stream_set_moved_callback(stream, stream_moved_callback, NULL); pa_stream_set_underflow_callback(stream, stream_underflow_callback, NULL); pa_stream_set_overflow_callback(stream, stream_overflow_callback, NULL); pa_stream_set_started_callback(stream, stream_started_callback, NULL); pa_stream_set_event_callback(stream, stream_event_callback, NULL); pa_stream_set_buffer_attr_callback(stream, stream_buffer_attr_callback, NULL); pa_zero(buffer_attr); buffer_attr.maxlength = (uint32_t) -1; buffer_attr.prebuf = (uint32_t) -1; if (latency_msec > 0) { buffer_attr.fragsize = buffer_attr.tlength = pa_usec_to_bytes(latency_msec * PA_USEC_PER_MSEC, &sample_spec); flags |= PA_STREAM_ADJUST_LATENCY; } else if (latency > 0) { buffer_attr.fragsize = buffer_attr.tlength = (uint32_t) latency; flags |= PA_STREAM_ADJUST_LATENCY; } else buffer_attr.fragsize = buffer_attr.tlength = (uint32_t) -1; if (process_time_msec > 0) { buffer_attr.minreq = pa_usec_to_bytes(process_time_msec * PA_USEC_PER_MSEC, &sample_spec); } else if (process_time > 0) buffer_attr.minreq = (uint32_t) process_time; else buffer_attr.minreq = (uint32_t) -1; if (mode == PLAYBACK) { pa_cvolume cv; if (pa_stream_connect_playback(stream, device, &buffer_attr, flags, volume_is_set ? pa_cvolume_set(&cv, sample_spec.channels, volume) : NULL, NULL) < 0) { pa_log(_("pa_stream_connect_playback() failed: %s"), pa_strerror(pa_context_errno(c))); goto fail; } } else { if (pa_stream_connect_record(stream, device, latency > 0 ? &buffer_attr : NULL, flags) < 0) { pa_log(_("pa_stream_connect_record() failed: %s"), pa_strerror(pa_context_errno(c))); goto fail; } } break; } case PA_CONTEXT_TERMINATED: quit(0); break; case PA_CONTEXT_FAILED: default: pa_log(_("Connection failure: %s"), pa_strerror(pa_context_errno(c))); goto fail; } return; fail: quit(1); }
/** * 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 gst_pulse_cvolume_from_linear (pa_cvolume * v, unsigned channels, gdouble volume) { pa_cvolume_set (v, channels, pa_sw_volume_from_linear (volume)); }
static pa_hook_result_t sink_input_neew(void *hook_data, void *call_data, void *slot_data) { static uint32_t route_flags = PA_POLICY_GROUP_FLAG_SET_SINK | PA_POLICY_GROUP_FLAG_ROUTE_AUDIO; static pa_volume_t max_volume = PA_VOLUME_NORM; struct pa_sink_input_new_data *data = (struct pa_sink_input_new_data *)call_data; struct userdata *u = (struct userdata *)slot_data; uint32_t flags; const char *group_name; const char *sinp_name; const char *sink_name; int local_route; int local_volume; struct pa_policy_group *group; pa_assert(u); pa_assert(data); if ((group_name = pa_classify_sink_input_by_data(u,data,&flags)) != NULL && (group = pa_policy_group_find(u, group_name) ) != NULL ){ /* Let's just set the policy group property here already so that we * don't have to classify again when the sink input is put, because we * can just retrieve the group from the proplist. Also, this prevents * the classification from breaking later because of the proplist * overwriting done below. */ pa_proplist_sets(data->proplist, PA_PROP_POLICY_GROUP, group_name); /* Proplist overwriting can also mess up the retrieval of * stream-specific flags later on, so we need to store those to the * proplist as well (ugly hack). We could probably cope without this * one though, since the stream-specific flags don't really seem to be * used. */ pa_proplist_set(data->proplist, PA_PROP_POLICY_STREAM_FLAGS, (void*)&flags, sizeof(flags)); if (group->properties != NULL) { pa_proplist_update(data->proplist, PA_UPDATE_REPLACE, group->properties); pa_log_debug("new sink input inserted into %s. " "force the following properties:", group_name); } if (group->sink != NULL) { sinp_name = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_NAME); if (!sinp_name) sinp_name = "<unknown>"; local_route = flags & PA_POLICY_LOCAL_ROUTE; local_volume = flags & PA_POLICY_LOCAL_VOLMAX; if (group->mutebyrt && !local_route) { sink_name = u->nullsink->name; pa_log_debug("force stream '%s'/'%s' to sink '%s' due to " "mute-by-route", group_name,sinp_name, sink_name); #ifdef HAVE_OLD_LIBPULSE data->sink = u->nullsink->sink; #else pa_sink_input_new_data_set_sink(data, u->nullsink->sink, false); #endif } else if (group->flags & route_flags) { sink_name = pa_sink_ext_get_name(group->sink); pa_log_debug("force stream '%s'/'%s' to sink '%s'", group_name, sinp_name, sink_name); #ifdef HAVE_OLD_LIBPULSE data->sink = group->sink; #else pa_sink_input_new_data_set_sink(data, group->sink, false); #endif } if (local_volume) { pa_log_debug("force stream '%s'/'%s' volume to %d", group_name, sinp_name, (max_volume * 100) / PA_VOLUME_NORM); pa_cvolume_set(&data->volume, data->channel_map.channels, max_volume); data->volume_is_set = TRUE; data->save_volume = FALSE; } } } return PA_HOOK_OK; }
bool AudioOutputPulseAudio::ConnectPlaybackStream(void) { QString fn_log_tag = "ConnectPlaybackStream, "; pstream = pa_stream_new(pcontext, "MythTV playback", &sample_spec, &channel_map); if (!pstream) { VBERROR(fn_log_tag + QString("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, &volume_control, 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: VERBOSE(VB_IMPORTANT, LOC_ERR + fn_log_tag + 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(fn_log_tag + 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(fn_log_tag + QString("fragment size %1, soundcard buffer size %2") .arg(fragment_size).arg(soundcard_buffer_size)); return (connected && !failed); }
CPulseAEStream::CPulseAEStream(pa_context *context, pa_threaded_mainloop *mainLoop, enum AEDataFormat format, unsigned int sampleRate, CAEChannelInfo channelLayout, unsigned int options) : m_fader(this) { ASSERT(channelLayout.Count()); m_Destroyed = false; m_Initialized = false; m_Paused = false; m_Stream = NULL; m_Context = context; m_MainLoop = mainLoop; m_format = format; m_sampleRate = sampleRate; m_channelLayout = channelLayout; m_options = options; m_DrainOperation = NULL; m_slave = NULL; pa_threaded_mainloop_lock(m_MainLoop); m_SampleSpec.channels = channelLayout.Count(); m_SampleSpec.rate = m_sampleRate; switch (m_format) { case AE_FMT_U8 : m_SampleSpec.format = PA_SAMPLE_U8; break; case AE_FMT_S16NE : m_SampleSpec.format = PA_SAMPLE_S16NE; break; case AE_FMT_S16LE : m_SampleSpec.format = PA_SAMPLE_S16LE; break; case AE_FMT_S16BE : m_SampleSpec.format = PA_SAMPLE_S16BE; break; case AE_FMT_S24NE3: m_SampleSpec.format = PA_SAMPLE_S24NE; break; case AE_FMT_S24NE4: m_SampleSpec.format = PA_SAMPLE_S24_32NE; break; case AE_FMT_S32NE : m_SampleSpec.format = PA_SAMPLE_S32NE; break; case AE_FMT_S32LE : m_SampleSpec.format = PA_SAMPLE_S32LE; break; case AE_FMT_S32BE : m_SampleSpec.format = PA_SAMPLE_S32BE; break; case AE_FMT_FLOAT : m_SampleSpec.format = PA_SAMPLE_FLOAT32NE; break; #if PA_CHECK_VERSION(1,0,0) case AE_FMT_DTS : case AE_FMT_EAC3 : case AE_FMT_AC3 : m_SampleSpec.format = PA_SAMPLE_S16NE; break; #endif default: CLog::Log(LOGERROR, "PulseAudio: Invalid format %i", format); pa_threaded_mainloop_unlock(m_MainLoop); m_format = AE_FMT_INVALID; return; } if (!pa_sample_spec_valid(&m_SampleSpec)) { CLog::Log(LOGERROR, "PulseAudio: Invalid sample spec"); pa_threaded_mainloop_unlock(m_MainLoop); Destroy(); return /*false*/; } m_frameSize = pa_frame_size(&m_SampleSpec); struct pa_channel_map map; map.channels = m_channelLayout.Count(); for (unsigned int ch = 0; ch < m_channelLayout.Count(); ++ch) switch(m_channelLayout[ch]) { case AE_CH_NULL: break; case AE_CH_MAX : break; case AE_CH_RAW : break; case AE_CH_FL : map.map[ch] = PA_CHANNEL_POSITION_FRONT_LEFT ; break; case AE_CH_FR : map.map[ch] = PA_CHANNEL_POSITION_FRONT_RIGHT ; break; case AE_CH_FC : map.map[ch] = PA_CHANNEL_POSITION_FRONT_CENTER ; break; case AE_CH_BC : map.map[ch] = PA_CHANNEL_POSITION_REAR_CENTER ; break; case AE_CH_BL : map.map[ch] = PA_CHANNEL_POSITION_REAR_LEFT ; break; case AE_CH_BR : map.map[ch] = PA_CHANNEL_POSITION_REAR_RIGHT ; break; case AE_CH_LFE : map.map[ch] = PA_CHANNEL_POSITION_LFE ; break; case AE_CH_FLOC: map.map[ch] = PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER ; break; case AE_CH_FROC: map.map[ch] = PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; break; case AE_CH_SL : map.map[ch] = PA_CHANNEL_POSITION_SIDE_LEFT ; break; case AE_CH_SR : map.map[ch] = PA_CHANNEL_POSITION_SIDE_RIGHT ; break; case AE_CH_TC : map.map[ch] = PA_CHANNEL_POSITION_TOP_CENTER ; break; case AE_CH_TFL : map.map[ch] = PA_CHANNEL_POSITION_TOP_FRONT_LEFT ; break; case AE_CH_TFR : map.map[ch] = PA_CHANNEL_POSITION_TOP_FRONT_RIGHT ; break; case AE_CH_TFC : map.map[ch] = PA_CHANNEL_POSITION_TOP_CENTER ; break; case AE_CH_TBL : map.map[ch] = PA_CHANNEL_POSITION_TOP_REAR_LEFT ; break; case AE_CH_TBR : map.map[ch] = PA_CHANNEL_POSITION_TOP_REAR_RIGHT ; break; case AE_CH_TBC : map.map[ch] = PA_CHANNEL_POSITION_TOP_REAR_CENTER ; break; default: break; } m_MaxVolume = CAEFactory::GetEngine()->GetVolume(); m_Volume = 1.0f; pa_volume_t paVolume = pa_sw_volume_from_linear((double)(m_Volume * m_MaxVolume)); pa_cvolume_set(&m_ChVolume, m_SampleSpec.channels, paVolume); #if PA_CHECK_VERSION(1,0,0) pa_format_info *info[1]; info[0] = pa_format_info_new(); switch(m_format) { case AE_FMT_DTS : info[0]->encoding = PA_ENCODING_DTS_IEC61937 ; break; case AE_FMT_EAC3: info[0]->encoding = PA_ENCODING_EAC3_IEC61937; break; case AE_FMT_AC3 : info[0]->encoding = PA_ENCODING_AC3_IEC61937 ; break; default: info[0]->encoding = PA_ENCODING_PCM ; break; } pa_format_info_set_rate (info[0], m_SampleSpec.rate); pa_format_info_set_channels (info[0], m_SampleSpec.channels); pa_format_info_set_channel_map (info[0], &map); pa_format_info_set_sample_format(info[0], m_SampleSpec.format); m_Stream = pa_stream_new_extended(m_Context, "audio stream", info, 1, NULL); pa_format_info_free(info[0]); #else m_Stream = pa_stream_new(m_Context, "audio stream", &m_SampleSpec, &map); #endif if (m_Stream == NULL) { CLog::Log(LOGERROR, "PulseAudio: Could not create a stream"); pa_threaded_mainloop_unlock(m_MainLoop); Destroy(); return /*false*/; } pa_stream_set_state_callback(m_Stream, CPulseAEStream::StreamStateCallback, this); pa_stream_set_write_callback(m_Stream, CPulseAEStream::StreamRequestCallback, this); pa_stream_set_latency_update_callback(m_Stream, CPulseAEStream::StreamLatencyUpdateCallback, this); pa_stream_set_underflow_callback(m_Stream, CPulseAEStream::StreamUnderflowCallback, this); int flags = PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE; if (options && AESTREAM_FORCE_RESAMPLE) flags |= PA_STREAM_VARIABLE_RATE; if (pa_stream_connect_playback(m_Stream, NULL, NULL, (pa_stream_flags)flags, &m_ChVolume, NULL) < 0) { CLog::Log(LOGERROR, "PulseAudio: Failed to connect stream to output"); pa_threaded_mainloop_unlock(m_MainLoop); Destroy(); return /*false*/; } /* Wait until the stream is ready */ do { pa_threaded_mainloop_wait(m_MainLoop); CLog::Log(LOGDEBUG, "PulseAudio: Stream %s", StreamStateToString(pa_stream_get_state(m_Stream))); } while (pa_stream_get_state(m_Stream) != PA_STREAM_READY && pa_stream_get_state(m_Stream) != PA_STREAM_FAILED); if (pa_stream_get_state(m_Stream) == PA_STREAM_FAILED) { CLog::Log(LOGERROR, "PulseAudio: Waited for the stream but it failed"); pa_threaded_mainloop_unlock(m_MainLoop); Destroy(); return /*false*/; } m_cacheSize = pa_stream_writable_size(m_Stream); pa_threaded_mainloop_unlock(m_MainLoop); m_Initialized = true; CLog::Log(LOGINFO, "PulseAEStream::Initialized"); CLog::Log(LOGINFO, " Sample Rate : %d", m_sampleRate); CLog::Log(LOGINFO, " Sample Format : %s", CAEUtil::DataFormatToStr(m_format)); CLog::Log(LOGINFO, " Channel Count : %d", m_channelLayout.Count()); CLog::Log(LOGINFO, " Channel Layout: %s", ((std::string)m_channelLayout).c_str()); CLog::Log(LOGINFO, " Frame Size : %d", m_frameSize); CLog::Log(LOGINFO, " Cache Size : %d", m_cacheSize); Resume(); return /*true*/; }