PageRenderTime 44ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/src/3rdparty/phonon/ds9/backend.cpp

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