[OpenAL] Streaming ohne CPU-Belastung und Problem mit Wiedergabe
-
Hm sorry, aber das hilft mir jetzt irgendwie gar nich weiter.
Auf die Idee mit dem Debugger bin ich auch schon gekommen. Mit dem eingebauten usleep hält er (logischerweise) immer in dieser Funktion an, ohne usleep hält er immer in verschiedenen Funktionen von OpenAL oder OggVorbis an.
Außerdem würde ein Zeitproblem ja nicht die Ursache für die schwankende CPU-Auslastung sein.
-
devkid schrieb:
1. Wenn ich das ganze so laufen lasse, hat meine CPU immer eine Auslastung von 100%...
Dein Programmteil besteht nur aus einer Schleife. Solange das Programm aktiv ist, läuft er die Schleife durch. Das verursacht doch eine CPU-Auslastung von 100%, oder? Ich habe bisher nie nachgeschaut.
devkid schrieb:
..., auch wenn die Zeit, die er fürs decodieren braucht, schon längst um ist (sollte ja aber auch nicht an einem Stück sein, weil er mir ja sonst den Arbeitsspeicher volllaufen lässt).
Wenn ich das richtig verstehe, decodiert er sofort die gesammte OggVorbis-Datei?
Dann solltest du mit AL_BUFFER_PROCESSED die abgespielten Buffer abfragen und nur diese neu füllen. Wenn noch keine Buffer abgespielt sind, sollte auch nichts nachgeladen werden.devkid schrieb:
2. Bei der Wiedergabe sind ab und zu ein paar kleine "Lücken" zu hören, bei denen nichts abgespielt wird (Dauer: ~0,05s, also wirklich sehr kurz). Ich verwende eine Buffer-Größe von 4096*8=32768, was eigentlich genug sein sollte, und insgesamt 2 Buffer.
Wenn du den Prozess mit usleep schlafen legst, wird er wohl nicht mehr rechtzeitig aufwachen, bevor die geladenen Buffer abgespielt wurden. Dann hat deine OpenAL Quelle nichts mehr zum Abspielen, bis die Buffer neu mit Daten gefüllt wurden.
Ich hoffe, ich habe dein Problem richtig verstanden.
Gruss
Gameco
-
Gameco schrieb:
Dein Programmteil besteht nur aus einer Schleife. Solange das Programm aktiv ist, läuft er die Schleife durch. Das verursacht doch eine CPU-Auslastung von 100%, oder? Ich habe bisher nie nachgeschaut.
Das muss denk ich mal auch so sein, war jetzt auch nur zum Vergleich mit der Sache mit
usleep ()
.Gameco schrieb:
Wenn ich das richtig verstehe, decodiert er sofort die gesammte OggVorbis-Datei?
Hm eigentlich doch nicht die ganze Datei auf einmal. Er decodiert und füllt die Buffer ja nur, wenn schon Buffer abgearbeitet sind.
Gameco schrieb:
Dann solltest du mit AL_BUFFER_PROCESSED die abgespielten Buffer abfragen und nur diese neu füllen. Wenn noch keine Buffer abgespielt sind, sollte auch nichts nachgeladen werden.
Das tue ich ja bereits. In der Hauptschleife frage ich ab, welche Buffer schon abgearbeitet sind. Diese fülle ich dann wieder mit Daten.
Gameco schrieb:
Wenn du den Prozess mit usleep schlafen legst, wird er wohl nicht mehr rechtzeitig aufwachen, bevor die geladenen Buffer abgespielt wurden. Dann hat deine OpenAL Quelle nichts mehr zum Abspielen, bis die Buffer neu mit Daten gefüllt wurden.
Das Problem tritt aber leider auch ohne das
usleep ()
auf.Für mein erstes Problem wär mir eine Funktion am liebsten, die den aufrufenden Thread blockt, bis ein oder mehrere Buffer abgearbeitet wurden. Mit
usleep ()
kann man je eh nur auf die Zeit spekulieren.
-
devkid schrieb:
Das Problem tritt aber leider auch ohne das
usleep ()
auf.Ich habe vor ein oder zwei Wochen mit OggVorbis angefangen, darum habe ich da nicht so viel Erfahrung mit, die ich teilen könnte. Ich habe nur gelesen, dass solche Lücken durch zu kleine Buffer enstehen können.
Ich verwende 2 Buffer mit einer Grösse von 4096 * 10 (Ich habe keinen Grund, warum ich genau diese Grösse verwende). Ich prüfe in einer Endlosschleife, ob ein Buffer abgespielt wurde, und wenn ja, fülle ich ihn sofort wieder. Auf meinem Windows XP mit OpenAL funktioniert das ohne Probleme.
-
Dieser Thread wurde von Moderator/in evilissimo aus dem Forum C++ in das Forum Spiele-/Grafikprogrammierung verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Also ich habe bisher alle ogg-Dateien, die ich abspielen wollte am Anfang komplett in den Systemspeicher geladen, in einen OpenAL-Buffer geschrieben und dann abgespielt. Dann hast du
1.) kein Problem mit dem Nachladen der Daten, weil du sie schon alle hast,
2.) brauchst du keine Schleife mehr, die sich darum kümmert, die Daten nachzuladen und in die Puffer zu schreiben und dadurch
3.) kein Problem mit dem Prozessor, weil der nichts zu tun hatDer einzige Nachteil ist, dass du etwas mehr Systemspeicher brauchst (aber in Zeiten von mehreren GB Arbeitsspeicher ist das ja eigentlich kein Problem) - kommt aber auch immer darauf an, wie groß deine Musikdatei ist!
-
Es kommt leider nicht auf die Größe der Musikdatei an, sondern auf die Länge. Die Datei wird dann ja komplett in den Arbeitsspeicher gelesen, was bei einem zehn Minuten langen Stück ja doch schon an die 100 MB sein können. Außerdem dauert alleine das Dekodieren schon eine gewissen Zeit (mindestens einige Sekunden).
@Gameco: Trotzdem danke erstmal. Verwendest du
Sleep ();
in der Schleife? Wenn ja, wie siehts da mit der CPU-Auslastung aus? Falls du die Zeit findest: könntest du mal einen kleinen Code-Schnippsel posten (oder no-pasten), der bei dir funktioniert?Hab das ganze auch mal mit PortAudio probiert, dort klappt das alles problemlos. Da kann man aber auch variable Buffer-Größen verwenden (wird von PortAudio berechnet, ebenso wie die Zeit für
usleep ();
).
-
devkid schrieb:
@Gameco: Trotzdem danke erstmal. Verwendest du
Sleep ();
in der Schleife?Nein, momentan geht das Programm dort so häufig durch, wie es der Prozessor erlaubt. Allerdings werden noch ein paar andere Sachen in der Schleife gemacht.
Ich habe aber vor, das irgendwann auf maximal 60 Aufrufe pro Sekunde zu begrenzen.devkid schrieb:
Falls du die Zeit findest: könntest du mal einen kleinen Code-Schnippsel posten (oder no-pasten), der bei dir funktioniert?
Ich habe mich stark am Tutorial auf DevMaster.net orientiert. Anstatt ov_open habe ich wegen Windows ov_open_callbacks verwendet. Den Rest der OggVorbis-relevanten Programmteile habe ich mehr oder weniger so übernommen.
-
Gameco schrieb:
Ich habe mich stark am Tutorial auf DevMaster.net orientiert. Anstatt ov_open habe ich wegen Windows ov_open_callbacks verwendet. Den Rest der OggVorbis-relevanten Programmteile habe ich mehr oder weniger so übernommen.
Hm ich hab eigentlich auch alles genau so gemacht, wie in diesem Tutorial.
Da das Programm bei dir so oft durchläuft wie nur möglich geh ich davon aus, dass du momentan auch eine CPU-Auslastung von 100% hast, oder?
-
devkid schrieb:
Hm ich hab eigentlich auch alles genau so gemacht, wie in diesem Tutorial.
Dann "müsste" es eigentlich funktionieren. Hast du schon versucht, verschiedene Ogg-Dateien abzuspielen? Vielleicht "stimmt" etwas mit der Datei nicht.
devkid schrieb:
Da das Programm bei dir so oft durchläuft wie nur möglich geh ich davon aus, dass du momentan auch eine CPU-Auslastung von 100% hast, oder?
Das stimmt.
-
Gameco schrieb:
devkid schrieb:
Hm ich hab eigentlich auch alles genau so gemacht, wie in diesem Tutorial.
Dann "müsste" es eigentlich funktionieren. Hast du schon versucht, verschiedene Ogg-Dateien abzuspielen? Vielleicht "stimmt" etwas mit der Datei nicht.
Hm das noch nicht, aber Totem, vlc, Banshee, Rhythmbox spielen die alle problemlos ab... Falls es doch irgendwie daran liegt, melde ich mich noch mal.
Sonst noch jemand ne Idee?
-
fülle_buffer_mit_raw_daten (); queue_buffer ();
In Deinem Pseudocode ist nicht nachvollziehbar was mit den bereits abgespielten passiert.
Damit man nicht staendig neue Buffer (de-)allozieren muss, nimmt man dafuer normalerweise einen Ring-Buffer.
Im Rahmen einer Audioapplikation realisiert man das am einfachsten durch einen Sample mit Looping:channels= 2 blockSize = 1024*channels // willkuerliche Blockgroesse blockCount= 10 // willkuerliche Blockanzahl Erzeuge Soundbuffer mit blockSize*blockCount Samples Dekodiere blockSize*blockCount nach Soundbuffer (initial komplett fuellen) Spiele Soundbuffer curBlock= 0 Thread { // Ermitteln welcher Block gerade abgespielt wird // (wenn Ende des Sample erreicht ist, geht's wegen Looping wieder bei 0 los) playBlock= (Lese aktuelle Abspielposition von Soundbuffer) / blockSize // SoundBuffer bis zur Abspielposition fuellen: while (playBlock!=curBlock) { Dekodiere blockSize nach Soundbuffer+blockSize*curBlock curBlock= (curBlock+1) % blockCount } // Buffer wieder voll. // Thread schlafen legen bis mindestens ein Block wieder abgespielt wurde: sleep( dauerEinesBlocks ) }