2017-10-28 7 views
1

小さなチャンクでソケットを介して生のオーディオデータを再生する必要があります。私は循環バッファを使用してObjective Cでいくつかの解決策を見つけたと読んでいますが、特にSwift 3では動作させることができませんでした。
誰か助けてくれますか?Swiftのソケットから生のオーディオデータを再生する方法

+0

着信オーディオデータの形式を知っていますか? – dave234

+0

@Daveバイト数が増えているので、フォーマットはPCM –

答えて

0

まず、リングバッファを実装します。

public struct RingBuffer<T> { 
    private var array: [T?] 
    private var readIndex = 0 
    private var writeIndex = 0 

    public init(count: Int) { 
    array = [T?](repeating: nil, count: count) 
    } 

    /* Returns false if out of space. */ 
    @discardableResult public mutating func write(element: T) -> Bool { 
    if !isFull { 
     array[writeIndex % array.count] = element 
     writeIndex += 1 
     return true 
    } else { 
     return false 
    } 
    } 

    /* Returns nil if the buffer is empty. */ 
    public mutating func read() -> T? { 
    if !isEmpty { 
     let element = array[readIndex % array.count] 
     readIndex += 1 
     return element 
    } else { 
     return nil 
    } 
    } 

    fileprivate var availableSpaceForReading: Int { 
    return writeIndex - readIndex 
    } 

    public var isEmpty: Bool { 
    return availableSpaceForReading == 0 
    } 

    fileprivate var availableSpaceForWriting: Int { 
    return array.count - availableSpaceForReading 
    } 

    public var isFull: Bool { 
    return availableSpaceForWriting == 0 
    } 
} 

その後、オーディオユニットを実装します。これは、あなたが循環バッファにデータを配置し、サウンドを再生する必要が固定値

private let sampleRate = 16000 
private let amplitude: Float = 1.0 
private let frequency: Float = 440 

/// Theta is changed over time as each sample is provided. 
private var theta: Float = 0.0 


private func renderCallback(_ inRefCon: UnsafeMutableRawPointer, 
          ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, 
          inTimeStamp: UnsafePointer<AudioTimeStamp>, 
          inBusNumber: UInt32, 
          inNumberFrames: UInt32, 
          ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus { 
    let abl = UnsafeMutableAudioBufferListPointer(ioData) 
    let buffer = abl[0] 
    let pointer: UnsafeMutableBufferPointer<Float32> = UnsafeMutableBufferPointer(buffer) 
    for frame in 0..<inNumberFrames { 
     let pointerIndex = pointer.startIndex.advanced(by: Int(frame)) 
     pointer[pointerIndex] = sin(theta) * amplitude 
     theta += 2.0 * Float(M_PI) * frequency/Float(sampleRate) 
    } 
    return noErr 
} 

ある

class ToneGenerator { 
    fileprivate var toneUnit: AudioUnit? = nil 

    init() { 
     setupAudioUnit() 
    } 

    deinit { 
     stop() 
    } 

    func setupAudioUnit() { 

     // Configure the description of the output audio component we want to find: 
     let componentSubtype: OSType 
     #if os(OSX) 
      componentSubtype = kAudioUnitSubType_DefaultOutput 
     #else 
      componentSubtype = kAudioUnitSubType_RemoteIO 
     #endif 
     var defaultOutputDescription = AudioComponentDescription(componentType: kAudioUnitType_Output, 
                   componentSubType: componentSubtype, 
                   componentManufacturer: kAudioUnitManufacturer_Apple, 
                   componentFlags: 0, 
                   componentFlagsMask: 0) 
     let defaultOutput = AudioComponentFindNext(nil, &defaultOutputDescription) 

     var err: OSStatus 

     // Create a new instance of it in the form of our audio unit: 
     err = AudioComponentInstanceNew(defaultOutput!, &toneUnit) 
     assert(err == noErr, "AudioComponentInstanceNew failed") 

     // Set the render callback as the input for our audio unit: 
     var renderCallbackStruct = AURenderCallbackStruct(inputProc: renderCallback as? AURenderCallback, 
                  inputProcRefCon: nil) 
     err = AudioUnitSetProperty(toneUnit!, 
            kAudioUnitProperty_SetRenderCallback, 
            kAudioUnitScope_Input, 
            0, 
            &renderCallbackStruct, 
            UInt32(MemoryLayout<AURenderCallbackStruct>.size)) 
     assert(err == noErr, "AudioUnitSetProperty SetRenderCallback failed") 

     // Set the stream format for the audio unit. That is, the format of the data that our render callback will provide. 
     var streamFormat = AudioStreamBasicDescription(mSampleRate: Float64(sampleRate), 
                 mFormatID: kAudioFormatLinearPCM, 
                 mFormatFlags: kAudioFormatFlagsNativeFloatPacked|kAudioFormatFlagIsNonInterleaved, 
                 mBytesPerPacket: 4 /*four bytes per float*/, 
      mFramesPerPacket: 1, 
      mBytesPerFrame: 4, 
      mChannelsPerFrame: 1, 
      mBitsPerChannel: 4*8, 
      mReserved: 0) 
     err = AudioUnitSetProperty(toneUnit!, 
            kAudioUnitProperty_StreamFormat, 
            kAudioUnitScope_Input, 
            0, 
            &streamFormat, 
            UInt32(MemoryLayout<AudioStreamBasicDescription>.size)) 
     assert(err == noErr, "AudioUnitSetProperty StreamFormat failed") 

    } 

    func start() { 
     var status: OSStatus 
     status = AudioUnitInitialize(toneUnit!) 
     status = AudioOutputUnitStart(toneUnit!) 
     assert(status == noErr) 
    } 

    func stop() { 
     AudioOutputUnitStop(toneUnit!) 
     AudioUnitUninitialize(toneUnit!) 
    } 

} 

を(必要に応じて変更します)。

+0

p.s.これは、udpの生のオーディオ用コードです。 PCM 16000 周波数440 –

+0

ここでバッファを読み込み、再生用に送信しますか?私は今あなたのコードを理解しようとしています –

関連する問題