Commit 8b98d4e9 authored by Harald Sitter's avatar Harald Sitter 🏳️‍🌈
Browse files

support backend-driven pulseaudio property setting

- pulstream: new property role (== PA's media.role)
- pulsesupport: new func streamproperties
  returns a hash of per-stream properties a backend can set
- pulsesupport: new func setupstreamenvironment
  can be used by a backend not supporting per-stream properties to set
  the properties to the right value as close to stream creation as possible
  to reduce the scope of 'reentrancy' issues, howeve if two MO's are
  started right after one another the second AO's envrionment will still
  shadow the first's

app_name/version/icon_name are retained as always-on override properties
as we consider them static and therefore backend driven setting isn't
really necessary (also not possible with VLC<2.1)

when using pvlc (which uses the setup function due to lack of property
support through libvlc) a warning will be displayed in debug mode to
make clear what could happen.

CCBUG: 321288
FIXED-IN: 4.7.0
parent 2e553fb8
......@@ -29,13 +29,14 @@
namespace Phonon
PulseStream::PulseStream(QString streamUuid)
PulseStream::PulseStream(QString streamUuid, QString role)
: QObject()
, mStreamUuid(streamUuid)
, mDevice(-1)
, mMute(false)
, mCachedVolume(-1)
, mRole(role)
......@@ -108,6 +109,11 @@ void PulseStream::setCachedVolume(qreal volume)
mCachedVolume = volume;
QString PulseStream::role() const
return mRole;
void PulseStream::applyCachedVolume()
if (mCachedVolume == -1)
......@@ -38,7 +38,7 @@ namespace Phonon
PulseStream(QString streamUuid);
PulseStream(QString streamUuid, QString role);
QString uuid() const;
......@@ -55,6 +55,8 @@ namespace Phonon
qreal cachedVolume() const;
void setCachedVolume(qreal volume);
QString role() const;
void usingDevice(int device);
void volumeChanged(qreal volume);
......@@ -71,6 +73,7 @@ namespace Phonon
bool mMute;
// -1 = not set
qreal mCachedVolume;
QString mRole;
} // namespace Phonon
......@@ -1120,18 +1120,22 @@ void PulseSupport::setCaptureDevicePriorityForCategory(Category category, QList<
static PulseStream* register_stream(QMap<QString,PulseStream*> &map, QString streamUuid, QString role)
logMessage(QString::fromLatin1("Initialising streamindex %1").arg(streamUuid));
if (!role.isEmpty()) {
logMessage(QString::fromLatin1("Setting role to %1 for streamindex %2").arg(role).arg(streamUuid));
qputenv("PULSE_PROP_media.role", role.toLatin1());
qputenv("PULSE_PROP_phonon.streamid", streamUuid.toLatin1());
qputenv("PULSE_PROP_OVERRIDE_"PA_PROP_APPLICATION_NAME, Platform::applicationName().toUtf8());
qputenv("PULSE_PROP_OVERRIDE_"PA_PROP_APPLICATION_VERSION, qApp->applicationVersion().toUtf8());
qputenv("PULSE_PROP_OVERRIDE_"PA_PROP_APPLICATION_ICON_NAME, qApp->applicationName().toUtf8());
PulseStream *stream = new PulseStream(streamUuid);
PulseStream *stream = new PulseStream(streamUuid, role);
map[streamUuid] = stream;
// Setup envrionment...
// These values are considered static, so we force property overrides for them.
if (!Platform::applicationName().isEmpty())
if (!qApp->applicationVersion().isEmpty())
if (!qApp->applicationName().isEmpty())
return stream;
......@@ -1182,6 +1186,59 @@ PulseStream *PulseSupport::registerCaptureStream(QString streamUuid, Category ca
QHash<QString, QString> PulseSupport::streamProperties(QString streamUuid) const
QHash<QString, QString> properties;
PulseStream *stream = 0;
// Try to find the stream among the known output streams.
if (!stream)
stream = s_outputStreams.value(streamUuid);
// Not an output stream, try capture streams.
if (!stream)
stream = s_captureStreams.value(streamUuid);
// Also no capture stream, start crying and return an empty hash.
if (!stream) {
qWarning() << Q_FUNC_INFO << "Requested UUID Could not be found. Returning with empty properties.";
return properties;
properties[QLatin1String(PA_PROP_PHONON_STREAMID)] = stream->uuid();
properties[QLatin1String(PA_PROP_MEDIA_ROLE)] = stream->role();
// Tear down environment before returning. This is to prevent backends from
// being overridden by the environment if present.
QHashIterator<QString, QString> it(properties);
while (it.hasNext()) {;
return properties;
void PulseSupport::setupStreamEnvironment(QString streamUuid)
pDebug() << "Please note that your current Phonon backend is trying to force"
" stream dependent PulseAudio properties through envrionment variables."
" Slightly unprecise timing in doing so will prevent the first"
" of two subsequently started AudioOutputs to have disfunct volume"
" control. Also see";
const QHash<QString, QString> properties = streamProperties(streamUuid);
QHashIterator<QString, QString> it(properties);
while (it.hasNext()) {;
qputenv(QString("PULSE_PROP_OVERRIDE_%1").arg(it.key()).toUtf8(), it.value().toUtf8());
void PulseSupport::emitObjectDescriptionChanged(ObjectDescriptionType type)
if (mEnabled)
......@@ -56,9 +56,11 @@ namespace Phonon
PulseStream *registerOutputStream(QString streamUuid, Category category);
PulseStream *registerCaptureStream(QString streamUuid, CaptureCategory category);
PHONON_DEPRECATED PulseStream *registerCaptureStream(QString streamUuid, Category category);
QHash<QString, QString> streamProperties(QString streamUuid) const;
void setupStreamEnvironment(QString streamUuid);
void emitObjectDescriptionChanged(ObjectDescriptionType);
bool setOutputName(QString streamUuid, QString name);
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment