Audio puffern und Frameweise als RTP Packet versenden
-
Hi an alle,
für einen VOIP Client muss ich Daten von einem Microphone aufzeichnen und diese frameweise als RTP Packet versenden.
Zuerst mal die Frage wenn ich die sprache mit WAVEFORM Audio aufzeichne, wie gebe ich diese am besten alles 20ms zum codieren weiter und wie hänge ich diese Frames dann anschließend an ein RTP Packet?
Obwohl ich mir letzteres schon einfach vorstelle habe ich vorwiegend ein Problem damit meine Aufzeichnung alle 20ms zu verarbeiten.
Hat jemand eine Idee wie man sowas machen könnte?
Gruß
CrazyPlaya
-
Ich verstehe noch nicht so ganz, wo dein Problem liegt? Du hast doch vermutlich eine feste Abtastrate. Mal angenommen, du tastest mit 48k ab, dann hast du doch 48 Abtastwerte pro ms und damit in 20 ms 48*20=960 Abtastwerte.
Du liest deine Daten ein, lässt nen Zähler mitlaufen und fängst bei 960 an mit bearbeiten...von RTP hab ich leider keinen Plan
-
Also ich habe von Audio Pufferung noch nicht soviel Ahnung. Also es geht hier ja um Live Übertragung. Ich spreche ins Mikro und sobald ich 20ms gesprochen habe soll der Puffer halt an die Funktion für die Codierung übergeben werden und von da aus dann an den Empfänger gesendet.
-
Von RTP hab ich auch keine Ahnung.
Anonsonsten würde ich so an die Sache rangehen: zwei Puffer (Stichwort: Double Buffer), jeder hat dabei Platz für 20ms.
Zunächst wird der eine mit den vom Mikrofon gelieferten Werte beschrieben.
Sobald er voll ist, wird er komprimiert. In der Zwischenzeit wird der zweite Puffer gefüllt. Wenn der voll ist wird der verarbeitet, während der erste wieder neu befüllt wird.
(Voraussetzung: die Verarbeitung geht schneller als Werte reinkommen)Auf Empfangsseite läuft's umgekehrt:
der erste Puffer wird mit empfangenen Daten gefüllt. Sobald der voll ist, beginnt die Ausgabe. Während dieser Zeit werden empfangene Daten in den zweiten Puffer geschrieben usw.
Hier muss natürlich sichergestellt sein, dass das Timing stimmt, d. h. genauso viele Daten angkommen, wie widergegeben werden.
-
Dieser Thread wurde von Moderator/in evilissimo aus dem Forum C++ in das Forum Rund um die Programmierung verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
@anonymus:
Der Begriff "double buffering" wird normalerweise nicht für Audio-Anwendungen verwendet - zumindest hab' ich ihn in dem Zusammenhang noch nicht gehört. Normalerweise verwendet man einen Ringpuffer den man in 2 oder mehr Teile unterteilt, oder gleich ganz ohne fixe Grenzen verwendet. Wenn man mit mehreren getrennten Puffern (anstelle eines Ringpuffers) arbeitet hat man auch üblicherweise mehr als 2 Puffer. Erst recht wenn die Puffer so kurz (20 ms) sind.@CrazyPlaya:
Unter Windows gibt's grundsätzlich 2 APIs: DirectSound und die waveIn Funktionen.DirectSound arbeitet mit einem Ringpuffer, die waveIn Funktionen mit mehreren getrennten Puffern. Die geringere Latenz solltest du mit DirectSound hinbekommen. Als dritte API gibt's dann noch ASIO, allerdings gibt's da soweit ich weiss nicht für alle Soundkarten Treiber.
Mit DirectSound definierst du also einfach einen Ringpuffer. Wie gross du den machst bleibt dir überlassen, aber ich würde den mal relativ gross ansetzen, mindestens 1-2 Sekunden. Daten verwerfen (wenn z.B. die max. Latenz überschritten wurde) kannst du später immer noch. Und bei kleinen Puffern ist es auch nicht so einfach rauszubekommen ob du eine komplette "Umdrehung" verschlafen hast -- was bei einem insgesamt 40ms langen Puffer schonmal vorkommen könnte. Dann kannst du dir Events setzen lassen wenn bestimmte Puffergrenzen überschritten werden. Blöderweise gibt's da einen Bug in vielen Soundkarten-Treibern (auch namhafter Hersteller), nämlich dass (zumindest beim Abspielen) diese Events zu oft gesetzt werden. Ideal ist IMO wenn du die Events verwendest um deinen Aufnahme-Thread aufwecken zu lassen, und zusätzlich noch alle paar Millisekunden selbst pollst (WaitForMultipleObject mit timeout). Und verlass dich nie darauf welcher Event getriggert hat -- also dass auch wirklich die Grenze des Events überschritten wurde der gerade gesetzt wurde. Wenn ein Event gesetzt wurde oder die Zeit fürs Polling abgelaufen ist hol dir einfach die aktuellen Zeiger/Cursor (IDirectSoundCaptureBuffer8::GetCurrentPosition), rechne dir anhand dieser Werte aus wieviel neue Samples im Puffer sind, kopier diese, und reich sie an den nächsten Teil weiter (Push-Modell) bzw. stell sie in eine Queue.
Der Rest sollte "relativ einfach" sein. Im Push-Modell musst du "nur noch" eine Funktion implementieren die diese Daten entgegennimmt und dann weiterverarbeitet. Wenn du da eine kleine Schnittstelle einziehst kannst du den Aufnahme-Teil (z.B. DirectSound) auch einfach unabhängig vom Rest austauschen.
An der Stelle kannst du z.B. auch schön Samples verwenfen wenn die max. Latenz überschritten wurde.
-
@Hustbaer: Ich habe noch nie mit directSound gearbeitet. Hast du evtl. Tutorials dazu parat? Das wäre super.
-
Nö, ich kenne keine Tutorials (gibt aber sicher welche). Im DirectX SDK sind aber Samples dabei, Google sollte auch einiges finden...
Und die Reference-Doku im MSDN ist eigentlich sehr gut.