iOS開發之音頻播放、錄音

來源:互聯網
上載者:User

標籤:

iOS的音頻播放可以分為短音頻播放(例如:音效等點綴音頻)和長音頻播放(例:音樂等主音頻)。前者不需要對進度、迴圈等進行控制,而後者需要精確的控制。在iOS中播放這兩種音頻分別使用AudioToolbox.framework和AVFoundation.framework來完成。

短音頻音效

AudioToolbox.framework是一套基於C語言的架構,使用它來播放音效其本質是將短音頻註冊到系統聲音服務(System Sound Service)。System Sound Service是一種簡單、底層的聲音播放服務,但是它本身也存在著一些限制:

  • No longer than 30 seconds in duration(播放時間小於30s)

  • In linear PCM or IMA4 (IMA/ADPCM) format(資料必須是pcm或者ima4格式的)

  • Packaged in a .caf.aif, or .wav file(音頻檔案必須打包成.caf,.aif,.wav檔案)

使用System Sound Service 播放音效的步驟如下(封裝成一個播放短音訊工具類):

+ (void)initialize {    // 載入所有音頻檔案    // 1.遍曆所有的plane.bundle的所有的音頻檔案    NSFileManager *manage = [NSFileManager defaultManager];        // 2.獲了plane.bundle的路徑    NSString *planePath   = [[NSBundle mainBundle] pathForResource:@"plane.bundle" ofType:nil];        NSArray *contents     = [manage contentsOfDirectoryAtPath:planePath error:nil];        // 3.遍曆裡面的mp3檔案,建立SystemSoundID;    NSMutableDictionary *soundDictM = [NSMutableDictionary dictionary];        for (NSString *soundName in contents) {        // 音訊URL        NSString *soundUrlPath = [planePath stringByAppendingPathComponent:soundName];                NSURL *soundUrl       = [NSURL fileURLWithPath:soundUrlPath];                SystemSoundID soundID;                // 建立聲音        AudioServicesCreateSystemSoundID((__bridge CFURLRef)soundUrl, &soundID);                soundDictM[soundName] = @(soundID);    }    soundDict = soundDictM;}- (void)playShortSoundWithName:(NSString *)soundName {    // 播放聲音    AudioServicesPlaySystemSound([soundDict[soundName] unsignedIntValue]);}

長音頻播放(使用AVFoundation.framework的AVAudioPlayer實現)

AVAudioPlayer的使用就比較簡單了:

  1.  初始化AVAudioPlayer對象,此時通常指定本地檔案路徑。
  2.  設定播放器的屬性,例如重複次數、音量大小等。
  3.  調用play方法播放.
屬性 說明
@property(readonly, getter=isPlaying) BOOL playing 是否現正播放,唯讀
@property(readonly) NSUInteger numberOfChannels 音頻聲道數,唯讀
@property(readonly) NSTimeInterval duration 音頻時間長度
@property(readonly) NSURL *url 音頻檔案路徑,唯讀
@property(readonly) NSData *data 音頻資料,唯讀
@property float pan 立體聲平衡,如果為-1.0則完全左聲道,如果0.0則左右聲道平衡,如果為1.0則完全為右聲道
@property float volume 音量大小,範圍0-1.0
@property BOOL enableRate 是否允許改變播放速率
@property float rate 播放速率,範圍0.5-2.0,如果為1.0則正常播放,如果要修改播放速率則必須設定enableRate為YES
@property NSTimeInterval currentTime 當前播放時間長度
@property(readonly) NSTimeInterval deviceCurrentTime 輸出裝置播放音訊時間,注意如果播放中被暫停此時間也會繼續累加
@property NSInteger numberOfLoops 迴圈播放次數,如果為0則不迴圈,如果小於0則無限迴圈,大於0則表示迴圈次數
@property(readonly) NSDictionary *settings 音頻播放設定資訊,唯讀
@property(getter=isMeteringEnabled) BOOL meteringEnabled 是否啟用音頻測量,預設為NO,一旦啟用音頻測量可以通過updateMeters方法更新測量值
對象方法 說明
- (instancetype)initWithContentsOfURL:(NSURL *)url error:(NSError **)outError 使用檔案URL初始化播放器,注意這個URL不能是HTTP URL,AVAudioPlayer不支援載入網路媒體流,只能播放本地檔案
- (instancetype)initWithData:(NSData *)data error:(NSError **)outError 使用NSData初始化播放器,注意使用此方法時必須檔案格式和檔案尾碼一致,否則出錯,所以相比此方法更推薦使用上述方法或- (instancetype)initWithData:(NSData *)data fileTypeHint:(NSString *)utiString error:(NSError **)outError方法進行初始化
- (BOOL)prepareToPlay; 載入音頻檔案到緩衝區,注意即使在播放之前音頻檔案沒有載入到緩衝區程式也會隱式調用此方法。
- (BOOL)play; 播放音頻檔案
- (BOOL)playAtTime:(NSTimeInterval)time 在指定的時間開始播放音頻
- (void)pause; 暫停播放
- (void)stop; 停止播放
- (void)updateMeters 更新音頻測量值,注意如果要更新音頻測量值必須設定meteringEnabled為YES,通過音頻測量值可以即時獲得音頻分貝等資訊
- (float)peakPowerForChannel:(NSUInteger)channelNumber;  獲得指定聲道的分貝峰值,注意如果要獲得分貝峰值必須在此之前調用updateMeters方法
- (float)averagePowerForChannel:(NSUInteger)channelNumber 獲得指定聲道的分貝平均值,注意如果要獲得分貝平均值必須在此之前調用updateMeters方法
@property(nonatomic, copy) NSArray *channelAssignments 獲得或設定播放聲道
代理方法 說明
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag 音頻播放完成
- (void)audioPlayerDecodeErrorDidOccur:(AVAudioPlayer *)player error:(NSError *)error 音頻解碼發生錯誤

下面就使用AVAudioPlayer實現一個簡單播放器,在這個播放器中實現了播放、暫停、顯示播放進度功能,當然例如調節音量、設定迴圈模式、甚至是聲波映像(通過分析音頻分貝值)等功能都可以實現,這裡就不再一一示範。介面效果如下:

- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view.    }- (IBAction)stop:(id)sender {    /**     *  Stops playback and undoes the setup needed for playback.     */    [_player stop];        // 自己指定播放的時間    _player.currentTime = 0;}- (IBAction)start:(id)sender {    // 擷取mp3路徑    NSURL *mp3Url = [[NSBundle mainBundle] URLForResource:@"bbqne.mp3" withExtension:nil];        static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        _player            = [[AVAudioPlayer alloc] initWithContentsOfURL:mp3Url error:nil];                /**         *  A Boolean value that specifies whether playback rate adjustment is enabled for an audio player.         */        _player.enableRate = YES;                /**         *  Prepares the audio player for playback by preloading its buffers.         */        [_player prepareToPlay];                // 這裡不能加全域斷點,不然會崩        /**         *  The number of times a sound will return to the beginning, upon reaching the end, to repeat playback.         */        _player.numberOfLoops    = MAXFLOAT;                _player.delegate         = self;                _displayLink             = [CADisplayLink displayLinkWithTarget:self                                                               selector:@selector(playMusic)];                [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];                AVAudioSession *session  = [AVAudioSession sharedInstance];                [[NSNotificationCenter defaultCenter] addObserver:self                                                 selector:@selector(handleInterruption:)                                                     name:AVAudioSessionInterruptionNotification                                                   object:session];                _timeSlider.maximumValue = _player.duration;    });        /**     *  Plays a sound asynchronously.     */    [_player play];    }/** *  改變進度條 */- (void)playMusic {    _timeSlider.value = _player.currentTime;        int sec           = _timeSlider.value;    _timeLabel.text   = [NSString stringWithFormat:@"%02d",sec];        [_player updateMeters];        double lowPassResults = pow(10, (0.05 * [self.player peakPowerForChannel:0]));        float result  = 10 * (float)lowPassResults;        NSLog(@"%.2f",result);}- (void)handleInterruption:(NSNotification *)noti {    // 處理中斷事件    NSLog(@"處理中斷事件");}- (IBAction)pause:(id)sender {    /**     *  Pauses playback; sound remains ready to resume playback from where it left off.     */    [_player pause];}/** *  指定當前播放的時間 */- (IBAction)timeChanged:(UISlider *)sender {    _player.currentTime = sender.value;}/** *  改變播放速度 */- (IBAction)rateChange:(UISlider *)sender {    _player.rate = sender.value;}/** *  改變播放音量 */- (IBAction)volunmChanged:(UISlider *)sender {    _player.volume = sender.value;}

錄音

在AVFoundation架構中還要一個AVAudioRecorder類專門處理錄音操作,它同樣支援多種音頻格式。與AVAudioPlayer類似,你完全可以將它看成是一個錄音機控制類,下面是常用的屬性和方法:

@property(readonly, getter=isRecording) BOOL recording; 是否正在錄音,唯讀
@property(readonly) NSURL *url 錄音檔案地址,唯讀
@property(readonly) NSDictionary *settings 錄音檔案設定,唯讀
@property(readonly) NSTimeInterval currentTime 錄音時間長度,唯讀,注意僅僅在錄音狀態可用
@property(readonly) NSTimeInterval deviceCurrentTime 輸入設定的時間長度,唯讀,注意此屬性一直可訪問
@property(getter=isMeteringEnabled) BOOL meteringEnabled; 是否啟用錄音測量,如果啟用錄音測量可以獲得錄音分貝等資料資訊
@property(nonatomic, copy) NSArray *channelAssignments 當前錄音的通道
對象方法 說明
- (instancetype)initWithURL:(NSURL *)url settings:(NSDictionary *)settings error:(NSError **)outError 錄音機對象初始化方法,注意其中的url必須是本地檔案url,settings是錄音格式、編碼等設定
- (BOOL)prepareToRecord 準備錄音,主要用於建立緩衝區,如果不手動調用,在調用record錄音時也會自動調用
- (BOOL)record 開始錄音
- (BOOL)recordAtTime:(NSTimeInterval)time 在指定的時間開始錄音,一般用於錄音暫停再恢複錄音
- (BOOL)recordForDuration:(NSTimeInterval) duration 按指定的時間長度開始錄音
- (BOOL)recordAtTime:(NSTimeInterval)time forDuration:(NSTimeInterval) duration 在指定的時間開始錄音,並指定錄音時間長度
- (void)pause; 暫停錄音
- (void)stop; 停止錄音
- (BOOL)deleteRecording; 刪除錄音,注意要刪除錄音此時錄音機必須處於停止狀態
- (void)updateMeters; 更新測量資料,注意只有meteringEnabled為YES此方法才可用
- (float)peakPowerForChannel:(NSUInteger)channelNumber; 指定通道的測量峰值,注意只有調用完updateMeters才有值
- (float)averagePowerForChannel:(NSUInteger)channelNumber 指定通道的測量平均值,注意只有調用完updateMeters才有值
代理方法 說明
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder successfully:(BOOL)flag 完成錄音
- (void)audioRecorderEncodeErrorDidOccur:(AVAudioRecorder *)recorder error:(NSError *)error

程式的構建主要分為以下幾步:

  1. 設定音頻會話類型為AVAudioSessionCategoryPlayAndRecord,因為程式中牽扯到錄音和播放操作。 
  2. 建立錄音機AVAudioRecorder,指定錄音儲存的路徑並且設定錄音屬性,注意對於一般的錄音檔案要求的採樣率、位元並不高,需要適當設定以保證錄音檔案的大小和效果。 
  3. 設定錄音機代理以便在錄音完成後播放錄音,開啟錄音測量保證能夠即時獲得錄音時的聲音強度。(注意聲音強度範圍-160到0,0代表最大輸入) 
  4. 建立音頻播放器AVAudioPlayer,用於在錄音完成之後播放錄音。 
  5. 建立一個定時器以便即時重新整理錄音測量值並更新錄音強度到UIProgressView中顯示。 
  6. 添加錄音、暫停、恢複、停止操作,需要注意錄音的恢複操作其實是有音頻會話管理的,恢複時只要再次調用record方法即可,無需手動管理恢復等。

下面是主要代碼

iOS開發之音頻播放、錄音

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.