src/3rdparty/phonon/ds9/backend.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /*  This file is part of the KDE project.
       
     2 
       
     3 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 
       
     5 This library is free software: you can redistribute it and/or modify
       
     6 it under the terms of the GNU Lesser General Public License as published by
       
     7 the Free Software Foundation, either version 2.1 or 3 of the License.
       
     8 
       
     9 This library is distributed in the hope that it will be useful,
       
    10 but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12 GNU Lesser General Public License for more details.
       
    13 
       
    14 You should have received a copy of the GNU Lesser General Public License
       
    15 along with this library.  If not, see <http://www.gnu.org/licenses/>.
       
    16 */
       
    17 
       
    18 #include "backend.h"
       
    19 #include "backendnode.h"
       
    20 
       
    21 #include "audiooutput.h"
       
    22 #include "effect.h"
       
    23 #include "mediaobject.h"
       
    24 #include "videowidget.h"
       
    25 #include "volumeeffect.h"
       
    26 
       
    27 //windows specific (DirectX Media Object)
       
    28 #include <dmo.h>
       
    29 
       
    30 #include <QtCore/QSettings>
       
    31 #include <QtCore/QSet>
       
    32 #include <QtCore/QVariant>
       
    33 
       
    34 #include <QtCore/QtPlugin>
       
    35 
       
    36 QT_BEGIN_NAMESPACE
       
    37 
       
    38 Q_EXPORT_PLUGIN2(phonon_ds9, Phonon::DS9::Backend);
       
    39 
       
    40 namespace Phonon
       
    41 {
       
    42     namespace DS9
       
    43     {
       
    44         bool Backend::AudioMoniker::operator==(const AudioMoniker &other)
       
    45         {
       
    46             return other->IsEqual(*this) == S_OK;
       
    47         }
       
    48 
       
    49 
       
    50         Backend::Backend(QObject *parent, const QVariantList &)
       
    51             : QObject(parent)
       
    52         {
       
    53             ::CoInitialize(0);
       
    54 
       
    55             //registering meta types
       
    56             qRegisterMetaType<HRESULT>("HRESULT");
       
    57             qRegisterMetaType<Graph>("Graph");
       
    58         }
       
    59 
       
    60         Backend::~Backend()
       
    61         {
       
    62             m_audioOutputs.clear();
       
    63             m_audioEffects.clear();
       
    64             ::CoUninitialize();
       
    65         }
       
    66 
       
    67         QMutex *Backend::directShowMutex()
       
    68         {
       
    69             return &qobject_cast<Backend*>(qt_plugin_instance())->m_directShowMutex;
       
    70         }
       
    71 
       
    72         QObject *Backend::createObject(BackendInterface::Class c, QObject *parent, const QList<QVariant> &args)
       
    73         {
       
    74             switch (c)
       
    75             {
       
    76             case MediaObjectClass:
       
    77                 return new MediaObject(parent);
       
    78             case AudioOutputClass:
       
    79                 return new AudioOutput(this, parent);
       
    80 #ifndef QT_NO_PHONON_EFFECT
       
    81             case EffectClass:
       
    82                 return new Effect(m_audioEffects[ args[0].toInt() ], parent);
       
    83 #endif //QT_NO_PHONON_EFFECT
       
    84 #ifndef QT_NO_PHONON_VIDEO
       
    85             case VideoWidgetClass:
       
    86                 return new VideoWidget(qobject_cast<QWidget *>(parent));
       
    87 #endif //QT_NO_PHONON_VIDEO
       
    88 #ifndef QT_NO_PHONON_VOLUMEFADEREFFECT
       
    89             case VolumeFaderEffectClass:
       
    90                 return new VolumeEffect(parent);
       
    91 #endif //QT_NO_PHONON_VOLUMEFADEREFFECT
       
    92             default:
       
    93                 return 0;
       
    94             }
       
    95         }
       
    96 
       
    97         bool Backend::supportsVideo() const
       
    98         {
       
    99 #ifndef QT_NO_PHONON_VIDEO
       
   100             return true;
       
   101 #else
       
   102             return false;
       
   103 #endif //QT_NO_PHONON_VIDEO
       
   104         }
       
   105 
       
   106         QStringList Backend::availableMimeTypes() const
       
   107         {
       
   108             QStringList ret;
       
   109             {
       
   110                 QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Multimedia\\mplayer2\\mime types"), QSettings::NativeFormat);
       
   111                 ret += settings.childGroups();
       
   112             }
       
   113             {
       
   114                 QSettings settings(QLatin1String("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Multimedia\\wmplayer\\mime types"), QSettings::NativeFormat);
       
   115                 ret += settings.childGroups();
       
   116             }
       
   117 
       
   118             ret.removeDuplicates();
       
   119             ret.replaceInStrings("\\", "/");
       
   120             qSort(ret);
       
   121             return ret;
       
   122         }
       
   123 
       
   124 		Filter Backend::getAudioOutputFilter(int index) const
       
   125 		{
       
   126 			Filter ret;
       
   127 			if (index >= 0 && index < m_audioOutputs.count()) {
       
   128 				m_audioOutputs.at(index)->BindToObject(0, 0, IID_IBaseFilter, reinterpret_cast<void**>(&ret));
       
   129 			} else {
       
   130 				//just return the default audio renderer (not directsound)
       
   131 				ret = Filter(CLSID_AudioRender, IID_IBaseFilter);
       
   132 			}
       
   133 			return ret;
       
   134 		}
       
   135 
       
   136 
       
   137         QList<int> Backend::objectDescriptionIndexes(Phonon::ObjectDescriptionType type) const
       
   138         {
       
   139             QMutexLocker locker(&m_directShowMutex);
       
   140             QList<int> ret;
       
   141 
       
   142             switch(type)
       
   143             {
       
   144             case Phonon::AudioOutputDeviceType:
       
   145                 {
       
   146 #ifdef Q_OS_WINCE
       
   147 					ret << 0; // only one audio device with index 0
       
   148 #else
       
   149 					ComPointer<ICreateDevEnum> devEnum(CLSID_SystemDeviceEnum, IID_ICreateDevEnum);
       
   150 					if (!devEnum) {
       
   151 						return ret; //it is impossible to enumerate the devices
       
   152 					}
       
   153                     ComPointer<IEnumMoniker> enumMon;
       
   154                     HRESULT hr = devEnum->CreateClassEnumerator(CLSID_AudioRendererCategory, enumMon.pparam(), 0);
       
   155                     if (FAILED(hr)) {
       
   156                         break;
       
   157                     }
       
   158                     AudioMoniker mon;
       
   159 
       
   160                     //let's reorder the devices so that directshound appears first
       
   161                     int nbds = 0; //number of directsound devices
       
   162 
       
   163                     while (S_OK == enumMon->Next(1, mon.pparam(), 0)) {
       
   164                         LPOLESTR str = 0;
       
   165                         mon->GetDisplayName(0,0,&str);
       
   166                         const QString name = QString::fromWCharArray(str);
       
   167 						ComPointer<IMalloc> alloc;
       
   168 						::CoGetMalloc(1, alloc.pparam());
       
   169                         alloc->Free(str);
       
   170 
       
   171                         int insert_pos = 0;
       
   172                         if (!m_audioOutputs.contains(mon)) {
       
   173                             insert_pos = m_audioOutputs.count();
       
   174                             m_audioOutputs.append(mon);
       
   175                         } else {
       
   176                             insert_pos = m_audioOutputs.indexOf(mon);
       
   177                         }
       
   178 
       
   179                         if (name.contains(QLatin1String("DirectSound"))) {
       
   180                             ret.insert(nbds++, insert_pos);
       
   181                         } else {
       
   182                             ret.append(insert_pos);
       
   183                         }
       
   184                     }
       
   185 #endif
       
   186 					break;
       
   187                 }
       
   188 #ifndef QT_NO_PHONON_EFFECT
       
   189             case Phonon::EffectType:
       
   190                 {
       
   191                     m_audioEffects.clear();
       
   192                     ComPointer<IEnumDMO> enumDMO;
       
   193                     HRESULT hr = ::DMOEnum(DMOCATEGORY_AUDIO_EFFECT, DMO_ENUMF_INCLUDE_KEYED, 0, 0, 0, 0, enumDMO.pparam());
       
   194                     if (SUCCEEDED(hr)) {
       
   195                         CLSID clsid;
       
   196                         while (S_OK == enumDMO->Next(1, &clsid, 0, 0)) {
       
   197                             ret += m_audioEffects.count();
       
   198                             m_audioEffects.append(clsid);
       
   199                         }
       
   200                     }
       
   201                     break;
       
   202                 }
       
   203                 break;
       
   204 #endif //QT_NO_PHONON_EFFECT
       
   205             default:
       
   206                 break;
       
   207             }
       
   208 			return ret;
       
   209         }
       
   210 
       
   211         QHash<QByteArray, QVariant> Backend::objectDescriptionProperties(Phonon::ObjectDescriptionType type, int index) const
       
   212         {
       
   213             QMutexLocker locker(&m_directShowMutex);
       
   214             QHash<QByteArray, QVariant> ret;
       
   215             switch (type)
       
   216             {
       
   217             case Phonon::AudioOutputDeviceType:
       
   218                 {
       
   219 #ifdef Q_OS_WINCE
       
   220 					ret["name"] = QLatin1String("default audio device");
       
   221 #else
       
   222                     const AudioMoniker &mon = m_audioOutputs[index];
       
   223                     LPOLESTR str = 0;
       
   224                     HRESULT hr = mon->GetDisplayName(0,0, &str);
       
   225                     if (SUCCEEDED(hr)) {
       
   226                         QString name = QString::fromWCharArray(str);
       
   227 						ComPointer<IMalloc> alloc;
       
   228 						::CoGetMalloc(1, alloc.pparam());
       
   229                         alloc->Free(str);
       
   230                         ret["name"] = name.mid(name.indexOf('\\') + 1);
       
   231 					}
       
   232 #endif
       
   233                 }
       
   234                 break;
       
   235 #ifndef QT_NO_PHONON_EFFECT
       
   236             case Phonon::EffectType:
       
   237                 {
       
   238                     WCHAR name[80]; // 80 is clearly stated in the MSDN doc
       
   239                     HRESULT hr = ::DMOGetName(m_audioEffects[index], name);
       
   240                     if (SUCCEEDED(hr)) {
       
   241                         ret["name"] = QString::fromWCharArray(name);
       
   242                     }
       
   243                 }
       
   244                 break;
       
   245 #endif //QT_NO_PHONON_EFFECT
       
   246             default:
       
   247                 break;
       
   248             }
       
   249 			return ret;
       
   250         }
       
   251 
       
   252         bool Backend::endConnectionChange(QSet<QObject *> objects)
       
   253         {
       
   254             //end of a transaction
       
   255             for(QSet<QObject *>::const_iterator it = objects.begin(); it != objects.end(); ++it) {
       
   256                 if (BackendNode *node = qobject_cast<BackendNode*>(*it)) {
       
   257                     MediaObject *mo = node->mediaObject();
       
   258                     if (mo) {
       
   259                         switch(mo->transactionState)
       
   260                         {
       
   261                         case Phonon::ErrorState:
       
   262                         case Phonon::StoppedState:
       
   263                         case Phonon::LoadingState:
       
   264                             //nothing to do
       
   265                             break;
       
   266                         case Phonon::PausedState:
       
   267                             mo->transactionState = Phonon::StoppedState;
       
   268                             mo->pause();
       
   269                             break;
       
   270                         default:
       
   271                             mo->transactionState = Phonon::StoppedState;
       
   272                             mo->play();
       
   273                             break;
       
   274                         }
       
   275 
       
   276                         if (mo->state() == Phonon::ErrorState)
       
   277                             return false;
       
   278                     }
       
   279                 }
       
   280             }
       
   281 
       
   282             return true;
       
   283         }
       
   284 
       
   285 
       
   286         bool Backend::startConnectionChange(QSet<QObject *> objects)
       
   287         {
       
   288             //let's save the state of the graph (before we stop it)
       
   289             for(QSet<QObject *>::const_iterator it = objects.begin(); it != objects.end(); ++it) {
       
   290                 if (BackendNode *node = qobject_cast<BackendNode*>(*it)) {
       
   291                     if (MediaObject *mo = node->mediaObject()) {
       
   292                         if (mo->state() != Phonon::StoppedState) {
       
   293                             mo->transactionState = mo->state();
       
   294                             mo->ensureStopped(); //we have to stop the graph..
       
   295                             if (mo->state() == Phonon::ErrorState)
       
   296                                 return false;
       
   297                         }
       
   298                     }
       
   299                 }
       
   300             }
       
   301 
       
   302             return true;
       
   303         }
       
   304 
       
   305         bool Backend::connectNodes(QObject *_source, QObject *_sink)
       
   306         {
       
   307             BackendNode *source = qobject_cast<BackendNode*>(_source);
       
   308             if (!source) {
       
   309                 return false;
       
   310             }
       
   311             BackendNode *sink = qobject_cast<BackendNode*>(_sink);
       
   312             if (!sink) {
       
   313                 return false;
       
   314             }
       
   315 
       
   316             //setting the graph if needed
       
   317             if (source->mediaObject() == 0 && sink->mediaObject() == 0) {
       
   318                     //error: no graph selected
       
   319                     return false;
       
   320             } else if (source->mediaObject() && source->mediaObject() != sink->mediaObject()) {
       
   321                 //this' graph becomes the common one
       
   322                 source->mediaObject()->grabNode(sink);
       
   323             } else if (source->mediaObject() == 0) {
       
   324                 //sink's graph becomes the common one
       
   325                 sink->mediaObject()->grabNode(source);
       
   326             }
       
   327 
       
   328             return source->mediaObject()->connectNodes(source, sink);
       
   329         }
       
   330 
       
   331         bool Backend::disconnectNodes(QObject *_source, QObject *_sink)
       
   332         {
       
   333             BackendNode *source = qobject_cast<BackendNode*>(_source);
       
   334             if (!source) {
       
   335                 return false;
       
   336             }
       
   337             BackendNode *sink = qobject_cast<BackendNode*>(_sink);
       
   338             if (!sink) {
       
   339                 return false;
       
   340             }
       
   341 
       
   342             return source->mediaObject() == 0 ||
       
   343                 source->mediaObject()->disconnectNodes(source, sink);
       
   344         }
       
   345     }
       
   346 }
       
   347 
       
   348 QT_END_NAMESPACE
       
   349 
       
   350 #include "moc_backend.cpp"