source: trunk/src/3rdparty/phonon/ds9/backend.cpp

Last change on this file was 561, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.1 sources.

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