2016-09-15 2 views
5

Ich versuche, Audio von dem Mikrofon zu einem anderen iPhone über Apples Multipeer Connectivity Framework zu streamen. Für die Audioaufnahme und -wiedergabe verwende ich AVAudioEngine (Vielen Dank an Rhythmic Fistman' s Antwort here).Versuchen, Audio von Mikrofon zu einem anderen Telefon über multipeer Konnektivität zu streamen

Ich erhalte Daten vom Mikrofon, indem ich einen Tipp auf den Eingang installiere, von diesem bekomme ich einen AVAudioPCMBuffer, den ich dann in ein Array von UInt8 umwandle, das ich dann auf das andere Telefon streame.

Aber wenn ich das Array zurück zu einem AVAudioPCMBuffer konvertiere, erhalte ich eine EXC_BAD_ACCESS-Ausnahme, wobei der Compiler auf die Methode verweist, in der ich das Byte-Array wieder in AVAudioPCMBuffer umwandle.

Hier ist der Code für ist, wo ich bin dabei, Konvertieren und Streamen des Eingangs:

input.installTap(onBus: 0, bufferSize: 2048, format: input.inputFormat(forBus: 0), block: { 
       (buffer: AVAudioPCMBuffer!, time: AVAudioTime!) -> Void in 

       let audioBuffer = self.typetobinary(buffer) 
       stream.write(audioBuffer, maxLength: audioBuffer.count) 
      }) 

für My beide Funktionen der Umwandlung der Daten (aus Martin.R ‚s Antwort genommen here):

func binarytotype <T> (_ value: [UInt8], _: T.Type) -> T { 
    return value.withUnsafeBufferPointer { 
     UnsafeRawPointer($0.baseAddress!).load(as: T.self) 
    } 

} 

func typetobinary<T>(_ value: T) -> [UInt8] { 
    var data = [UInt8](repeating: 0, count: MemoryLayout<T>.size) 
    data.withUnsafeMutableBufferPointer { 
     UnsafeMutableRawPointer($0.baseAddress!).storeBytes(of: value, as: T.self) 
    } 
    return data 
} 

Und auf der Empfängerseite:

func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) { 
    if streamName == "voice" { 

     stream.schedule(in: RunLoop.current, forMode: .defaultRunLoopMode) 
     stream.open() 

     var bytes = [UInt8](repeating: 0, count: 8) 
     stream.read(&bytes, maxLength: bytes.count) 

     let audioBuffer = self.binarytotype(bytes, AVAudioPCMBuffer.self) //Here is where the app crashes 

     do { 
      try engine.start() 

      audioPlayer.scheduleBuffer(audioBuffer, completionHandler: nil) 
      audioPlayer.play() 
     }catch let error { 
      print(error.localizedDescription) 

     } 
    } 
} 

die Sache ist, dass ich das Byte-Array vor und zurück konvertieren kann und Sound von ihm vor dem Streamen es (auf dem gleichen Telefon) aber nicht den AVAudioPCMBuffer auf der Empfängerseite erstellen kann. Weiß jemand, warum die Konvertierung auf der Empfängerseite nicht funktioniert? Ist das der richtige Weg?

Jede Hilfe, Gedanken/Eingabe dazu wäre sehr willkommen.

+0

können Sie einen Hinweis geben, wie Audio-Queue oder jedes Beispielprojekt zu verwenden? –

+0

Nein, ich kann nicht fürchte ich. – nullforlife

Antwort

4

Ihre AVAudioPCMBuffer Serialisierung/Deserialisierung ist falsch.

Swift3 Casting hat sich sehr verändert & scheint mehr kopieren als Swift2 erfordern.

Hier ist, wie Sie zwischen [UInt8] und AVAudioPCMBuffer s umwandeln kann:

N. B: Dieser Code geht davon aus mono float Daten bei 44,1 kHz.
Vielleicht möchten Sie das ändern.

func copyAudioBufferBytes(_ audioBuffer: AVAudioPCMBuffer) -> [UInt8] { 
    let srcLeft = audioBuffer.floatChannelData![0] 
    let bytesPerFrame = audioBuffer.format.streamDescription.pointee.mBytesPerFrame 
    let numBytes = Int(bytesPerFrame * audioBuffer.frameLength) 

    // initialize bytes to 0 (how to avoid?) 
    var audioByteArray = [UInt8](repeating: 0, count: numBytes) 

    // copy data from buffer 
    srcLeft.withMemoryRebound(to: UInt8.self, capacity: numBytes) { srcByteData in 
     audioByteArray.withUnsafeMutableBufferPointer { 
      $0.baseAddress!.initialize(from: srcByteData, count: numBytes) 
     } 
    } 

    return audioByteArray 
} 

func bytesToAudioBuffer(_ buf: [UInt8]) -> AVAudioPCMBuffer { 
    // format assumption! make this part of your protocol? 
    let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: true) 
    let frameLength = UInt32(buf.count)/fmt.streamDescription.pointee.mBytesPerFrame 

    let audioBuffer = AVAudioPCMBuffer(pcmFormat: fmt, frameCapacity: frameLength) 
    audioBuffer.frameLength = frameLength 

    let dstLeft = audioBuffer.floatChannelData![0] 
    // for stereo 
    // let dstRight = audioBuffer.floatChannelData![1] 

    buf.withUnsafeBufferPointer { 
     let src = UnsafeRawPointer($0.baseAddress!).bindMemory(to: Float.self, capacity: Int(frameLength)) 
     dstLeft.initialize(from: src, count: Int(frameLength)) 
    } 

    return audioBuffer 
} 
+0

Vielen Dank noch einmal Rhythmic Fistman! Das scheint zu funktionieren, aber ich habe ein paar Probleme. Wenn ich mit dem iPhone 5s aufnehme, wird die Aufnahme in 8kHz und im iPhone 6s 16kHz gemacht. Dies bringt das Programm zum Absturz, wenn ich einen 16kHz-Stream aussende und die Methode verwende (die einen 8kHz-Stream haben möchte). Hast du Tipps, wie du den Stream konvertieren kannst, bevor ich ihn sende? Auch wenn ich den Stream von den 5s zu den 6s sende und die Methode zum Empfang eines 8kHz-Streams einstellt, kommt der Sound nicht durch. Es spielt nur für ein paar Millisekunden weiße Noise, pausiert und wiederholt. Irgendwelche Gedanken? – nullforlife

+1

Ich empfehle, eine Abtastrate zu wählen und diese überall zu verwenden. Sie können dazu konvertieren, indem Sie Ihrer Engine einen 'AVAudioMixer' hinzufügen oder' AVAudioConverter' verwenden. –

+0

Hallo @RhythmicFistman, ich hatte eine Frage, ich hoffte, du könntest antworten. Ich verwende Ihren Algorithmus oben, und ich frage mich, was die Variable NumBytes ist. Basierend auf dieser Variable, wenn ich versuche, diese Daten in den Stream zu schreiben, sendet sie über 17000 Bytes pro Schreibvorgang, was unglaublich hoch erscheint.Schließlich schlägt der Schreibvorgang fehl, weil der Pufferspeicher der anderen Geräte voll ist ... – Logan

Verwandte Themen