[英]Recording and then Playing Audio using AVAudioRecorder and AVAudioPLayer
[英]AVAudioRecorder / AVAudioPlayer - append recording to file
有沒有辦法錄制到音頻文件的末尾? 我們不能暫停錄制而不是停止錄制,因為用戶需要以后能夠返回應用並為錄制添加更多音頻。 目前,音頻作為NSData存儲在CoreData中。 NSData的AppendData
不起作用,因為生成的音頻文件仍然報告它只與原始數據一樣長。
另一種可能性是將原始音頻文件與新音頻文件連接起來,並將它們連接成一個音頻文件,如果有任何方法可以做到這一點。
這可以使用AVMutableComposionTrack insertTimeRange:ofTrack:atTime:error
相當容易地完成。 代碼有點冗長,但它實際上就像4個步驟:
// Create a new audio track we can append to
AVMutableComposition* composition = [AVMutableComposition composition];
AVMutableCompositionTrack* appendedAudioTrack =
[composition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
// Grab the two audio tracks that need to be appended
AVURLAsset* originalAsset = [[AVURLAsset alloc]
initWithURL:[NSURL fileURLWithPath:originalAudioPath] options:nil];
AVURLAsset* newAsset = [[AVURLAsset alloc]
initWithURL:[NSURL fileURLWithPath:newAudioPath] options:nil];
NSError* error = nil;
// Grab the first audio track and insert it into our appendedAudioTrack
AVAssetTrack *originalTrack = [originalAsset tracksWithMediaType:AVMediaTypeAudio];
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, originalAsset.duration);
[appendedAudioTrack insertTimeRange:timeRange
ofTrack:[originalTrack objectAtIndex:0]
atTime:kCMTimeZero
error:&error];
if (error)
{
// do something
return;
}
// Grab the second audio track and insert it at the end of the first one
AVAssetTrack *newTrack = [newAsset tracksWithMediaType:AVMediaTypeAudio];
timeRange = CMTimeRangeMake(kCMTimeZero, newAsset.duration);
[appendedAudioTrack insertTimeRange:timeRange
ofTrack:[newTrack objectAtIndex:0]
atTime:originalAsset.duration
error:&error];
if (error)
{
// do something
return;
}
// Create a new audio file using the appendedAudioTrack
AVAssetExportSession* exportSession = [AVAssetExportSession
exportSessionWithAsset:composition
presetName:AVAssetExportPresetAppleM4A];
if (!exportSession)
{
// do something
return;
}
NSString* appendedAudioPath= @""; // make sure to fill this value in
exportSession.outputURL = [NSURL fileURLWithPath:appendedAudioPath];
exportSession.outputFileType = AVFileTypeAppleM4A;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
// exported successfully?
switch (exportSession.status)
{
case AVAssetExportSessionStatusFailed:
break;
case AVAssetExportSessionStatusCompleted:
// you should now have the appended audio file
break;
case AVAssetExportSessionStatusWaiting:
break;
default:
break;
}
NSError* error = nil;
}];
您可以通過創建一個追加兩個音頻文件AVMutableCompositionTrack
添加兩個文件和導出使用該組合物后exportAsynchronouslyWithCompletionHandler
的方法AVAssetExportSession
。
有關詳細信息,請參閱以下鏈接。
希望這有助於解決您的問題。
我沒有完整的代碼示例,但擴展音頻文件服務可以幫助您連接兩個音頻文件。 在Xcode中搜索擴展音頻文件服務或訪問以下鏈接。
我們對我們的應用程序的要求與OP描述的相同,並且遇到了相同的問題(即,如果用戶想要聽到她記錄的內容,則必須停止錄制,而不是暫停錄制)。 我們的應用程序( 項目的Github repo )使用AVQueuePlayer
進行播放,並使用類似於kermitology連接部分錄音的答案的方法,以及一些顯着的差異:
最后一項的基本原理是AVAudioRecorder
簡單錄音將有一個軌道,這整個解決方法的主要原因是連接資產中的那些單軌(見附錄3 )。 那么為什么不使用AVMutableComposition
的insertTimeRange
方法,而是采用AVAsset
而不是AVAssetTrack
?
相關部分:( 完整代碼 )
import UIKit
import AVFoundation
class RecordViewController: UIViewController {
/* App allows volunteers to record newspaper articles for the
blind and print-impaired, hence the name.
*/
var articleChunks = [AVURLAsset]()
func concatChunks() {
let composition = AVMutableComposition()
/* `CMTimeRange` to store total duration and know when to
insert subsequent assets.
*/
var insertAt = CMTimeRange(start: kCMTimeZero, end: kCMTimeZero)
repeat {
let asset = self.articleChunks.removeFirst()
let assetTimeRange =
CMTimeRange(start: kCMTimeZero, end: asset.duration)
do {
try composition.insertTimeRange(assetTimeRange,
of: asset,
at: insertAt.end)
} catch {
NSLog("Unable to compose asset track.")
}
let nextDuration = insertAt.duration + assetTimeRange.duration
insertAt = CMTimeRange(start: kCMTimeZero, duration: nextDuration)
} while self.articleChunks.count != 0
let exportSession =
AVAssetExportSession(
asset: composition,
presetName: AVAssetExportPresetAppleM4A)
exportSession?.outputFileType = AVFileType.m4a
exportSession?.outputURL = /* create URL for output */
// exportSession?.metadata = ...
exportSession?.exportAsynchronously {
switch exportSession?.status {
case .unknown?: break
case .waiting?: break
case .exporting?: break
case .completed?: break
case .failed?: break
case .cancelled?: break
case .none: break
}
}
/* Clean up (delete partial recordings, etc.) */
}
這個圖幫助我繞過了什么期望什么和從哪里繼承。 ( NSObject
隱含地暗示為沒有繼承箭頭的超類。)
附錄1:我對switch
部分有所保留,而不是在AVAssetExportSessionStatus
上使用KVO,但是文檔很清楚,當寫完成或寫入失敗時,會調用exportAsynchronously
的回調塊“。
附錄2:萬一有人AVQueuePlayer
問題: 'AVPlayerItem不能與多個AVPlayer實例關聯'
附錄3:除非你是用立體聲錄音,但據我所知,移動設備有一個輸入。 此外,使用精美的音頻混合還需要使用AVCompositionTrack
。 一個好的SO線程:適當的AVAudioRecorder設置錄制語音?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.