1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
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 https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #ifndef MOCKAUDIODECODERCONTROL_H |
30 | #define MOCKAUDIODECODERCONTROL_H |
31 | |
32 | #include "qmediacontrol.h" |
33 | #include "qaudiodecodercontrol.h" |
34 | |
35 | #include <QtCore/qpair.h> |
36 | |
37 | #include "qaudiobuffer.h" |
38 | #include <QTimer> |
39 | #include <QIODevice> |
40 | |
41 | #define MOCK_DECODER_MAX_BUFFERS 10 |
42 | |
43 | QT_BEGIN_NAMESPACE |
44 | |
45 | class MockAudioDecoderControl : public QAudioDecoderControl |
46 | { |
47 | Q_OBJECT |
48 | |
49 | public: |
50 | MockAudioDecoderControl(QObject *parent = 0) |
51 | : QAudioDecoderControl(parent) |
52 | , mState(QAudioDecoder::StoppedState) |
53 | , mDevice(0) |
54 | , mPosition(-1) |
55 | , mSerial(0) |
56 | { |
57 | mFormat.setChannelCount(1); |
58 | mFormat.setSampleSize(8); |
59 | mFormat.setSampleRate(1000); |
60 | mFormat.setCodec("audio/x-raw" ); |
61 | mFormat.setSampleType(QAudioFormat::UnSignedInt); |
62 | } |
63 | |
64 | QAudioDecoder::State state() const |
65 | { |
66 | return mState; |
67 | } |
68 | |
69 | QString sourceFilename() const |
70 | { |
71 | return mSource; |
72 | } |
73 | |
74 | QAudioFormat audioFormat() const |
75 | { |
76 | return mFormat; |
77 | } |
78 | |
79 | void setAudioFormat(const QAudioFormat &format) |
80 | { |
81 | if (mFormat != format) { |
82 | mFormat = format; |
83 | emit formatChanged(format: mFormat); |
84 | } |
85 | } |
86 | |
87 | void setSourceFilename(const QString &fileName) |
88 | { |
89 | mSource = fileName; |
90 | mDevice = 0; |
91 | stop(); |
92 | } |
93 | |
94 | QIODevice* sourceDevice() const |
95 | { |
96 | return mDevice; |
97 | } |
98 | |
99 | void setSourceDevice(QIODevice *device) |
100 | { |
101 | mDevice = device; |
102 | mSource.clear(); |
103 | stop(); |
104 | } |
105 | |
106 | // When decoding we decode to first buffer, then second buffer |
107 | // we then stop until the first is read again and so on, for |
108 | // 5 buffers |
109 | void start() |
110 | { |
111 | if (mState == QAudioDecoder::StoppedState) { |
112 | if (!mSource.isEmpty()) { |
113 | mState = QAudioDecoder::DecodingState; |
114 | emit stateChanged(newState: mState); |
115 | emit durationChanged(duration: duration()); |
116 | |
117 | QTimer::singleShot(msec: 50, receiver: this, SLOT(pretendDecode())); |
118 | } else { |
119 | emit error(error: QAudioDecoder::ResourceError, errorString: "No source set" ); |
120 | } |
121 | } |
122 | } |
123 | |
124 | void stop() |
125 | { |
126 | if (mState != QAudioDecoder::StoppedState) { |
127 | mState = QAudioDecoder::StoppedState; |
128 | mSerial = 0; |
129 | mPosition = 0; |
130 | mBuffers.clear(); |
131 | emit stateChanged(newState: mState); |
132 | emit bufferAvailableChanged(available: false); |
133 | } |
134 | } |
135 | |
136 | QAudioBuffer read() |
137 | { |
138 | QAudioBuffer a; |
139 | if (mBuffers.length() > 0) { |
140 | a = mBuffers.takeFirst(); |
141 | mPosition = a.startTime() / 1000; |
142 | emit positionChanged(position: mPosition); |
143 | |
144 | if (mBuffers.isEmpty()) |
145 | emit bufferAvailableChanged(available: false); |
146 | |
147 | if (mBuffers.isEmpty() && mSerial >= MOCK_DECODER_MAX_BUFFERS) { |
148 | mState = QAudioDecoder::StoppedState; |
149 | emit finished(); |
150 | emit stateChanged(newState: mState); |
151 | } else |
152 | QTimer::singleShot(msec: 50, receiver: this, SLOT(pretendDecode())); |
153 | } |
154 | |
155 | return a; |
156 | } |
157 | |
158 | bool bufferAvailable() const |
159 | { |
160 | return mBuffers.length() > 0; |
161 | } |
162 | |
163 | qint64 position() const |
164 | { |
165 | return mPosition; |
166 | } |
167 | |
168 | qint64 duration() const |
169 | { |
170 | return (sizeof(mSerial) * MOCK_DECODER_MAX_BUFFERS * qint64(1000)) / (mFormat.sampleRate() * mFormat.channelCount()); |
171 | } |
172 | |
173 | private slots: |
174 | void pretendDecode() |
175 | { |
176 | // Check if we've reached end of stream |
177 | if (mSerial >= MOCK_DECODER_MAX_BUFFERS) |
178 | return; |
179 | |
180 | // We just keep the length of mBuffers to 3 or less. |
181 | if (mBuffers.length() < 3) { |
182 | QByteArray b(sizeof(mSerial), 0); |
183 | memcpy(dest: b.data(), src: &mSerial, n: sizeof(mSerial)); |
184 | qint64 position = (sizeof(mSerial) * mSerial * qint64(1000000)) / (mFormat.sampleRate() * mFormat.channelCount()); |
185 | mSerial++; |
186 | mBuffers.push_back(t: QAudioBuffer(b, mFormat, position)); |
187 | emit bufferReady(); |
188 | if (mBuffers.count() == 1) |
189 | emit bufferAvailableChanged(available: true); |
190 | } |
191 | } |
192 | |
193 | public: |
194 | QAudioDecoder::State mState; |
195 | QString mSource; |
196 | QIODevice *mDevice; |
197 | QAudioFormat mFormat; |
198 | qint64 mPosition; |
199 | |
200 | int mSerial; |
201 | QList<QAudioBuffer> mBuffers; |
202 | }; |
203 | |
204 | QT_END_NAMESPACE |
205 | |
206 | #endif // QAUDIODECODERCONTROL_H |
207 | |