| 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 "audiodevices.h" |
| 52 | |
| 53 | // Utility functions for converting QAudioFormat fields into text |
| 54 | |
| 55 | static QString toString(QAudioFormat::SampleType sampleType) |
| 56 | { |
| 57 | QString result("Unknown" ); |
| 58 | switch (sampleType) { |
| 59 | case QAudioFormat::SignedInt: |
| 60 | result = "SignedInt" ; |
| 61 | break; |
| 62 | case QAudioFormat::UnSignedInt: |
| 63 | result = "UnSignedInt" ; |
| 64 | break; |
| 65 | case QAudioFormat::Float: |
| 66 | result = "Float" ; |
| 67 | break; |
| 68 | case QAudioFormat::Unknown: |
| 69 | result = "Unknown" ; |
| 70 | } |
| 71 | return result; |
| 72 | } |
| 73 | |
| 74 | static QString toString(QAudioFormat::Endian endian) |
| 75 | { |
| 76 | QString result("Unknown" ); |
| 77 | switch (endian) { |
| 78 | case QAudioFormat::LittleEndian: |
| 79 | result = "LittleEndian" ; |
| 80 | break; |
| 81 | case QAudioFormat::BigEndian: |
| 82 | result = "BigEndian" ; |
| 83 | break; |
| 84 | } |
| 85 | return result; |
| 86 | } |
| 87 | |
| 88 | |
| 89 | AudioDevicesBase::AudioDevicesBase(QWidget *parent) |
| 90 | : QMainWindow(parent) |
| 91 | { |
| 92 | setupUi(this); |
| 93 | } |
| 94 | |
| 95 | AudioDevicesBase::~AudioDevicesBase() {} |
| 96 | |
| 97 | |
| 98 | AudioTest::AudioTest(QWidget *parent) |
| 99 | : AudioDevicesBase(parent) |
| 100 | { |
| 101 | connect(sender: testButton, signal: &QPushButton::clicked, receiver: this, slot: &AudioTest::test); |
| 102 | connect(sender: modeBox, signal: QOverload<int>::of(ptr: &QComboBox::activated), receiver: this, slot: &AudioTest::modeChanged); |
| 103 | connect(sender: deviceBox, signal: QOverload<int>::of(ptr: &QComboBox::activated), receiver: this, slot: &AudioTest::deviceChanged); |
| 104 | connect(sender: sampleRateBox, signal: QOverload<int>::of(ptr: &QComboBox::activated), receiver: this, slot: &AudioTest::sampleRateChanged); |
| 105 | connect(sender: channelsBox, signal: QOverload<int>::of(ptr: &QComboBox::activated), receiver: this, slot: &AudioTest::channelChanged); |
| 106 | connect(sender: codecsBox, signal: QOverload<int>::of(ptr: &QComboBox::activated), receiver: this, slot: &AudioTest::codecChanged); |
| 107 | connect(sender: sampleSizesBox, signal: QOverload<int>::of(ptr: &QComboBox::activated), receiver: this, slot: &AudioTest::sampleSizeChanged); |
| 108 | connect(sender: sampleTypesBox, signal: QOverload<int>::of(ptr: &QComboBox::activated), receiver: this, slot: &AudioTest::sampleTypeChanged); |
| 109 | connect(sender: endianBox, signal: QOverload<int>::of(ptr: &QComboBox::activated), receiver: this, slot: &AudioTest::endianChanged); |
| 110 | connect(sender: populateTableButton, signal: &QPushButton::clicked, receiver: this, slot: &AudioTest::populateTable); |
| 111 | |
| 112 | modeBox->setCurrentIndex(0); |
| 113 | modeChanged(idx: 0); |
| 114 | deviceBox->setCurrentIndex(0); |
| 115 | deviceChanged(idx: 0); |
| 116 | } |
| 117 | |
| 118 | void AudioTest::test() |
| 119 | { |
| 120 | // tries to set all the settings picked. |
| 121 | testResult->clear(); |
| 122 | |
| 123 | if (!m_deviceInfo.isNull()) { |
| 124 | if (m_deviceInfo.isFormatSupported(format: m_settings)) { |
| 125 | testResult->setText(tr(s: "Success" )); |
| 126 | nearestSampleRate->setText("" ); |
| 127 | nearestChannel->setText("" ); |
| 128 | nearestCodec->setText("" ); |
| 129 | nearestSampleSize->setText("" ); |
| 130 | nearestSampleType->setText("" ); |
| 131 | nearestEndian->setText("" ); |
| 132 | } else { |
| 133 | QAudioFormat nearest = m_deviceInfo.nearestFormat(format: m_settings); |
| 134 | testResult->setText(tr(s: "Failed" )); |
| 135 | nearestSampleRate->setText(QString("%1" ).arg(a: nearest.sampleRate())); |
| 136 | nearestChannel->setText(QString("%1" ).arg(a: nearest.channelCount())); |
| 137 | nearestCodec->setText(nearest.codec()); |
| 138 | nearestSampleSize->setText(QString("%1" ).arg(a: nearest.sampleSize())); |
| 139 | nearestSampleType->setText(toString(sampleType: nearest.sampleType())); |
| 140 | nearestEndian->setText(toString(endian: nearest.byteOrder())); |
| 141 | } |
| 142 | } |
| 143 | else |
| 144 | testResult->setText(tr(s: "No Device" )); |
| 145 | } |
| 146 | |
| 147 | void AudioTest::modeChanged(int idx) |
| 148 | { |
| 149 | testResult->clear(); |
| 150 | deviceBox->clear(); |
| 151 | const QAudio::Mode mode = idx == 0 ? QAudio::AudioInput : QAudio::AudioOutput; |
| 152 | for (auto &deviceInfo: QAudioDeviceInfo::availableDevices(mode)) |
| 153 | deviceBox->addItem(atext: deviceInfo.deviceName(), auserData: QVariant::fromValue(value: deviceInfo)); |
| 154 | |
| 155 | deviceBox->setCurrentIndex(0); |
| 156 | deviceChanged(idx: 0); |
| 157 | } |
| 158 | |
| 159 | void AudioTest::deviceChanged(int idx) |
| 160 | { |
| 161 | testResult->clear(); |
| 162 | |
| 163 | if (deviceBox->count() == 0) |
| 164 | return; |
| 165 | |
| 166 | // device has changed |
| 167 | m_deviceInfo = deviceBox->itemData(index: idx).value<QAudioDeviceInfo>(); |
| 168 | |
| 169 | sampleRateBox->clear(); |
| 170 | QList<int> sampleRatez = m_deviceInfo.supportedSampleRates(); |
| 171 | for (int i = 0; i < sampleRatez.size(); ++i) |
| 172 | sampleRateBox->addItem(atext: QString("%1" ).arg(a: sampleRatez.at(i))); |
| 173 | if (sampleRatez.size()) |
| 174 | m_settings.setSampleRate(sampleRatez.at(i: 0)); |
| 175 | |
| 176 | channelsBox->clear(); |
| 177 | QList<int> chz = m_deviceInfo.supportedChannelCounts(); |
| 178 | for (int i = 0; i < chz.size(); ++i) |
| 179 | channelsBox->addItem(atext: QString("%1" ).arg(a: chz.at(i))); |
| 180 | if (chz.size()) |
| 181 | m_settings.setChannelCount(chz.at(i: 0)); |
| 182 | |
| 183 | codecsBox->clear(); |
| 184 | QStringList codecs = m_deviceInfo.supportedCodecs(); |
| 185 | for (int i = 0; i < codecs.size(); ++i) |
| 186 | codecsBox->addItem(atext: QString("%1" ).arg(a: codecs.at(i))); |
| 187 | if (codecs.size()) |
| 188 | m_settings.setCodec(codecs.at(i: 0)); |
| 189 | // Add false to create failed condition! |
| 190 | codecsBox->addItem(atext: "audio/test" ); |
| 191 | |
| 192 | sampleSizesBox->clear(); |
| 193 | QList<int> sampleSizez = m_deviceInfo.supportedSampleSizes(); |
| 194 | for (int i = 0; i < sampleSizez.size(); ++i) |
| 195 | sampleSizesBox->addItem(atext: QString("%1" ).arg(a: sampleSizez.at(i))); |
| 196 | if (sampleSizez.size()) |
| 197 | m_settings.setSampleSize(sampleSizez.at(i: 0)); |
| 198 | |
| 199 | sampleTypesBox->clear(); |
| 200 | QList<QAudioFormat::SampleType> sampleTypez = m_deviceInfo.supportedSampleTypes(); |
| 201 | |
| 202 | for (int i = 0; i < sampleTypez.size(); ++i) |
| 203 | sampleTypesBox->addItem(atext: toString(sampleType: sampleTypez.at(i))); |
| 204 | if (sampleTypez.size()) |
| 205 | m_settings.setSampleType(sampleTypez.at(i: 0)); |
| 206 | |
| 207 | endianBox->clear(); |
| 208 | QList<QAudioFormat::Endian> endianz = m_deviceInfo.supportedByteOrders(); |
| 209 | for (int i = 0; i < endianz.size(); ++i) |
| 210 | endianBox->addItem(atext: toString(endian: endianz.at(i))); |
| 211 | if (endianz.size()) |
| 212 | m_settings.setByteOrder(endianz.at(i: 0)); |
| 213 | |
| 214 | allFormatsTable->clearContents(); |
| 215 | } |
| 216 | |
| 217 | void AudioTest::populateTable() |
| 218 | { |
| 219 | int row = 0; |
| 220 | |
| 221 | QAudioFormat format; |
| 222 | for (auto codec: m_deviceInfo.supportedCodecs()) { |
| 223 | format.setCodec(codec); |
| 224 | for (auto sampleRate: m_deviceInfo.supportedSampleRates()) { |
| 225 | format.setSampleRate(sampleRate); |
| 226 | for (auto channels: m_deviceInfo.supportedChannelCounts()) { |
| 227 | format.setChannelCount(channels); |
| 228 | for (auto sampleType: m_deviceInfo.supportedSampleTypes()) { |
| 229 | format.setSampleType(sampleType); |
| 230 | for (auto sampleSize: m_deviceInfo.supportedSampleSizes()) { |
| 231 | format.setSampleSize(sampleSize); |
| 232 | for (auto endian: m_deviceInfo.supportedByteOrders()) { |
| 233 | format.setByteOrder(endian); |
| 234 | if (m_deviceInfo.isFormatSupported(format)) { |
| 235 | allFormatsTable->setRowCount(row + 1); |
| 236 | |
| 237 | QTableWidgetItem *codecItem = new QTableWidgetItem(format.codec()); |
| 238 | allFormatsTable->setItem(row, column: 0, item: codecItem); |
| 239 | |
| 240 | QTableWidgetItem *sampleRateItem = new QTableWidgetItem(QString("%1" ).arg(a: format.sampleRate())); |
| 241 | allFormatsTable->setItem(row, column: 1, item: sampleRateItem); |
| 242 | |
| 243 | QTableWidgetItem *channelsItem = new QTableWidgetItem(QString("%1" ).arg(a: format.channelCount())); |
| 244 | allFormatsTable->setItem(row, column: 2, item: channelsItem); |
| 245 | |
| 246 | QTableWidgetItem *sampleTypeItem = new QTableWidgetItem(toString(sampleType: format.sampleType())); |
| 247 | allFormatsTable->setItem(row, column: 3, item: sampleTypeItem); |
| 248 | |
| 249 | QTableWidgetItem *sampleSizeItem = new QTableWidgetItem(QString("%1" ).arg(a: format.sampleSize())); |
| 250 | allFormatsTable->setItem(row, column: 4, item: sampleSizeItem); |
| 251 | |
| 252 | QTableWidgetItem *byteOrderItem = new QTableWidgetItem(toString(endian: format.byteOrder())); |
| 253 | allFormatsTable->setItem(row, column: 5, item: byteOrderItem); |
| 254 | |
| 255 | ++row; |
| 256 | } |
| 257 | } |
| 258 | } |
| 259 | } |
| 260 | } |
| 261 | } |
| 262 | } |
| 263 | } |
| 264 | |
| 265 | void AudioTest::sampleRateChanged(int idx) |
| 266 | { |
| 267 | // sample rate has changed |
| 268 | m_settings.setSampleRate(sampleRateBox->itemText(index: idx).toInt()); |
| 269 | } |
| 270 | |
| 271 | void AudioTest::channelChanged(int idx) |
| 272 | { |
| 273 | m_settings.setChannelCount(channelsBox->itemText(index: idx).toInt()); |
| 274 | } |
| 275 | |
| 276 | void AudioTest::codecChanged(int idx) |
| 277 | { |
| 278 | m_settings.setCodec(codecsBox->itemText(index: idx)); |
| 279 | } |
| 280 | |
| 281 | void AudioTest::sampleSizeChanged(int idx) |
| 282 | { |
| 283 | m_settings.setSampleSize(sampleSizesBox->itemText(index: idx).toInt()); |
| 284 | } |
| 285 | |
| 286 | void AudioTest::sampleTypeChanged(int idx) |
| 287 | { |
| 288 | switch (sampleTypesBox->itemText(index: idx).toInt()) { |
| 289 | case QAudioFormat::SignedInt: |
| 290 | m_settings.setSampleType(QAudioFormat::SignedInt); |
| 291 | break; |
| 292 | case QAudioFormat::UnSignedInt: |
| 293 | m_settings.setSampleType(QAudioFormat::UnSignedInt); |
| 294 | break; |
| 295 | case QAudioFormat::Float: |
| 296 | m_settings.setSampleType(QAudioFormat::Float); |
| 297 | } |
| 298 | } |
| 299 | |
| 300 | void AudioTest::endianChanged(int idx) |
| 301 | { |
| 302 | switch (endianBox->itemText(index: idx).toInt()) { |
| 303 | case QAudioFormat::LittleEndian: |
| 304 | m_settings.setByteOrder(QAudioFormat::LittleEndian); |
| 305 | break; |
| 306 | case QAudioFormat::BigEndian: |
| 307 | m_settings.setByteOrder(QAudioFormat::BigEndian); |
| 308 | } |
| 309 | } |
| 310 | |