File indexing completed on 2024-05-12 04:44:37

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