我的博客:http://blog.csdn.net/nsydianzi
1.短音频
C语言方法:导入AudioToolbox/AudioToolbox.h库
思路步骤:
第一步:获取音频文件的url,并且定义一个音频ID(SystemSoundID由系统自动提供)
第二步:加载对应的音频文件到内存,并对应上音频ID
第三步:播放音频
//音频文件的URL
NSURL *soundUrl = [[NSBundle mainBundle] URLForResource:@"/plane.bundle/enemy1_down.mp3" withExtension:nil];
//音频ID,一个音频文件对应一个soundID
SystemSoundID soundId;
NSLog(@"%d",soundId);
//加载了音频文件到内存
AudioServicesCreateSystemSoundID((__bridge CFURLRef)soundUrl, &soundId);
//播放音频
AudioServicesPlaySystemSound(soundId);
可以抽取一个播放类,用来播放音乐,这个类最好是一个单例,不然音频文件加载太多次,会有内存问题
+(void)initialize{ //加载这个类时,自动将短音频加载进内存
//1.加载所有音频文件
//1.1 遍历plane.bundle的所有音频文件
NSFileManager *manager = [NSFileManager defaultManager];
//1.2获取plane.bundle的路径
NSString *planePath = [[NSBundle mainBundle] pathForResource:@"plane.bundle" ofType:nil];
NSError *error = nil;
NSArray *contents = [manager contentsOfDirectoryAtPath:planePath error:&error];
NSLog(@"%@",contents);
//1.3 遍历里面的mp3文件,创建SystemSoundID
NSMutableDictionary *soundDictM = [NSMutableDictionary dictionary];
for (NSString *mp3Name in contents) {
//音频文件的URL
NSString *soundUrlStr = [planePath stringByAppendingPathComponent:mp3Name];
NSURL *soundUrl = [NSURL fileURLWithPath:soundUrlStr];
//音频ID,一个音频文件对应一个soundID
SystemSoundID soundId;
AudioServicesCreateSystemSoundID((__bridge CFURLRef)(soundUrl), &soundId);
//1.4通过字典存储soundID @{"enemy1_down.mp3":11111,"enemy2_down.mp3",11112}
soundDictM[mp3Name] = @(soundId);
}
NSLog(@"%@",soundDictM);
soundDict = soundDictM;
}
//2.给一个方法播放音频文件
-(void)playMp3WithName:(NSString *)mp3Name{ //调用这个公开的方法播放音乐
//通过键值获取soundId
SystemSoundID soundId = [soundDict[mp3Name] unsignedIntValue];
//播放
AudioServicesPlaySystemSound(soundId);
//振动
//AudioServicesPlayAlertSound(<#SystemSoundID inSystemSoundID#>)
}
2.长音频播放
使用系统提供的OC库,AVFoundation
播放思路:
1. 从mainBundle中获取音频的url
创建一个AVAdioPlayer对象,这就是一个播放器对象,音频的播放由这个对象控制
2.player对象准备播放,调用prepareToPlay播放
3.播放,暂停,停止
[self.player play]; //播放
[self.player pause]; //暂停
[self.player stop]; //停止,停止方法需要将播放的当前时间置0.//self.player.currentTime = 0;
- 这里解释pause和stop方法的区别,调用stop之后虽然是要将当前的时间置为0,但是他们的底层调用方法是不一样的,调用stop方法是会撤销prepareToPlay做的设置,而调用pause方法不会撤销。
- 说明白点就是,调用stop之后,要重新播放音乐的话需要重新设置prepareToPlay方法。而pause不是的。
@property BOOL enableRate;//如果你想设置音频播放的速率,你应该将这个属性设置为yes,并且你必须在发送
prepareToPlay这个消息之前.这句是我直接翻译的苹果官方的解释,但是我发现即使我在prepareToPlay方法后面设置也没问题,不知是什么原因.
- 2016-1-23 AVFoudation开发秘籍 第24页
- 解释:
- prepareToPlay 在AVAdioPlayer调用paly这个方法的时候会隐性的调用prepareToPlay这个方法,但是如果自己显式的调用这个方法 可以降低调用play方法时和听到输出声音之间的延时。
@property NSInteger numberOfLoops;//设置音频要播放的次数,如果你设置为0,就会播放1次,设置为1,就会播放2次.并且如果是负数,将会一直播放,知道你停止这段音频;
@property NSTimeInterval currentTime;//音频当前播放的时间
//监听音乐的中断
AVAudioSession *session = [AVAudioSession sharedInstance];
[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(handleInterruption:)name:AVAudioSessionInterruptionNotification object:session];
-(void)handleInterruption:(NSNotification *)noti
{
NSLog(@"%@",noti.userInfo);
}
// AVAudioSessionInterruptionTypeKey = 1 //开始中断
// AVAudioSessionInterruptionTypeKey = 0 //结束中断
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController ()<AVAudioPlayerDelegate>
@property (weak, nonatomic) IBOutlet UISlider *timeSlider;
@property(nonatomic,strong)AVAudioPlayer *player;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//获取mp3路径
NSURL *mp3Url = [[NSBundle mainBundle] URLForResource:@"bbqne.mp3" withExtension:nil];
//播放音乐
NSError *error = nil;
// 1.创建一个音乐播放器
AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:mp3Url error:&error];
if (error) {
NSLog(@"%@",error);
}
// 2.准备播放
[player prepareToPlay];
// 打开可以改变速度的开头
player.enableRate = YES;
// 播放次数
player.numberOfLoops = 0;//0代表播放一次 1代表播放2次
player.delegate = self;
self.player = player;
//设置timeSlider的最大值
self.timeSlider.maximumValue = self.player.duration;
//监听音乐的中断
AVAudioSession *session = [AVAudioSession sharedInstance];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:session];
}
/**
* 处理中断
*/
-(void)handleInterruption:(NSNotification *)noti{
NSLog(@"%@",noti.userInfo);
}
- (IBAction)stopBtnClick:(id)sender {
[self.player stop];
//自己指定播放的时候到0的位置
self.player.currentTime = 0;
}
- (IBAction)playBtnClick:(id)sender {
// 3.播放
[self.player play];
}
- (IBAction)pauseBtnClick:(id)sender {
[self.player pause];
}
/**
* 播放时间变化
*
*/
- (IBAction)timeChange:(UISlider *)sender {
NSLog(@"时间变化:%f",sender.value);
self.player.currentTime = sender.value;
}
/**
* 播放速度变化
*
*/
- (IBAction)rateChange:(UISlider *)sender {
self.player.rate = sender.value;
}
/*
*播放音量的改变
*/
- (IBAction)volumnChange:(UISlider *)sender {
self.player.volume = sender.value;
}
#pragma mark - AVAuidoPalyer的代理
#pragma mark 音乐播放完成后调用
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
NSLog(@"%s",__func__);
}
@end
如果要做歌词显示,这里提供个思路
1.首先设置一个定时器,这里可以用懒加载,给定时器关联一个方法.
2.关联的方法中倒序遍历歌词,判断当前时间是否是大于歌词模型中的播放时间,如果是的话,执行选中cell的方法.
3.将定时器加入到当前的runloop中
4.音频播放完成后,将定时器移除.
@property(nonatomic,strong)CADisplayLink *link;//定时器
-(CADisplayLink *)link{
if (!_link) {
_link = [CADisplayLink displayLinkWithTarget:selfselector:@selector(update)];
}
return _link;
}
[self.link addToRunLoop:[NSRunLoop mainRunLoop]forMode:NSDefaultRunLoopMode];
/**
* 刷新诗词 读 的进度
*/
-(void)update{
double currentTime = self.wordsPlayer.currentTime;
NSLog(@"当前播放的时间 %lf",currentTime);
//倒序遍历诗词
//self.words -> CZWord
//总的"句数"
NSInteger numberOfWord = self.words.count;
//诗词最大的索引
NSInteger maxIndex = numberOfWord - 1;
for (NSInteger i = maxIndex; i >=0 ; i--) {
//获取遍历的诗词
CZWord *word = self.words[i];
if (currentTime >= word.time) {
NSLog(@"当前诗词的索引为 %ld",i);
[self selectedCellWithIndex:i];
break;
}
}
}
/**
* 选中表格
*
*/
-(void)selectedCellWithIndex:(NSInteger)index{
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:indexinSection:0];
//选中
[self.tableView selectRowAtIndexPath:indexPath animated:NOscrollPosition:UITableViewScrollPositionMiddle];
}
#pragma mark AudioPlayer代理
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
//当诗词播放完成后,背景音乐停止
[self.bgMusicPalyer stop];
//定时器也要移除
[self.link removeFromRunLoop:[NSRunLoop mainRunLoop]forMode:NSDefaultRunLoopMode];
}
录音Record
同样要用到AVFoundation中的对象AVAudioRecorder
步骤也简单:
1:设置音频文件保存的路径
2:创建一个字典对象,将录音的设置保存进去,例如,音频编码格式,采样频率,音频频道,线性音频的位深度
//setting 录音时的设置
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
//音频编码格式
settings[AVFormatIDKey] = @(kAudioFormatAppleIMA4);
//音频采样频率
settings[AVSampleRateKey] = @(8000.0);
//音频频道
settings[AVNumberOfChannelsKey] = @(1);
//音频线性音频的位深度
settings[AVLinearPCMBitDepthKey] = @(8);
3.创建录音器对象AVAudioRecorder,将路径和设置初始化
4.准备录音和开始录音
5.结束录音
/**
* 开始录音
*
*/
- (IBAction)startRecord:(UIButton *)sender {
NSLog(@"%s",__func__);
//1.创建录音器
//1.1URL 是录音文件保存的地址
//音频文件保存在沙盒 document/20150228171912.caf
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = @"yyyyMMddHHmmss";
NSString *timeStr = [dateFormatter stringFromDate:[NSDate date]];
//音频文件名
NSString *audioName = [timeStr stringByAppendingString:@".caf"];
//doc目录
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
//拼接音频URL
NSString *fileURL = [doc stringByAppendingPathComponent:audioName];
NSLog(@"%@",fileURL);
//保存文件路径到数组
[self.data addObject:fileURL];
//setting 录音时的设置
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
//音频编码格式
settings[AVFormatIDKey] = @(kAudioFormatAppleIMA4);
//音频采样频率
settings[AVSampleRateKey] = @(8000.0);
//音频频道
settings[AVNumberOfChannelsKey] = @(1);
//音频线性音频的位深度
settings[AVLinearPCMBitDepthKey] = @(8);
self.recorder = [[AVAudioRecorder alloc] initWithURL:[NSURL fileURLWithPath:fileURL] settings:settings error:nil];
//录音的准备
[self.recorder prepareToRecord];
//录音
[self.recorder record];
}
设置音乐的后台播放需要如下设置
1.在didFinishLaunching方法激活音频的会话类型即可
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
//设置音乐后台播放的会话类型
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil];
return YES;
}
2.在applicationDidEnterBackground方法开始后台任务,代码如下
- (void)applicationDidEnterBackground:(UIApplication *)application {
//开启后台任务
[application beginBackgroundTaskWithExpirationHandler:nil];
}
3.在info.plist中添加'Required background modes'选向,然后再添加'App plays audio or streams audio/video using AirPlay'