iOS开发-AVAudioPlayer

简述

AVAudioPlayer 是一个属于 AVFoundation.framework 的一个类,它的功能类似于一个功能强大的播放器,AVAudioPlayer 支持广泛的音频格式,主要是以下这些格式。

  • AAC
  • AMR (Adaptive multi-Rate,一种语音格式)
  • ALAC (Apple lossless Audio Codec)
  • iLBC (internet Low Bitrate Codec,另一种语音格式)
  • IMA4 (IMA/ADPCM)
  • linearPCM (uncompressed)
  • u-law 和 a-law
  • MP3 (MPEG-Laudio Layer 3)

AVAudioPlayer 的使用

AVAudioPlayer 初始化

  1. initWithContentsOfURL: error: 从URL加载音频,返回 AVAudioPlayer 对象
  2. initWithData: error: 加载NSdata对象的音频文件,返回 AVAudioPlayer 对象

AVAudioPlayer方法调用

  1. - (BOOL)play 开始或恢复播放,调用该方法时,如果该音频还没有准备好,程序会隐士执行 - (BOOL)prepareToPlay 方法
  2. - (void)pause 暂停
  3. - (void)stop 停止
  4. - (BOOL)playAtTime:(NSTimeInterval)time NS_AVAILABLE(10_7, 4_0) 在某个时间点播放
  5. - (BOOL)prepareToPlay 准备开始播放
  6. - (void)updateMeters 更新音频测量值,注意如果要更新音频测量值必须设置meteringEnabled为YES,通过音频测量值可以即时获得音频分贝等信息
  7. - (float)averagePowerForChannel:(NSUInteger)channelNumber 获得指定声道的分贝峰值,注意如果要获得分贝峰值必须在此之前调用updateMeters方法

使用 AVAudioPlayer 读取音频信息

  1. volume 播放器的音频增益,值:0.0~1.0
  2. pan NS_AVAILABLE(10_7, 4_0) 立体声设置 设为 -1.0 则左边播放 设为 0.0 则中央播放 设为 1.0 则右边播放
  3. enableRate 是否允许改变播放速率
  4. rate NS_AVAILABLE(10_8, 5_0) 播放速率 0.5 (半速播放) ~ 2.0(倍速播放) 注1.0 是正常速度
  5. playing 是否正在播放音频
  6. numberOfLoops 循环次数,如果要单曲循环,设置为负数
  7. numberOfChannels 该音频的声道次数 (只读)
  8. duration 该音频时长
  9. currentTime 该音频的播放点
  10. deviceCurrentTime 输出设备播放音频的时间,注意如果播放中被暂停此时间也会继续累加
  11. url 音频文件路径,只读
  12. data 音频数据,只读
  13. channelAssignments 获得或设置播放声道

代理方法

  1. - (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag; 音频播放完成
  2. - (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError * __nullable)error 音频解码发生错误
  3. - (void)audioPlayerBeginInterruption:(AVAudioPlayer *)player 如果音频被中断,比如有电话呼入,该方法就会被回调,该方法可以保存当前播放信息,以便恢复继续播放的进度

代码

AVAudioPlayer 初始化

首先导入两首格式为 mp3 的歌曲,再导入歌手图片

在 ViewController.h 导入

#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>

然后必须持有一个 AVAudioPlayer 对象,若此对象不是属性,则无法播放

@property (nonatomic , strong) AVAudioPlayer *player;

添加控件如图所示,给控件命名

storyboard
storyboard

获取制定 url 对象

NSURL *url = [[NSBundle mainBundle] URLForResource:@"吴亦凡-时间煮雨" withExtension:@"mp3"];

初始化 AVAudioPlayer 对象

self.player = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:nil];

设置代理

self.player.delegate = self;

这样就播放器就初始化完成了

将storyboard里面 开始 按钮绑定 - (IBAction)start:(id)sender 方法

- (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;

将storyboard里面 停止 按钮绑定 - (IBAction)stop:(id)sender 方法

- (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 添加代码:

<key>UIBackgroundModes</key>
    <array>
        <string>audio</string>
    </array>

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

//设置锁屏仍能继续播放
[[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];
        }
    }
}

这样就能在拔掉耳机的时候,暂停播放了!!!

但是似乎还是差了一些什么,好像锁屏界面空空如也啊!!!

定制锁屏界面

设置后台播放时显示的东西,例如歌曲名字,图片等

要用到 <MediaPlayer/MediaPlayer.h> 这个库,刚才已经导入过

- (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;
        }
    }
}

效果图:

播放页面
播放页面

锁屏页面
锁屏页面

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

Demo地址:
点此下载

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容