当前位置: 首页 > 编程笔记 >

iOS多媒体音频(下)-录音及其播放的实例

笪烨
2023-03-14
本文向大家介绍iOS多媒体音频(下)-录音及其播放的实例,包括了iOS多媒体音频(下)-录音及其播放的实例的使用技巧和注意事项,需要的朋友参考一下

上一篇中总结了iOS中音效和音频播放的最基本使用方法,其中音频的播放控制是使用AVFoundation.framework框架中的AVAudioPlayer播放器对象来实现的,而这里音频的录制则是使用了同样框架下的一个叫AVAudioRecorder的录音机对象来实现,这两个类的用法流程非常类似,类的属性和方法也类似,例如:播放器中需要获取音频文件的url,而录音机要在沙盒中Docuemnt目录下创建一个音频文件路径url;

播放器有isPlaying变量判断是否正在播放,录音机中有isRecording变量表示是否正在录制;currentTime在播放器中表示播放时间,在录音机中则表示录音时间;播放器通过prepareToPlay方法加载文件到缓冲区,录音机通过prepareToRecord创建缓冲区;播放音频有play方法,音频录制有record方法,另外都有pause暂停方法和stop停止方法等等,具体可直接打开两个类的头文件详细了解。

这里实现最基本的录音流程以及录音过程的控制,并通过之前使用的AVAudioPlayer来播放录制好的音频。注意iOS录制的音频为caf格式,如果需要通用化可以通过lame等插件将caf格式音频转成mp3格式。

录音

这里实现开始录音,暂停,继续以及停止录音。

创建文件目录

iOS沙盒内胡要有三个目录:Documents目录,tmp目录以及Library目录,其中Documents目录用来存放用户的应用程序数据,需要定期备份的数据要放在这里,和plist文件存储一样,我们要找到存放文件的路径,然后在该路径下放一个我们的文件,因此要自定义一个带后缀的文件名,将获得的路径和文件名拼在一起记得到我们的文件的绝对路径:

// 文件名
#define fileName_caf @"demoRecord.caf"
// 录音文件绝对路径
@property (nonatomic, copy) NSString *filepathCaf;

// 获取沙盒Document文件路径
NSString *sandBoxPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
// 拼接录音文件绝对路径
_filepathCaf = [sandBoxPath stringByAppendingPathComponent:fileName_caf];

创建音频会话

录音前要创建一个音频会话,同时要设置录音类型,提供的类型有以下几种:

  • AVF_EXPORT NSString *const AVAudioSessionCategoryAmbient; // 用于录制背景声音,像雨声、汽车引擎发动噪音等,可和其他音乐混合
  • AVF_EXPORT NSString *const AVAudioSessionCategorySoloAmbient; // 也是背景声音,但其他音乐会被强制停止
  • AVF_EXPORT NSString *const AVAudioSessionCategoryPlayback; // 音轨
  • AVF_EXPORT NSString *const AVAudioSessionCategoryRecord; // 录音
  • AVF_EXPORT NSString *const AVAudioSessionCategoryPlayAndRecord; // 录音和回放
  • AVF_EXPORT NSString *const AVAudioSessionCategoryAudioProcessing; // 用于底层硬件编码信号处理等
  • AVF_EXPORT NSString *const AVAudioSessionCategoryMultiRoute; // 内置硬件相关,iOS 6.0以上可用

常用的是AVAudioSessionCategoryPlayAndRecord类型,便于录音后播放。

// 创建音频会话
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
// 设置录音类别(这里选用录音后可回放录音类型)
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[audioSession setActive:YES error:nil];

录音设置

录音前要根据需要对录音进行一些相应的基本设置,例如录音格式(LinearPCM)、采样率、通道数等等,设置保存在一个字典内并作为初始化录音机的一个参数。

// 录音设置
-(NSDictionary *)getAudioSetting{
  // LinearPCM 是iOS的一种无损编码格式,但是体积较为庞大
  // 录音设置信息字典
  NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];
  // 录音格式
  [recordSettings setValue :@(kAudioFormatLinearPCM) forKey: AVFormatIDKey];
  // 采样率
  [recordSettings setValue :@11025.0 forKey: AVSampleRateKey];
  // 通道数(双通道)
  [recordSettings setValue :@2 forKey: AVNumberOfChannelsKey];
  // 每个采样点位数(有8、16、24、32)
  [recordSettings setValue :@16 forKey: AVLinearPCMBitDepthKey];
  // 采用浮点采样
  [recordSettings setValue:@YES forKey:AVLinearPCMIsFloatKey];
  // 音频质量
  [recordSettings setValue:@(AVAudioQualityMedium) forKey:AVEncoderAudioQualityKey];
  // 其他可选的设置
  // ... ...

  return recordSettings;
}

创建录音机对象

录音机对象的创建主要是利用上面的保存路径和录音设置进行初始化得到:

// 懒加载录音机对象get方法
- (AVAudioRecorder *)audioRecorder {
  if (!_audioRecorder) {
    // 保存录音文件的路径url
    NSURL *url = [NSURL URLWithString:_filepathCaf];
    // 创建录音格式设置setting
    NSDictionary *setting = [self getAudioSetting];
    // error
    NSError *error=nil;

    _audioRecorder = [[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
    _audioRecorder.delegate = self;
    _audioRecorder.meteringEnabled = YES;// 监控声波
    if (error) {
      NSLog(@"创建录音机对象时发生错误,错误信息:%@",error.localizedDescription);
      return nil;
    }
  }
  return _audioRecorder;
}

录音控制方法

录音过程控制主要是开始录音、暂停、继续和停止录音,其中开始录音和继续录音都是record方法。

// 开始录音或者继续录音
- (IBAction)startOrResumeRecord {
  // 注意调用audiorecorder的get方法
  if (![self.audioRecorder isRecording]) {
    // 如果该路径下的音频文件录制过则删除
    [self deleteRecord];
    // 开始录音,会取得用户使用麦克风的同意
    [_audioRecorder record];
  }
}

// 录音暂停
- (IBAction)pauseRecord {
  if (_audioRecorder) {
    [_audioRecorder pause];
  }
}

// 结束录音
- (IBAction)stopRecord {
  [_audioRecorder stop];
}

录音播放

录音的播放很简单,就是之前AVAudioPlayer音频播放的简单应用,播放的路径即我们录音时创建好的音频路径。但这里注意为了保证每次都播放最新录制的音频,播放器的get方法要每次重新创建初始化。

// audioPlayer懒加载getter方法
- (AVAudioPlayer *)audioPlayer {
  _audioRecorder = NULL; // 每次都创建新的播放器,删除旧的

  // 资源路径
  NSURL *url = [NSURL fileURLWithPath:_filepathCaf];

  // 初始化播放器,注意这里的Url参数只能为本地文件路径,不支持HTTP Url
  NSError *error = nil;
  _audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];

  //设置播放器属性
  _audioPlayer.numberOfLoops = 0;// 不循环
  _audioPlayer.delegate = self;
  _audioPlayer.volume = 0.5; // 音量
  [_audioPlayer prepareToPlay];// 加载音频文件到缓存【这个函数在调用play函数时会自动调用】

  if(error){
    NSLog(@"初始化播放器过程发生错误,错误信息:%@",error.localizedDescription);
    return nil;
  }

  return _audioPlayer;
}

// 播放录制好的音频
- (IBAction)playRecordedAudio {
  // 没有文件不播放
  if (![[NSFileManager defaultManager] fileExistsAtPath:self.filepathCaf]) return;
  // 播放最新的录音
  [self.audioPlayer play];
}

完整源码和Demo下载

//
// ViewController.m
// IOSRecorderDemo
//
// Created by Xinhou Jiang on 29/12/16.
// Copyright © 2016年 Xinhou Jiang. All rights reserved.
//

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>

// 文件名
#define fileName_caf @"demoRecord.caf"

@interface ViewController ()

// 录音文件绝对路径
@property (nonatomic, copy) NSString *filepathCaf;
// 录音机对象
@property (nonatomic, strong) AVAudioRecorder *audioRecorder;
// 播放器对象,和上一章音频播放的方法相同,只不过这里简单播放即可
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
// 用一个processview显示声波波动情况
@property (nonatomic, weak) IBOutlet UIProgressView *processView;
// 用一个label显示录制时间
@property (nonatomic, weak) IBOutlet UILabel *recordTime;
// UI刷新监听器
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // 初始化工作
  [self initData];
}

// 初始化
- (void)initData {
  // 获取沙盒Document文件路径
  NSString *sandBoxPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
  // 拼接录音文件绝对路径
  _filepathCaf = [sandBoxPath stringByAppendingPathComponent:fileName_caf];

  // 1.创建音频会话
  AVAudioSession *audioSession=[AVAudioSession sharedInstance];
  // 设置录音类别(这里选用录音后可回放录音类型)
  [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
  [audioSession setActive:YES error:nil];

  // 2.开启定时器
  [self timer];
}

#pragma mark -录音设置工具函数
// 懒加载录音机对象get方法
- (AVAudioRecorder *)audioRecorder {
  if (!_audioRecorder) {
    // 保存录音文件的路径url
    NSURL *url = [NSURL URLWithString:_filepathCaf];
    // 创建录音格式设置setting
    NSDictionary *setting = [self getAudioSetting];
    // error
    NSError *error=nil;

    _audioRecorder = [[AVAudioRecorder alloc]initWithURL:url settings:setting error:&error];
    _audioRecorder.delegate = self;
    _audioRecorder.meteringEnabled = YES;// 监控声波
    if (error) {
      NSLog(@"创建录音机对象时发生错误,错误信息:%@",error.localizedDescription);
      return nil;
    }
  }
  return _audioRecorder;
}

// audioPlayer懒加载getter方法
- (AVAudioPlayer *)audioPlayer {
  _audioRecorder = NULL; // 每次都创建新的播放器,删除旧的

  // 资源路径
  NSURL *url = [NSURL fileURLWithPath:_filepathCaf];

  // 初始化播放器,注意这里的Url参数只能为本地文件路径,不支持HTTP Url
  NSError *error = nil;
  _audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:url error:&error];

  //设置播放器属性
  _audioPlayer.numberOfLoops = 0;// 不循环
  _audioPlayer.delegate = self;
  _audioPlayer.volume = 0.5; // 音量
  [_audioPlayer prepareToPlay];// 加载音频文件到缓存【这个函数在调用play函数时会自动调用】

  if(error){
    NSLog(@"初始化播放器过程发生错误,错误信息:%@",error.localizedDescription);
    return nil;
  }

  return _audioPlayer;
}

// 计时器get方法
- (NSTimer *)timer {
  if (!_timer) {
    _timer = [NSTimer scheduledTimerWithTimeInterval:0.1f repeats:YES block:^(NSTimer * _Nonnull timer) {
      if(_audioRecorder) {
        // 1.更新录音时间,单位秒
        int curInterval = [_audioRecorder currentTime];
        _recordTime.text = [NSString stringWithFormat:@"%02d:%02d",curInterval/60,curInterval%60];
        // 2.声波显示
        //更新声波值
        [self.audioRecorder updateMeters];
        //第一个通道的音频,音频强度范围:[-160~0],这里调整到0~160
        float power = [self.audioRecorder averagePowerForChannel:0] + 160;
        [_processView setProgress:power/160.0];
      }
    }];
  }
  return _timer;
}

// 录音设置
-(NSDictionary *)getAudioSetting{
  // LinearPCM 是iOS的一种无损编码格式,但是体积较为庞大
  // 录音设置信息字典
  NSMutableDictionary *recordSettings = [[NSMutableDictionary alloc] init];
  // 录音格式
  [recordSettings setValue :@(kAudioFormatLinearPCM) forKey: AVFormatIDKey];
  // 采样率
  [recordSettings setValue :@11025.0 forKey: AVSampleRateKey];
  // 通道数(双通道)
  [recordSettings setValue :@2 forKey: AVNumberOfChannelsKey];
  // 每个采样点位数(有8、16、24、32)
  [recordSettings setValue :@16 forKey: AVLinearPCMBitDepthKey];
  // 采用浮点采样
  [recordSettings setValue:@YES forKey:AVLinearPCMIsFloatKey];
  // 音频质量
  [recordSettings setValue:@(AVAudioQualityMedium) forKey:AVEncoderAudioQualityKey];
  // 其他可选的设置
  // ... ...

  return recordSettings;
}

// 删除filepathCaf路径下的音频文件
-(void)deleteRecord{
  NSFileManager* fileManager=[NSFileManager defaultManager];
  if ([[NSFileManager defaultManager] fileExistsAtPath:self.filepathCaf]) {
    // 文件已经存在
    if ([fileManager removeItemAtPath:self.filepathCaf error:nil]) {
      NSLog(@"删除成功");
    }else {
      NSLog(@"删除失败");
    }
  }else {
    return; // 文件不存在无需删除
  }
}

#pragma mark -录音流程控制函数
// 开始录音或者继续录音
- (IBAction)startOrResumeRecord {
  // 注意调用audiorecorder的get方法
  if (![self.audioRecorder isRecording]) {
    // 如果该路径下的音频文件录制过则删除
    [self deleteRecord];
    // 开始录音,会取得用户使用麦克风的同意
    [_audioRecorder record];
  }
}

// 录音暂停
- (IBAction)pauseRecord {
  if (_audioRecorder) {
    [_audioRecorder pause];
  }
}

// 结束录音
- (IBAction)stopRecord {
  [_audioRecorder stop];
}

#pragma mark -录音播放
// 播放录制好的音频
- (IBAction)playRecordedAudio {
  // 没有文件不播放
  if (![[NSFileManager defaultManager] fileExistsAtPath:self.filepathCaf]) return;
  // 播放最新的录音
  [self.audioPlayer play];
}

@end

Demo下载:demo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。

 类似资料:
  • 我正在开发一个包含一些音频播放器的RecyclerView的应用程序。应用程序将下载。3gp文件(如果尚未下载)。 当我单击playAudio按钮时,音频未被播放。 这是我的适配器代码: 我怎样才能解决这个问题?

  • 我正在使用Android Media Player从我的服务器播放音乐。可以使用MediaPlayer将播放音频保存到存储吗?

  • 本文向大家介绍Android实现多媒体之播放音乐,包括了Android实现多媒体之播放音乐的使用技巧和注意事项,需要的朋友参考一下 闲来无聊,最近了解了一下多媒体的一些初步知识。 音频播放主要设计到MediaPlayer这个类,播放音频的路径可以来源于三个地方。 1.应用内的音频 2.  播放内存卡里的音乐,这一部分代码就是替换前面的mediaPlayer = MediaPlayer.create

  • 大家好,我正在尝试使用两个独立的媒体播放器实例播放音频和视频文件。当我从一开始播放它时,它工作得很好。但当我寻找时,我可以看到音频和视频的延迟 这是我寻找音频和视频的代码 //sikAudio(msec); if(media播放器!=null) { // 没有直播流,如果(medialayer.get持续时间() }

  • 本文向大家介绍Android多媒体应用使用MediaPlayer播放音频,包括了Android多媒体应用使用MediaPlayer播放音频的使用技巧和注意事项,需要的朋友参考一下 Android提供了对常用音频和视频格式的支持,它所支持的音频格式有MP3(.mp3)、3GPP(.3gp)、Ogg(.ogg)和WAVE(.ave)等,支持的视频格式有3GPP(.3gp)和MPEG-4(.mp4)等。

  • 多媒体 HTML5 前的多媒体需要借助第三方插件,例如 Flash,但是 HTML5 将网页中的多媒体带入了新的一章。 基本用法 // 音频 // 指定资源类型可以帮助浏览器更快的定位解码 <audio autobuffer autoloop loop controls> <source src="/media/audio.mp3" type="audio/mpeg"> <source s