实例讲解iOS音乐播放器DOUAudioStreamer用法

所属分类: 软件编程 / IOS 阅读数: 2057
收藏 0 赞 0 分享

好久没有写东西了,最近加班太严重,今天抽空把用到的音乐播放器DOUAudioStreamer整理一下,由于项目之前用的是AVPlayer,这个也可以,但是就是要先缓存一段时间再播放,老板看了之后要求,要变缓存变播放(有网时,点击播放按钮就立刻播放),怎么不早说!怎么不早说!怎么不早说!还能怎样?只能原谅他,继续敲代码。。。。。。(还是直接上代码吧)

一、导入三方库

pod 'DOUAudioStreamer'

或者GitHup下载地址:https://github.com/douban/DOUAudioStreamer

二、使用

1.从demo中获取NAKPlaybackIndicatorView文件和MusicIndicator.h和MusicIndicator.m 文件,并导入头文件

//音乐播放
#import "DOUAudioStreamer.h"
#import "NAKPlaybackIndicatorView.h"
#import "MusicIndicator.h"
#import "Track.h"

如图:

2.创建一个Track类,用于音乐播放的URL存放

3.需要的界面.h中,添加DOUAudioStreamer,并用单利来初始化

+ (instancetype)sharedInstance ;
@property (nonatomic, strong) DOUAudioStreamer *streamer;

 

如图:

在.m中实现:

static void *kStatusKVOKey = &kStatusKVOKey;
static void *kDurationKVOKey = &kDurationKVOKey;
static void *kBufferingRatioKVOKey = &kBufferingRatioKVOKey;
@property (strong, nonatomic) MusicIndicator *musicIndicator;
@property (nonatomic, strong) Track *audioTrack;
+ (instancetype)sharedInstance {
 static HYNEntertainmentController *_sharedMusicVC = nil;
 static dispatch_once_t onceToken;
 dispatch_once(&onceToken, ^{
  _sharedMusicVC = [[HYNEntertainmentController alloc] init];
  _sharedMusicVC.streamer = [[DOUAudioStreamer alloc] init];
 }); 
 return _sharedMusicVC;
}

 

播放按钮事件

#pragma mark ---音乐播放按钮
-(void)playMusicStart:(UIButton *)sender
{
  //通过按钮获取cell
  MusicCollectionViewCell *musicCell = (MusicCollectionViewCell *)[[sender superview] superview];
 if(_playFirst == 0){//_playFirst == 0首次播放,其他为暂停
  NSURL *url = [NSURL URLWithString:HttpImgUrl(musicCell.model.musicUrl)];
  _audioTrack.audioFileURL = url;
  @try {
   [self removeStreamerObserver];
  } @catch(id anException){ 
  }
  //在DOUAudioStreamer进行播放时,必须先置为nil
  _streamer = nil;
  _streamer = [DOUAudioStreamer streamerWithAudioFile:_audioTrack];
  [self addStreamerObserver];
  [_streamer play];
 }
 if([_streamer status] == DOUAudioStreamerPaused ||
  [_streamer status] == DOUAudioStreamerIdle){
  [sender setBackgroundImage:[UIImage imageNamed:@"music_play_icon"] forState:UIControlStateNormal];
  [_streamer play]; 
 }else{
  [sender setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal];
  [_streamer pause]; 
 }
 _playFirst++;
 
}

 

对添加监听

- (void)addStreamerObserver {
 [_streamer addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:kStatusKVOKey];
 [_streamer addObserver:self forKeyPath:@"duration" options:NSKeyValueObservingOptionNew context:kDurationKVOKey];
 [_streamer addObserver:self forKeyPath:@"bufferingRatio" options:NSKeyValueObservingOptionNew context:kBufferingRatioKVOKey]; 
}
/// 播放器销毁
- (void)dealloc{
 if (_streamer !=nil) {
  [_streamer pause];
  [_streamer removeObserver:self forKeyPath:@"status" context:kStatusKVOKey];
  [_streamer removeObserver:self forKeyPath:@"duration" context:kDurationKVOKey];
  [_streamer removeObserver:self forKeyPath:@"bufferingRatio" context:kBufferingRatioKVOKey];
  
  _streamer =nil;
 } 
}
- (void)removeStreamerObserver {
 
 [_streamer removeObserver:self forKeyPath:@"status"];
 [_streamer removeObserver:self forKeyPath:@"duration"];
 [_streamer removeObserver:self forKeyPath:@"bufferingRatio"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
 if (context == kStatusKVOKey) {
  [self performSelector:@selector(updateStatus)
      onThread:[NSThread mainThread]
     withObject:nil
    waitUntilDone:NO];
 } else if (context == kDurationKVOKey) {
  [self performSelector:@selector(updateSliderValue:)
      onThread:[NSThread mainThread]
     withObject:nil
    waitUntilDone:NO];
 } else if (context == kBufferingRatioKVOKey) {
  [self performSelector:@selector(updateBufferingStatus)
      onThread:[NSThread mainThread]
     withObject:nil
    waitUntilDone:NO];
 } else {
  [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
 }
}
- (void)updateSliderValue:(id)timer {
}
-(void)updateBufferingStatus
{ 
}
- (void)updateStatus {
 //self.musicIsPlaying = NO;
 _musicIndicator.state = NAKPlaybackIndicatorViewStateStopped;
 switch ([_streamer status]) {
  case DOUAudioStreamerPlaying:
   // self.musicIsPlaying = YES;
   _musicIndicator.state = NAKPlaybackIndicatorViewStatePlaying;
   break;
  case DOUAudioStreamerPaused:
   break;
  case DOUAudioStreamerIdle:
   break;
  case DOUAudioStreamerFinished:
   break;
  case DOUAudioStreamerBuffering:
   _musicIndicator.state = NAKPlaybackIndicatorViewStatePlaying;
   break;  
  case DOUAudioStreamerError:
   break;
 } 
}

这样就能播放了。

锁屏时的音乐显示、拔出耳机后暂停播放、监听音频打断事件

-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
//接受远程控制
[self becomeFirstResponder];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
//这个不能忘记了
-(BOOL)canBecomeFirstResponder{
return YES;
}
- (void)viewDidLoad {
[super viewDidLoad];
//音乐播放器
[self initPlayer];
}
#pragma mark =========================音乐播放==============================
//音乐播放器
-(void)initPlayer
{
_audioTrack = [[Track alloc] init];
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
//让app支持接受远程控制事件
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
//添加通知,拔出耳机后暂停播放
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChange:) name:AVAudioSessionRouteChangeNotification object:nil];
// 监听音频打断事件
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionWasInterrupted:) name:AVAudioSessionInterruptionNotification object:session];
}
// 监听音频打断事件
- (void)audioSessionWasInterrupted:(NSNotification *)notification
{
 //被打断时
if (AVAudioSessionInterruptionTypeBegan == [notification.userInfo[AVAudioSessionInterruptionTypeKey] intValue])
{
 
[_streamer pause];
UIButton *btn = (UIButton *)[self.view viewWithTag:2000];
[btn setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal];
}
else if (AVAudioSessionInterruptionTypeEnded == [notification.userInfo[AVAudioSessionInterruptionTypeKey] intValue])
{
}
}
// 拔出耳机后暂停播放
-(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"]) {
[_streamer pause];
UIButton *btn = (UIButton *)[self.view viewWithTag:2000];
[btn setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal];
}
}
}
//锁屏时音乐显示(这个方法可以在点击播放时,调用传值)
- (void)setupLockScreenInfoWithSing:(NSString *)sign WithSigner:(NSString *)signer WithImage:(UIImage *)image
{
// 1.获取锁屏中心
MPNowPlayingInfoCenter *playingInfoCenter = [MPNowPlayingInfoCenter defaultCenter];
//初始化一个存放音乐信息的字典
NSMutableDictionary *playingInfoDict = [NSMutableDictionary dictionary];
// 2、设置歌曲名
if (sign) {
[playingInfoDict setObject:sign forKey:MPMediaItemPropertyAlbumTitle];
}
// 设置歌手名
if (signer) {
[playingInfoDict setObject:signer forKey:MPMediaItemPropertyArtist];
}
// 3设置封面的图片
//UIImage *image = [self getMusicImageWithMusicId:self.currentModel];
if (image) {
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:image];
[playingInfoDict setObject:artwork forKey:MPMediaItemPropertyArtwork];
}
// 4设置歌曲的总时长
//[playingInfoDict setObject:self.currentModel.detailDuration forKey:MPMediaItemPropertyPlaybackDuration];
//音乐信息赋值给获取锁屏中心的nowPlayingInfo属性
playingInfoCenter.nowPlayingInfo = playingInfoDict;
// 5.开启远程交互
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
}
//锁屏时操作
- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {
if (receivedEvent.type == UIEventTypeRemoteControl) {
UIButton *sender = (UIButton *)[self.view viewWithTag:2000];
switch (receivedEvent.subtype) {//判断是否为远程控制
case UIEventSubtypeRemoteControlPause:
[[HYNEntertainmentController sharedInstance].streamer pause];
[sender setBackgroundImage:[UIImage imageNamed:@"music_stop_icon"] forState:UIControlStateNormal];
break;
case UIEventSubtypeRemoteControlStop:
break;
case UIEventSubtypeRemoteControlPlay:
[[HYNEntertainmentController sharedInstance].streamer play];
[sender setBackgroundImage:[UIImage imageNamed:@"music_play_icon"] forState:UIControlStateNormal];
break;
case UIEventSubtypeRemoteControlTogglePlayPause:
break;
case UIEventSubtypeRemoteControlNextTrack:
break;
case UIEventSubtypeRemoteControlPreviousTrack:
break;
default:
break;
}
}
}

整体图片:

上图为未播放

上图为播放中

上图为锁屏时状态

应该没有什么要添加的了,暂时告一段落,有不足之处,可以在下方的留言区讨论,感谢对脚本之家的支持。

更多精彩内容其他人还在看

详解优化iOS程序性能的25个方法

本篇文章主要介绍了优化iOS程序性能的25个方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
收藏 0 赞 0 分享

详解iOS开发中解析JSON中的boolean类型的数据遇到的问题

这篇文章主要介绍了详解iOS开发中解析JSON中的boolean类型的数据遇到的问题,具有一定的参考价值,有兴趣的可以了解一下。
收藏 0 赞 0 分享

iOS中模态Model视图跳转和Push视图跳转的需求实现方法

这篇文章主要介绍了iOS中模态Model视图跳转和Push视图跳转的需求实现,非常不错,具有参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

iOS+PHP注册登录系统 iOS部分(下)

这篇文章主要介绍了iOS+PHP注册登录系统的iOS部分,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

详解iOS - ASIHTTPRequest 网络请求

本篇文章主要介绍了iOS - ASIHTTPRequest 网络请求 ,详细的介绍了 ASIHTTPRequest的使用,具有一定的参考价值,有兴趣的可以了解一下。
收藏 0 赞 0 分享

零基础学习iOS直播之采集

直播的采集由采集的设备(摄像头、话筒)不同分为视频采集和音频采集,本篇文章会分别介绍,需要的朋友一起来看下吧
收藏 0 赞 0 分享

iOS自带动画效果的实例代码

本文给大家分享ios自带动画效果的实现代码,非常不错,具有参考借鉴价值,需要的朋友参考下吧
收藏 0 赞 0 分享

零基础学习iOS直播之播放

对于直播来说,客户端主要做两件事情,推流和播放。本篇主要对播放进行详细介绍,需要的朋友一起来看下吧
收藏 0 赞 0 分享

详解iOS中集成ijkplayer视频直播框架

ijkplayer 是一款做视频直播的框架, 基于ffmpeg, 支持Android和iOS,本文将详细的讲一下在iOS中如何集成ijkplayer, 即便以前从没有接触过,按着下面做也可以集成成功!下面跟着小编一起来看下吧
收藏 0 赞 0 分享

iOS 将系统自带的button改装成上图片下文字的样子

这篇文章主要介绍了 iOS 将系统自带的button改装成上图片下文字的样子,代码是通过继承UIButton,然后再重写layoutSubviews方法,对自带的图片和titleLabel进行重新的layout。下面通过本文给大家分享下实现代码
收藏 0 赞 0 分享
查看更多