强制iPhone麦克风作为音频输入

时间:2010-10-23 02:23:14

标签: ios core-audio microphone

我正在开发一个iOS应用程序(目前专门针对iPhone),要求应用程序仅从iPhone内置麦克风录制音频(即使插入了耳机/耳机),以及在耳机播放(假设现在插入耳机)。

我想知道目前是否可以使用可用的API?如果是这样,有人可以说明我该如何做到这一点?

谢谢!

6 个答案:

答案 0 :(得分:8)

我相信这个问题的答案是'不'。我使用iPhone 4和新到iOS 4 AVFoundation进行实验,重点关注AVCaptureDevice类。

我在应用程序中添加了以下内容:

NSLog(@"%@", [AVCaptureDevice devices]);

因此要求列出可用于捕获音频和/或视频的所有设备。没有插入耳机,我得到:

(
    "Back Camera",
    "Front Camera",
    "iPhone Microphone" 
)

耳机插入后,我得到:

(
    "Back Camera",
    "Front Camera",
    Headphones
)

因此,只要耳机可用,iPhone麦克风就会从可用的AVCaptureDevices列表中删除。为了进一步探讨这一点,我添加了一些代码来获取可用音频设备的AVCaptureDevice实例并打印其唯一ID。对于将自己标识为“iPhone麦克风”的设备和将自己标识为“耳机”的设备,我得到了:

com.apple.avfoundation.avcapturedevice.built-in_audio:0

在我看来,很明显两个设备不能具有相同的唯一ID,所以显然它是同一设备改变其状态。尽管AVCaptureDevices在设置状态方面有很多东西,但它仅限于焦点,曝光,闪光和白平衡等视觉效果。

答案 1 :(得分:4)

看起来真的不可能。

我的目标是将输出发送到蓝牙耳机并记录输入。 到目前为止,我可以看到,我最好的选择是:“PlayAndRecord + AllowBluetoothInput”属性 (iphone 4,诺基亚BH-214耳机)

重要的是,根据Apple文档,当音频路径发生变化时,您必须重新覆盖音频类别!

这是我的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, &currentRouteDescriptionDictionary);
    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(@"]--------------------------[  ]-----------------------------[");        

}

}

答案 2 :(得分:3)

由于苹果从7.0开始重新改变音频系统,我将在这里发布更新代码:

#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(@"]--------------------------[  ]-----------------------------[");

}

请记住添加观察者,因为音频会话的委托也已弃用:

[[NSNotificationCenter defaultCenter] addObserver: self
                                                 selector: @selector(audioInterruption:)
                                                     name: AVAudioSessionInterruptionNotification
                                                   object: nil];

PS:你不需要在这里重置类别(如在6.0中)

答案 3 :(得分:2)

我非常有信心通过您的应用程序的音频会话可以实现:

  

音频会话是中介   您的应用程序和iOS之间。每   iPhone应用程序只有一个   音频会话。您将其配置为   表达你的应用程序的音频   意图。首先,你回答一些问题   关于你如何想要你的问题   申请表现:

     
      
  • 您希望如何申请   响应中断,例如a   打电话?
  •   
  • 你打算混合你的   应用程序的声音来自   其他正在运行的应用程序,或者你   打算让他们沉默?
  •   
  • 应该如何   您的应用程序响应音频   路由更改,例如,当用户   插入或拔下耳机?
  •   
     

使用   手头的答案,你使用音频   会话接口(声明于   AudioToolbox / AudioServices.h)来   配置你的音频会话和你的   应用

挖掘这些文档:

让我知道它是怎么回事!

答案 4 :(得分:2)

这是不可能的,我试图弄清楚路由改变了监听器(使用AudioSession)。我的结果是:由于Apple提供的categories,您无法单独配置输入或输出。我尝试* PlayAndRecord,当我配对一个蓝牙设备时,路由改变如下:

old route : HeadsetBT
new route : SpeakerAndMicrophone

事实上,我的蓝牙不是耳机,只是扬声器......所以对我来说没有解决方案。

答案 5 :(得分:-1)

我发现,当使用AirPod pro耳机并尝试录制语音邮件问候语时,即使耳机已完全连接并在使用中,手机仍使用了内置麦克风。