diff options
author | Andy Nichols <andy.nichols@digia.com> | 2013-03-08 15:18:36 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-09-19 14:36:28 +0200 |
commit | b357c55f2dfe44e5c2a2524b93478aecf668ca0a (patch) | |
tree | 6dec038966d3a45e708a3c4f8d8bb4df1e55bd46 /src/plugins/coreaudio/coreaudiosessionmanager.mm | |
parent | 044e48d5a4e0281efb1f6d5136c9a732e3119559 (diff) |
CoreAudio: Create an audio plugin supporting iOS and OS X
This removes the Mac audio backend that was hardcoded into QtMultimedia
and adds a new audio plugin using the CoreAudio API.
Change-Id: Ib15291825f9452a3763e0eeb281d952deb0bad3d
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@digia.com>
Reviewed-by: Christian Stromme <christian.stromme@digia.com>
Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
Diffstat (limited to 'src/plugins/coreaudio/coreaudiosessionmanager.mm')
-rw-r--r-- | src/plugins/coreaudio/coreaudiosessionmanager.mm | 481 |
1 files changed, 481 insertions, 0 deletions
diff --git a/src/plugins/coreaudio/coreaudiosessionmanager.mm b/src/plugins/coreaudio/coreaudiosessionmanager.mm new file mode 100644 index 000000000..4b3bdb7dc --- /dev/null +++ b/src/plugins/coreaudio/coreaudiosessionmanager.mm @@ -0,0 +1,481 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** 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, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "coreaudiosessionmanager.h" + +#import <AVFoundation/AVAudioSession.h> +#import <Foundation/Foundation.h> + +QT_BEGIN_NAMESPACE + +@interface CoreAudioSessionObserver : NSObject +{ + CoreAudioSessionManager *m_sessionManager; + AVAudioSession *m_audioSession; +} + +@property (readonly, getter=sessionManager) CoreAudioSessionManager *m_sessionManager; +@property (readonly, getter=audioSession) AVAudioSession *m_audioSession; + +-(CoreAudioSessionObserver *)initWithAudioSessionManager:(CoreAudioSessionManager *)sessionManager; + +-(BOOL)activateAudio; +-(BOOL)deactivateAudio; + +//Notification handlers +-(void)audioSessionInterruption:(NSNotification *)notification; +-(void)audioSessionRouteChange:(NSNotification *)notification; +-(void)audioSessionMediaServicesWereReset:(NSNotification *)notification; + +@end //interface CoreAudioSessionObserver + +@implementation CoreAudioSessionObserver + +@synthesize m_sessionManager, m_audioSession; + +-(CoreAudioSessionObserver *)initWithAudioSessionManager:(CoreAudioSessionManager *)sessionManager +{ + if (!(self = [super init])) + return nil; + + self->m_sessionManager = sessionManager; + self->m_audioSession = [AVAudioSession sharedInstance]; + + //Set up observers + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(audioSessionInterruption:) + name:AVAudioSessionInterruptionNotification + object:self->m_audioSession]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(audioSessionMediaServicesWereReset:) + name:AVAudioSessionMediaServicesWereResetNotification + object:self->m_audioSession]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(audioSessionRouteChange:) + name:AVAudioSessionRouteChangeNotification + object:self->m_audioSession]; + + return self; +} + +-(void)dealloc +{ +#ifdef QT_DEBUG_COREAUDIO + qDebug() << Q_FUNC_INFO; +#endif + [[NSNotificationCenter defaultCenter] removeObserver:self + name:AVAudioSessionInterruptionNotification + object:self->m_audioSession]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:AVAudioSessionMediaServicesWereResetNotification + object:self->m_audioSession]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:AVAudioSessionRouteChangeNotification + object:self->m_audioSession]; + [super dealloc]; +} + +-(BOOL)activateAudio +{ + NSError *error = nil; + BOOL success = [self->m_audioSession setActive:YES error:&error]; + if (![self->m_audioSession setActive:YES error:&error]) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audio session activation failed: %s", [[error localizedDescription] UTF8String]); + } else { + qDebug("audio session activated"); +#endif + } + + return success; +} + +-(BOOL)deactivateAudio +{ + NSError *error = nil; + BOOL success = [m_audioSession setActive:NO error:&error]; +#ifdef QT_DEBUG_COREAUDIO + if (!success) { + qDebug("%s", [[error localizedDescription] UTF8String]); + } +#endif + return success; +} + +-(void)audioSessionInterruption:(NSNotification *)notification +{ + NSNumber *type = [[notification userInfo] valueForKey:AVAudioSessionInterruptionTypeKey]; + if ([type intValue] == AVAudioSessionInterruptionTypeBegan) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession Interuption begain"); +#endif + } else if ([type intValue] == AVAudioSessionInterruptionTypeEnded) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession Interuption ended"); +#endif + NSNumber *option = [[notification userInfo] valueForKey:AVAudioSessionInterruptionOptionKey]; + if ([option intValue] == AVAudioSessionInterruptionOptionShouldResume) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession is active and immediately ready to be used."); +#endif + } else { + [self activateAudio]; + } + } +} + +-(void)audioSessionMediaServicesWereReset:(NSNotification *)notification +{ + Q_UNUSED(notification) +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession Media Services were reset"); +#endif + //Reactivate audio when this occurs + [self activateAudio]; +} + +-(void)audioSessionRouteChange:(NSNotification *)notification +{ + NSNumber *reason = [[notification userInfo] valueForKey:AVAudioSessionRouteChangeReasonKey]; + NSUInteger reasonEnum = [reason intValue]; + + if (reasonEnum == AVAudioSessionRouteChangeReasonUnknown) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession route changed. reason: unknown"); +#endif + } else if (reasonEnum == AVAudioSessionRouteChangeReasonNewDeviceAvailable) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession route changed. reason: new device available"); +#endif + } else if (reasonEnum == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession route changed. reason: old device unavailable"); +#endif + } else if (reasonEnum == AVAudioSessionRouteChangeReasonCategoryChange) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession route changed. reason: category changed"); +#endif + } else if (reasonEnum == AVAudioSessionRouteChangeReasonOverride) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession route changed. reason: override"); +#endif + } else if (reasonEnum == AVAudioSessionRouteChangeReasonWakeFromSleep) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession route changed. reason: woken from sleep"); +#endif + } else if (reasonEnum == AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory) { +#ifdef QT_DEBUG_COREAUDIO + qDebug("audioSession route changed. reason: no suitable route for category"); +#endif + } + +} + +@end //implementation CoreAudioSessionObserver + +CoreAudioSessionManager::CoreAudioSessionManager() : + QObject(0) +{ + m_sessionObserver = [[CoreAudioSessionObserver alloc] initWithAudioSessionManager:this]; + setActive(true); + setCategory(CoreAudioSessionManager::PlayAndRecord, CoreAudioSessionManager::MixWithOthers); +} + +CoreAudioSessionManager::~CoreAudioSessionManager() +{ +#ifdef QT_DEBUG_COREAUDIO + qDebug() << Q_FUNC_INFO; +#endif + [m_sessionObserver release]; +} + + +CoreAudioSessionManager &CoreAudioSessionManager::instance() +{ + static CoreAudioSessionManager instance; + return instance; +} + +bool CoreAudioSessionManager::setActive(bool active) +{ + if (active) { + return [m_sessionObserver activateAudio]; + } else { + return [m_sessionObserver deactivateAudio]; + } +} + +bool CoreAudioSessionManager::setCategory(CoreAudioSessionManager::AudioSessionCategorys category, CoreAudioSessionManager::AudioSessionCategoryOptions options) +{ + NSString *targetCategory = nil; + + switch (category) { + case CoreAudioSessionManager::Ambient: + targetCategory = AVAudioSessionCategoryAmbient; + break; + case CoreAudioSessionManager::SoloAmbient: + targetCategory = AVAudioSessionCategorySoloAmbient; + break; + case CoreAudioSessionManager::Playback: + targetCategory = AVAudioSessionCategoryPlayback; + break; + case CoreAudioSessionManager::Record: + targetCategory = AVAudioSessionCategoryRecord; + break; + case CoreAudioSessionManager::PlayAndRecord: + targetCategory = AVAudioSessionCategoryPlayAndRecord; + break; + case CoreAudioSessionManager::AudioProcessing: + targetCategory = AVAudioSessionCategoryAudioProcessing; + break; + case CoreAudioSessionManager::MultiRoute: + targetCategory = AVAudioSessionCategoryMultiRoute; + break; + } + + if (targetCategory == nil) + return false; + + return [[m_sessionObserver audioSession] setCategory:targetCategory + withOptions:(AVAudioSessionCategoryOptions)options + error:nil]; +} + +bool CoreAudioSessionManager::setMode(CoreAudioSessionManager::AudioSessionModes mode) +{ + NSString *targetMode = nil; + switch (mode) { + case CoreAudioSessionManager::Default: + targetMode = AVAudioSessionModeDefault; + break; + case CoreAudioSessionManager::VoiceChat: + targetMode = AVAudioSessionModeVoiceChat; + break; + case CoreAudioSessionManager::GameChat: + targetMode = AVAudioSessionModeGameChat; + break; + case CoreAudioSessionManager::VideoRecording: + targetMode = AVAudioSessionModeVideoRecording; + break; + case CoreAudioSessionManager::Measurement: + targetMode = AVAudioSessionModeMeasurement; + break; + case CoreAudioSessionManager::MoviePlayback: + targetMode = AVAudioSessionModeMoviePlayback; + break; + } + + if (targetMode == nil) + return false; + + return [[m_sessionObserver audioSession] setMode:targetMode error:nil]; + +} + +CoreAudioSessionManager::AudioSessionCategorys CoreAudioSessionManager::category() +{ + NSString *category = [[m_sessionObserver audioSession] category]; + AudioSessionCategorys localCategory = Ambient; + + if (category == AVAudioSessionCategoryAmbient) { + localCategory = Ambient; + } else if (category == AVAudioSessionCategorySoloAmbient) { + localCategory = SoloAmbient; + } else if (category == AVAudioSessionCategoryPlayback) { + localCategory = Playback; + } else if (category == AVAudioSessionCategoryRecord) { + localCategory = Record; + } else if (category == AVAudioSessionCategoryPlayAndRecord) { + localCategory = PlayAndRecord; + } else if (category == AVAudioSessionCategoryAudioProcessing) { + localCategory = AudioProcessing; + } else if (category == AVAudioSessionCategoryMultiRoute) { + localCategory = MultiRoute; + } + + return localCategory; +} + +CoreAudioSessionManager::AudioSessionModes CoreAudioSessionManager::mode() +{ + NSString *mode = [[m_sessionObserver audioSession] mode]; + AudioSessionModes localMode = Default; + + if (mode == AVAudioSessionModeDefault) { + localMode = Default; + } else if (mode == AVAudioSessionModeVoiceChat) { + localMode = VoiceChat; + } else if (mode == AVAudioSessionModeGameChat) { + localMode = GameChat; + } else if (mode == AVAudioSessionModeVideoRecording) { + localMode = VideoRecording; + } else if (mode == AVAudioSessionModeMeasurement) { + localMode = Measurement; + } else if (mode == AVAudioSessionModeMoviePlayback) { + localMode = MoviePlayback; + } + + return localMode; +} + +QList<QByteArray> CoreAudioSessionManager::inputDevices() +{ + //TODO: Add support for USB input devices + //Right now the default behavior on iOS is to have only one input route + //at a time. + QList<QByteArray> inputDevices; + inputDevices << "default"; + return inputDevices; +} + +QList<QByteArray> CoreAudioSessionManager::outputDevices() +{ + //TODO: Add support for USB output devices + //Right now the default behavior on iOS is to have only one output route + //at a time. + QList<QByteArray> outputDevices; + outputDevices << "default"; + return outputDevices; +} + +int CoreAudioSessionManager::inputChannelCount() +{ + return [[m_sessionObserver audioSession] inputNumberOfChannels]; +} + +int CoreAudioSessionManager::outputChannelCount() +{ + return [[m_sessionObserver audioSession] outputNumberOfChannels]; +} + +float CoreAudioSessionManager::currentIOBufferDuration() +{ + return [[m_sessionObserver audioSession] IOBufferDuration]; +} + +float CoreAudioSessionManager::preferredSampleRate() +{ + return [[m_sessionObserver audioSession] preferredSampleRate]; +} + +#ifdef QT_DEBUG_COREAUDIO +QDebug operator<<(QDebug dbg, CoreAudioSessionManager::AudioSessionCategorys category) +{ + QDebug output = dbg.nospace(); + switch (category) { + case CoreAudioSessionManager::Ambient: + output << "AudioSessionCategoryAmbient"; + break; + case CoreAudioSessionManager::SoloAmbient: + output << "AudioSessionCategorySoloAmbient"; + break; + case CoreAudioSessionManager::Playback: + output << "AudioSessionCategoryPlayback"; + break; + case CoreAudioSessionManager::Record: + output << "AudioSessionCategoryRecord"; + break; + case CoreAudioSessionManager::PlayAndRecord: + output << "AudioSessionCategoryPlayAndRecord"; + break; + case CoreAudioSessionManager::AudioProcessing: + output << "AudioSessionCategoryAudioProcessing"; + break; + case CoreAudioSessionManager::MultiRoute: + output << "AudioSessionCategoryMultiRoute"; + break; + } + return output; +} + +QDebug operator<<(QDebug dbg, CoreAudioSessionManager::AudioSessionCategoryOptions option) +{ + QDebug output = dbg.nospace(); + switch (option) { + case CoreAudioSessionManager::None: + output << "AudioSessionCategoryOptionNone"; + break; + case CoreAudioSessionManager::MixWithOthers: + output << "AudioSessionCategoryOptionMixWithOthers"; + break; + case CoreAudioSessionManager::DuckOthers: + output << "AudioSessionCategoryOptionDuckOthers"; + break; + case CoreAudioSessionManager::AllowBluetooth: + output << "AudioSessionCategoryOptionAllowBluetooth"; + break; + case CoreAudioSessionManager::DefaultToSpeaker: + output << "AudioSessionCategoryOptionDefaultToSpeaker"; + break; + } + return output; +} + +QDebug operator<<(QDebug dbg, CoreAudioSessionManager::AudioSessionModes mode) +{ + QDebug output = dbg.nospace(); + switch (mode) { + case CoreAudioSessionManager::Default: + output << "AudioSessionModeDefault"; + break; + case CoreAudioSessionManager::VoiceChat: + output << "AudioSessionModeVoiceChat"; + break; + case CoreAudioSessionManager::GameChat: + output << "AudioSessionModeGameChat"; + break; + case CoreAudioSessionManager::VideoRecording: + output << "AudioSessionModeVideoRecording"; + break; + case CoreAudioSessionManager::Measurement: + output << "AudioSessionModeMeasurement"; + break; + case CoreAudioSessionManager::MoviePlayback: + output << "AudioSessionModeMoviePlayback"; + break; + } + return output; +} +#endif + +QT_END_NAMESPACE + +#include "moc_coreaudiosessionmanager.cpp" |