有没有办法录制到音频文件的末尾?我们不能暂停录制而不是停止录制,因为用户需要以后能够返回应用并为录制添加更多音频。目前,音频作为NSData存储在CoreData中。 NSData的AppendData
不起作用,因为生成的音频文件仍然报告它只与原始数据一样长。
另一种可能性是将原始音频文件与新音频文件连接起来,并将它们连接成一个音频文件,如果有任何方法可以做到这一点。
答案 0 :(得分:7)
使用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;
}];
答案 1 :(得分:4)
添加两个文件并使用AVMutableCompositionTrack
exportAsynchronouslyWithCompletionHandler
方法导出合成后,您可以通过创建AVAssetExportSession
附加两个音频文件。
请参阅以下链接了解更多详情。
AVAssetExportSession Class Reference
希望这有助于解决您的问题。
答案 2 :(得分:1)
我没有完整的代码示例,但扩展音频文件服务可以帮助您连接两个音频文件。在Xcode中搜索扩展音频文件服务或访问以下链接。
答案 3 :(得分:0)
我们的应用程序与OP描述的要求相同,并遇到了相同的问题(即,如果用户想要听取她记录的内容,则必须停止录制,而不是暂停录制点)。我们的应用(project's Github repo)使用AVQueuePlayer
进行播放,使用类似kermitology's answer的方法连接部分录音,但有一些明显的差异:
最后一项背后的理由是,AVAudioRecorder
的简单录音将有一首曲目,整个解决方法的主要原因是连接资产中的那些单曲(参见附录3 )。那么为什么不使用AVMutableComposition
insertTimeRange
方法,而是使用AVAsset
代替AVAssetTrack
?
相关部分:(full code)
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
&#39 ; s回调块"在写入完成时或在写入失败的情况下被调用"。
附录2:万一有人遇到AVQueuePlayer
问题:'An AVPlayerItem cannot be associated with more than one instance of AVPlayer'
附录3 :除非您是以立体声录制,但据我所知,移动设备只有一个输入。此外,使用花哨的音频混合还需要使用AVCompositionTrack
。一个好的SO线程:正确的AVAudioRecorder Settings for Recording Voice?