场景
把多条mp3音频合并为一条保存并进行播放
解决方案
- 首先把全部音频路径生成为一个数组:NSMutableArray * fileUrlArr = @[].mutableCopy; [mp3NameArr enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { NSString *mp3Name = [NSString stringWithFormat:@"%@",obj]; // mp3路径 NSString *audioFileURL = [[NSBundle mainBundle] pathForResource:mp3Name ofType:@"mp3"]; [fileUrlArr addObject:audioFileURL]; }];///合并音频 - (void) mergeAVAssetWithSourceURLs:(NSArray *)sourceURLsArr completed:(void (^)(NSString * outputFileUrlStr)) completed{ //创建音频轨道,并获取多个音频素材的轨道 AVMutableComposition *composition = [AVMutableComposition composition]; //音频插入的开始时间,用于记录每次添加音频文件的开始时间 __block CMTime beginTime = kCMTimeZero; [sourceURLsArr enumerateObjectsUsingBlock:^(id _Nonnull audioFileURL, NSUInteger idx, BOOL * _Nonnull stop) { //获取音频素材 AVURLAsset *audioAsset1 = [AVURLAsset assetWithURL:[NSURL fileURLWithPath:audioFileURL]]; //音频轨道 AVMutableCompositionTrack *audioTrack1 = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:0]; //获取音频素材轨道 AVAssetTrack *audioAssetTrack1 = [[audioAsset1 tracksWithMediaType:AVMediaTypeAudio] firstObject]; //音频合并- 插入音轨文件 [audioTrack1 insertTimeRange:CMTimeRangeMake(kCMTimeZero, audioAsset1.duration) ofTrack:audioAssetTrack1 atTime:beginTime error:nil]; // 记录尾部时间 beginTime = CMTimeAdd(beginTime, audioAsset1.duration); }]; //导出合并后的音频文件 //音频文件目前只找到支持m4a 类型的 AVAssetExportSession *session = [[AVAssetExportSession alloc]initWithAsset:composition presetName:AVAssetExportPresetAppleM4A]; NSDateFormatter *formater = [[NSDateFormatter alloc] init]; [formater setDateFormat:@"yyyy-MM-dd-HH:mm:ss-SSS"]; NSString * timeFromDateStr = [formater stringFromDate:[NSDate date]]; NSString *outPutFilePath = [NSHomeDirectory() stringByAppendingFormat:@"/tmp/sound-%@.mp4", timeFromDateStr]; // 音频文件输出 session.outputURL = [NSURL fileURLWithPath:outPutFilePath]; session.outputFileType = AVFileTypeAppleM4A; //与上述的`present`相对应 session.shouldOptimizeForNetworkUse = YES; //优化网络 [session exportAsynchronouslyWithCompletionHandler:^{ if (session.status == AVAssetExportSessionStatusCompleted) { NSLog(@"合并成功----%@", outPutFilePath); if (completed) { completed(outPutFilePath); } } else { // 其他情况, 具体请看这里`AVAssetExportSessionStatus`. NSLog(@"合并失败----%ld", (long)session.status); if (completed) { completed(nil); } } }]; }
- 通过以下方法合并音频,保存在一个随机文件中,因为文件如果已存在或者文件目录写入失败,会出现【AVAssetExportSessionStatusFailed】错误码
- 输出合并音频// 合并音频文件生成新的音频 [self mergeAVAssetWithSourceURLs:musicArr completed:^(NSString *outputFileUrlStr) { if (!outputFileUrlStr) { NSLog(@"声音生成失败!"); return; } self.audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:[NSURL fileURLWithPath:outputFileUrlStr] error:nil]; [self.audioPlayer play]; }];
参考:
https://www.cxyzjd.com/article/ismilesky/52780349
https://www.jianshu.com/p/3e357e3129b8
http://www.cocoachina.com/articles/17624