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的主要内容,如果未能解决你的问题,请参考以下文章

将 AVAudioPCMBuffer 写入压缩的 AVAudioFile

swift: Swift 中的 SnapKit 不起作用

Swift 接收 javascript 消息不起作用

为啥将原始字节写入分区不起作用[扇区写入]?

SWIFT :- swift 中的通用链接不起作用

为啥减去 NSDecimalNumbers 不起作用 - Swift 3