强制iPhone麦克风作为audioinput
我正在开发iOS应用程序(目前专门针对iPhone),要求应用程序仅从iPhone内置麦克风 (即使在插入耳机/耳机时) 录制audio ,并在耳机中播放(假设耳机已插入目前)。
我想知道现在是否有可用的API? 如果是这样的话,谁能请介绍一下我该怎么做呢?
谢谢!
我相信这个问题的答案是“不”。 我使用iPhone 4和新的iOS 4 AVFoundation进行实验,专注于AVCaptureDevice类。
我将以下内容添加到应用程序中:
NSLog(@"%@", [AVCaptureDevice devices]);
因此,要求列出可用于捕获audio和/或video的所有设备。 没有插入耳机,我得到:
( "Back Camera", "Front Camera", "iPhone Microphone" )
随着耳机插入我得到:
( "Back Camera", "Front Camera", Headphones )
所以,只要耳机可用,iPhone麦克风就会从可用AVCaptureDevices列表中删除。 为了进一步探究,我添加了一小段代码来获取可用audio设备的AVCaptureDevice实例并打印其唯一的ID。 对于将设备标识为“iPhone麦克风”并将设备标识为“耳机”的设备,我得到:
com.apple.avfoundation.avcapturedevice.built-in_audio:0
在我看来,显而易见的是,两个设备不能有相同的唯一ID,所以显然它是同一个设备改变它的状态。 尽pipeAVCaptureDevices有很多设置状态的东西,但它仅限于焦点,曝光,闪光和白平衡等视觉效果。
看起来真的不可能。
我的目标是发送输出到蓝牙耳机,并logging它的input。 据我所见,我最好的select是:“PlayAndRecord + AllowBluetoothInput”属性(iphone 4,诺基亚BH-214耳机)
重要的是,根据苹果文件,当audio路线改变时,你总是必须重新覆盖你的audio类别!
这是我的ROUTE CHANGE LISTENER方法,打印: RouteChangeReasons,outputRoute,audioRout :
void RouteChangeListener(void *inClientData, AudioSessionPropertyID inID, UInt32 inDataSize, const void *inData) { if (inID == kAudioSessionProperty_AudioRouteChange) { NSLog(@"]-----------------[ Audio Route Change ]--------------------["); // ************************************************************************************************ // Check route change reason ********************************************************************** // ************************************************************************************************ CFDictionaryRef routeDict = (CFDictionaryRef)inData; NSNumber* reasonValue = (NSNumber*)CFDictionaryGetValue(routeDict, CFSTR(kAudioSession_AudioRouteChangeKey_Reason)); int reason = [reasonValue intValue]; if (reason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) { NSLog(@"] Logic: audio route change reason: OldDeviceUnavailable"); }else if (reason == kAudioSessionRouteChangeReason_NewDeviceAvailable ) { NSLog(@"] Logic: audio route change reason: NewDeviceAvailable"); }else if (reason == kAudioSessionRouteChangeReason_Unknown ) { NSLog(@"] Logic: audio route change reason: Unknown"); }else if (reason == kAudioSessionRouteChangeReason_CategoryChange ) { NSLog(@"] Logic: audio route change reason: CategoryChange"); }else if (reason == kAudioSessionRouteChangeReason_Override ) { NSLog(@"] Logic: audio route change reason: Override"); }else if (reason == kAudioSessionRouteChangeReason_WakeFromSleep ) { NSLog(@"] Logic: audio route change reason: WakeFromSleep"); }else if (reason == kAudioSessionRouteChangeReason_NoSuitableRouteForCategory ) { NSLog(@"] Logic: audio route chang reasone: NoSuitableRouteForCategory"); } // ************************************************************************************************ // Check output type ****************************************************************************** // ************************************************************************************************ CFDictionaryRef currentRouteDescriptionDictionary = nil; UInt32 dataSize = sizeof(currentRouteDescriptionDictionary); AudioSessionGetProperty(kAudioSessionProperty_AudioRouteDescription, &dataSize, ¤tRouteDescriptionDictionary); if (currentRouteDescriptionDictionary) { CFArrayRef outputs = CFDictionaryGetValue(currentRouteDescriptionDictionary, kAudioSession_AudioRouteKey_Outputs); if(CFArrayGetCount(outputs) > 0) { CFDictionaryRef currentOutput = CFArrayGetValueAtIndex(outputs, 0); CFStringRef outputType = CFDictionaryGetValue(currentOutput, kAudioSession_AudioRouteKey_Type); if ( (CFStringCompare(outputType, kAudioSessionOutputRoute_AirPlay, 0) == kCFCompareEqualTo) ) { // if Airplay NSLog(@"] Logic: output changed to Airplay"); } else if ( (CFStringCompare(outputType, kAudioSessionOutputRoute_BluetoothA2DP, 0) == kCFCompareEqualTo) ) { // if Bluetooth A2DP NSLog(@"] Logic: output changed to A2DP"); // Mix with others category UInt32 doSetProperty = 1; AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); // Bluetooth support enable UInt32 allowBluetoothInput = 1; AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,sizeof (allowBluetoothInput),&allowBluetoothInput); } else if ( (CFStringCompare(outputType, kAudioSessionOutputRoute_BluetoothHFP, 0) == kCFCompareEqualTo) ) { // if Bluetooth HFP NSLog(@"] Logic: output changed to HFP"); // Mix with others category UInt32 doSetProperty = 1; AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); // Bluetooth support enable UInt32 allowBluetoothInput = 1; AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,sizeof (allowBluetoothInput),&allowBluetoothInput); } else if ( (CFStringCompare(outputType, kAudioSessionOutputRoute_LineOut, 0) == kCFCompareEqualTo) ) { // if Line Out NSLog(@"] Logic: output changed to Line Out"); } else if ( (CFStringCompare(outputType, kAudioSessionOutputRoute_Headphones, 0) == kCFCompareEqualTo) ) { // if Headphones NSLog(@"] Logic: output changed to Headphone"); // Mix with others category UInt32 doSetProperty = 1; AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); // Bluetooth support disable UInt32 allowBluetoothInput = 0; AudioSessionSetProperty (kAudioSessionProperty_OverrideCategoryEnableBluetoothInput,sizeof (allowBluetoothInput),&allowBluetoothInput); } else if ( (CFStringCompare(outputType, kAudioSessionOutputRoute_BuiltInSpeaker, 0) == kCFCompareEqualTo) ) { // if Built In Speaker NSLog(@"] Logic: output changed to Built In Speaker"); // Mix with others category UInt32 doSetProperty = 1; AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); } else if ( (CFStringCompare(outputType, kAudioSessionOutputRoute_USBAudio, 0) == kCFCompareEqualTo) ) { // if USB audio NSLog(@"] Logic: output changed to USB Audio"); } else if ( (CFStringCompare(outputType, kAudioSessionOutputRoute_HDMI, 0) == kCFCompareEqualTo) ) { // if HDMI NSLog(@"] Logic: output changed to HDMI"); } else if ( (CFStringCompare(outputType, kAudioSessionOutputRoute_BuiltInReceiver, 0) == kCFCompareEqualTo) ) { // if Built in Reciever NSLog(@"] Logic: output changed to Built in Reciever"); // Mix with others category UInt32 doSetProperty = 1; AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers,sizeof(doSetProperty),&doSetProperty); } else { // Unknown audio type NSLog(@"] Logic: WARNING: Unknown audio type: %@",(NSString*)outputType); } } } // ************************************************************************************************ // Check audio route ****************************************************************************** // ************************************************************************************************ UInt32 routeSize = sizeof(CFStringRef); CFStringRef route; AudioSessionGetProperty(kAudioSessionProperty_AudioRoute, &routeSize, &route); NSLog(@"] Logic: the audio route is: %@",(NSString*)route); // ************************************************************************************************ NSLog(@"]--------------------------[ ]-----------------------------["); }
}
由于苹果从7.0开始重新改变audio系统,我将在这里发布更新的代码:
#pragma mark Route change listener // ********************************************************************************************************* // *********** Route change listener *********************************************************************** // ********************************************************************************************************* -(void)routeChanged:(NSNotification*)notification { NSLog(@"]-----------------[ Audio Route Change ]--------------------["); AVAudioSession *session = [AVAudioSession sharedInstance]; //AVAudioSessionRouteDescription* prevRoute = [[notification userInfo] objectForKey:AVAudioSessionRouteChangePreviousRouteKey]; // Reason NSInteger reason = [[[notification userInfo] objectForKey:AVAudioSessionRouteChangeReasonKey] integerValue]; switch (reason) { case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: NSLog(@"] Audio Route: The route changed because no suitable route is now available for the specified category."); break; case AVAudioSessionRouteChangeReasonWakeFromSleep: NSLog(@"] Audio Route: The route changed when the device woke up from sleep."); break; case AVAudioSessionRouteChangeReasonOverride: NSLog(@"] Audio Route: The output route was overridden by the app."); break; case AVAudioSessionRouteChangeReasonCategoryChange: NSLog(@"] Audio Route: The category of the session object changed."); break; case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: NSLog(@"] Audio Route: The previous audio output path is no longer available."); break; case AVAudioSessionRouteChangeReasonNewDeviceAvailable: NSLog(@"] Audio Route: A preferred new audio output path is now available."); break; case AVAudioSessionRouteChangeReasonUnknown: NSLog(@"] Audio Route: The reason for the change is unknown."); break; default: NSLog(@"] Audio Route: The reason for the change is very unknown."); break; } // Output AVAudioSessionPortDescription *output = [[session.currentRoute.outputs count]?session.currentRoute.outputs:nil objectAtIndex:0]; if ([output.portType isEqualToString:AVAudioSessionPortLineOut]) { NSLog(@"] Audio Route: Output Port: LineOut"); } else if ([output.portType isEqualToString:AVAudioSessionPortHeadphones]) { NSLog(@"] Audio Route: Output Port: Headphones"); } else if ([output.portType isEqualToString:AVAudioSessionPortBluetoothA2DP]) { NSLog(@"] Audio Route: Output Port: BluetoothA2DP"); } else if ([output.portType isEqualToString:AVAudioSessionPortBuiltInReceiver]) { NSLog(@"] Audio Route: Output Port: BuiltInReceiver"); } else if ([output.portType isEqualToString:AVAudioSessionPortBuiltInSpeaker]) { NSLog(@"] Audio Route: Output Port: BuiltInSpeaker"); } else if ([output.portType isEqualToString:AVAudioSessionPortHDMI]) { NSLog(@"] Audio Route: Output Port: HDMI"); } else if ([output.portType isEqualToString:AVAudioSessionPortAirPlay]) { NSLog(@"] Audio Route: Output Port: AirPlay"); } else if ([output.portType isEqualToString:AVAudioSessionPortBluetoothLE]) { NSLog(@"] Audio Route: Output Port: BluetoothLE"); } else { NSLog(@"] Audio Route: Output Port: Unknown: %@",output.portType); } // Input AVAudioSessionPortDescription *input = [[session.currentRoute.inputs count] ? session.currentRoute.inputs:nil objectAtIndex:0]; if ([input.portType isEqualToString:AVAudioSessionPortLineIn]) { NSLog(@"] Audio Route: Input Port: LineIn"); } else if ([input.portType isEqualToString:AVAudioSessionPortBuiltInMic]) { NSLog(@"] Audio Route: Input Port: BuiltInMic"); } else if ([input.portType isEqualToString:AVAudioSessionPortHeadsetMic]) { NSLog(@"] Audio Route: Input Port: HeadsetMic"); } else if ([input.portType isEqualToString:AVAudioSessionPortBluetoothHFP]) { NSLog(@"] Audio Route: Input Port: BluetoothHFP"); } else if ([input.portType isEqualToString:AVAudioSessionPortUSBAudio]) { NSLog(@"] Audio Route: Input Port: USBAudio"); } else if ([input.portType isEqualToString:AVAudioSessionPortCarAudio]) { NSLog(@"] Audio Route: Input Port: CarAudio"); } else { NSLog(@"] Audio Input Port: Unknown: %@",input.portType); } NSLog(@"]--------------------------[ ]-----------------------------["); }
请记住添加观察者,因为audio会话的委托也被弃用:
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(audioInterruption:) name: AVAudioSessionInterruptionNotification object: nil];
PS:你不需要重置类别(如6.0)
我非常有信心通过您的应用程序的audio会话,这是可能的:
audio会话是您的应用程序和iOS之间的中介。 每个iPhone应用程序只有一个audio会话。 你configuration它来expression你的应用程序的audio意图。 首先,您回答一些关于您希望应用程序行为的问题:
- 您希望您的应用程序如何响应中断,如电话?
- 您是否打算将应用程序的声音与来自其他正在运行的应用程序的声音混合在一起,还是打算将其沉默?
- 您的应用程序应该如何响应audio路由更改,例如,用户插入或拔下耳机时?
有了答案,您可以使用audio会话界面(在AudioToolbox / AudioServices.h中声明)来configuration您的audio会话和您的应用程序。
挖掘这些文档:
- 核心audio概述 – audio会话:与Core Audio合作
- audio会话编程
- audio会话编程 – 处理audio硬件路由更改
让我知道它是怎么回事!
这是不可能的,我试图找出路由更改侦听器(与AudioSession)。 我的结果是:由于Apple提供的类别,您不能单独configurationinput或输出。 我尝试* PlayAndRecord,当我配对蓝牙设备,路线变化是这样的:
old route : HeadsetBT new route : SpeakerAndMicrophone
事实上,我的蓝牙不是一个耳机,只是扬声器…所以对我来说,没有解决scheme。