ios android mid音频文件,iOS 录音 音频 视频 控制中心

录音

最近项目中需要录音功能,为此在写了一个录音的小模块。

首先需要添加AVFoundation.framework

lame.h 帮助链接

下面直接上代码

#import

#import

#import

typedef void(^AudioModelBlock)(NSInteger duration);

@protocol AudioModelDelegate

- (void)recordResult:(NSString *)path error:(NSError *)error;

@end

@interface AudioModel : NSObject {

AVAudioRecorder *_audioRecorder;

AVAudioPlayer *_audioPlayer;

NSTimer *_timer;

NSString *_name;

}

@property (nonatomic, assign) NSInteger duration;

@property (nonatomic, copy) AudioModelBlock block;

@property (nonatomic, assign) id delegate;

#pragma mark - record

//开始录音 或 恢复录音

- (void)record;

//暂停录音

- (void)pauseRecotd;

//停止录音

- (void)stopRecord;

#pragma mark - play

//播放录音

- (void)playRecord:(NSString *)path;

#pragma mark - file

//移除录音

- (void)removeFile;

#import "AudioModel.h"

#import "lame.h"

@implementation AudioModel

- (instancetype)init {

self = [super init];

if (self) {

}

return self;

}

#pragma mark - setting

//获取录音文件设置

- (NSDictionary *)getAudioSetting {

NSMutableDictionary *dicM = [NSMutableDictionary dictionary];

//设置录音格式

[dicM setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];

//设置录音采样率

[dicM setObject:@(20000) forKey:AVSampleRateKey];

//设置通道,这里采用单声通道

[dicM setObject:@(2) forKey:AVNumberOfChannelsKey];

// //每个采样点位数,8,16,24,32

// [dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];

// [dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];

//音频编码质量

[dicM setObject:@(AVAudioQualityMedium) forKey:AVEncoderAudioQualityKey];

//其他

return dicM;

}

#pragma mark - path

- (NSString *)getBasePath {

NSString *urlStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];

urlStr = [urlStr stringByAppendingPathComponent:[YLSaveObjectToLocal loadObjectForKey:@"userMid"]];

urlStr = [urlStr stringByAppendingPathComponent:[YLCoreTool getNowWithFormatter:@"yyyyMMdd"]];

NSFileManager *fileManager = [NSFileManager defaultManager];

if ([fileManager fileExistsAtPath:urlStr]) {

}

else {

[fileManager createDirectoryAtPath:urlStr withIntermediateDirectories:YES attributes:nil error:nil];

}

return urlStr;

}

//获取录音文件保存路径

- (NSString *)getSavePath {

NSString *urlStr = [self getBasePath];

urlStr = [urlStr stringByAppendingPathComponent:_name];

urlStr = [urlStr stringByAppendingString:@".caf"];

return urlStr;

}

- (NSString *)getMp3FilePath {

NSString *urlStr = [self getBasePath];

urlStr = [urlStr stringByAppendingPathComponent:_name];

urlStr = [urlStr stringByAppendingString:@".mp3"];

return urlStr;

}

- (void)removeFile {

NSString *urlStr = [self getBasePath];

urlStr = [urlStr stringByAppendingPathComponent:_name];

NSFileManager *fileManager = [NSFileManager defaultManager];

NSArray *arr = @[@".caf",@".mp3"];

for (NSString *type in arr) {

NSString *path = [urlStr stringByAppendingString:type];

if ([fileManager fileExistsAtPath:path]) {

[fileManager removeItemAtPath:path error:nil];

}

}

}

#pragma mark - action

//开始录音 或 恢复录音

- (void)record {

_name = [YLCoreTool getNowWithFormatter:@"yyyyMMdd_HHmmss"];

//创建录音文件保存路径

NSURL *url = [NSURL URLWithString: [self getSavePath]];

//创建录音格式设置

NSDictionary *setting = [self getAudioSetting];

//设置音频会话 不然不录制

AVAudioSession *audioSession = [AVAudioSession sharedInstance];

//设置为播放和录音状态,以便可以在录制完之后播放录音

[audioSession setCategory:AVAudioSessionCategoryRecord error:nil];

[audioSession setActive:YES error:nil];

//创建录音机

NSError *error = nil;

_audioRecorder = [[AVAudioRecorder alloc] initWithURL:url settings:setting error:&error];

_audioRecorder.delegate = self;

if (error) {

NSLog(@"creat audioRecorder error:%@", error.localizedDescription);

} else {

if (![_audioRecorder isRecording]) {

if ([_audioRecorder prepareToRecord]) {

if ([_audioRecorder record]) {

self.timer.fireDate = [NSDate distantPast];

}

}

}

}

}

//暂停录音

- (void)pauseRecotd {

if ([_audioRecorder isRecording]) {

[_audioRecorder pause];

self.timer.fireDate = [NSDate distantFuture];

}

}

//停止录音

- (void)stopRecord {

[_audioRecorder stop];

self.timer.fireDate = [NSDate distantFuture];

}

//计时器计时

- (void)handleTimerAction {

self.duration = _audioRecorder.currentTime;

}

//播放录音

- (void)playRecord:(NSString *)path {

//播放声音小时可以设置

AVAudioSession *audioSession = [AVAudioSession sharedInstance];

[audioSession setCategory :AVAudioSessionCategoryPlayback error:nil];

[audioSession setActive:YES error:nil];

NSURL *url = [NSURL URLWithString: path];

NSError *error = nil;

_audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];

_audioPlayer.numberOfLoops = 0;

_audioPlayer.delegate = self;

[_audioPlayer prepareToPlay];

if (error) {

NSLog(@"creat audioPlayer error: %@", error.localizedDescription);

}

else {

[_audioPlayer play];

}

}

- (void)playAVItem {

}

#pragma mark - AVAudioRecorderDelegate

- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error {

if (error) {

NSLog(@"%@",error.localizedDescription);

}

}

- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag {

NSLog(@"录制完成");

[self convertToMp3];

_audioRecorder = nil;

}

#pragma mark - AVAudioPlayerDelegate

- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {

_audioPlayer = nil;

}

#pragma mark - tool

- (void)convertToMp3

{

NSString *filePath = [self getMp3FilePath];

@try {

int read,write;

//只读方式打开被转换音频文件

FILE *pcm = fopen([[self getSavePath] cStringUsingEncoding:1], "rb");

fseek(pcm, 4 * 1024, SEEK_CUR);//删除头,否则在前一秒钟会有杂音

//只写方式打开生成的MP3文件

FILE *mp3 = fopen([filePath cStringUsingEncoding:1], "wb");

const int PCM_SIZE = 8192;

const int MP3_SIZE = 8192;

short int pcm_buffer[PCM_SIZE * 2];

unsigned char mp3_buffer[MP3_SIZE];

//这里要注意,lame的配置要跟AVAudioRecorder的配置一致,否则会造成转换不成功

lame_t lame = lame_init();

lame_set_VBR(lame, vbr_default);

lame_set_num_channels(lame,2);//默认为2双通道

lame_set_in_samplerate(lame, 20000);//11025.0

lame_set_brate(lame,8);

lame_set_mode(lame,3);

lame_set_quality(lame,5); /* 2=high 5 = medium 7=low 音质*/

lame_init_params(lame);

do {

//以二进制形式读取文件中的数据

read = (int)fread(pcm_buffer, 2 * sizeof(short int), PCM_SIZE, pcm);

if (read == 0)

write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);

else

write = lame_encode_buffer_interleaved(lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);

//二进制形式写数据到文件中 mp3_buffer:数据输出到文件的缓冲区首地址 write:一个数据块的字节数 1:指定一次输出数据块的个数 mp3:文件指针

fwrite(mp3_buffer, write, 1, mp3);

} while (read != 0);

lame_close(lame);

fclose(mp3);

fclose(pcm);

} @catch (NSException *exception) {

NSLog(@"%@",[exception description]);

} @finally {

NSLog(@"MP3生成成功!!!");

if ([self.delegate respondsToSelector:@selector(recordResult:error:)]) {

[self.delegate recordResult:[self getMp3FilePath] error:nil];

}

}

}

#pragma mark - set and get

- (void)setDuration:(NSInteger)duration {

_duration = duration;

if (self.block) {

self.block(_duration);

}

}

-(NSTimer *)timer{

if (!_timer) {

_timer=[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(handleTimerAction) userInfo:nil repeats:YES];

}

return _timer;

}

/**

* 录音声波状态设置

*/

// _audioRecorder.meteringEnabled = YES;//如果需要监控声波则必须设置为YES

//-(void)audioPowerChange{

// [self.audioRecorder updateMeters];//更新测量值

// float power= [self.audioRecorder averagePowerForChannel:0];//取得第一个通道的音频,注意音频强度范围时-160到0

// CGFloat progress=(1.0/160.0)*(power+160.0);

// [self.audioPower setProgress:progress];

//}

// 获取音频时长

//AVURLAsset* audioAsset =[AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:self.savePath] options:nil];

//CMTime audioDuration = audioAsset.duration;

//float audioDurationSeconds = CMTimeGetSeconds(audioDuration);

音频和视频

音频和视频播放使用的ZFPlayer,有兴趣的话可以自己研究下

控制中心 后台播放

需要打开相应的Background Models

294455c995bb?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

屏幕快照 2018-08-20 下午5.23.51.png

AppDelegate 中

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

//处理中断事件的通知 播放

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterreption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];

//开启后台处理多媒体事件

[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

return YES;

}

//处理中断事件

-(void)handleInterreption:(NSNotification *)sender

{

ZFPlayerView *player = [ZFPlayerView sharedPlayerView];

if(player.state == ZFPlayerStatePause)

{

[player play];

}

else

{

[player pause];

}

}

- (void)applicationDidEnterBackground:(UIApplication *)application {

//ZFPlayerView会监听UIApplicationWillResignActiveNotification,自动关闭后台播放

//这里是重新打开

[self handleInterreption:nil];

}

//控制中心操作

- (void)remoteControlReceivedWithEvent:(UIEvent *)event {

if (event.type == UIEventTypeRemoteControl) {

NSInteger order = -1;

switch (event.subtype) {

case UIEventSubtypeRemoteControlPause:

order = UIEventSubtypeRemoteControlPause;

break;

case UIEventSubtypeRemoteControlPlay:

order = UIEventSubtypeRemoteControlPlay;

break;

case UIEventSubtypeRemoteControlNextTrack:

order = UIEventSubtypeRemoteControlNextTrack;

break;

case UIEventSubtypeRemoteControlPreviousTrack:

order = UIEventSubtypeRemoteControlPreviousTrack;

break;

case UIEventSubtypeRemoteControlTogglePlayPause:

order = UIEventSubtypeRemoteControlTogglePlayPause;

break;

default:

order = -1;

break;

}

NSDictionary *dict = @{@"order":@(order)};

[[NSNotificationCenter defaultCenter] postNotificationName:@"kAppDidReceiveRemoteControlNotification" object:nil userInfo:dict];

}

}

控制文件中,如ViewController等

这里需要添加MediaPlayer.framework

#import

//监听控制中心事件

- (void)viewDidLoad {

[super viewDidLoad];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(listeningRemoteControl:) name:@"kAppDidReceiveRemoteControlNotification" object:nil];

}

//model 为自己定义

//播放时调用此函数更新控制中心

- (void)setNowPlayingInfo:(Model *)model {

NSMutableDictionary *songDict = [NSMutableDictionary dictionary];

//歌名

[songDict setObject:model.title forKey:MPMediaItemPropertyTitle];

//歌手名

[songDict setObject:AppName forKey:MPMediaItemPropertyArtist];

//总时长

[songDict setObject:[NSNumber numberWithInt:[model.time intValue] * 60] forKey:MPMediaItemPropertyPlaybackDuration];

//图片

MPMediaItemArtwork *imageItem = [[MPMediaItemArtwork alloc] initWithImage:[UIImage imageNamed:[NSString stringWithFormat:@"%@Logo", PREFIX_NAME]]];

[songDict setObject:imageItem forKey:MPMediaItemPropertyArtwork];

[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:songDict];

}

//控制中心事件操作

-(void)listeningRemoteControl:(NSNotification *)sender

{

NSDictionary *dict=sender.userInfo;

NSInteger order = [[dict objectForKey:@"order"] integerValue];

switch (order) {

//暂停

case UIEventSubtypeRemoteControlPause:

[self.playerView pause];

break;

//播放

case UIEventSubtypeRemoteControlPlay:

[self.playerView play];

break;

//暂停播放切换

case UIEventSubtypeRemoteControlTogglePlayPause:

{

if(self.playerView.state == ZFPlayerStatePause)

{

[self.playerView play];

}

else

{

[self.playerView pause];

}

break;

}

//下一首

case UIEventSubtypeRemoteControlNextTrack:

{

NSInteger index = [self.models indexOfObject:self.currentModel];

index = index + 1;

if (index < self.models.count) {

//这里是用于等待界面渲染

[NSTimer scheduledTimerWithTimeInterval:0.02 repeats:NO block:^(NSTimer * timer) {

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:index];

[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];

}];

}

break;

}

//上一首

case UIEventSubtypeRemoteControlPreviousTrack:

{

NSInteger index = [self.models indexOfObject:self.currentModel];

index = index - 1;

if (index >= 0) {

if (index < self.models.count) {

[NSTimer scheduledTimerWithTimeInterval:0.02 repeats:NO block:^(NSTimer * timer) {

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:index];

[self tableView:self.tableView didSelectRowAtIndexPath:indexPath];

}];

}

}

break;

}

default:

break;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值