耳机插好了吗? IOS 7

Posted

技术标签:

【中文标题】耳机插好了吗? IOS 7【英文标题】:Are headphones plugged in? iOS7 【发布时间】:2014-02-13 01:56:36 【问题描述】:

为 iPhone 开发一个应用程序,其中包含需要通过耳机收听的音频文件。

如何检查耳机是否未插入,以便告诉用户插入耳机。

我有来自另一个线程的以下代码,但不推荐使用 audiosessionGetProperty 方法。任何人都知道如何更改以下代码以使其工作或拥有自己的代码/解决方案。

谢谢。

- (BOOL)isHeadsetPluggedIn 
    UInt32 routeSize = sizeof (CFStringRef);
    CFStringRef route;


    //Maybe changing it to something like the following would work for iOS7?
    //AVAudioSession* session = [AVAudioSession sharedInstance];
    //OSStatus error = [session setCategory:kAudioSessionProperty_AudioRoute...?


    //the line below is whats giving me the warning
    OSStatus error = AudioSessionGetProperty (kAudioSessionProperty_AudioRoute,
                                              &routeSize,
                                              &route);

    /* Known values of route:
     * "Headset"
     * "Headphone"
     * "Speaker"
     * "SpeakerAndMicrophone"
     * "HeadphonesAndMicrophone"
     * "HeadsetInOut"
     * "ReceiverAndMicrophone"
     * "Lineout"
     */

    if (!error && (route != NULL)) 

        NSString* routeStr = (__bridge NSString*)route;

        NSRange headphoneRange = [routeStr rangeOfString : @"Head"];

        if (headphoneRange.location != NSNotFound) return YES;

    

    return NO;

【问题讨论】:

完整的工作代码是什么意思? 【参考方案1】:

这应该可以,但我现在无法测试它,我会在晚上做。

- (BOOL)isHeadsetPluggedIn 
    AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
    for (AVAudioSessionPortDescription* desc in [route outputs]) 
        if ([[desc portType] isEqualToString:AVAudioSessionPortHeadphones])
            return YES;
    
    return NO;

【讨论】:

很高兴为您提供帮助:) 我如何把它变成一个动作【参考方案2】:

只是为了扩展@Antonio 的答案。如果需要检测用户是否拔出或插入耳机。

#import <AVFoundation/AVFoundation.h>

// [AVAudioSession sharedInstance]; // @Boris edited: you may need it if there is no `AVAudioSession instance` created before. If doesn't work, uncomment this line.
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:)
                                             name:AVAudioSessionRouteChangeNotification
                                           object:nil];
// don't forget to `removeObserver:`

// If the user pulls out he headphone jack, stop playing.
- (void)audioRouteChangeListenerCallback:(NSNotification*)notification

    NSDictionary *interuptionDict = notification.userInfo;

    NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];

    switch (routeChangeReason) 

        case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
            NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable");
            NSLog(@"Headphone/Line plugged in");
            break;

        case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
            NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable");
            NSLog(@"Headphone/Line was pulled. Stopping player....");
            break;

        case AVAudioSessionRouteChangeReasonCategoryChange:
            // called at start - also when other audio wants to play
            NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");
            break;
    

【讨论】:

非常感谢我已经对此进行了测试并且效果很好! 来自文档:如果您的应用针对 iOS 9.0 及更高版本或 macOS 10.11 及更高版本,则无需在其 dealloc 方法中取消注册观察者。 直到我将 AVAudioSession.sharedInstance() 作为参数 object 传递给通知中心而不是 nil 之前,这对我不起作用,即 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];【参考方案3】:

斯威夫特 3:

检查耳机是否连接

extension AVAudioSession 

    static var isHeadphonesConnected: Bool 
        return sharedInstance().isHeadphonesConnected
    

    var isHeadphonesConnected: Bool 
        return !currentRoute.outputs.filter  $0.isHeadphones .isEmpty
    



extension AVAudioSessionPortDescription 
    var isHeadphones: Bool 
        return portType == AVAudioSessionPortHeadphones
    

那你可以print("isHeadphones connected: \(AVAudioSession.isHeadphonesConnected)")

聆听变化

Swift 3 中,语法是这样的:

func handleRouteChange(_ notification: Notification) 
    guard
    let userInfo = notification.userInfo,
    let reasonRaw = userInfo[AVAudioSessionRouteChangeReasonKey] as? NSNumber,
    let reason = AVAudioSessionRouteChangeReason(rawValue: reasonRaw.uintValue)
    else  fatalError("Strange... could not get routeChange") 
    switch reason 
    case .oldDeviceUnavailable:
        print("oldDeviceUnavailable")
    case .newDeviceAvailable:
        print("newDeviceAvailable") 
        if AVAudioSession.isHeadphonesConnected 
             print("Just connected headphones")
         
    case .routeConfigurationChange:
        print("routeConfigurationChange")
    case .categoryChange:
        print("categoryChange")
    default:
        print("not handling reason")
    


func listenForNotifications() 
    NotificationCenter.default.addObserver(self, selector: #selector(handleRouteChange(_:)), name: NSNotification.Name.AVAudioSessionRouteChange, object: nil)

注意使用:

 if AVAudioSession.isHeadphonesConnected 
    print("Just connected headphones")
 

【讨论】:

这如何回答这个问题?是否插入耳机不接听。 @Jonny 我编辑了我的答案,包括检查耳机。如果对您有帮助,请点赞我的回答。 这行得通吗?在 Swift 3 中 AVAudioSession 中没有成员 isHeadphonesConnected developer.apple.com/documentation/avfoundation/avaudiosession @thuanle,仔细看代码,isHeadphonesConnected在扩展中使用。【参考方案4】:

Swift 2.0 中@Warif 的代码改动不大...

func audioRouteChangeListenerCallback (notif: NSNotification)
        let userInfo:[NSObject:AnyObject] = notif.userInfo!
        println("\(userInfo)")
        let routChangeReason = UInt((userInfo[AVAudioSessionRouteChangeReasonKey]?.integerValue)!)
        switch routChangeReason 
        case AVAudioSessionRouteChangeReason.NewDeviceAvailable.rawValue:
            self.println("Headphone/Line plugged in");
            break;

        case AVAudioSessionRouteChangeReason.OldDeviceUnavailable.rawValue:
            //If the headphones was pulled move to speaker
            do 
                try AVAudioSession.sharedInstance().overrideOutputAudioPort(AVAudioSessionPortOverride.Speaker)
             catch _ 
            
            self.println("Headphone/Line was pulled. Stopping player....");
            break;

        case AVAudioSessionRouteChangeReason.CategoryChange.rawValue:
            // called at start - also when other audio wants to play
            self.println("AVAudioSessionRouteChangeReasonCategoryChange");
            break;
        default:
            break;
        
    

:D

【讨论】:

【参考方案5】:

在 Swift 中(从 1.2 开始):

    func headsetPluggedIn() -> Bool 
    let route = AVAudioSession.sharedInstance().currentRoute
    return (route.outputs as! [AVAudioSessionPortDescription]).filter( $0.portType == AVAudioSessionPortHeadphones ).count > 0

【讨论】:

【参考方案6】:

Swift 3.0 版本

检查耳机是否已插入或任何蓝牙设备是否已连接音频输出的方法 func bluetoothOrHeadphonesConnected() -> Bool 让输出 = AVAudioSession.sharedInstance().currentRoute.outputs 在输出中输出 如果 output.portType == AVAudioSessionPortBluetoothA2DP || output.portType == AVAudioSessionPortBluetoothHFP || output.portType == AVAudioSessionPortBluetoothLE || output.portType == AVAudioSessionPortHeadphones 返回真 返回假 在收听任何音频时检查耳机是否已拔出非常重要。 私人函数 setupObservers() NotificationCenter.default.addObserver(self,选择器:#selector(self.audioRouteChangeListener),名称:.AVAudioSessionRouteChange,对象:nil) func audioRouteChangeListener(通知:通知) 守卫让 audioRouteChangeReason = notification.userInfo![AVAudioSessionRouteChangeReasonKey] 为?其他返回 切换 audioRouteChangeReason 案例 AVAudioSessionRouteChangeReason.oldDeviceUnavailable.hashValue: //拔掉 默认: 休息

【讨论】:

请不要在多个问题上发帖identical answers。发布一个好的答案,然后投票/标记以关闭其他问题作为重复问题。如果问题不是重复的,调整您对该问题的回答。 感谢@PaulRoub 的建议 该问题断言该应用程序尤其需要与耳机一起使用。您列出的蓝牙端口也可以应用于汽车、便携式扬声器等。【参考方案7】:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(plugout:) name:AVAudioSessionRouteChangeNotification object:nil];
-(void)plugout:(NSNotification*)notification

    isRemovedHeadset = YES;

并在你的

中使用这个 isRemovedHeadset 布尔值来处理你的代码
if (moviePlayer.playbackState == MPMoviePlaybackStatePaused) 

    if(isRemovedHeadset)
    
        isRemovedHeadset = NO;
        [moviePlayer prepareToPlay];
        [moviePlayer play];
        return;
    

【讨论】:

【参考方案8】:

@Sajjon 在 Swift 5 上使用 RxSwift 解决方案

func handleRouteChange(_ notification: Notification) 
    guard
        let userInfo = notification.userInfo,
        let reasonRaw = userInfo[AVAudioSessionRouteChangeReasonKey] as? NSNumber,
        let reason = AVAudioSession.RouteChangeReason(rawValue: reasonRaw.uintValue)
        else  fatalError("Strange... could not get routeChange") 
    switch reason 
    case .oldDeviceUnavailable:
        print("oldDeviceUnavailable")
    case .newDeviceAvailable:
        print("newDeviceAvailable")
        if AVAudioSession.isHeadphonesConnected 
            print("Just connected headphones")
        
    case .routeConfigurationChange:
        print("routeConfigurationChange")
    case .categoryChange:
        print("categoryChange")
    default:
        print("not handling reason")
    


func listenForNotifications() 
    NotificationCenter.default.rx
        .notification(AVAudioSession.routeChangeNotification)
        .subscribe(onNext:  (n) in
            self.handleRouteChange(n)
        )
        .disposed(by: disposeBag)

【讨论】:

以上是关于耳机插好了吗? IOS 7的主要内容,如果未能解决你的问题,请参考以下文章

腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?

用耳机延长线接耳机对效果影响大吗?啥品牌的延长线好了?

iOS耳机监听

ios 耳机插入拔出检测

iOS AudioServicesPlayAlertSound 使用耳机静音

如何在 iOS 设备上检测耳机(扬声器)的可用性?