首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >设置AVAudioFile‘`framePosition`’会导致崩溃

设置AVAudioFile‘`framePosition`’会导致崩溃
EN

Stack Overflow用户
提问于 2020-11-10 02:02:45
回答 1查看 301关注 0票数 1

每当我将framePosition的AVAudioFile设置为当前framePosition以外的其他内容时,就会发生崩溃:

错误- 6658

我在Apple上查到的是:

kExtAudioFileError_InvalidSeek:尝试写入或偏移量是超出范围的。

这对我来说很奇怪,因为我可以确认我试图设置为framePosition的位置比AVAudioFile的length小,并且高于0,所以帧不应该超出界限。

代码:

代码语言:javascript
复制
  // Start Recording to file
  func startRecording(atTimeInFile: TimeInterval) throws {
    let tapNode: AVAudioNode = mixerNode
    let format = tapNode.outputFormat(forBus: 0)
    let semaphore = DispatchSemaphore(value: 0)
    
    duration = 0
    startTime = atTimeInFile
    
    // Check to see if recording file already has content
    
    let f: AVAudioFile? = {
      if FileManager.default.fileExists(atPath: FileManagerHelper.recordingLocalURL().relativePath) {
        return try? AVAudioFile(forReading: FileManagerHelper.recordingLocalURL())
      } else {
        return nil
      }
    }()
    
    if let f = f {
      // The file we opened for writing already has data written to it
      // Let's load the buffer data in from that the file
      guard let bufferData = AVAudioPCMBuffer(pcmFormat: f.processingFormat, frameCapacity: AVAudioFrameCount(f.length)) else {
        throw NSError(domain: "Failed to load the content of the existing file.", code: -10, userInfo: nil)
      }
      
      bufferData.frameLength = bufferData.frameCapacity
      
      do {
        try f.read(into: bufferData)
      } catch {
        throw NSError(domain: "Failed to read from the content of the existing file.", code: -20, userInfo: nil)
      }
      
      // AVAudioFile uses the Core Audio Format (CAF) to write to disk.
      // So we're using the caf file extension.
      file = try AVAudioFile(forWriting: FileManagerHelper.recordingLocalURL(), settings: format.settings)
      
      do {
        file!.framePosition = 0
        try self.file!.write(from: bufferData)
      } catch {
        throw NSError(domain: "Failed to write from the content of the existing file.", code: -30, userInfo: nil)
      }
    }
    
    else {
      file = try AVAudioFile(forWriting: FileManagerHelper.recordingLocalURL(), settings: format.settings)
    }

    if file!.duration == 0 {
      file!.framePosition = AVAudioFramePosition(0)
    } else {
      let percentThrough = CGFloat(atTimeInFile) / CGFloat(file!.duration)
      let pos = AVAudioFramePosition(percentThrough * CGFloat(file!.length))
      
      file!.framePosition = pos // CRASH OCCURS HERE
    }
    
    tapNode.installTap(onBus: 0, bufferSize: bufferSize, format: format, block: {
      (buffer, _) in
      do {
        buffer.frameLength = 1024 // Tap is now called every 40ms. By default, tap is called every 0.375s
        try self.file!.write(from: buffer)
        self.delegate?.recorderDidRecieveAudioBuffer(self, buffer: buffer)
        semaphore.signal()
      } catch {
        log("Error writing mic data to file.", msgType: .error)
      }
    })

    try engine.start()

    semaphore.wait()
    state = .recording
    startObservingTime()
  }

以下是对坠机事件的全面描述:

代码语言:javascript
复制
    ExtAudioFile.cpp:1084:Seek: about to throw -66568: seek to frame in audio file
2020-11-09 18:01:46.032612-0800 Application[15316:800908] [avae]            AVAEInternal.h:109   [AVAudioFile.mm:515:-[AVAudioFile setFramePosition:]: (ExtAudioFileSeek(_imp->_extAudioFile, pos)): error -66568
2020-11-09 18:01:46.034491-0800 Application[15316:800908] *** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -66568'
*** First throw call stack:
(0x187b1c878 0x19c072c50 0x187a22000 0x197aa3e48 0x197b4270c 0x1004fc164 0x10048b43c 0x10048b198 0x10048b254 0x18a010e54 0x18a01a7b8 0x18a0173f4 0x18a01696c 0x18a00aa98 0x18a009e44 0x18a5111b4 0x18a4ea4ec 0x18a574488 0x18a577440 0x18a56e8ec 0x187a9876c 0x187a98668 0x187a97960 0x187a91a8c 0x187a9121c 0x19eb10784 0x18a4ca200 0x18a4cfa74 0x10048f270 0x1877516c0)
libc++abi.dylib: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'error -66568'
terminating with uncaught exception of type NSException

UPDATE 1:我注意到我可以设置framePosition of f,打开forReading的AVAudioFile,但是仍然不能设置file的帧位置,AVAudioFile是用相同的URL打开的。

更新2:我尝试将文件写入一个单独的,而不是通过

代码语言:javascript
复制
file = try AVAudioFile(forWriting: FileManagerHelper.recordingLocalURL(), settings: format.settings)

使用

代码语言:javascript
复制
file = try AVAudioFile(forWriting: FileManagerHelper.recordingLocalURL2(), settings: format.settings)

if let f = f块中。

然而,当我设置名望位置时,我仍然会有出界的错误。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-11-10 05:21:49

我怀疑这是因为你先写,然后试图覆盖以后。也许试着阅读数据,然后把它写回去。

如果已经定义了相同的格式,那么在创建写入文件时,我还添加了一些内容,以防出现问题。

代码语言:javascript
复制
  // Start Recording to file
  func startRecording(atTimeInFile: TimeInterval) throws {
    let tapNode: AVAudioNode = mixerNode
    let format = tapNode.outputFormat(forBus: 0)
    let semaphore = DispatchSemaphore(value: 0)
    
    duration = 0
    startTime = atTimeInFile

    // Check to see if recording file already has content
    let f: AVAudioFile? = {
      if FileManager.default.fileExists(atPath: FileManagerHelper.recordingLocalURL().relativePath) {
        return try? AVAudioFile(forReading: FileManagerHelper.recordingLocalURL())
      } else {
        return nil
      }
    }()
    
    // AVAudioFile uses the Core Audio Format (CAF) to write to disk.
    // So we're using the caf file extension.
    self.file = try? AVAudioFile(forWriting: FileManagerHelper.recordingLocalURL(),
                                 settings: format.settings,
                                 commonFormat: f?.fileFormat ?? format.commonFormat)

    guard let file = self.file else { throw NSError(domain: "Failed to open file for writing") }

    var pos = AVAudioFramePosition(0)
    if let dur = f?.duration,
       let len = f?.length {
      if dur != 0 {
        let percentThrough = CGFloat(atTimeInFile) / CGFloat(dur)
        pos = AVAudioFramePosition(percentThrough * CGFloat(len))
      }
    }

    tapNode.installTap(onBus: 0,
                       bufferSize: bufferSize,
                       format: format,
                       block: { (buffer, _) in
      do {
        if let fread = f {
          guard let bufferData = AVAudioPCMBuffer(pcmFormat: fread.processingFormat,
                                                  frameCapacity: AVAudioFrameCount(pos)) else {
            throw NSError(domain: "Failed to load the content of the existing file.",
                          code: 0,
                          userInfo: nil)
          }

          // read in the data before
          fread.framePosition = AVFramePosition(0)
          try fread.read(into: bufferData)

          // write it to file
          try file.write(from: bufferData)

          // now write the new data
          buffer.frameLength = 1024 // Tap is now called every 40ms. By default, tap is called every 0.375s
          try file.write(from: buffer)

          // now read in the rest if possible
          if file.framePosition < fread.length {
            guard let afterBufferData = AVAudioPCMBuffer(pcmFormat: fread.processingFormat,
                                                         frameCapacity: AVAudioFrameCount(fread.length - file.framePosition)) else {
              throw NSError(domain: "Failed to load extra content of the existing file.",
                            code: 0,
                            userInfo: nil)
            }

            fread.framePosition = file.framePosition
            try fread.read(into: afterBufferData)
            try file.write(from: afterBufferData)
          }
        } else {
          // now write the new data if there wasn't pre-existing
          buffer.frameLength = 1024 // Tap is now called every 40ms. By default, tap is called every 0.375s
          file.write(from: buffer)
        }

        // end the closure
        self.delegate?.recorderDidRecieveAudioBuffer(self, buffer: buffer)
        semaphore.signal()
      } catch {
        semaphore.signal()
        log("Error writing mic data to file.", msgType: .error)
      }
    })

    try engine.start()

    _ = semaphore.wait()
    state = .recording
    startObservingTime()
  }

另外,如果你每隔40毫秒做一次,这可能会非常慢。我建议重构读取所有的“点击”缓冲区,然后复制读旧的,写新的,写旧的结构。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64761792

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档