耳机插好了吗? 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手机插入耳机后仍外放的尴尬?