iOS中如何用AVAudioRecorder在通话时录制静音以保证录制时长准确
iOS 实现通话期间录制静音以保证时长准确
你的需求是在电话中断期间保持录音时长连续,用静音填充通话时段,这需要绕开iOS音频会话中断的限制——因为系统在通话时会抢占音频会话,无法直接持续录制,所以我们可以通过记录中断时长+追加静音数据的方式实现。
修改中断处理逻辑
首先,添加变量记录中断开始时间,替换原有的暂停恢复逻辑:
// 头文件或类扩展中添加属性 @property (nonatomic, strong) NSDate *interruptionStartDate; @property (nonatomic, assign) NSTimeInterval totalInterruptionDuration; // 累计中断时长,用于多次中断场景 - (void)handleAudioSessionInterruption:(NSNotification *)notification { NSNumber *interruptionType = [[notification userInfo] objectForKey:AVAudioSessionInterruptionTypeKey]; switch (interruptionType.unsignedIntegerValue) { case AVAudioSessionInterruptionTypeBegan:{ _currentAudioSessionMode = EXAVAudioSessionModeInactive; if (_audioRecorder.recording) { [_audioRecorder pause]; _interruptionStartDate = [NSDate date]; // 记录中断起始时间 [self demoteAudioSessionIfPossible]; } } break; case AVAudioSessionInterruptionTypeEnded:{ _currentAudioSessionMode = EXAVAudioSessionModeActive; if (_audioRecorder && !_audioRecorder.recording) { if (_allowsAudioRecording) { // 计算本次中断时长 NSTimeInterval interruptionDuration = [[NSDate date] timeIntervalSinceDate:_interruptionStartDate]; _totalInterruptionDuration += interruptionDuration; // 累计时长 _interruptionStartDate = nil; [self promoteAudioSessionIfNecessary]; [_audioRecorder record]; } } } break; default: break; } }
实现静音数据追加
在录音结束时,使用AVFoundation的合成API,将累计中断时长的静音片段追加到录音文件末尾,保证总时长准确:
// 录音结束时调用此方法,追加累计静音时长 - (void)appendTotalSilenceToFinalRecording { if (_totalInterruptionDuration <= 0) return; NSURL *originalFileURL = _audioRecorder.url; if (!originalFileURL) return; // 1. 创建音频合成对象 AVMutableComposition *composition = [AVMutableComposition composition]; // 2. 导入原录音文件 AVURLAsset *originalAsset = [AVURLAsset assetWithURL:originalFileURL]; AVAssetTrack *originalAudioTrack = [originalAsset tracksWithMediaType:AVMediaTypeAudio].firstObject; if (!originalAudioTrack) return; CMTimeRange originalTimeRange = CMTimeRangeMake(kCMTimeZero, originalAsset.duration); NSError *insertError; [composition insertTimeRange:originalTimeRange ofTrack:originalAudioTrack atTime:kCMTimeZero error:&insertError]; if (insertError) { NSLog(@"导入原录音失败: %@", insertError.localizedDescription); return; } // 3. 添加静音片段 AVMutableCompositionTrack *silenceTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; CMTime silenceCMTime = CMTimeMakeWithSeconds(_totalInterruptionDuration, originalAsset.duration.timescale); CMTimeRange silenceTimeRange = CMTimeRangeMake(originalAsset.duration, silenceCMTime); [silenceTrack insertEmptyTimeRange:silenceTimeRange]; // 4. 导出合并后的文件 NSURL *tempOutputURL = [self temporaryAudioFileURL]; // 生成临时输出路径 AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetAppleM4A]; exportSession.outputURL = tempOutputURL; exportSession.outputFileType = AVFileTypeAppleM4A; exportSession.shouldOptimizeForNetworkUse = YES; [exportSession exportAsynchronouslyWithCompletionHandler:^{ dispatch_async(dispatch_get_main_queue(), ^{ if (exportSession.status == AVAssetExportSessionStatusCompleted) { // 替换原录音文件 NSError *fileError; NSFileManager *fileManager = [NSFileManager defaultManager]; [fileManager removeItemAtURL:originalFileURL error:&fileError]; if (!fileError) { [fileManager moveItemAtURL:tempOutputURL toURL:originalFileURL error:&fileError]; if (fileError) { NSLog(@"替换原文件失败: %@", fileError.localizedDescription); } } else { NSLog(@"删除原文件失败: %@", fileError.localizedDescription); } // 重置累计时长 _totalInterruptionDuration = 0; } else { NSLog(@"导出静音合成文件失败: %@", exportSession.error.localizedDescription); } }); }]; } // 生成临时音频文件路径 - (NSURL *)temporaryAudioFileURL { NSString *tempDir = NSTemporaryDirectory(); NSString *fileName = [NSString stringWithFormat:@"temp_silence_merge_%@.m4a", [[NSUUID UUID] UUIDString]]; return [NSURL fileURLWithPath:[tempDir stringByAppendingPathComponent:fileName]]; }
注意事项
- 文件格式兼容性:上述代码针对M4A格式(AVFileTypeAppleM4A),若使用其他录音格式,需对应修改导出的
outputFileType。 - 性能优化:音频合成导出是异步操作,若录音时长较长,建议在后台线程处理,避免阻塞主线程。
- 权限与文件访问:确保App拥有录音权限,且录音文件路径有可写权限,避免文件操作失败。
内容的提问来源于stack exchange,提问作者Grzegorz Brzęczyszczykiewicz
相关产品推荐
相关产品推荐

