File indexing completed on 2025-02-16 07:33:46
0001 /* 0002 Copyright (C) 2007-2008 Tanguy Krotoff <tkrotoff@gmail.com> 0003 Copyright (C) 2008 Lukas Durfina <lukas.durfina@gmail.com> 0004 Copyright (C) 2009 Fathi Boudra <fabo@kde.org> 0005 Copyright (C) 2013-2018 Harald Sitter <sitter@kde.org> 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Lesser General Public 0009 License as published by the Free Software Foundation; either 0010 version 2.1 of the License, or (at your option) any later version. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Lesser General Public License for more details. 0016 0017 You should have received a copy of the GNU Lesser General Public 0018 License along with this library. If not, see <http://www.gnu.org/licenses/>. 0019 */ 0020 0021 #include "audiooutput.h" 0022 0023 #include <phonon/pulsesupport.h> 0024 0025 #include <vlc/vlc.h> 0026 0027 #include "backend.h" 0028 #include "utils/debug.h" 0029 #include "devicemanager.h" 0030 #include "mediaobject.h" 0031 #include "media.h" 0032 0033 namespace Phonon { 0034 namespace VLC { 0035 0036 AudioOutput::AudioOutput(QObject *parent) 0037 : QObject(parent) 0038 , m_volume(0.75) 0039 , m_explicitVolume(false) 0040 , m_muted(false) 0041 , m_category(Phonon::NoCategory) 0042 { 0043 } 0044 0045 AudioOutput::~AudioOutput() 0046 { 0047 } 0048 0049 static libvlc_media_player_role categoryToRole(Category category) 0050 { 0051 switch(category) { 0052 case NoCategory: 0053 return libvlc_role_None; 0054 case NotificationCategory: 0055 return libvlc_role_Notification; 0056 case MusicCategory: 0057 return libvlc_role_Music; 0058 case VideoCategory: 0059 return libvlc_role_Video; 0060 case CommunicationCategory: 0061 return libvlc_role_Communication; 0062 case GameCategory: 0063 return libvlc_role_Game; 0064 case AccessibilityCategory: 0065 return libvlc_role_Accessibility; 0066 } 0067 return libvlc_role_None; 0068 } 0069 0070 void AudioOutput::handleConnectToMediaObject(MediaObject *mediaObject) 0071 { 0072 Q_UNUSED(mediaObject); 0073 setOutputDeviceImplementation(); 0074 if (!PulseSupport::getInstance()->isActive()) { 0075 // Rely on libvlc for updates if PASupport is not active 0076 connect(m_player, SIGNAL(mutedChanged(bool)), 0077 this, SLOT(onMutedChanged(bool))); 0078 connect(m_player, SIGNAL(volumeChanged(float)), 0079 this, SLOT(onVolumeChanged(float))); 0080 applyVolume(); 0081 } 0082 libvlc_media_player_set_role(*m_player, categoryToRole(m_category)); 0083 } 0084 0085 void AudioOutput::handleAddToMedia(Media *media) 0086 { 0087 media->addOption(":audio"); 0088 PulseSupport *pulse = PulseSupport::getInstance(); 0089 if (pulse && pulse->isActive()) { 0090 pulse->setupStreamEnvironment(m_streamUuid); 0091 } 0092 } 0093 0094 qreal AudioOutput::volume() const 0095 { 0096 return m_volume; 0097 } 0098 0099 void AudioOutput::setVolume(qreal volume) 0100 { 0101 if (m_player) { 0102 debug() << "async setting of volume to" << volume; 0103 m_volume = volume; 0104 m_explicitVolume = true; 0105 applyVolume(); 0106 } 0107 } 0108 0109 void AudioOutput::setMuted(bool mute) 0110 { 0111 if (mute == m_player->mute()) { 0112 // Make sure we actually have propagated the mutness into the frontend. 0113 onMutedChanged(mute); 0114 return; 0115 } 0116 m_player->setMute(mute); 0117 } 0118 0119 void AudioOutput::setCategory(Category category) 0120 { 0121 m_category = category; 0122 } 0123 0124 int AudioOutput::outputDevice() const 0125 { 0126 return m_device.index(); 0127 } 0128 0129 bool AudioOutput::setOutputDevice(int deviceIndex) 0130 { 0131 const AudioOutputDevice device = AudioOutputDevice::fromIndex(deviceIndex); 0132 if (!device.isValid()) { 0133 error() << Q_FUNC_INFO << "Unable to find the output device with index" << deviceIndex; 0134 return false; 0135 } 0136 return setOutputDevice(device); 0137 } 0138 0139 bool AudioOutput::setOutputDevice(const AudioOutputDevice &newDevice) 0140 { 0141 debug() << Q_FUNC_INFO; 0142 0143 if (!newDevice.isValid()) { 0144 error() << "Invalid audio output device"; 0145 return false; 0146 } 0147 0148 if (newDevice == m_device) 0149 return true; 0150 0151 m_device = newDevice; 0152 if (m_player) { 0153 setOutputDeviceImplementation(); 0154 } 0155 0156 return true; 0157 } 0158 0159 void AudioOutput::setStreamUuid(QString uuid) 0160 { 0161 DEBUG_BLOCK; 0162 debug() << uuid; 0163 m_streamUuid = uuid; 0164 } 0165 0166 void AudioOutput::setOutputDeviceImplementation() 0167 { 0168 Q_ASSERT(m_player); 0169 0170 // VLC 2.2 has the PulseSupport overrides always disabled because of 0171 // incompatibility. Also see backend.cpp for more detals. 0172 // To get access to the correct activity state we need to temporarily 0173 // enable pulse and then disable it again. This is necessary because isActive 0174 // is in fact isActive&isEnabled............. 0175 PulseSupport::getInstance()->enable(true); 0176 const bool pulseActive = PulseSupport::getInstance()->isActive(); 0177 PulseSupport::getInstance()->enable(false); 0178 0179 if (pulseActive) { 0180 m_player->setAudioOutput("pulse"); 0181 debug() << "Setting aout to pulse"; 0182 return; 0183 } 0184 0185 const QVariant dalProperty = m_device.property("deviceAccessList"); 0186 if (!dalProperty.isValid()) { 0187 error() << "Device" << m_device.property("name") << "has no access list"; 0188 return; 0189 } 0190 const DeviceAccessList deviceAccessList = dalProperty.value<DeviceAccessList>(); 0191 if (deviceAccessList.isEmpty()) { 0192 error() << "Device" << m_device.property("name") << "has an empty access list"; 0193 return; 0194 } 0195 0196 // ### we're not trying the whole access list (could mean same device on different soundsystems) 0197 const DeviceAccess &firstDeviceAccess = deviceAccessList.first(); 0198 0199 QByteArray soundSystem = firstDeviceAccess.first; 0200 debug() << "Setting output soundsystem to" << soundSystem; 0201 m_player->setAudioOutput(soundSystem); 0202 0203 QByteArray deviceName = firstDeviceAccess.second.toLatin1(); 0204 if (!deviceName.isEmpty()) { 0205 // print the name as possibly messed up by toLatin1() to see conversion problems 0206 debug() << "Setting output device to" << deviceName << '(' << m_device.property("name") << ')'; 0207 m_player->setAudioOutputDevice(soundSystem, deviceName); 0208 } 0209 } 0210 0211 void AudioOutput::applyVolume() 0212 { 0213 if (m_player && m_explicitVolume) { 0214 const int preVolume = m_player->audioVolume(); 0215 const int newVolume = m_volume * 100; 0216 m_player->setAudioVolume(newVolume); 0217 0218 debug() << "Volume changed from" << preVolume << "to" << newVolume; 0219 } 0220 } 0221 0222 void AudioOutput::onMutedChanged(bool mute) 0223 { 0224 m_muted = mute; 0225 emit mutedChanged(mute); 0226 } 0227 0228 void AudioOutput::onVolumeChanged(float volume) 0229 { 0230 m_volume = volume; 0231 emit volumeChanged(volume); 0232 } 0233 0234 } 0235 } // Namespace Phonon::VLC