streamrestore.cpp 5.24 KB
Newer Older
1
/*
2
3
4
    SPDX-FileCopyrightText: 2016 David Rosca <nowrep@gmail.com>

    SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5
6
7
8
*/

#include "streamrestore.h"
#include "context.h"
9
#include "context_p.h"
Nicolas Fella's avatar
Nicolas Fella committed
10
#include "streamrestore_p.h"
11

12
#include "debug.h"
13
#include "pulseobject_p.h"
14

David Rosca's avatar
David Rosca committed
15
namespace PulseAudioQt
16
17
18
{
StreamRestore::StreamRestore(quint32 index, const QVariantMap &properties, QObject *parent)
    : PulseObject(parent)
Nicolas Fella's avatar
Nicolas Fella committed
19
    , d(new StreamRestorePrivate(this))
20
{
Nicolas Fella's avatar
Nicolas Fella committed
21
22
    memset(&d->m_volume, 0, sizeof(d->m_volume));
    memset(&d->m_channelMap, 0, sizeof(d->m_channelMap));
23

Nicolas Fella's avatar
Nicolas Fella committed
24
    d->m_index = index;
Nicolas Fella's avatar
Nicolas Fella committed
25
26
27
28
29
30
31
    PulseObject::d->m_properties = properties;
}

StreamRestore::~StreamRestore()
{
}

32
StreamRestorePrivate::StreamRestorePrivate(StreamRestore *q)
Nicolas Fella's avatar
Nicolas Fella committed
33
    : q(q)
Nicolas Fella's avatar
Nicolas Fella committed
34
35
36
37
38
{
}

StreamRestorePrivate::~StreamRestorePrivate()
{
39
40
}

41
void StreamRestorePrivate::update(const pa_ext_stream_restore_info *info)
42
{
Nicolas Fella's avatar
Nicolas Fella committed
43
    q->PulseObject::d->updatePulseObject(info);
44
    m_cache.valid = false;
45

46
    const QString infoDevice = QString::fromUtf8(info->device);
47
48
49
    if (m_device != infoDevice) {
        m_device = infoDevice;
        Q_EMIT q->deviceChanged();
50
    }
51
52
53
    if (m_muted != info->mute) {
        m_muted = info->mute;
        Q_EMIT q->mutedChanged();
54
    }
55
    if (!pa_cvolume_equal(&m_volume, &info->volume)) {
56
57
58
        m_volume = info->volume;
        Q_EMIT q->volumeChanged();
        Q_EMIT q->channelVolumesChanged();
59
    }
60
    if (!pa_channel_map_equal(&m_channelMap, &info->channel_map)) {
61
62
        m_channels.clear();
        m_channels.reserve(info->channel_map.channels);
63
        for (int i = 0; i < info->channel_map.channels; ++i) {
64
            m_channels << QString::fromUtf8(pa_channel_position_to_pretty_string(info->channel_map.map[i]));
65
        }
66
67
        m_channelMap = info->channel_map;
        Q_EMIT q->channelsChanged();
68
69
70
71
72
    }
}

QString StreamRestore::device() const
{
Nicolas Fella's avatar
Nicolas Fella committed
73
    return d->m_device;
74
75
76
77
}

void StreamRestore::setDevice(const QString &device)
{
Nicolas Fella's avatar
Nicolas Fella committed
78
79
80
    if (d->m_cache.valid) {
        if (d->m_cache.device != device) {
            d->writeChanges(d->m_cache.volume, d->m_cache.muted, device);
81
        }
82
    } else {
Nicolas Fella's avatar
Nicolas Fella committed
83
84
        if (d->m_device != device) {
            d->writeChanges(d->m_volume, d->m_muted, device);
85
        }
86
    }
87
88
89
90
}

qint64 StreamRestore::volume() const
{
Nicolas Fella's avatar
Nicolas Fella committed
91
    return d->m_volume.values[0];
92
93
94
95
}

void StreamRestore::setVolume(qint64 volume)
{
Nicolas Fella's avatar
Nicolas Fella committed
96
    pa_cvolume vol = d->m_cache.valid ? d->m_cache.volume : d->m_volume;
97
98
99
100
101
102
103

    // If no channel exists force one. We need one to be able to control the volume
    // See https://bugs.kde.org/show_bug.cgi?id=407397
    if (vol.channels == 0) {
        vol.channels = 1;
    }

104
105
106
    for (int i = 0; i < vol.channels; ++i) {
        vol.values[i] = volume;
    }
107

Nicolas Fella's avatar
Nicolas Fella committed
108
109
    if (d->m_cache.valid) {
        d->writeChanges(vol, d->m_cache.muted, d->m_cache.device);
110
    } else {
Nicolas Fella's avatar
Nicolas Fella committed
111
        d->writeChanges(vol, d->m_muted, d->m_device);
112
    }
113
114
115
116
}

bool StreamRestore::isMuted() const
{
Nicolas Fella's avatar
Nicolas Fella committed
117
    return d->m_muted;
118
119
120
121
}

void StreamRestore::setMuted(bool muted)
{
Nicolas Fella's avatar
Nicolas Fella committed
122
123
124
    if (d->m_cache.valid) {
        if (d->m_cache.muted != muted) {
            d->writeChanges(d->m_cache.volume, muted, d->m_cache.device);
125
        }
126
    } else {
Nicolas Fella's avatar
Nicolas Fella committed
127
128
        if (d->m_muted != muted) {
            d->writeChanges(d->m_volume, muted, d->m_device);
129
        }
130
    }
131
132
133
134
135
136
137
138
139
140
141
142
}

bool StreamRestore::hasVolume() const
{
    return true;
}

bool StreamRestore::isVolumeWritable() const
{
    return true;
}

143
QVector<QString> StreamRestore::channels() const
144
{
Nicolas Fella's avatar
Nicolas Fella committed
145
    return d->m_channels;
146
147
}

148
QVector<qreal> StreamRestore::channelVolumes() const
149
{
150
    QVector<qreal> ret;
Nicolas Fella's avatar
Nicolas Fella committed
151
152
153
    ret.reserve(d->m_volume.channels);
    for (int i = 0; i < d->m_volume.channels; ++i) {
        ret << d->m_volume.values[i];
154
155
156
157
158
159
    }
    return ret;
}

void StreamRestore::setChannelVolume(int channel, qint64 volume)
{
Nicolas Fella's avatar
Nicolas Fella committed
160
161
    Q_ASSERT(channel >= 0 && channel < d->m_volume.channels);
    pa_cvolume vol = d->m_cache.valid ? d->m_cache.volume : d->m_volume;
162
    vol.values[channel] = volume;
163

Nicolas Fella's avatar
Nicolas Fella committed
164
165
    if (d->m_cache.valid) {
        d->writeChanges(vol, d->m_cache.muted, d->m_cache.device);
166
    } else {
Nicolas Fella's avatar
Nicolas Fella committed
167
        d->writeChanges(vol, d->m_muted, d->m_device);
168
    }
169
170
171
172
173
174
175
176
177
178
}

quint32 StreamRestore::deviceIndex() const
{
    return PA_INVALID_INDEX;
}

void StreamRestore::setDeviceIndex(quint32 deviceIndex)
{
    Q_UNUSED(deviceIndex);
179
    qCWarning(PULSEAUDIOQT) << "Not implemented";
180
181
}

Nicolas Fella's avatar
Nicolas Fella committed
182
void StreamRestorePrivate::writeChanges(const pa_cvolume &volume, bool muted, const QString &device)
183
{
184
    const QByteArray nameData = q->name().toUtf8();
185
186
187
188
    const QByteArray deviceData = device.toUtf8();

    pa_ext_stream_restore_info info;
    info.name = nameData.constData();
189
    info.channel_map = m_channelMap;
190
191
192
193
    info.volume = volume;
    info.device = deviceData.isEmpty() ? nullptr : deviceData.constData();
    info.mute = muted;

194
195
196
197
198
199
200
    // If no channel exists force one. We need one to be able to control the volume
    // See https://bugs.kde.org/show_bug.cgi?id=407397
    if (info.channel_map.channels == 0) {
        info.channel_map.channels = 1;
        info.channel_map.map[0] = PA_CHANNEL_POSITION_MONO;
    }

201
202
203
204
205
    m_cache.valid = true;
    m_cache.volume = volume;
    m_cache.muted = muted;
    m_cache.device = device;

Nicolas Fella's avatar
Nicolas Fella committed
206
    Context::instance()->d->streamRestoreWrite(&info);
207
208
}

Nicolas Fella's avatar
Nicolas Fella committed
209
210
211
212
213
quint32 StreamRestore::index() const
{
    return d->m_index;
}

David Rosca's avatar
David Rosca committed
214
} // PulseAudioQt