iOS swift malloc ошибка
Я хочу записывать аудио на iOS в реальном времени, анализировать необработанные аудиоданные и сохранять части записанных данных. Я записываю данные с помощью этого кода: https://gist.github.com/hotpaw2/ba815fc23b5d642705f2b1dedfaf0107
Теперь мои данные сохраняются в массиве 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: ошибка:]: ошибка -50 ampitudeDemo (79264,0x70000f7cb000) malloc: * ошибка для объекта 0x7fc5b9057e00: неверная контрольная сумма для освобожденного объекта - возможно, объект был изменен после освобождения, * установить точку останова в malloc_error_break для отладки
Я уже искал много других вопросов, но не смог найти ничего, что помогло бы мне.
2 ответа
В вашем коде в этой строке:
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)
}
Некоторые заметки добавлены в качестве комментариев, пожалуйста, проверьте их, прежде чем пытаться этот код.
ОБНОВЛЕНИЕ Извините, за показ непроверенного кода исправлены две вещи:
- Вам необходимо указать
commonFormat:
при создании экземпляраAVAudioFile
, int16ChannelData
(и другие данные канала) не возвращает ожидаемые указатели, как описано в его документации при чередовании, цикл заполнения данных изменен, чтобы соответствовать фактическому поведению.
Пожалуйста, попробуй.
Вы, кажется, выбрали frameCapacity
произвольно 3000
,
Установите его на фактическое количество образцов:
let audioFileBuffer = AVAudioPCMBuffer(pcmFormat: format, frameCapacity: AVAudioFrameCount(circBuffer.count))