2017-01-05 10 views
3

Я хочу записывать аудио на iOS в реальном времени, анализировать необработанные аудиоданные и сохранять части записанных данных. Я записываю данные с помощью этого кода: https://gist.github.com/hotpaw2/ba815fc23b5d642705f2b1dedfaf0107iOS Swift malloc error

Теперь мои данные сохраняются в массиве Float, и я хочу сохранить его в аудиофайл. Я пытался делать это с этим кодом:

let fileMgr = FileManager.default 
    let dirPaths = fileMgr.urls(for: .documentDirectory, in: .userDomainMask) 
    let recordSettings = [AVEncoderAudioQualityKey: AVAudioQuality.min.rawValue, 
         AVEncoderBitRateKey: 16, 
         AVNumberOfChannelsKey: 2, 
         AVSampleRateKey: 44100] as [String: Any] 
    let soundFileUrl = dirPaths[0].appendingPathComponent("recording-" + getDate() + ".pcm") 


    do { 
     let audioFile = try AVAudioFile(forWriting: soundFileUrl, settings: recordSettings) 
     let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 44100, channels: 2, interleaved: true) 

     let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: 3000) 

     for i in 0..<circBuffer.count { 
      audioFileBuffer.int16ChannelData?.pointee[i] = Int16(circBuffer[i]) 
     } 

     try audioFile.write(from: audioFileBuffer) 

    } 

На последней строке, я получаю ошибку, которая говорит:

ОШИБКА:> avae> AVAudioFile.mm:306: - [AVAudioFile writeFromBuffer: ошибка:] : error -50 амплификацияDemo (79264,0x70000f7cb000) malloc: * ошибка для объекта 0x7fc5b9057e00: некорректная контрольная сумма для освобожденного объекта - объект, вероятно, был изменен после освобождения. * установить точку останова в malloc_error_break для отладки

Я уже искал в большом количестве других вопросов, но я не мог найти ничего, что помогло мне.

ответ

1

В коде на этой линии:

let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: 3000) 

объявление AVAudioPCMBuffer мощность 3000 кадров * 2 канала, что означает, выделенный буфер для ваших audioFileBuffer могут содержать 6000 образцов. Если индекс для данных канала превышает этот предел, ваш код разрушает соседние регионы в куче, что приводит к тому, что объект , вероятно, был изменен.

Таким образом, ваш circBuffer.count может превышать этот предел. Вам необходимо выделить достаточный размер буфера для AVAudioPCMBuffer.

do { 
     //### You need to specify common format 
     let audioFile = try AVAudioFile(forWriting: soundFileUrl, settings: recordSettings, commonFormat: .pcmFormatInt16, interleaved: true) 

     let channels = 2 
     let format = AVAudioFormat(commonFormat: .pcmFormatInt16, sampleRate: 44100, channels: AVAudioChannelCount(channels), interleaved: true) 
     let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(circBuffer.count/channels)) //<-allocate enough frames 
     //### `stride` removed as it seems useless... 
     let int16ChannelData = audioFileBuffer.int16ChannelData! //<-cannot be nil for the `format` above 

     //When interleaved, channel data of AVAudioPCMBuffer is not as described in its doc: 
     // https://developer.apple.com/reference/avfoundation/avaudiopcmbuffer/1386212-floatchanneldata . 
     // The following code is modified to work with actual AVAudioPCMBuffer. 
     //Assuming `circBuffer` as 
     // Interleaved, 2 channel, Float32 
     // Each sample is normalized to [-1.0, 1.0] (as usual floating point audio format) 
     for i in 0..<circBuffer.count { 
      int16ChannelData[0][i] = Int16(circBuffer[i] * Float(Int16.max)) 
     } 
     //You need to update `frameLength` of the `AVAudioPCMBuffer`. 
     audioFileBuffer.frameLength = AVAudioFrameCount(circBuffer.count/channels) 

     try audioFile.write(from: audioFileBuffer) 

    } catch { 
     print("Error", error) 
    } 

Некоторые замечания добавлены в виде комментариев, пожалуйста, проверьте их перед тем, как попробовать этот код.


UPDATE К сожалению, для показа непроверенного кода, две вещей исправлены:

  • Вы должны указать commonFormat: при инстанцировании AVAudioFile.
  • int16ChannelData (и другие данные канала) не возвращает ожидаемые указатели, как описано в его документации при чередовании, цикл заполнения данных, модифицированный для соответствия фактическому поведению.

Попробуйте.

+0

Спасибо, это помогло. Но все же созданные звуковые файлы пустые, и я получаю ошибку: «ERROR:> avae> AVAudioFile.mm:306: - [AVAudioFile writeFromBuffer: error:]: error -50« Любая идея, почему это происходит? – user7310287

+0

@ user7310287, извините, я должен был проверить мой код немного больше, я просто проверил запись в буфер, не вызывает сбой.Но не проверено с фактической записью в файл будет успешным или нет. Теперь, проверяя фактическое поведение iOS, снимите флажок «Принять», пока я не смогу найти исправления. – OOPer

1

Вы, кажется, выбрали frameCapacity произвольно, чтобы 3000.

Установите его фактический подсчет образца:

let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(circBuffer.count))