1/*
2 Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com>
3 Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com>
4 Copyright (C) 2009 Fathi Boudra <fabo@kde.org>
5 Copyright (C) 2013-2018 Harald Sitter <sitter@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public
9 License as published by the Free Software Foundation; either
10 version 2.1 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "audiooutput.h"
22
23#include <phonon/pulsesupport.h>
24
25#include <vlc/vlc.h>
26
27#include "backend.h"
28#include "utils/debug.h"
29#include "devicemanager.h"
30#include "mediaobject.h"
31#include "media.h"
32
33namespace Phonon {
34namespace VLC {
35
36AudioOutput::AudioOutput(QObject *parent)
37 : QObject(parent)
38 , m_volume(0.75)
39 , m_explicitVolume(false)
40 , m_muted(false)
41 , m_category(Phonon::NoCategory)
42{
43}
44
45AudioOutput::~AudioOutput()
46{
47}
48
49static libvlc_media_player_role categoryToRole(Category category)
50{
51 switch(category) {
52 case NoCategory:
53 return libvlc_role_None;
54 case NotificationCategory:
55 return libvlc_role_Notification;
56 case MusicCategory:
57 return libvlc_role_Music;
58 case VideoCategory:
59 return libvlc_role_Video;
60 case CommunicationCategory:
61 return libvlc_role_Communication;
62 case GameCategory:
63 return libvlc_role_Game;
64 case AccessibilityCategory:
65 return libvlc_role_Accessibility;
66 }
67 return libvlc_role_None;
68}
69
70void AudioOutput::handleConnectToMediaObject(MediaObject *mediaObject)
71{
72 Q_UNUSED(mediaObject);
73 setOutputDeviceImplementation();
74 if (!PulseSupport::getInstance()->isActive()) {
75 // Rely on libvlc for updates if PASupport is not active
76 connect(sender: m_player, SIGNAL(mutedChanged(bool)),
77 receiver: this, SLOT(onMutedChanged(bool)));
78 connect(sender: m_player, SIGNAL(volumeChanged(float)),
79 receiver: this, SLOT(onVolumeChanged(float)));
80 applyVolume();
81 }
82 libvlc_media_player_set_role(p_mi: *m_player, role: categoryToRole(category: m_category));
83}
84
85void AudioOutput::handleAddToMedia(Media *media)
86{
87 media->addOption(option: ":audio");
88 PulseSupport *pulse = PulseSupport::getInstance();
89 if (pulse && pulse->isActive()) {
90 pulse->setupStreamEnvironment(m_streamUuid);
91 }
92}
93
94qreal AudioOutput::volume() const
95{
96 return m_volume;
97}
98
99void AudioOutput::setVolume(qreal volume)
100{
101 if (m_player) {
102 debug() << "async setting of volume to" << volume;
103 m_volume = volume;
104 m_explicitVolume = true;
105 applyVolume();
106 }
107}
108
109void AudioOutput::setMuted(bool mute)
110{
111 if (mute == m_player->mute()) {
112 // Make sure we actually have propagated the mutness into the frontend.
113 onMutedChanged(mute);
114 return;
115 }
116 m_player->setMute(mute);
117}
118
119void AudioOutput::setCategory(Category category)
120{
121 m_category = category;
122}
123
124int AudioOutput::outputDevice() const
125{
126 return m_device.index();
127}
128
129bool AudioOutput::setOutputDevice(int deviceIndex)
130{
131 const AudioOutputDevice device = AudioOutputDevice::fromIndex(index: deviceIndex);
132 if (!device.isValid()) {
133 error() << Q_FUNC_INFO << "Unable to find the output device with index" << deviceIndex;
134 return false;
135 }
136 return setOutputDevice(device);
137}
138
139bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice)
140{
141 debug() << Q_FUNC_INFO;
142
143 if (!newDevice.isValid()) {
144 error() << "Invalid audio output device";
145 return false;
146 }
147
148 if (newDevice == m_device)
149 return true;
150
151 m_device = newDevice;
152 if (m_player) {
153 setOutputDeviceImplementation();
154 }
155
156 return true;
157}
158
159void AudioOutput::setStreamUuid(QString uuid)
160{
161 DEBUG_BLOCK;
162 debug() << uuid;
163 m_streamUuid = uuid;
164}
165
166void AudioOutput::setOutputDeviceImplementation()
167{
168 Q_ASSERT(m_player);
169
170 // VLC 2.2 has the PulseSupport overrides always disabled because of
171 // incompatibility. Also see backend.cpp for more detals.
172 // To get access to the correct activity state we need to temporarily
173 // enable pulse and then disable it again. This is necessary because isActive
174 // is in fact isActive&isEnabled.............
175 PulseSupport::getInstance()->enable(enabled: true);
176 const bool pulseActive = PulseSupport::getInstance()->isActive();
177 PulseSupport::getInstance()->enable(enabled: false);
178
179 if (pulseActive) {
180 m_player->setAudioOutput("pulse");
181 debug() << "Setting aout to pulse";
182 return;
183 }
184
185 const QVariant dalProperty = m_device.property(name: "deviceAccessList");
186 if (!dalProperty.isValid()) {
187 error() << "Device" << m_device.property(name: "name") << "has no access list";
188 return;
189 }
190 const DeviceAccessList deviceAccessList = dalProperty.value<DeviceAccessList>();
191 if (deviceAccessList.isEmpty()) {
192 error() << "Device" << m_device.property(name: "name") << "has an empty access list";
193 return;
194 }
195
196 // ### we're not trying the whole access list (could mean same device on different soundsystems)
197 const DeviceAccess &firstDeviceAccess = deviceAccessList.first();
198
199 QByteArray soundSystem = firstDeviceAccess.first;
200 debug() << "Setting output soundsystem to" << soundSystem;
201 m_player->setAudioOutput(soundSystem);
202
203 QByteArray deviceName = firstDeviceAccess.second.toLatin1();
204 if (!deviceName.isEmpty()) {
205 // print the name as possibly messed up by toLatin1() to see conversion problems
206 debug() << "Setting output device to" << deviceName << '(' << m_device.property(name: "name") << ')';
207 m_player->setAudioOutputDevice(outputName: soundSystem, deviceName);
208 }
209}
210
211void AudioOutput::applyVolume()
212{
213 if (m_player && m_explicitVolume) {
214 const int preVolume = m_player->audioVolume();
215 const int newVolume = m_volume * 100;
216 m_player->setAudioVolume(newVolume);
217
218 debug() << "Volume changed from" << preVolume << "to" << newVolume;
219 }
220}
221
222void AudioOutput::onMutedChanged(bool mute)
223{
224 m_muted = mute;
225 emit mutedChanged(mute);
226}
227
228void AudioOutput::onVolumeChanged(float volume)
229{
230 m_volume = volume;
231 emit volumeChanged(volume);
232}
233
234}
235} // Namespace Phonon::VLC
236

source code of phonon-vlc/src/audio/audiooutput.cpp