AVAudioFile 写入不起作用 Swift iOS 14
Posted
技术标签:
【中文标题】AVAudioFile 写入不起作用 Swift iOS 14【英文标题】:AVAudioFile write not working Swift iOS 14 【发布时间】:2021-06-14 02:46:59 【问题描述】:我有以下功能:
private func getPCMBuffer(utterance: AVSpeechUtterance,
completion: @escaping (Result<AVAudioPCMBuffer, Failures>) -> Void
)
speechSynthesizer.write(utterance) (buffer: AVAudioBuffer) in
guard let pcmBuffer = buffer as? AVAudioPCMBuffer else
fatalError("unknown buffer type: \(buffer)")
completion(.success(pcmBuffer))
completion(.failure(.failed))
返回给我一个 AVAudioPCMBuffer。我已经验证了我传入的话语是正确的。
当我尝试将此 AVAudioPCMBuffer 写入本地 URL 时出现问题,如下所示:
getPCMBuffer(utterance: speechUtterance) result in
switch result
case .success(let buffer):
var settings: [String : Any] = [:]
let savePathUrl: URL = URL(fileURLWithPath: NSHomeDirectory() + "/Documents/audioFile.caf")
settings[AVFormatIDKey] = kAudioFormatMPEG4AAC
settings[AVAudioFileTypeKey] = kAudioFileCAFType
settings[AVSampleRateKey] = buffer.format.sampleRate
settings[AVNumberOfChannelsKey] = 2
settings[AVLinearPCMIsFloatKey] = (buffer.format.commonFormat == .pcmFormatInt32)
do
let tempFile = try AVAudioFile(forWriting: savePathUrl, settings: settings, commonFormat: buffer.format.commonFormat, interleaved: buffer.format.isInterleaved)
try tempFile.write(from: buffer)
catch
print(error)
case .failure(let failure):
print(failure.localizedDescription)
我遇到以下错误:CABufferList.h:179:BytesConsumed: ASSERTION FAILURE [(nBytes mDataByteSize) != 0 is false]:
在我尝试做的那一行:
try tempFile.write(from: buffer)
【问题讨论】:
预感:你确定可以同时使用 kAudioFormatMPEG4AAC 和 kAudioFileCAFType 吗?我在这里可能很偏僻,但由于编码错误,数据的大小似乎错误。 嘿,我试过只使用 kAudioFormatMPEG4AAC,但确实收到错误代码 1718449215,这是一个无效的音频格式类型错误。我还打印了buffer.format,即:1 ch
表示它是单声道(一个通道),但您使用settings[AVNumberOfChannelsKey] = 2
声明立体声可能是问题所在?
如果我将其更改为 1,我将不再收到错误,但现在当我打开我在文档目录中写入的音频文件时,它只有 0 秒长并且没有声音。 (我以前也遇到过这个问题)。您知道将 pcmBuffer 写入文档目录的方法吗?网上找不到好的资源
如果使用buffer.format.settings
进行设置会得到什么?
【参考方案1】:
有几件事情需要考虑:
-
必须使用正确的文件格式。
writeUtterance:toBufferCallback:
的回调被多次调用,每次都带有合成音频的下一个块。据我所知,它每次最多可以合成 10 毫秒的音频。 (无证)
您必须关闭文件才能刷新它。关闭是通过释放对对象的引用来完成的。 (未记录)。
@property (readonly, nonatomic) AVSpeechSynthesizer *synth;
@property (strong, nonatomic) AVAudioFile *file;
...
_synth = [[AVSpeechSynthesizer alloc] init];
self.synth.delegate = self;
...
- (void)speechSynthesizer:(AVSpeechSynthesizer *)synthesizer
didFinishSpeechUtterance:(AVSpeechUtterance *)utterance
self.file = nil; // releasing the file will close it
NSLog(@"Finished");
- (void)generateTranscript
AVSpeechUtterance *utterance =
[AVSpeechUtterance speechUtteranceWithString:...];
utterance.voice = ...;
[[AVAudiosession sharedInstance] setCategory:AVAudioSessionCategoryPlayback
withOptions:AVAudioSessionCategoryOptionMixWithOthers
error:nil];
[self.synth writeUtterance:utterance toBufferCallback:^(AVAudioBuffer * _Nonnull buffer)
NSAssert([buffer isKindOfClass:AVAudioPCMBuffer.class], @"");
NSError *error;
if (!self.file)
NSURL *url = [NSURL fileURLWithPath:[NSTemporaryDirectory()
stringByAppendingPathComponent:@"recording.m4a"]];
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
settings[AVFormatIDKey] = @(kAudioFormatMPEG4AAC);
settings[AVEncoderAudioQualityKey] = @(AVAudioQualityMax);
settings[AVSampleRateKey] = buffer.format.settings[AVSampleRateKey]; // 22050 Hz
settings[AVNumberOfChannelsKey] = buffer.format.settings[AVNumberOfChannelsKey]; // 1 channel
self.file = [[AVAudioFile alloc] initForWriting:url settings:settings
commonFormat:buffer.format.commonFormat // AVAudioPCMFormatInt16
interleaved:buffer.format.interleaved // YES
error:&error];
if (error)
NSLog(@"%@", error);
return;
[self.file writeFromBuffer:(AVAudioPCMBuffer *)buffer error:&error];
if (error)
NSLog(@"%@", error);
return;
AVAudioFrameCount frameCont = ((AVAudioPCMBuffer *)buffer).frameLength;
double sampleRate = buffer.format.sampleRate;
NSLog(@"Written %.4lfs", (double)frameCont / sampleRate);
];
关于格式,我还建议阅读AVSpeechSynthesisVoice audioFileSettings
文档。
【讨论】:
以上是关于AVAudioFile 写入不起作用 Swift iOS 14的主要内容,如果未能解决你的问题,请参考以下文章