1/****************************************************************************
2**
3** Copyright (C) 2017 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
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** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "audiodecoder.h"
52#include <stdio.h>
53
54AudioDecoder::AudioDecoder(bool isPlayback, bool isDelete)
55 : m_cout(stdout, QIODevice::WriteOnly)
56{
57 m_isPlayback = isPlayback;
58 m_isDelete = isDelete;
59
60 // Make sure the data we receive is in correct PCM format.
61 // Our wav file writer only supports SignedInt sample type.
62 QAudioFormat format;
63 format.setChannelCount(2);
64 format.setSampleSize(16);
65 format.setSampleRate(48000);
66 format.setCodec("audio/pcm");
67 format.setSampleType(QAudioFormat::SignedInt);
68 m_decoder.setAudioFormat(format);
69
70 connect(sender: &m_decoder, signal: &QAudioDecoder::bufferReady,
71 receiver: this, slot: &AudioDecoder::bufferReady);
72 connect(sender: &m_decoder, signal: QOverload<QAudioDecoder::Error>::of(ptr: &QAudioDecoder::error),
73 receiver: this, slot: QOverload<QAudioDecoder::Error>::of(ptr: &AudioDecoder::error));
74 connect(sender: &m_decoder, signal: &QAudioDecoder::stateChanged,
75 receiver: this, slot: &AudioDecoder::stateChanged);
76 connect(sender: &m_decoder, signal: &QAudioDecoder::finished,
77 receiver: this, slot: &AudioDecoder::finished);
78 connect(sender: &m_decoder, signal: &QAudioDecoder::positionChanged,
79 receiver: this, slot: &AudioDecoder::updateProgress);
80 connect(sender: &m_decoder, signal: &QAudioDecoder::durationChanged,
81 receiver: this, slot: &AudioDecoder::updateProgress);
82
83 connect(sender: &m_soundEffect, signal: &QSoundEffect::statusChanged,
84 receiver: this, slot: &AudioDecoder::playbackStatusChanged);
85 connect(sender: &m_soundEffect, signal: &QSoundEffect::playingChanged,
86 receiver: this, slot: &AudioDecoder::playingChanged);
87
88 m_progress = -1.0;
89}
90
91void AudioDecoder::setSourceFilename(const QString &fileName)
92{
93 m_decoder.setSourceFilename(fileName);
94}
95
96void AudioDecoder::start()
97{
98 m_decoder.start();
99}
100
101void AudioDecoder::stop()
102{
103 m_decoder.stop();
104}
105
106void AudioDecoder::setTargetFilename(const QString &fileName)
107{
108 m_targetFilename = fileName;
109}
110
111void AudioDecoder::bufferReady()
112{
113 // read a buffer from audio decoder
114 QAudioBuffer buffer = m_decoder.read();
115 if (!buffer.isValid())
116 return;
117
118 if (!m_fileWriter.isOpen() && !m_fileWriter.open(fileName: m_targetFilename, format: buffer.format())) {
119 m_decoder.stop();
120 return;
121 }
122
123 m_fileWriter.write(buffer);
124}
125
126void AudioDecoder::error(QAudioDecoder::Error error)
127{
128 switch (error) {
129 case QAudioDecoder::NoError:
130 return;
131 case QAudioDecoder::ResourceError:
132 m_cout << "Resource error\n";
133 break;
134 case QAudioDecoder::FormatError:
135 m_cout << "Format error\n";
136 break;
137 case QAudioDecoder::AccessDeniedError:
138 m_cout << "Access denied error\n";
139 break;
140 case QAudioDecoder::ServiceMissingError:
141 m_cout << "Service missing error\n";
142 break;
143 }
144
145 emit done();
146}
147
148void AudioDecoder::stateChanged(QAudioDecoder::State newState)
149{
150 switch (newState) {
151 case QAudioDecoder::DecodingState:
152 m_cout << "Decoding...\n";
153 break;
154 case QAudioDecoder::StoppedState:
155 m_cout << "Decoding stopped\n";
156 break;
157 }
158}
159
160void AudioDecoder::finished()
161{
162 if (!m_fileWriter.close())
163 m_cout << "Failed to finilize output file\n";
164
165 m_cout << "Decoding finished\n";
166
167 if (m_isPlayback) {
168 m_cout << "Starting playback\n";
169 m_soundEffect.setSource(QUrl::fromLocalFile(localfile: m_targetFilename));
170 m_soundEffect.play();
171 } else {
172 emit done();
173 }
174}
175
176void AudioDecoder::playbackStatusChanged()
177{
178 if (m_soundEffect.status() == QSoundEffect::Error) {
179 m_cout << "Playback error\n";
180 emit done();
181 }
182}
183
184void AudioDecoder::playingChanged()
185{
186 if (!m_soundEffect.isPlaying()) {
187 m_cout << "Playback finished\n";
188 if (m_isDelete)
189 QFile::remove(fileName: m_targetFilename);
190 emit done();
191 }
192}
193
194void AudioDecoder::updateProgress()
195{
196 qint64 position = m_decoder.position();
197 qint64 duration = m_decoder.duration();
198 qreal progress = m_progress;
199 if (position >= 0 && duration > 0)
200 progress = position / (qreal)duration;
201
202 if (progress > m_progress + 0.1) {
203 m_cout << "Decoding progress: " << (int)(progress * 100.0) << "%\n";
204 m_progress = progress;
205 }
206}
207

source code of qtmultimedia/examples/multimedia/audiodecoder/audiodecoder.cpp