gpt4 book ai didi

ios - AudioToolBox Recorder 受到 AVFoundation AudioPlayer 的影响

转载 作者:行者123 更新时间:2023-12-01 19:58:22 25 4
gpt4 key购买 nike

所以,我有以下类(class):

  • 录音机(使用 AudioToolboxCoreAudio )记录音频。
  • 音频播放器(使用 AVFoundation )

  • 录音机捕获音频,将其发送到服务器,然后服务器回复另一个音频,然后播放器播放接收到的音频。

    当我再次尝试调用录音机录制音频时,它没有正确录制音频。

    关于如何重置录音机以便在音频播放器完成播放后它可以正确录音的任何想法?

    我尝试再次初始化录音机(就在录音之前),但这不起作用。

    影响录音机的行是下面的 2 行,不幸的是,需要使用 AVFoundation 播放音频.
    let sharedSession = AVAudioSession.sharedInstance()
    try sharedSession.setCategory(AVAudioSessionCategoryPlayback)

    执行流程
  • 录音机音频
  • 向服务器发送和接收音频
  • 从服务器录音机播放音频此时录音机无法正确录音
  • 向服务器发送和接收音频 失败
  • 播放音频失败

  • 先感谢您!


    友情链接 recorder project

    录音机:
    import UIKit
    import CoreAudio
    import AudioToolbox
    class SpeechRecorder: NSObject {

    static let sharedInstance = SpeechRecorder()

    // MARK:- properties
    @objc enum Status: Int {
    case ready
    case busy
    case error
    }

    internal struct RecordState {
    var format: AudioStreamBasicDescription
    var queue: UnsafeMutablePointer<AudioQueueRef?>
    var buffers: [AudioQueueBufferRef?]
    var file: AudioFileID?
    var currentPacket: Int64
    var recording: Bool
    };

    private var _recordState: RecordState?
    private var _audioURL:URL?

    var format: AudioFormatID {
    get { return _recordState!.format.mFormatID }
    set { _recordState!.format.mFormatID = newValue }
    }

    var sampleRate: Float64 {
    get { return _recordState!.format.mSampleRate }
    set { _recordState!.format.mSampleRate = newValue }
    }

    var formatFlags: AudioFormatFlags {
    get { return _recordState!.format.mFormatFlags }
    set { _recordState!.format.mFormatFlags = newValue }
    }

    var channelsPerFrame: UInt32 {
    get { return _recordState!.format.mChannelsPerFrame }
    set { _recordState!.format.mChannelsPerFrame = newValue }
    }

    var bitsPerChannel: UInt32 {
    get { return _recordState!.format.mBitsPerChannel }
    set { _recordState!.format.mBitsPerChannel = newValue }
    }

    var framesPerPacket: UInt32 {
    get { return _recordState!.format.mFramesPerPacket }
    set { _recordState!.format.mFramesPerPacket = newValue }
    }

    var bytesPerFrame: UInt32 {
    get { return _recordState!.format.mBytesPerFrame }
    set { _recordState!.format.mBytesPerFrame = newValue }
    }

    var bytesPerPacket: UInt32 {
    get { return _recordState!.format.mBytesPerPacket }
    set { _recordState!.format.mBytesPerPacket = newValue }
    }

    //MARK: - Handlers
    public var handler: ((_ status:Status, _ data:NSData?, _ errorDesc:String?) -> Void)?

    // MARK:- Init
    override init()
    {
    super.init()
    self._recordState = RecordState(format: AudioStreamBasicDescription(),
    queue: UnsafeMutablePointer<AudioQueueRef?>.allocate(capacity: 1),
    buffers: [AudioQueueBufferRef?](repeating: nil, count: 1),
    file: nil,
    currentPacket: 0,
    recording: false)
    }//eom



    // MARK:- OutputFile
    private func getDocumentsPath()->URL
    {
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    return documentsDirectory
    }

    func setOutputFileNameWithDocumentsDirectory(nameDesired:String)
    {
    _audioURL = getDocumentsPath().appendingPathComponent(nameDesired)
    setOutputFile(url: _audioURL!)
    }//eom

    func setOutputFileNameWithTempDirectory(nameDesired:String)
    {
    let tempDir = NSTemporaryDirectory()
    let tempURLdir = URL(fileURLWithPath: tempDir)
    _audioURL = tempURLdir.appendingPathComponent(nameDesired)
    setOutputFile(url: _audioURL!)
    }//eom

    private func setOutputFile(path: String)
    {
    setOutputFile(url: URL(fileURLWithPath: path))
    }//eom

    private func setOutputFile(url: URL)
    {
    AudioFileCreateWithURL(url as CFURL,
    kAudioFileWAVEType,
    &_recordState!.format,
    AudioFileFlags.dontPageAlignAudioData.union(.eraseFile),
    &_recordState!.file)
    }

    // MARK:- Start / Stop Recording
    func start()
    {
    handler?(.busy, nil, nil)

    self._recordState?.currentPacket = 0

    let inputAudioQueue: AudioQueueInputCallback =
    { (userData: UnsafeMutableRawPointer?,
    audioQueue: AudioQueueRef,
    bufferQueue: AudioQueueBufferRef,
    startTime: UnsafePointer<AudioTimeStamp>,
    packets: UInt32,
    packetDescription: UnsafePointer<AudioStreamPacketDescription>?) in

    let internalRSP = unsafeBitCast(userData, to: UnsafeMutablePointer<RecordState>.self)
    if packets > 0
    {
    var packetsReceived = packets
    let outputStream:OSStatus = AudioFileWritePackets(internalRSP.pointee.file!,
    false,
    bufferQueue.pointee.mAudioDataByteSize,
    packetDescription,
    internalRSP.pointee.currentPacket,
    &packetsReceived,
    bufferQueue.pointee.mAudioData)
    if outputStream != 0
    {
    if verbose
    {

    print("Error with AudioFileWritePackets")
    //<----DEBUG
    switch outputStream
    {
    case kAudioFilePermissionsError:
    print("kAudioFilePermissionsError")
    break
    case kAudioFileNotOptimizedError:
    print("kAudioFileNotOptimizedError")
    break
    case kAudioFileInvalidChunkError:
    print("kAudioFileInvalidChunkError")
    break
    case kAudioFileDoesNotAllow64BitDataSizeError:
    print("kAudioFileDoesNotAllow64BitDataSizeError")
    break
    case kAudioFileInvalidPacketOffsetError:
    print("kAudioFileInvalidPacketOffsetError")
    break
    case kAudioFileInvalidFileError:
    print("kAudioFileInvalidFileError")
    break
    case kAudioFileOperationNotSupportedError:
    print("kAudioFileOperationNotSupportedError")
    break
    case kAudioFileNotOpenError:
    print("kAudioFileNotOpenError")
    break
    case kAudioFileEndOfFileError:
    print("kAudioFileEndOfFileError")
    break
    case kAudioFilePositionError:
    print("kAudioFilePositionError")
    break
    case kAudioFileFileNotFoundError:
    print("kAudioFileFileNotFoundError")
    break
    case kAudioFileUnspecifiedError:
    print("kAudioFileUnspecifiedError")
    break
    case kAudioFileUnsupportedFileTypeError:
    print("kAudioFileUnsupportedFileTypeError")
    break
    case kAudioFileUnsupportedDataFormatError:
    print("kAudioFileUnsupportedDataFormatError")
    break
    case kAudioFileUnsupportedPropertyError:
    print("kAudioFileUnsupportedPropertyError")
    break
    case kAudioFileBadPropertySizeError:
    print("kAudioFileBadPropertySizeError")
    break
    default:
    print("unknown error")
    break
    }
    //<----DEBUG
    }
    }
    internalRSP.pointee.currentPacket += Int64(packetsReceived)
    }

    if internalRSP.pointee.recording
    {
    let outputStream:OSStatus = AudioQueueEnqueueBuffer(audioQueue, bufferQueue, 0, nil)
    if outputStream != 0
    {
    if verbose
    {
    print("Error with AudioQueueEnqueueBuffer")
    //<----DEBUG
    switch outputStream
    {
    case kAudioFilePermissionsError:
    print("kAudioFilePermissionsError")
    break
    case kAudioFileNotOptimizedError:
    print("kAudioFileNotOptimizedError")
    break
    case kAudioFileInvalidChunkError:
    print("kAudioFileInvalidChunkError")
    break
    case kAudioFileDoesNotAllow64BitDataSizeError:
    print("kAudioFileDoesNotAllow64BitDataSizeError")
    break
    case kAudioFileInvalidPacketOffsetError:
    print("kAudioFileInvalidPacketOffsetError")
    break
    case kAudioFileInvalidFileError:
    print("kAudioFileInvalidFileError")
    break
    case kAudioFileOperationNotSupportedError:
    print("kAudioFileOperationNotSupportedError")
    break
    case kAudioFileNotOpenError:
    print("kAudioFileNotOpenError")
    break
    case kAudioFileEndOfFileError:
    print("kAudioFileEndOfFileError")
    break
    case kAudioFilePositionError:
    print("kAudioFilePositionError")
    break
    case kAudioFileFileNotFoundError:
    print("kAudioFileFileNotFoundError")
    break
    case kAudioFileUnspecifiedError:
    print("kAudioFileUnspecifiedError")
    break
    case kAudioFileUnsupportedFileTypeError:
    print("kAudioFileUnsupportedFileTypeError")
    break
    case kAudioFileUnsupportedDataFormatError:
    print("kAudioFileUnsupportedDataFormatError")
    break
    case kAudioFileUnsupportedPropertyError:
    print("kAudioFileUnsupportedPropertyError")
    break
    case kAudioFileBadPropertySizeError:
    print("kAudioFileBadPropertySizeError")
    break
    default:
    print("unknown error")
    break
    //<----DEBUG
    }
    }
    }
    }
    }

    let queueResults = AudioQueueNewInput(&_recordState!.format, inputAudioQueue, &_recordState, nil, nil, 0, _recordState!.queue)
    if queueResults == 0
    {
    let bufferByteSize: Int = calculate(format: _recordState!.format, seconds: 0.5)
    for index in (0..<_recordState!.buffers.count)
    {
    AudioQueueAllocateBuffer(_recordState!.queue.pointee!, UInt32(bufferByteSize), &_recordState!.buffers[index])
    AudioQueueEnqueueBuffer(_recordState!.queue.pointee!, _recordState!.buffers[index]!, 0, nil)
    }

    AudioQueueStart(_recordState!.queue.pointee!, nil)
    _recordState?.recording = true
    }
    else
    {
    handler?(.error, nil, "Error setting audio input.")
    }
    }//eom

    func stop()
    {
    _recordState?.recording = false
    if let recordingState: RecordState = _recordState
    {
    AudioQueueStop(recordingState.queue.pointee!, true)
    AudioQueueDispose(recordingState.queue.pointee!, true)
    AudioFileClose(recordingState.file!)

    let audioData:NSData? = NSData(contentsOf: _audioURL!)
    handler?(.ready, audioData, nil)
    }
    }//eom

    // MARK:- Helper methods
    func calculate(format: AudioStreamBasicDescription, seconds: Double) -> Int
    {
    let framesRequiredForBufferTime = Int(ceil(seconds * format.mSampleRate))
    if framesRequiredForBufferTime > 0

    {
    return (framesRequiredForBufferTime * Int(format.mBytesPerFrame))
    }
    else
    {
    var maximumPacketSize = UInt32(0)
    if format.mBytesPerPacket > 0
    {
    maximumPacketSize = format.mBytesPerPacket
    }
    else
    {
    audioQueueProperty(propertyId: kAudioQueueProperty_MaximumOutputPacketSize, value: &maximumPacketSize)
    }

    var packets = 0
    if format.mFramesPerPacket > 0
    {
    packets = (framesRequiredForBufferTime / Int(format.mFramesPerPacket))
    } else
    {
    packets = framesRequiredForBufferTime
    }

    if packets == 0
    {
    packets = 1
    }

    return (packets * Int(maximumPacketSize))
    }
    }//eom

    func audioQueueProperty<T>(propertyId: AudioQueuePropertyID, value: inout T)
    {
    let propertySize = UnsafeMutablePointer<UInt32>.allocate(capacity: 1)
    propertySize.pointee = UInt32(MemoryLayout<T>.size)

    let queueResults = AudioQueueGetProperty(_recordState!.queue.pointee!, propertyId, &value, propertySize)
    propertySize.deallocate(capacity: 1)

    if queueResults != 0 {
    handler?(.error, nil, "Unable to get audio queue property.")
    }
    }//eom
    }

    玩家:
    import UIKit
    import AVFoundation


    protocol AudioPlayerDelegate {
    func audioPlayer_playbackError(playerItemID:String, error:String)
    func audioPlayer_playbackSuccess(playerItemID:String)
    }

    class AudioPlayer: NSObject, AVAudioPlayerDelegate
    {
    //properties
    private var _audioPlayer:AVAudioPlayer?
    var delegate:AudioPlayerDelegate?
    var playerItemID:String = ""
    var volume:Float?

    //MARK: - Play Audio
    func playAudioFromData(_ playerItemID:String, dataToPlay:Data)
    {
    do {
    let sharedSession = AVAudioSession.sharedInstance()
    try sharedSession.setCategory(AVAudioSessionCategoryPlayback)
    try sharedSession.setActive(true)

    _audioPlayer = try AVAudioPlayer(data: dataToPlay)

    _audioPlayer?.numberOfLoops = 0
    _audioPlayer?.isMeteringEnabled = true
    _audioPlayer?.delegate = self

    //volume
    if volume != nil {
    _audioPlayer?.volume = volume!
    }

    //id
    self.playerItemID = playerItemID

    _audioPlayer?.play()
    }
    catch let error {
    self.delegate?.audioPlayer_playbackError(playerItemID: self.playerItemID, error: error.localizedDescription)
    }
    }//eom

    func playAudioFromUrl(_ url:URL)
    {
    do {
    let sharedSession = AVAudioSession.sharedInstance()
    try sharedSession.setCategory(AVAudioSessionCategoryPlayback)
    try sharedSession.setActive(true)

    if FileManager.default.fileExists(atPath: url.path) {
    _audioPlayer = try AVAudioPlayer(contentsOf: url)

    _audioPlayer?.numberOfLoops = 0
    _audioPlayer?.isMeteringEnabled = true
    _audioPlayer?.delegate = self

    //volume
    if volume != nil {
    _audioPlayer?.volume = volume!
    }

    //id
    self.playerItemID = url.absoluteString

    _audioPlayer?.play()
    }
    else {
    self.delegate?.audioPlayer_playbackError(playerItemID: self.playerItemID, error: "audio file does not exist")
    }
    }
    catch let error {
    self.delegate?.audioPlayer_playbackError(playerItemID: self.playerItemID, error: error.localizedDescription)
    }
    }//eom

    //MARK: - Player Options
    func pausePlay()
    {
    _audioPlayer?.pause()
    }//eom

    func stopPlay()
    {
    _audioPlayer?.stop()

    do {
    let sharedSession = AVAudioSession.sharedInstance()
    try sharedSession.setActive(false)
    }
    catch let error {
    if verbose { print("un-able to set session to inactive, error: \(error)") }
    }
    }//eom

    //MARK: - Delegates
    func audioPlayerDecodeErrorDidOccur(_ player: AVAudioPlayer, error: Error?) {
    //inactive session
    do {
    let sharedSession = AVAudioSession.sharedInstance()
    try sharedSession.setActive(false)
    }
    catch let error {
    if verbose { print("un-able to set session to inactive, error: \(error)") }
    }

    //report status
    if error != nil {
    self.delegate?.audioPlayer_playbackError(playerItemID: self.playerItemID, error: error!.localizedDescription)
    }
    else {
    self.delegate?.audioPlayer_playbackError(playerItemID: self.playerItemID, error: "decode error did occurred")
    }

    //reset
    self._audioPlayer?.delegate = nil
    self._audioPlayer = nil
    self.playerItemID = ""
    }//eom

    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {

    //inactive session
    do {
    let sharedSession = AVAudioSession.sharedInstance()
    try sharedSession.setActive(false)
    }
    catch let error {
    if verbose { print("un-able to set session to inactive, error: \(error)") }
    }

    //report status
    if flag {
    delegate?.audioPlayer_playbackSuccess(playerItemID: self.playerItemID)
    }
    else {
    delegate?.audioPlayer_playbackError(playerItemID: self.playerItemID, error: "player finish playing with error")
    }

    //reset
    self._audioPlayer?.delegate = nil
    self._audioPlayer = nil
    self.playerItemID = ""
    }//eom

    }//eoc

    最佳答案

    如果您要同时使用 AudioToolBox 和 AVFoundation,您可能需要小心使用 AudioSession。 AVFoundation 对后端的 AudioSession 做了很多更新。

    对您的播放器的快速修复是删除任何 Audio Session 调用,如下所示:

    let sharedSession = AVAudioSession.sharedInstance()
    try sharedSession.setCategory(AVAudioSessionCategoryPlayback)
    try sharedSession.setActive(true)

    _audioPlayer?.numberOfLoops = 0
    _audioPlayer?.isMeteringEnabled = true

    如需更高级的音频处理,请查看 Learning Core Audio by Chris Adamson, Kevin Avila 本书

    关于ios - AudioToolBox Recorder 受到 AVFoundation AudioPlayer 的影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41230997/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com