iOS开发-AVAudioPlayer音乐播放、按钮音效震动

AVAudioPlayer 是一个属于 AVFoundation.framework 的一个类,它的功能类似于一个功能强大的播放器,AVAudioPlayer 支持广泛的音频格式。
主要是以下这些格式:AAC AMR iLBC IMA4 linearPCM u-law MP3

AVAudioPlayer 的方法

1. 初始化
  • initWithContentsOfURL: error: 从URL加载音频,返回 AVAudioPlayer 对象
  • initWithData: error: 加载NSdata对象的音频文件,返回 AVAudioPlayer 对象
2. 方法调用
  • - (BOOL)play 开始或恢复播放,调用该方法时,如果该音频还没有准备好,程序会隐士执行 - (BOOL)prepareToPlay 方法
  • - (void)pause 暂停
  • - (void)stop 停止
  • - (BOOL)playAtTime:(NSTimeInterval)time NS_AVAILABLE(10_7, 4_0) 在某个时间点播放
  • - (BOOL)prepareToPlay 准备开始播放
  • - (void)updateMeters 更新音频测量值,注意如果要更新音频测量值必须设置meteringEnabled为YES,通过音频测量值可以即时获得音频分贝等信息
  • - (float)averagePowerForChannel:(NSUInteger)channelNumber 获得指定声道的分贝峰值,注意如果要获得分贝峰值必须在此之前调用updateMeters方法
3. 读取音频信息
  • -volume 播放器的音频增益,值:0.0~1.0
  • pan NS_AVAILABLE(10_7, 4_0) 立体声设置 设为 -1.0 则左边播放 设为 0.0 则中央播放 设为 1.0 则右边播放
  • enableRate 是否允许改变播放速率
  • rate NS_AVAILABLE(10_8, 5_0) 播放速率 0.5 (半速播放) ~ 2.0(倍速播放) 注1.0 是正常速度
  • playing 是否正在播放音频
  • numberOfLoops 循环次数,如果要单曲循环,设置为负数
  • numberOfChannels 该音频的声道次数 (只读)
  • duration 该音频时长
  • currentTime 该音频的播放点
  • deviceCurrentTime 输出设备播放音频的时间,注意如果播放中被暂停此时间也会继续累加
  • url 音频文件路径,只读
  • data 音频数据,只读
  • channelAssignments 获得或设置播放声道
4. 代理方法
  • - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag; 音频播放完成
  • - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error 音频解码发生错误
  • - (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player 如果音频被中断,比如有电话呼入,该方法就会被回调,该方法可以保存当前播放信息,以便恢复继续播放的进度

案例

这里简单做了一个播放器

iOS开发-AVAudioPlayer音乐播放、按钮音效震动_第1张图片
播放器

代码

导入头文件

#import 
#import 

必须持有一个 AVAudioPlayer 对象

@property (nonatomic , strong) AVAudioPlayer *player;

初始化AVAudioPlayer

//获取制定 url 对象
NSURL *url = [[NSBundle mainBundle] URLForResource:@"吴亦凡-时间煮雨" withExtension:@"mp3"];
//初始化 AVAudioPlayer 对象
self.player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];
//代理
self.player.delegate = self;

开始播放按钮点击事件

- (IBAction)start:(id)sender {
    if ([self.player isPlaying]) {
        [self.startBtn setBackgroundImage:[UIImage imageNamed:@"播放"] forState:0];
        [self.player pause];
    } else {
        [self.startBtn setBackgroundImage:[UIImage imageNamed:@"暂停"] forState:0];
        [self.player play];
    }
    if (_timer == nil) {
        _timer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
    }
}

注: 上诉代码中定义了一个 NSTimer 变量,因为播放器没有播放进程的委托,所以只能自定义NSTimer变量对播放器进行监控

@property (strong, nonatomic) NSTimer *timer;

停止播放点击事件

- (IBAction)stop:(id)sender {
    [self.player stop];
    //计时器停止
    [_timer invalidate];
    //释放定时器
    _timer = nil;
}

设置刚才绑定的定时器调用方法updateProgress

-(void)updateProgress{
    //进度条显示播放进度
    self.progress.progress = self.player.currentTime/self.player.duration;
    self.info1.text = [NSString stringWithFormat:@"当前播放时间%f",self.player.currentTime];
}

实现 AVAudioPlayer 的委托方法

/// 完成播放代理
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
    if (player == _player && flag) {
        [self.startBtn setBackgroundImage:[UIImage imageNamed:@"播放"] forState:0];
    }
}

/// 播放被中断代理
-(void)audioPlayerBeginInterruption:(AVAudioPlayer *)player{
    if (player == _player){
        NSLog(@"播放被中断");
    }
}

此时,音乐就可以播放了!!!

但是,人们使用音乐大都是后台播放,那么如何添加后台播放支持呢?

后台播放

在项目里 info.plist 右键 open As -- source code 添加代码:

UIBackgroundModes
    
        audio
    

同样,代码里面也要添加后台播放支持

// 下面这个类别用于音频比较次要的应用,应用的音频会和其他应用的音频实现混音
// 然后关闭屏幕或者静音开关打开时音频将静音。
NSString *const AVAudioSessionCategoryAmbient; 
// 默认类别
//(1)允许播放Playback不允许录制;
//(2)当用户打开静音时,就是设备侧边的那个静音开关,那么应用内正在播放的音频将静音;
//(3)当用户锁定屏幕或屏幕自动变暗时,应用内的应用内正在播放的音频将静音;
//(4)当你应用内的音频开始时,如果这个时候有其他应用比如iPod正在播放音乐,那么iPod将暂停播放
NSString *const AVAudioSessionCategorySoloAmbient; 
// 下面这个类别应用侧重音频播放,使用这个类别时,关闭屏幕或静音开关打开
// 时音频将继续播放,与其他应用音频不混音。要使应用能后台继续需要相关设置。
NSString *const AVAudioSessionCategoryPlayback; 
// 下面这个类别应用将侧重录音。将使播放的音频静音,屏幕关闭时录制音频将继续。
// 要使应用能后台继续需要相关设置。
NSString *const AVAudioSessionCategoryRecord;
// 下面这个类别应用允许音频播放和录制,比如用于VOIP语音通话应用。播放和录音
// 可以同时进行,关闭屏幕将可以继续。要使应用能后台继续需要相关设置。
 NSString *const AVAudioSessionCategoryPlayAndRecord; 
// 下面这个类别用于音频处理,详细见开发文档
NSString *const AVAudioSessionCategoryAudioProcessing; 
// 下面这个类别可以实现同时多个输出,详细见开发文档
NSString *const AVAudioSessionCategoryMultiRoute; 
//设置锁屏仍能继续播放
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error:nil];
[[AVAudioSession sharedInstance] setActive: YES error: nil];

这样 音乐在后台就可以播放了!!

那么很多播放器都有一个功能,那就是在用户拔掉耳机的时候,暂停播放

监听播放设备

//添加通知,拔出耳机后暂停播放
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChange:) name:AVAudioSessionRouteChangeNotification object:nil];

/**
 *  一旦输出改变则执行此方法
 *  @param notification 输出改变通知对象
 */
-(void)routeChange:(NSNotification *)notification{
    NSDictionary *dic=notification.userInfo;
    int changeReason= [dic[AVAudioSessionRouteChangeReasonKey] intValue];
    //等于AVAudioSessionRouteChangeReasonOldDeviceUnavailable表示旧输出不可用
    if (changeReason==AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
        AVAudioSessionRouteDescription *routeDescription=dic[AVAudioSessionRouteChangePreviousRouteKey];
        AVAudioSessionPortDescription *portDescription= [routeDescription.outputs firstObject];
        //原设备为耳机则暂停
        if ([portDescription.portType isEqualToString:@"Headphones"]) {
            [self.player pause];
        }
    }
}

这样就能在拔掉耳机的时候,暂停播放了!!!
但是似乎还是差了一些什么,好像锁屏界面空空如也啊!!!

定制锁屏界面

设置后台播放时显示的东西,例如歌曲名字,图片等
要用到 这个库,刚才已经导入过

- (void)setPlayingInfo {
    //    设置后台播放时显示的东西,例如歌曲名字,图片等
    MPMediaItemArtwork *artWork = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:@"吴亦凡.jpg"]];

    NSDictionary *dic = @{MPMediaItemPropertyTitle:@"时间煮雨",
                          MPMediaItemPropertyArtist:@"吴亦凡",
                          MPMediaItemPropertyArtwork:artWork
                          };
    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dic];
}

这样,图片就在锁屏界面显示了,不过,锁屏界面上面的三个按钮,怎么控制播放呢!!

接收锁屏歌曲按钮控制 (上一首,播放,下一首)

首先,你要在一个继承 UIResponder 类里面接收远程控制,本文以 ViewController 为例
添加如下代码,接受远程控制和取消远程控制。

- (void)viewDidAppear:(BOOL)animated {
    //    接受远程控制
    [self becomeFirstResponder];
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}

- (void)viewDidDisappear:(BOOL)animated {
    //    取消远程控制
    [self resignFirstResponder];
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
}

接收方法设置

- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
    if (event.type == UIEventTypeRemoteControl) {  //判断是否为远程控制
        switch (event.subtype) {
            case  UIEventSubtypeRemoteControlPlay:
                if (![_player isPlaying]) {
                    [_player play];
                }
                break;
            case UIEventSubtypeRemoteControlPause:
                if ([_player isPlaying]) {
                    [_player pause];
                }
                break;
            case UIEventSubtypeRemoteControlNextTrack:
                NSLog(@"下一首");
                break;
            case UIEventSubtypeRemoteControlPreviousTrack:
                NSLog(@"上一首 ");
                break;
            default:
                break;
        }
    }
}

iOS开发-AVAudioPlayer音乐播放、按钮音效震动_第2张图片
效果图

这样,播放器的基本功能就已经完成 !! 代码多有不祥之处,时间匆忙,敬请谅解,不实之处,请多包涵!!

有时需要按钮震动或使用系统级别音效

先看一个例子

- (void)playCoinSound {
    //创建SystemSoundID对象,用于绑定声音文件
    SystemSoundID soundFileObj;
    //获取声音文件的路径
    NSString *sourcePath = [[NSBundle mainBundle] pathForResource:@"10010" ofType:@"mp3"];
    //将string转为url
    NSURL *sourceUrl = [NSURL fileURLWithPath:sourcePath];
    //将声音文件和SystemSoundID绑定
    AudioServicesCreateSystemSoundID((__bridge CFURLRef _Nonnull)(sourceUrl), &soundFileObj);
    //播放声音,但此方法只能播放30s以内的文件
    AudioServicesPlaySystemSound(soundFileObj);
}
  • 这个方法可以播放30s一下的音频文件
/*!
    This function will be deprecated in a future release. Use AudioServicesPlaySystemSoundWithCompletion instead.
 
    @function       AudioServicesPlaySystemSound
    @abstract       Play the sound designated by the provided SystemSoundID.
    @discussion     A SystemSoundID indicating the desired System Sound to be played.
    @param          inSystemSoundID
                        A SystemSoundID for the System Sound server to play.
*/
extern void 
AudioServicesPlaySystemSound(SystemSoundID inSystemSoundID)                                         
                                                                API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
  • 这个方法可以播放音效并且带震动效果
/*!
    This function will be deprecated in a future release. Use AudioServicesPlayAlertSoundWithCompletion instead.
 
    @function       AudioServicesPlayAlertSound
    @abstract       Play an Alert Sound
    @discussion     Play the provided SystemSoundID with AlertSound behavior.
    @param          inSystemSoundID
                        A SystemSoundID for the System Sound server to play. On the desktop you
                        can pass the kSystemSoundID_UserPreferredAlert constant to playback the alert sound 
                        selected by the user in System Preferences. On iOS there is no preferred user alert sound.
*/
extern void 
AudioServicesPlayAlertSound(SystemSoundID inSystemSoundID)                                          
                                                                API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
  • 只要震动效果
//需要导入
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);

参考文献:

  • iOS开发-AVAudioPlayer
  • 如何在静音模式下播放声音(需要设置AVAudioSession)
  • Apple Development Document

你可能感兴趣的:(iOS开发-AVAudioPlayer音乐播放、按钮音效震动)