1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: http://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtFeedback module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL3$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see http://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at http://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPLv3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or later as published by the Free |
28 | ** Software Foundation and appearing in the file LICENSE.GPL included in |
29 | ** the packaging of this file. Please review the following information to |
30 | ** ensure the GNU General Public License version 2.0 requirements will be |
31 | ** met: http://www.gnu.org/licenses/gpl-2.0.html. |
32 | ** |
33 | ** $QT_END_LICENSE$ |
34 | ** |
35 | ****************************************************************************/ |
36 | |
37 | #include <QtCore/QtPlugin> |
38 | #include <QtCore/QCoreApplication> |
39 | #include <QtCore/QFile> |
40 | |
41 | #include <QDebug> |
42 | #include "qfeedback.h" |
43 | |
44 | QT_BEGIN_NAMESPACE |
45 | |
46 | QFeedbackMMK::QFeedbackMMK() : QObject(qApp) |
47 | { |
48 | } |
49 | |
50 | QFeedbackMMK::~QFeedbackMMK() |
51 | { |
52 | foreach(FeedbackInfo fi, mEffects.values()) { |
53 | delete fi.soundEffect; |
54 | } |
55 | } |
56 | |
57 | void QFeedbackMMK::setLoaded(QFeedbackFileEffect *effect, bool load) |
58 | { |
59 | if (!effect) |
60 | return; |
61 | |
62 | // See if we have seen this effect before |
63 | FeedbackInfo fi = mEffects.value(akey: effect); |
64 | |
65 | if (load) { |
66 | // Well.. we might already have an effect, since we don't create them until |
67 | // we load... |
68 | if (fi.loaded) { |
69 | // We've already loaded? |
70 | return; |
71 | } else { |
72 | if (fi.soundEffect) { |
73 | // We've started a load, they must just be impatient |
74 | // Pushing this elevator button does nothing.. |
75 | return; |
76 | } else { |
77 | // New sound effect! |
78 | QUrl url = effect->source(); |
79 | if (QFile::exists(fileName: url.toLocalFile())) { |
80 | fi.soundEffect = new QSoundEffect(this); |
81 | mEffects.insert(akey: effect, avalue: fi); |
82 | mEffectMap.insert(akey: fi.soundEffect, avalue: effect); |
83 | |
84 | connect(sender: fi.soundEffect, SIGNAL(statusChanged()), receiver: this, SLOT(soundEffectStatusChanged())); |
85 | connect(sender: fi.soundEffect, SIGNAL(playingChanged()), receiver: this, SLOT(soundEffectPlayingChanged())); |
86 | fi.soundEffect->setSource(url); |
87 | |
88 | // conceptually we're now loading, so we have to do this manually?? |
89 | QMetaObject::invokeMethod(obj: effect, member: "stateChanged" ); |
90 | } else { |
91 | reportLoadFinished(effect, success: false); |
92 | } |
93 | } |
94 | } |
95 | } else { |
96 | // Time to unload. |
97 | if (fi.soundEffect) { |
98 | mEffectMap.remove(akey: fi.soundEffect); |
99 | fi.soundEffect->deleteLater(); |
100 | } |
101 | mEffects.remove(akey: effect); |
102 | } |
103 | } |
104 | |
105 | void QFeedbackMMK::setEffectState(QFeedbackFileEffect *effect, QFeedbackEffect::State state) |
106 | { |
107 | FeedbackInfo fi = mEffects.value(akey: effect); |
108 | switch (state) |
109 | { |
110 | case QFeedbackEffect::Stopped: |
111 | if (fi.playing) { |
112 | Q_ASSERT(fi.soundEffect); |
113 | fi.playing = false; |
114 | mEffects.insert(akey: effect, avalue: fi); // overwrite previous version |
115 | fi.soundEffect->stop(); |
116 | } |
117 | break; |
118 | |
119 | case QFeedbackEffect::Paused: |
120 | // Well, we can't pause, really |
121 | reportError(effect, QFeedbackEffect::UnknownError); |
122 | break; |
123 | |
124 | case QFeedbackEffect::Running: |
125 | if (fi.playing) { |
126 | // We're already playing. |
127 | } else if (fi.soundEffect) { |
128 | fi.playing = true; |
129 | mEffects.insert(akey: effect, avalue: fi); // overwrite previous version |
130 | fi.soundEffect->play(); |
131 | } |
132 | break; |
133 | default: |
134 | break; |
135 | } |
136 | } |
137 | |
138 | QFeedbackEffect::State QFeedbackMMK::effectState(const QFeedbackFileEffect *effect) |
139 | { |
140 | FeedbackInfo fi = mEffects.value(akey: effect); |
141 | if (fi.soundEffect) { |
142 | if (fi.playing) // we might not be loaded, however |
143 | return QFeedbackEffect::Running; |
144 | if (fi.loaded) |
145 | return QFeedbackEffect::Stopped; // No idle? |
146 | return QFeedbackEffect::Loading; |
147 | } |
148 | return QFeedbackEffect::Stopped; |
149 | } |
150 | |
151 | int QFeedbackMMK::effectDuration(const QFeedbackFileEffect *effect) |
152 | { |
153 | Q_UNUSED(effect); |
154 | // XXX This isn't supported by MMK currently |
155 | return 0; |
156 | } |
157 | |
158 | QStringList QFeedbackMMK::supportedMimeTypes() |
159 | { |
160 | return QSoundEffect::supportedMimeTypes(); |
161 | } |
162 | |
163 | void QFeedbackMMK::soundEffectStatusChanged() |
164 | { |
165 | QSoundEffect* se = qobject_cast<QSoundEffect*>(object: sender()); |
166 | if (se) { |
167 | // Hmm, now look up the right sound effect |
168 | QFeedbackFileEffect* fe = mEffectMap.value(akey: se); |
169 | if (!fe) |
170 | return; |
171 | |
172 | FeedbackInfo fi = mEffects.value(akey: fe); |
173 | |
174 | switch(se->status()) { |
175 | case QSoundEffect::Error: |
176 | if (!fi.soundEffect || !fi.loaded) { |
177 | // Error before we got loaded, so fail the load |
178 | mEffectMap.remove(akey: se); |
179 | mEffects.remove(akey: fe); |
180 | se->deleteLater(); |
181 | reportLoadFinished(fe, success: false); // this ends our involvement |
182 | } else { |
183 | reportError(fe, QFeedbackEffect::UnknownError); // this doesn't do much |
184 | } |
185 | break; |
186 | |
187 | case QSoundEffect::Ready: |
188 | if (fe->state() == QFeedbackEffect::Loading) { |
189 | reportLoadFinished(fe, success: true); |
190 | |
191 | FeedbackInfo fi = mEffects.value(akey: fe); |
192 | fi.loaded = true; |
193 | mEffects.insert(akey: fe, avalue: fi); |
194 | |
195 | QMetaObject::invokeMethod(obj: fe, member: "stateChanged" ); |
196 | } |
197 | break; |
198 | |
199 | default: |
200 | // Nothing to handle here? |
201 | break; |
202 | } |
203 | } |
204 | } |
205 | |
206 | void QFeedbackMMK::soundEffectPlayingChanged() |
207 | { |
208 | QSoundEffect* se = qobject_cast<QSoundEffect*>(object: sender()); |
209 | if (se) { |
210 | QFeedbackFileEffect* fileEffect = mEffectMap.value(akey: se); |
211 | FeedbackInfo fi = mEffects.value(akey: fileEffect); |
212 | |
213 | if (fi.soundEffect == se) { |
214 | if (fi.playing != se->isPlaying()) { |
215 | fi.playing = se->isPlaying(); |
216 | mEffects.insert(akey: fileEffect, avalue: fi); // overwrite previous version |
217 | |
218 | QFeedbackFileEffect* fe = mEffectMap.value(akey: se); |
219 | // Emit the stateChanged() signal |
220 | if (fe) { |
221 | QMetaObject::invokeMethod(obj: fe, member: "stateChanged" ); |
222 | } |
223 | } else { |
224 | // Do nothing, internal state is already ok |
225 | } |
226 | } |
227 | } |
228 | } |
229 | |
230 | QT_END_NAMESPACE |
231 | |