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

Другие вопросы по тегам