简体   繁体   English

AVAudioFile 写不工作 Swift iOS 14

[英]AVAudioFile write not working Swift iOS 14

I have the following function:我有以下 function:

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))
}

Which returns to me an AVAudioPCMBuffer.它返回给我一个 AVAudioPCMBuffer。 I have verified the utterance I pass in speaks properly.我已经验证了我传递的话语是正确的。

The issue comes when I try to write this AVAudioPCMBuffer into a URL locally, like this:当我尝试在本地将此 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)
                    }
                }

I am met with the following error: CABufferList.h:179:BytesConsumed: ASSERTION FAILURE [(nBytes <= buf->mDataByteSize):= 0 is false]:我遇到以下错误:CABufferList.h:179:BytesConsumed: ASSERTION FAILURE [(nBytes <= buf->mDataByteSize):= 0 is false]:

on the line where I try to do:在我尝试做的事情上:

try tempFile.write(from: buffer)

There are several things to consider:有几件事情需要考虑:

  1. Must use a correct format for the file.必须使用正确的文件格式。
  2. The callback of writeUtterance:toBufferCallback: is called multiple times, each time with a the next chunk of the synthesized audio. writeUtterance:toBufferCallback:的回调被多次调用,每次都是合成音频的下一个块。 As far as I can tell, it synthesizes up to 10ms of the audio each time.据我所知,它每次最多可以合成 10 毫秒的音频。 (undocumented) (无证)
  3. You must close the file in order to flush it.您必须关闭文件才能刷新它。 Closing is done by releasing the reference to the object.关闭是通过释放对 object 的引用来完成的。 (undocumented). (无证)。
@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);
  }];
}

This works for me这对我有用

` `

private func uploadBuffer(_ buffer: AVAudioPCMBuffer) {
    

    let fileManager = FileManager.default
        do {


            let documentDirectory = try! fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create:false)
            try! FileManager.default.createDirectory(atPath: documentDirectory.path, withIntermediateDirectories: true, attributes: nil)

            let fileURL = documentDirectory.appendingPathComponent("out.wav")
            print(fileURL.path)
            let audioFile = try! AVAudioFile(forWriting: fileURL, settings: buffer.format.settings, commonFormat: buffer.format.commonFormat, interleaved: true)
            try! audioFile.write(from: buffer)
            
            
  
            
            
        } catch {
            print(error)
        }
    
    

    
}

` `

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM