summaryrefslogtreecommitdiffstats
path: root/src/plugins/coreaudio/coreaudiosessionmanager.mm
diff options
context:
space:
mode:
authorAndy Nichols <andy.nichols@digia.com>2013-03-08 15:18:36 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 14:36:28 +0200
commitb357c55f2dfe44e5c2a2524b93478aecf668ca0a (patch)
tree6dec038966d3a45e708a3c4f8d8bb4df1e55bd46 /src/plugins/coreaudio/coreaudiosessionmanager.mm
parent044e48d5a4e0281efb1f6d5136c9a732e3119559 (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.mm481
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"