AVAudioPlayer音頻播放器
- (void)viewDidLoad {
[super viewDidLoad];
_player = [self playForFile:@"guitar"];
}
- (AVAudioPlayer *)playForFile:(NSString *)file{
NSURL *fileUrl = [[NSBundle mainBundle] URLForResource:file withExtension:@"mp3"];
NSError *error;
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileUrl error:&error];
if (player) {
player.numberOfLoops = -1;//無限循環(huán)播放
player.enableRate = YES;//允許設(shè)置播放速率
[player prepareToPlay];
}else{
NSLog(@"Error creating player : %@",[error localizedDescription]);
}
return player;
}
- (void)play{
if (![_player isPlaying]) {
[_player play];
}
}
- (void)stop{
if ([_player isPlaying]) {
[_player stop];
_player.currentTime = 0.0;
}
}
此時運營程序并調(diào)用play方法,音樂會響起。但是如果此時切換手機左側(cè)的“鈴音/靜音”開關(guān),或者點擊手機鎖屏按鈕,正在播放的聲音會消失。現(xiàn)在我們要對AVAudioSession進行配置,可在 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions中配置以下代碼
AVAudioSession *sessioin = [AVAudioSession sharedInstance];
if (![sessioin setCategory:AVAudioSessionCategoryPlayback error:nil]) {
NSLog(@"error....");
}
if (![sessioin setActive:YES error:nil]) {
NSLog(@"error.....");
}
此時再切換“鈴音/靜音”開關(guān)時音樂播放已經(jīng)不受影響了,但是點擊鎖屏按鈕時音樂還是會暫停,接下來設(shè)置info.plist文件
Required background modes中添加App plays audio or streams audio/video using AirPlay
或者在Source Code中添加
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
</array>
接下來再次切換“鈴音/靜音”、點擊鎖屏按鈕時音樂播放不會再暫停了
處理中斷事件
當(dāng)接到來電或者其它應(yīng)用占用音頻播放時,音頻播放會消失暫停。當(dāng)正在播放的音頻被暫停時,AVAudioSession會發(fā)出通知AVAudioSessionInterruptionNotification,接下來處理AVAudioSessionInterruptionNotification通知
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioInterruption:) name:AVAudioSessionInterruptionNotification object:nil];
- (void) audioInterruption:(NSNotification *)notifi{
AVAudioSessionInterruptionType type = [[notifi.userInfo objectForKey:AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
AVAudioSessionInterruptionOptions options = [[notifi.userInfo objectForKey:AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
if (type == AVAudioSessionInterruptionTypeBegan) {
//中斷音樂播放
[self stop];
}else if (type == AVAudioSessionInterruptionTypeEnded && options == AVAudioSessionInterruptionOptionShouldResume) {
//中斷結(jié)束,繼續(xù)播放音樂
[self play];
}
}
AVAudioSessionInterruptionType、AVAudioSessionInterruptionOptions是一個枚舉類型
typedef NS_ENUM(NSUInteger, AVAudioSessionInterruptionType)
{
AVAudioSessionInterruptionTypeBegan = 1, /* the system has interrupted your audio session */
AVAudioSessionInterruptionTypeEnded = 0, /* the interruption has ended */
};
/* For use with AVAudioSessionInterruptionNotification */
typedef NS_OPTIONS(NSUInteger, AVAudioSessionInterruptionOptions)
{
AVAudioSessionInterruptionOptionShouldResume = 1
};
對線路改變的影響
當(dāng)插拔耳機、連接斷開藍牙耳機等操作時,AVAudioSession會發(fā)出音頻線路變化通知AVAudioSessionRouteChangeNotification
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChanged:) name:AVAudioSessionRouteChangeNotification object:nil];
- (void) audioRouteChanged:(NSNotification *)notifi{
AVAudioSessionRouteChangeReason reason = [[notifi.userInfo objectForKey:AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue];
if (reason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
[self stop];
}
}
AVAudioSessionRouteChangeReason枚舉類型
typedef NS_ENUM(NSUInteger, AVAudioSessionRouteChangeReason)
{
AVAudioSessionRouteChangeReasonUnknown = 0,
AVAudioSessionRouteChangeReasonNewDeviceAvailable = 1,
AVAudioSessionRouteChangeReasonOldDeviceUnavailable = 2,
AVAudioSessionRouteChangeReasonCategoryChange = 3,
AVAudioSessionRouteChangeReasonOverride = 4,
AVAudioSessionRouteChangeReasonWakeFromSleep = 6,
AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory = 7,
AVAudioSessionRouteChangeReasonRouteConfigurationChange = 8 // added in iOS 7
};
/* values for AVAudioSessionRouteChangeReasonKey in AVAudioSessionRouteChangeNotification userInfo dictionary
AVAudioSessionRouteChangeReasonUnknown
The reason is unknown.
AVAudioSessionRouteChangeReasonNewDeviceAvailable
A new device became available (e.g. headphones have been plugged in).
AVAudioSessionRouteChangeReasonOldDeviceUnavailable
The old device became unavailable (e.g. headphones have been unplugged).
AVAudioSessionRouteChangeReasonCategoryChange
The audio category has changed (e.g. AVAudioSessionCategoryPlayback has been changed to AVAudioSessionCategoryPlayAndRecord).
AVAudioSessionRouteChangeReasonOverride
The route has been overridden (e.g. category is AVAudioSessionCategoryPlayAndRecord and the output
has been changed from the receiver, which is the default, to the speaker).
AVAudioSessionRouteChangeReasonWakeFromSleep
The device woke from sleep.
AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory
Returned when there is no route for the current category (for instance, the category is AVAudioSessionCategoryRecord
but no input device is available).
AVAudioSessionRouteChangeReasonRouteConfigurationChange
Indicates that the set of input and/our output ports has not changed, but some aspect of their
configuration has changed. For example, a port's selected data source has changed.
*/
同時也可以根據(jù)AVAudioSessionPort判斷
if (reason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
AVAudioSessionRouteDescription *routeDescription = [notifi.userInfo objectForKey:AVAudioSessionRouteChangePreviousRouteKey];
AVAudioSessionPortDescription *portDes = routeDescription.outputs[0];
NSString *portType = portDes.portType;
//判斷播放音頻的設(shè)備
if ([portType isEqualToString:AVAudioSessionPortHeadphones]) {
[self stop];
}
}
/* output port types */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortLineOut API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Line level output on a dock connector */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortHeadphones API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Headphone or headset output */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortBluetoothA2DP API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Output on a Bluetooth A2DP device */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortBuiltInReceiver API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* The speaker you hold to your ear when on a phone call */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortBuiltInSpeaker API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Built-in speaker on an iOS device */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortHDMI API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Output via High-Definition Multimedia Interface */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortAirPlay API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Output on a remote Air Play device */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortBluetoothLE API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Output on a Bluetooth Low Energy device */
/* port types that refer to either input or output */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortBluetoothHFP API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Input or output on a Bluetooth Hands-Free Profile device */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortUSBAudio API_AVAILABLE(ios(6.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Input or output on a Universal Serial Bus device */
AVF_EXPORT AVAudioSessionPort const AVAudioSessionPortCarAudio API_AVAILABLE(ios(7.0), watchos(2.0), tvos(9.0)) API_UNAVAILABLE(macos); /* Input or output via Car Audio */