聊聊iOS开发中耳机的那点事(监听耳机拔插、耳机线控)-b-LMLPHP

前言


iOS开发当中有关于视音频播放的开发不在少数,用户时常会使用到一种输出设备,那就是"耳机",这一篇博客写的就是关于耳机的一些开发相关的技术点.

检测耳机是否插入


看到上面的标题的时候一定要注意,这里说的是"检测耳机是否插入",这里只是一次性的检测,不是实时监控耳机的拔插,但是有一些时候,下面的这个方法已经足够满足我们的开发需求了.
首先,我们需要导入AVFoundation.framework这个框架如下图.

聊聊iOS开发中耳机的那点事(监听耳机拔插、耳机线控)-b-LMLPHP

导入AVFoundation.framework框架

然后导入头文件,实现下面的方法
#import <AVFoundation/AVFoundation.h>  //导入头文件
- (BOOL)isHeadsetPluggedIn {      
   AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];      
   for (AVAudioSessionPortDescription* desc in [route outputs]) {          
       if ([[desc portType] isEqualToString:AVAudioSessionPortHeadphones])              
           return YES;      
   }      
   return NO;  
}
 

监听耳机的拔插 (iOS6.0的实现)


其实这几天一直在看网上的相关的资料,发现监听耳机拔插大多数是一些iOS6.0左右的老方法,我们就先抛砖引玉一下,先看看iOS6.0是如何监听耳机拔插事件.
首先,我们需要导入AVFoundation.framework这个框架如下图.

aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJDQzA1MTVGNkE2MjExRTRBRjEzODVCM0Q0NEVFMjFBIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJDQzA1MTYwNkE2MjExRTRBRjEzODVCM0Q0NEVFMjFBIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkNDMDUxNUQ2QTYyMTFFNEFGMTM4NUIzRDQ0RUUyMUEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkNDMDUxNUU2QTYyMTFFNEFGMTM4NUIzRDQ0RUUyMUEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6p+a6fAAAAD0lEQVR42mJ89/Y1QIABAAWXAsgVS/hWAAAAAElFTkSuQmCC" alt="" data-ratio="0.5472473294987674" data-src="//bbsmax.ikafan.com/static/L3Byb3h5L2h0dHAvbW1iaXoucXBpYy5jbi9tbWJpel9qcGcvZzR1b0pPTUEzOExaeFlEMXBJUmhXTzNBazY1YzFyWmljWEVkRUIzd2dIZEpHU2F6UXFaZXY3d3Rra1RqTnBEbWh3cnVDaHJUTGJ5V2MwT2MzODVrYkJnLzA/d3hfZm10PWpwZWc=.jpg" data-type="jpeg" data-w="1217" />

导入AVFoundation.framework框架

iOS6.0的监听耳机拔插主要是对AVAudioSession单例对象中的AudioSessionAddPropertyListener 这个 block函数的实现完成的,这个函数在耳机拔插的时候调用才会调用.这里的监听耳机拔插事件我直接写在了AppDelegate中- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions,我们看一下具体的代码实现.
#import "AppDelegate.h"
#import <AVFoundation/AVFoundation.h>//导入头文件
@interface AppDelegate ()<AVAudioSessionDelegate> @end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {      
   [[AVAudioSession sharedInstance] setDelegate:self];//初始化单例设置代理      
   [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];//设置AVAudioSession单例对象的类型      
   AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,audioRouteChangeListenerCallback, (__bridge void *)(self));//调用block函数      
   return YES;
}//对block函数其中的方法进行实现
void audioRouteChangeListenerCallback (void *inUserData, AudioSessionPropertyID inPropertyID, UInt32 inPropertyValueSize,const void *inPropertyValue ) {    // ensure that this callback was invoked for a route change      
if (inPropertyID != kAudioSessionProperty_AudioRouteChange) return;      {        
   // Determines the reason for the route change, to ensure that it is not          
   //      because of a category change.          
   CFDictionaryRef routeChangeDictionary = (CFDictionaryRef)inPropertyValue;        CFNumberRef routeChangeReasonRef = (CFNumberRef)CFDictionaryGetValue (routeChangeDictionary, CFSTR (kAudioSession_AudioRouteChangeKey_Reason) );          
   SInt32 routeChangeReason;        
   CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);        if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {            //Handle Headset Unplugged              
   NSLog(@"没有耳机!");          
} else if (routeChangeReason == kAudioSessionRouteChangeReason_NewDeviceAvailable) {            //Handle Headset plugged in              
   NSLog(@"有耳机!");          
}      }  }
 

监听耳机的拔插 (iOS6.0之后的实现)


其实,如果不是一个有警告情结的程序猿,上面的监听耳机拔插实现已经完全能满足工作需求,但是对于我这么一个有警告情结的程序猿,心中对上面的程序运行过程出现的警告十分的反感,在上面的AVAudioSession很多方法被弃用之后,我们需要使用通知来实现监听耳机的拔插.所以就出现了下面的方法.
下面的方法我为了方便,就直接下载Demo的ViewController中,和上面一样,我们需要导入AVFoundation.framework这个框架.然后我们在ViewController导入头文件.然后我们需要监听的通知名称如下.
具体的代码实现,如下.
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {    
   [super viewDidLoad];      
   [[AVAudioSession sharedInstance] setActive:YES error:nil];//创建单例对象并且使其设置为活跃状态.      
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:)   name:AVAudioSessionRouteChangeNotification object:nil];//设置通知
}//通知方法的实现
- (void)audioRouteChangeListenerCallback:(NSNotification*)notification {    
       NSDictionary *interuptionDict = notification.userInfo;    
       NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];    
       switch (routeChangeReason) {        
           case AVAudioSessionRouteChangeReasonNewDeviceAvailable:            
               NSLog(@"AVAudioSessionRouteChangeReasonNewDeviceAvailable");            
               tipWithMessage(@"耳机插入");            
               break;        
           case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:            
               NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable");                 tipWithMessage(@"耳机拔出,停止播放操作");            
               break;                    case AVAudioSessionRouteChangeReasonCategoryChange:            // called at start - also when other audio wants to play            
               tipWithMessage(@"AVAudioSessionRouteChangeReasonCategoryChange");            
               break;    
    }
}//不管何时,只要有通知中心的出现,在dealloc的方法中都要移除所有观察者. -(void)dealloc{      
   [[NSNotificationCenter defaultCenter] removeObserver:self];  
}
//自定提醒窗口 NS_INLINE void tipWithMessage(NSString *message){    
   dispatch_async(dispatch_get_main_queue(), ^{        
       UIAlertView *alerView = [[UIAlertView alloc] initWithTitle:@"提示" message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil, nil];          
       [alerView show];          
       [alerView performSelector:@selector(dismissWithClickedButtonIndex:animated:) withObject:@[@0, @1] afterDelay:0.9];      
  });  
}
 

监听耳机的拔插的注意事项(必看部分)


  • 1.开发人员测试监听耳机的拔插的代码的时候,要使用真机测试.模拟器是没有耳机插孔的,除非你给电脑凿一个孔.
04-26 14:14
查看更多