/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtMultimedia module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists for the convenience // of other Qt classes. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include #include #include #include #include "qaudio_mac_p.h" #include "qaudiodeviceinfo_mac_p.h" QT_BEGIN_NAMESPACE QAudioDeviceInfoInternal::QAudioDeviceInfoInternal(QByteArray const& handle, QAudio::Mode) { QDataStream ds(handle); quint32 did, tm; ds >> did >> tm >> name; deviceId = AudioDeviceID(did); mode = QAudio::Mode(tm); } bool QAudioDeviceInfoInternal::isFormatSupported(const QAudioFormat& format) const { QAudioDeviceInfoInternal *self = const_cast(this); return format.isValid() && format.codec() == QString::fromLatin1("audio/pcm") && self->frequencyList().contains(format.frequency()) && self->channelsList().contains(format.channels()) && self->sampleSizeList().contains(format.sampleSize()); } QAudioFormat QAudioDeviceInfoInternal::preferredFormat() const { QAudioFormat rc; UInt32 propSize = 0; if (AudioDeviceGetPropertyInfo(deviceId, 0, mode == QAudio::AudioInput, kAudioDevicePropertyStreams, &propSize, 0) == noErr) { const int sc = propSize / sizeof(AudioStreamID); if (sc > 0) { AudioStreamID* streams = new AudioStreamID[sc]; if (AudioDeviceGetProperty(deviceId, 0, mode == QAudio::AudioInput, kAudioDevicePropertyStreams, &propSize, streams) == noErr) { for (int i = 0; i < sc; ++i) { if (AudioStreamGetPropertyInfo(streams[i], 0, kAudioStreamPropertyPhysicalFormat, &propSize, 0) == noErr) { AudioStreamBasicDescription sf; if (AudioStreamGetProperty(streams[i], 0, kAudioStreamPropertyPhysicalFormat, &propSize, &sf) == noErr) { rc = toQAudioFormat(sf); break; } } } } delete streams; } } return rc; } QAudioFormat QAudioDeviceInfoInternal::nearestFormat(const QAudioFormat& format) const { QAudioFormat rc(format); QAudioFormat target = preferredFormat(); if (!format.codec().isEmpty() && format.codec() != QString::fromLatin1("audio/pcm")) return QAudioFormat(); rc.setCodec(QString::fromLatin1("audio/pcm")); if (rc.frequency() != target.frequency()) rc.setFrequency(target.frequency()); if (rc.channels() != target.channels()) rc.setChannels(target.channels()); if (rc.sampleSize() != target.sampleSize()) rc.setSampleSize(target.sampleSize()); if (rc.byteOrder() != target.byteOrder()) rc.setByteOrder(target.byteOrder()); if (rc.sampleType() != target.sampleType()) rc.setSampleType(target.sampleType()); return rc; } QString QAudioDeviceInfoInternal::deviceName() const { return name; } QStringList QAudioDeviceInfoInternal::codecList() { return QStringList() << QString::fromLatin1("audio/pcm"); } QList QAudioDeviceInfoInternal::frequencyList() { QSet rc; // Add some common frequencies rc << 8000 << 11025 << 22050 << 44100; // UInt32 propSize = 0; if (AudioDeviceGetPropertyInfo(deviceId, 0, mode == QAudio::AudioInput, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, 0) == noErr) { const int pc = propSize / sizeof(AudioValueRange); if (pc > 0) { AudioValueRange* vr = new AudioValueRange[pc]; if (AudioDeviceGetProperty(deviceId, 0, mode == QAudio::AudioInput, kAudioDevicePropertyAvailableNominalSampleRates, &propSize, vr) == noErr) { for (int i = 0; i < pc; ++i) rc << vr[i].mMaximum; } delete vr; } } return rc.toList(); } QList QAudioDeviceInfoInternal::channelsList() { QList rc; // Can mix down to 1 channel rc << 1; UInt32 propSize = 0; int channels = 0; if (AudioDeviceGetPropertyInfo(deviceId, 0, mode == QAudio::AudioInput, kAudioDevicePropertyStreamConfiguration, &propSize, 0) == noErr) { AudioBufferList* audioBufferList = static_cast(qMalloc(propSize)); if (audioBufferList != 0) { if (AudioDeviceGetProperty(deviceId, 0, mode == QAudio::AudioInput, kAudioDevicePropertyStreamConfiguration, &propSize, audioBufferList) == noErr) { for (int i = 0; i < int(audioBufferList->mNumberBuffers); ++i) { channels += audioBufferList->mBuffers[i].mNumberChannels; rc << channels; } } qFree(audioBufferList); } } return rc; } QList QAudioDeviceInfoInternal::sampleSizeList() { return QList() << 8 << 16 << 24 << 32 << 64; } QList QAudioDeviceInfoInternal::byteOrderList() { return QList() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian; } QList QAudioDeviceInfoInternal::sampleTypeList() { return QList() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float; } static QByteArray get_device_info(AudioDeviceID audioDevice, QAudio::Mode mode) { UInt32 size; QByteArray device; QDataStream ds(&device, QIODevice::WriteOnly); AudioStreamBasicDescription sf; CFStringRef name; Boolean isInput = mode == QAudio::AudioInput; // Id ds << quint32(audioDevice); // Mode size = sizeof(AudioStreamBasicDescription); if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioDevicePropertyStreamFormat, &size, &sf) != noErr) { return QByteArray(); } ds << quint32(mode); // Name size = sizeof(CFStringRef); if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioObjectPropertyName, &size, &name) != noErr) { qWarning() << "QAudioDeviceInfo: Unable to find device name"; } ds << QCFString::toQString(name); CFRelease(name); return device; } QByteArray QAudioDeviceInfoInternal::defaultInputDevice() { AudioDeviceID audioDevice; UInt32 size = sizeof(audioDevice); if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size, &audioDevice) != noErr) { qWarning() << "QAudioDeviceInfo: Unable to find default input device"; return QByteArray(); } return get_device_info(audioDevice, QAudio::AudioInput); } QByteArray QAudioDeviceInfoInternal::defaultOutputDevice() { AudioDeviceID audioDevice; UInt32 size = sizeof(audioDevice); if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size, &audioDevice) != noErr) { qWarning() << "QAudioDeviceInfo: Unable to find default output device"; return QByteArray(); } return get_device_info(audioDevice, QAudio::AudioOutput); } QList QAudioDeviceInfoInternal::availableDevices(QAudio::Mode mode) { QList devices; UInt32 propSize = 0; if (AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propSize, 0) == noErr) { const int dc = propSize / sizeof(AudioDeviceID); if (dc > 0) { AudioDeviceID* audioDevices = new AudioDeviceID[dc]; if (AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propSize, audioDevices) == noErr) { for (int i = 0; i < dc; ++i) { QByteArray info = get_device_info(audioDevices[i], mode); if (!info.isNull()) devices << info; } } delete audioDevices; } } return devices; } QT_END_NAMESPACE