| 1 | /****************************************************************************
|
|---|
| 2 | **
|
|---|
| 3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
|---|
| 4 | ** All rights reserved.
|
|---|
| 5 | ** Contact: Nokia Corporation ([email protected])
|
|---|
| 6 | **
|
|---|
| 7 | ** This file is part of the QtMultimedia module of the Qt Toolkit.
|
|---|
| 8 | **
|
|---|
| 9 | ** $QT_BEGIN_LICENSE:LGPL$
|
|---|
| 10 | ** Commercial Usage
|
|---|
| 11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
|---|
| 12 | ** accordance with the Qt Commercial License Agreement provided with the
|
|---|
| 13 | ** Software or, alternatively, in accordance with the terms contained in
|
|---|
| 14 | ** a written agreement between you and Nokia.
|
|---|
| 15 | **
|
|---|
| 16 | ** GNU Lesser General Public License Usage
|
|---|
| 17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|---|
| 18 | ** General Public License version 2.1 as published by the Free Software
|
|---|
| 19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|---|
| 20 | ** packaging of this file. Please review the following information to
|
|---|
| 21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|---|
| 22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|---|
| 23 | **
|
|---|
| 24 | ** In addition, as a special exception, Nokia gives you certain additional
|
|---|
| 25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
|---|
| 26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|---|
| 27 | **
|
|---|
| 28 | ** GNU General Public License Usage
|
|---|
| 29 | ** Alternatively, this file may be used under the terms of the GNU
|
|---|
| 30 | ** General Public License version 3.0 as published by the Free Software
|
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
|---|
| 32 | ** packaging of this file. Please review the following information to
|
|---|
| 33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
|---|
| 34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
|---|
| 35 | **
|
|---|
| 36 | ** If you have questions regarding the use of this file, please contact
|
|---|
| 37 | ** Nokia at [email protected].
|
|---|
| 38 | ** $QT_END_LICENSE$
|
|---|
| 39 | **
|
|---|
| 40 | ****************************************************************************/
|
|---|
| 41 |
|
|---|
| 42 | //
|
|---|
| 43 | // W A R N I N G
|
|---|
| 44 | // -------------
|
|---|
| 45 | //
|
|---|
| 46 | // This file is not part of the Qt API. It exists for the convenience
|
|---|
| 47 | // of other Qt classes. This header file may change from version to
|
|---|
| 48 | // version without notice, or even be removed.
|
|---|
| 49 | //
|
|---|
| 50 | // We mean it.
|
|---|
| 51 | //
|
|---|
| 52 |
|
|---|
| 53 | #include <QtCore/qstringlist.h>
|
|---|
| 54 | #include <QtCore/qlist.h>
|
|---|
| 55 | #include <QtCore/qbytearray.h>
|
|---|
| 56 | #include <QtCore/qdatastream.h>
|
|---|
| 57 | #include <QtCore/qdebug.h>
|
|---|
| 58 | #include <private/qcore_mac_p.h>
|
|---|
| 59 |
|
|---|
| 60 | #include <QtMultimedia/qaudiodeviceinfo.h>
|
|---|
| 61 | #include "qaudio_mac_p.h"
|
|---|
| 62 | #include "qaudiodeviceinfo_mac_p.h"
|
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 |
|
|---|
| 66 | QT_BEGIN_NAMESPACE
|
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 | QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray const& handle, QAudio::Mode)
|
|---|
| 70 | {
|
|---|
| 71 | QDataStream ds(handle);
|
|---|
| 72 | quint32 did, tm;
|
|---|
| 73 |
|
|---|
| 74 | ds >> did >> tm >> name;
|
|---|
| 75 | deviceId = AudioDeviceID(did);
|
|---|
| 76 | mode = QAudio::Mode(tm);
|
|---|
| 77 | }
|
|---|
| 78 |
|
|---|
| 79 | bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const
|
|---|
| 80 | {
|
|---|
| 81 | QAudioDeviceInfoInternal *self = const_cast<QAudioDeviceInfoInternal*>(this);
|
|---|
| 82 |
|
|---|
| 83 | return format.isValid()
|
|---|
| 84 | && format.codec() == QString::fromLatin1("audio/pcm")
|
|---|
| 85 | && self->frequencyList().contains(format.frequency())
|
|---|
| 86 | && self->channelsList().contains(format.channels())
|
|---|
| 87 | && self->sampleSizeList().contains(format.sampleSize());
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const
|
|---|
| 91 | {
|
|---|
| 92 | QAudioFormat rc;
|
|---|
| 93 |
|
|---|
| 94 | UInt32 propSize = 0;
|
|---|
| 95 |
|
|---|
| 96 | if (AudioDeviceGetPropertyInfo(deviceId,
|
|---|
| 97 | 0,
|
|---|
| 98 | mode == QAudio::AudioInput,
|
|---|
| 99 | kAudioDevicePropertyStreams,
|
|---|
| 100 | &propSize,
|
|---|
| 101 | 0) == noErr) {
|
|---|
| 102 |
|
|---|
| 103 | const int sc = propSize / sizeof(AudioStreamID);
|
|---|
| 104 |
|
|---|
| 105 | if (sc > 0) {
|
|---|
| 106 | AudioStreamID* streams = new AudioStreamID[sc];
|
|---|
| 107 |
|
|---|
| 108 | if (AudioDeviceGetProperty(deviceId,
|
|---|
| 109 | 0,
|
|---|
| 110 | mode == QAudio::AudioInput,
|
|---|
| 111 | kAudioDevicePropertyStreams,
|
|---|
| 112 | &propSize,
|
|---|
| 113 | streams) == noErr) {
|
|---|
| 114 |
|
|---|
| 115 | for (int i = 0; i < sc; ++i) {
|
|---|
| 116 | if (AudioStreamGetPropertyInfo(streams[i],
|
|---|
| 117 | 0,
|
|---|
| 118 | kAudioStreamPropertyPhysicalFormat,
|
|---|
| 119 | &propSize,
|
|---|
| 120 | 0) == noErr) {
|
|---|
| 121 |
|
|---|
| 122 | AudioStreamBasicDescription sf;
|
|---|
| 123 |
|
|---|
| 124 | if (AudioStreamGetProperty(streams[i],
|
|---|
| 125 | 0,
|
|---|
| 126 | kAudioStreamPropertyPhysicalFormat,
|
|---|
| 127 | &propSize,
|
|---|
| 128 | &sf) == noErr) {
|
|---|
| 129 | rc = toQAudioFormat(sf);
|
|---|
| 130 | break;
|
|---|
| 131 | }
|
|---|
| 132 | }
|
|---|
| 133 | }
|
|---|
| 134 | }
|
|---|
| 135 |
|
|---|
| 136 | delete streams;
|
|---|
| 137 | }
|
|---|
| 138 | }
|
|---|
| 139 |
|
|---|
| 140 | return rc;
|
|---|
| 141 | }
|
|---|
| 142 |
|
|---|
| 143 | QAudioFormat QAudioDeviceInfoInternal::nearestFormat(const QAudioFormat& format) const
|
|---|
| 144 | {
|
|---|
| 145 | QAudioFormat rc(format);
|
|---|
| 146 | QAudioFormat target = preferredFormat();
|
|---|
| 147 |
|
|---|
| 148 | if (!format.codec().isEmpty() && format.codec() != QString::fromLatin1("audio/pcm"))
|
|---|
| 149 | return QAudioFormat();
|
|---|
| 150 |
|
|---|
| 151 | rc.setCodec(QString::fromLatin1("audio/pcm"));
|
|---|
| 152 |
|
|---|
| 153 | if (rc.frequency() != target.frequency())
|
|---|
| 154 | rc.setFrequency(target.frequency());
|
|---|
| 155 | if (rc.channels() != target.channels())
|
|---|
| 156 | rc.setChannels(target.channels());
|
|---|
| 157 | if (rc.sampleSize() != target.sampleSize())
|
|---|
| 158 | rc.setSampleSize(target.sampleSize());
|
|---|
| 159 | if (rc.byteOrder() != target.byteOrder())
|
|---|
| 160 | rc.setByteOrder(target.byteOrder());
|
|---|
| 161 | if (rc.sampleType() != target.sampleType())
|
|---|
| 162 | rc.setSampleType(target.sampleType());
|
|---|
| 163 |
|
|---|
| 164 | return rc;
|
|---|
| 165 | }
|
|---|
| 166 |
|
|---|
| 167 | QString QAudioDeviceInfoInternal::deviceName() const
|
|---|
| 168 | {
|
|---|
| 169 | return name;
|
|---|
| 170 | }
|
|---|
| 171 |
|
|---|
| 172 | QStringList QAudioDeviceInfoInternal::codecList()
|
|---|
| 173 | {
|
|---|
| 174 | return QStringList() << QString::fromLatin1("audio/pcm");
|
|---|
| 175 | }
|
|---|
| 176 |
|
|---|
| 177 | QList<int> QAudioDeviceInfoInternal::frequencyList()
|
|---|
| 178 | {
|
|---|
| 179 | QSet<int> rc;
|
|---|
| 180 |
|
|---|
| 181 | // Add some common frequencies
|
|---|
| 182 | rc << 8000 << 11025 << 22050 << 44100;
|
|---|
| 183 |
|
|---|
| 184 | //
|
|---|
| 185 | UInt32 propSize = 0;
|
|---|
| 186 |
|
|---|
| 187 | if (AudioDeviceGetPropertyInfo(deviceId,
|
|---|
| 188 | 0,
|
|---|
| 189 | mode == QAudio::AudioInput,
|
|---|
| 190 | kAudioDevicePropertyAvailableNominalSampleRates,
|
|---|
| 191 | &propSize,
|
|---|
| 192 | 0) == noErr) {
|
|---|
| 193 |
|
|---|
| 194 | const int pc = propSize / sizeof(AudioValueRange);
|
|---|
| 195 |
|
|---|
| 196 | if (pc > 0) {
|
|---|
| 197 | AudioValueRange* vr = new AudioValueRange[pc];
|
|---|
| 198 |
|
|---|
| 199 | if (AudioDeviceGetProperty(deviceId,
|
|---|
| 200 | 0,
|
|---|
| 201 | mode == QAudio::AudioInput,
|
|---|
| 202 | kAudioDevicePropertyAvailableNominalSampleRates,
|
|---|
| 203 | &propSize,
|
|---|
| 204 | vr) == noErr) {
|
|---|
| 205 |
|
|---|
| 206 | for (int i = 0; i < pc; ++i)
|
|---|
| 207 | rc << vr[i].mMaximum;
|
|---|
| 208 | }
|
|---|
| 209 |
|
|---|
| 210 | delete vr;
|
|---|
| 211 | }
|
|---|
| 212 | }
|
|---|
| 213 |
|
|---|
| 214 | return rc.toList();
|
|---|
| 215 | }
|
|---|
| 216 |
|
|---|
| 217 | QList<int> QAudioDeviceInfoInternal::channelsList()
|
|---|
| 218 | {
|
|---|
| 219 | QList<int> rc;
|
|---|
| 220 |
|
|---|
| 221 | // Can mix down to 1 channel
|
|---|
| 222 | rc << 1;
|
|---|
| 223 |
|
|---|
| 224 | UInt32 propSize = 0;
|
|---|
| 225 | int channels = 0;
|
|---|
| 226 |
|
|---|
| 227 | if (AudioDeviceGetPropertyInfo(deviceId,
|
|---|
| 228 | 0,
|
|---|
| 229 | mode == QAudio::AudioInput,
|
|---|
| 230 | kAudioDevicePropertyStreamConfiguration,
|
|---|
| 231 | &propSize,
|
|---|
| 232 | 0) == noErr) {
|
|---|
| 233 |
|
|---|
| 234 | AudioBufferList* audioBufferList = static_cast<AudioBufferList*>(qMalloc(propSize));
|
|---|
| 235 |
|
|---|
| 236 | if (audioBufferList != 0) {
|
|---|
| 237 | if (AudioDeviceGetProperty(deviceId,
|
|---|
| 238 | 0,
|
|---|
| 239 | mode == QAudio::AudioInput,
|
|---|
| 240 | kAudioDevicePropertyStreamConfiguration,
|
|---|
| 241 | &propSize,
|
|---|
| 242 | audioBufferList) == noErr) {
|
|---|
| 243 |
|
|---|
| 244 | for (int i = 0; i < int(audioBufferList->mNumberBuffers); ++i) {
|
|---|
| 245 | channels += audioBufferList->mBuffers[i].mNumberChannels;
|
|---|
| 246 | rc << channels;
|
|---|
| 247 | }
|
|---|
| 248 | }
|
|---|
| 249 |
|
|---|
| 250 | qFree(audioBufferList);
|
|---|
| 251 | }
|
|---|
| 252 | }
|
|---|
| 253 |
|
|---|
| 254 | return rc;
|
|---|
| 255 | }
|
|---|
| 256 |
|
|---|
| 257 | QList<int> QAudioDeviceInfoInternal::sampleSizeList()
|
|---|
| 258 | {
|
|---|
| 259 | return QList<int>() << 8 << 16 << 24 << 32 << 64;
|
|---|
| 260 | }
|
|---|
| 261 |
|
|---|
| 262 | QList<QAudioFormat::Endian> QAudioDeviceInfoInternal::byteOrderList()
|
|---|
| 263 | {
|
|---|
| 264 | return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian;
|
|---|
| 265 | }
|
|---|
| 266 |
|
|---|
| 267 | QList<QAudioFormat::SampleType> QAudioDeviceInfoInternal::sampleTypeList()
|
|---|
| 268 | {
|
|---|
| 269 | return QList<QAudioFormat::SampleType>() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float;
|
|---|
| 270 | }
|
|---|
| 271 |
|
|---|
| 272 | static QByteArray get_device_info(AudioDeviceID audioDevice, QAudio::Mode mode)
|
|---|
| 273 | {
|
|---|
| 274 | UInt32 size;
|
|---|
| 275 | QByteArray device;
|
|---|
| 276 | QDataStream ds(&device, QIODevice::WriteOnly);
|
|---|
| 277 | AudioStreamBasicDescription sf;
|
|---|
| 278 | CFStringRef name;
|
|---|
| 279 | Boolean isInput = mode == QAudio::AudioInput;
|
|---|
| 280 |
|
|---|
| 281 | // Id
|
|---|
| 282 | ds << quint32(audioDevice);
|
|---|
| 283 |
|
|---|
| 284 | // Mode
|
|---|
| 285 | size = sizeof(AudioStreamBasicDescription);
|
|---|
| 286 | if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioDevicePropertyStreamFormat,
|
|---|
| 287 | &size, &sf) != noErr) {
|
|---|
| 288 | return QByteArray();
|
|---|
| 289 | }
|
|---|
| 290 | ds << quint32(mode);
|
|---|
| 291 |
|
|---|
| 292 | // Name
|
|---|
| 293 | size = sizeof(CFStringRef);
|
|---|
| 294 | if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioObjectPropertyName,
|
|---|
| 295 | &size, &name) != noErr) {
|
|---|
| 296 | qWarning() << "QAudioDeviceInfo: Unable to find device name";
|
|---|
| 297 | }
|
|---|
| 298 | ds << QCFString::toQString(name);
|
|---|
| 299 |
|
|---|
| 300 | CFRelease(name);
|
|---|
| 301 |
|
|---|
| 302 | return device;
|
|---|
| 303 | }
|
|---|
| 304 |
|
|---|
| 305 | QByteArray QAudioDeviceInfoInternal::defaultInputDevice()
|
|---|
| 306 | {
|
|---|
| 307 | AudioDeviceID audioDevice;
|
|---|
| 308 | UInt32 size = sizeof(audioDevice);
|
|---|
| 309 |
|
|---|
| 310 | if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size,
|
|---|
| 311 | &audioDevice) != noErr) {
|
|---|
| 312 | qWarning() << "QAudioDeviceInfo: Unable to find default input device";
|
|---|
| 313 | return QByteArray();
|
|---|
| 314 | }
|
|---|
| 315 |
|
|---|
| 316 | return get_device_info(audioDevice, QAudio::AudioInput);
|
|---|
| 317 | }
|
|---|
| 318 |
|
|---|
| 319 | QByteArray QAudioDeviceInfoInternal::defaultOutputDevice()
|
|---|
| 320 | {
|
|---|
| 321 | AudioDeviceID audioDevice;
|
|---|
| 322 | UInt32 size = sizeof(audioDevice);
|
|---|
| 323 |
|
|---|
| 324 | if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size,
|
|---|
| 325 | &audioDevice) != noErr) {
|
|---|
| 326 | qWarning() << "QAudioDeviceInfo: Unable to find default output device";
|
|---|
| 327 | return QByteArray();
|
|---|
| 328 | }
|
|---|
| 329 |
|
|---|
| 330 | return get_device_info(audioDevice, QAudio::AudioOutput);
|
|---|
| 331 | }
|
|---|
| 332 |
|
|---|
| 333 | QList<QByteArray> QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode)
|
|---|
| 334 | {
|
|---|
| 335 | QList<QByteArray> devices;
|
|---|
| 336 |
|
|---|
| 337 | UInt32 propSize = 0;
|
|---|
| 338 |
|
|---|
| 339 | if (AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propSize, 0) == noErr) {
|
|---|
| 340 |
|
|---|
| 341 | const int dc = propSize / sizeof(AudioDeviceID);
|
|---|
| 342 |
|
|---|
| 343 | if (dc > 0) {
|
|---|
| 344 | AudioDeviceID* audioDevices = new AudioDeviceID[dc];
|
|---|
| 345 |
|
|---|
| 346 | if (AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propSize, audioDevices) == noErr) {
|
|---|
| 347 | for (int i = 0; i < dc; ++i) {
|
|---|
| 348 | QByteArray info = get_device_info(audioDevices[i], mode);
|
|---|
| 349 | if (!info.isNull())
|
|---|
| 350 | devices << info;
|
|---|
| 351 | }
|
|---|
| 352 | }
|
|---|
| 353 |
|
|---|
| 354 | delete audioDevices;
|
|---|
| 355 | }
|
|---|
| 356 | }
|
|---|
| 357 |
|
|---|
| 358 | return devices;
|
|---|
| 359 | }
|
|---|
| 360 |
|
|---|
| 361 |
|
|---|
| 362 | QT_END_NAMESPACE
|
|---|
| 363 |
|
|---|