CSCore Mikrofon-Übertragung mit UDP

  • VB.NET

Es gibt 14 Antworten in diesem Thema. Der letzte Beitrag () ist von MarioGeier00.

    CSCore Mikrofon-Übertragung mit UDP

    Hallo Liebe Vb-ler

    Ich möchte per CSCore einen "Sprachchat" erstellen. In meinem Fall heißt das also, dass ich einen Client-Computer habe und der sich mit einem Server-Computer verbindet und sich beide die Daten des Mirkrofons zusenden. Das Aufnehmen mittels CSCore-DLL, das Versenden per UDPClient, das Abspeichern beim jeweils anderen Computer und das wiedergeben nach dem Speichern klappt einwandfrei.
    Bloß hätte ich das gerne gleich nach dem Empfangen abgespielt. Der Ansatz wäre, dass man die Bytes, die am UdpClient empfangen werden, in einen Stream schreibt und diesen einem Steuerelement(z.B ActiveX ?) zum direkten abspielen übergibt, oder, indem man die CSCore-Libary zu hilfe nimmt und den Stream damit abspielt. Bloß habe ich bei keinen der beiden Möglichkeiten eine Ahnung, wie man das macht bzw. welches Steuerelement man dazu nimmt.

    Wie kann ich also das Array von byte, das mittels UDPClient emfangen wurde, in einen NEUEN Stream schreiben? Vllt MemoryStream!?
    Und wie kann ich den Stream dann mit der CSCore-Libary wiedergeben?

    Vielen Danke für hilfreiche Antworten schonmal im vorraus ;)

    Und noch eine optionale Frage: Ich möchte eine Visualisierung des Sounds mit CSCore machen. Aber ich habe das Problem, dass bei mir der Import-Ausdruck von CSCore.Visualization grün unterringelt wird und Visual Basic das ganze deswegen nicht importiert. Also kann ich den Code zur Visualisierung nicht nutzen. Ich kann mir vorstellen, dass der Fehler was mit der Projektmappe zu tun hat.

    Aber was kann ich dagegen tun?

    Mit freundlichen Grüßen

    Mario Geier ^^

    MarioGeier00 schrieb:

    Und wie kann ich den Stream dann mit der CSCore-Libary wiedergeben?

    Es gibt die WriteableBufferingSource-Klasse, welcher du ein Format angeben musst und in welche du Daten schreiben kannst. In deinem Fall würde ich FillWithZeros auf true lassen. Ansonsten bricht der Stream ab sobald du einmal keine Daten bekommst (so hörst du einfach nur nichts). Bedenke, dass das Teil nichts dekodiert. Müssen also Rohdaten rein. Kannst du anschließend prima wiedergeben.

    Visualisierungen sind nicht Standard. Es gibt ein Beispiele mit Visualisierungen. Dort kannst du den Code entnehmen.


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.
    Vielen Dank für deine Antwort, denn von alleine drauf zu kommen ist einfach zu schwierig :D

    Jedoch habe ich noch zu wenig Erfahrung mit CSCore und deshalb funktioniert der Code wahrscheinlich auch nicht:

    Quellcode

    1. ​Dim SoundOut As New SoundOut.DirectSoundOut()
    2. Dim source As ISampleSource
    3. Private Sub UdpWorker_DoWork() Handles UdpWorker.DoWork
    4. Dim Udp As New UdpClient(Endpoint.Port)
    5. Dim BufferingSource As New Streams.WriteableBufferingSource(New WaveFormat(11000, 8, 2))
    6. BufferingSource.FillWithZeros = True
    7. source = BufferingSource.ToSampleSource
    8. SoundOut.Initialize(source.ToWaveSource())
    9. SoundOut.Play()
    10. Do
    11. Dim rec = Udp.Receive(Endpoint)
    12. BufferingSource.Write(rec, 0, rec.Length)
    13. Loop
    14. End Sub


    Also das Empfangen von Daten funktioniert, also er läuft die Do-Schleife immer durch. Bloß wird nichts abgespielt. Habe auch schon versucht den Code so zu gestalten:

    Quellcode

    1. Dim Udp As New UdpClient(Endpoint.Port)Dim BufferingSource As New Streams.WriteableBufferingSource(New WaveFormat(11000, 8, 2))
    2. BufferingSource.FillWithZeros = True
    3. Do
    4. Dim rec = Udp.Receive(Endpoint)
    5. BufferingSource.Write(rec, 0, rec.Length)
    6. source = BufferingSource.ToSampleSource
    7. SoundOut.Initialize(source.ToWaveSource())
    8. SoundOut.Play()
    9. Loop​


    Jedoch bringt er mir dann bei der zweiten Version bei 'SoundOut.Play()', das die Variable SoundOut nicht Initialisiert sei.
    Was stimmt am Code nicht?

    Mit freundlichen Grüßen

    Mario Geier
    Hab gerade mal genauer nachgeschaut und gesehen, dass in das WritableBufferingSource gar nichts reingeschreiben wird. Der BufferingSource.Write()-Befehl wird zwar ausgeführt, und in der Variable rec stehen auch ganz viele Bytes, aber wenn ich dann direkt dannach den BufferingSource.Read()-Befehl ausführe bringt er mir, dass die Anzahl an Bytes, die ich lesen möchte, mehr seinen als reingeschrieben sind. Das stimmt natürlich nicht, da ich vorher mehr als 7000 Bytes von dem UdpClienten reingeschrieben habe. Und auch wenn ich per Haltepunkt mir die Variable anschaue zeigt er mir bei length -1 der Variable BufferingSource an. Was tun?
    Nimm den nuget build. Und das mit dem lesen ist gewollt. Wäre der Puffer leer, so würde das Playback stoppen. Deshalb FillWithZeros (er liest immer die angeforderten Bytes nur wenn nicht so viel im Puffer ist wird mit nullen aufgefüllt (du hörst nix, playback läuft aber).


    Opensource Audio-Bibliothek auf github: KLICK, im Showroom oder auf NuGet.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „thefiloe“ ()

    Also du meinst, wenn ich die 1.1 Version nehm, dann geht der Fehler mit der fehlgeschalgenen Initialisierung weg?

    Ich hab gerade versucht des von nuget herunterzuladen, aber ich bin andscheinend echt zu blöd dafür. Kannst mir mal nen Link schicken? Weil bei mir lädt der nur so komische .nupkg Dateien herunter.

    Und der Code von DirectSoundOut passt so?

    Grüße Mario
    @MarioGeier00
    ich bin andscheinend echt zu blöd dafür. [...] Weil bei mir lädt der nur so komische .nupkg Dateien herunter.

    Jo, ist eigentlich ganz einfach. Im Anhang zwei Fotos. Als erstes musst du den Nuget-Package-Manager in VS öffnen und anschließend CSCore suchen. Ich habe alle wichtigen Stellen markiert ;)
    Bilder
    • 1.png

      60,55 kB, 736×650, 73 mal angesehen
    • 2.png

      66,66 kB, 1.186×690, 82 mal angesehen
    Mfg
    Vincent

    Danke 'VincentTB', ich werde es gleich mal ausprobieren.

    Kannst du mir sagen ob der Code den ich oben gepostet hab so stimmt? Hab nämlich immer noch das Problem, das er mir bei der Play methode den fehler ausgibt, dass es noch nicht initialisiert sei. Oder liegt das nur an der Version von der CSCore Libary?

    Grüße Mario ^^
    Jetzt funktioniert es endgültig :D

    Habe aber noch ne Frage:

    Wenn ich jetzt also über die Wan-Ip/DDNS von dem Client-Computer über UDP die Daten sende wäre das für mein Verständnis noch möglich, da ich ja an meinem Router die Ports forwarden kann. Jedoch wenn ich das Ganze nun in anderer Richtung machen würde, also zum Client hin, dann würde das nicht funktionieren, da am Client Router kein Port forgewardet wurde. Geht es mit Udp also nicht wie mit Tcp, dass ich an den Client Daten über die entstehende Verbindung sende, ohne, dass dort portforwarding durchgeführt wurde?
    Verstehe nicht ganz was du sagen willst, aber meinst du dass bei peer2peer die portweiterleitung aktiviert werden muss (auf beiden Seiten)?
    Wenn ja, kannst du das umgehen indem du UDP Hole Punching implementierst.
    Dazu brauchst du noch einen externen Server und musst dann folgende Schritte durchführen:

    Client1 sendet Server dass er sich mit Client2 verbinden möchte.
    Server registriert das.
    Client 2 sendet Server dasselbe.
    Server registriert das.
    Anschließend sendet der Server die IP und den PORT von dem Client1 und Client2 jeweils ihre Daten gesendet haben und schickt Sie dem gegenüber
    Dadurch das beim senden eines Packets der Port freigeschaltet wird, können Client2 und Client1 nun direkt eine Verbindung aufbauen (ohne das die Firewall dies abfängt, also kein Portforwarding mehr nötig.)

    Wenn du eine konkrete Implementierung sehen möchtest, ich hab die letzten Tage an einem kleinen Sprachchat gearbeitet, der das implementiert + Chats mit mehreren Leuten und Gruppenchats
    Sorry, das ich das Thema nochmal aufwühle, ich bekomme es aber iwie nicht hin, mit der klasse wasapi in cscore, die mein Micro aufnimmt, ein Linespektrum zu erzeugen. ?(

    Code bis jetzt:

    VB.NET-Quellcode

    1. ​Private _soundIn As New WasapiCapture
    2. Private _writer As IWriteable
    3. Private BufferingSource As Streams.WriteableBufferingSource
    4. Private _finalSource As IWaveSource
    5. Dim buffer As Byte()
    6. Public Sub StartRecording(ByVal FileStream As Stream)
    7. If _soundIn.RecordingState = RecordingState.Recording Then StopRecording()
    8. If GetCaptureMode() = CaptureMode.Microphone Then
    9. _soundIn = New WasapiCapture()
    10. Else
    11. _soundIn = New WasapiLoopbackCapture()
    12. End If
    13. _soundIn.Device = GetSelectedDevice()
    14. _soundIn.Initialize()
    15. Dim soundInSource = New SoundInSource(_soundIn)
    16. Dim singleBlockNotificationStream = New SingleBlockNotificationStream(soundInSource.ToSampleSource)
    17. _finalSource = singleBlockNotificationStream.ToWaveSource()
    18. _writer = New WaveWriter(DataStream, _finalSource.WaveFormat)
    19. buffer = New Byte(_finalSource.WaveFormat.BytesPerSecond / 2 - 1) {}
    20. ' ?
    21. AddHandler _soundIn.DataAvailable, AddressOf NewDataAvailable
    22. ' ?
    23. AddHandler singleBlockNotificationStream.SingleBlockRead, AddressOf blockRead
    24. _soundIn.Start()
    25. End Sub
    26. Sub blockRead(s, a)
    27. ' Zu Testzwecken, hier würde ich dem LineSpectrum anfügen
    28. MsgBox(a.Left & " ; " & a.Right)
    29. End Sub
    30. Sub NewDataAvailable()
    31. Dim read As Integer = 1
    32. Do
    33. read = _finalSource.Read(buffer, 0, buffer.Length)
    34. If read <= 0 Then Exit Do
    35. _writer.Write(buffer, 0, read)
    36. Loop
    37. End Sub


    Ich weiß net ob des stimmt, bei der MsgBox jedenfalls zeigt er mir 0 ; 0 an, immer.

    Und übrigens: bei wasapiout, also wenn ich sound abspiele, funktioniert das Linespectrum :D


    LG Mario Geier