Riesenringpuffer

  • Themenstarter Gelöschtes Mitglied 9001
  • Beginndatum
G

Gelöschtes Mitglied 9001

Gast
Hallo Forum,

wie man einen Ringpuffer implementiert, ist mir klar, schon gefühlt hundertmal gemacht. Nun sind die Bedingungen aber etwas ungünstig: der Puffer soll bis zu einige Gigabyte umfassen (~5GB), der verfügbare Arbeitsspeicher ist < 1GB, Festplatte ist eine Micro-SD-Karte (ja, es ist ein Raspi).
Bei jedem Schreib- und Lesevorgang werden Datenblöcke von ca 1-2 MB in den Puffer eingefügt/herausgeholt. Mein erster Gedanke war natürlich, FileChannel zu verwenden. Dann erinnerte ich mich, dass SD-Karten es nicht so sehr mögen, häufig beschrieben zu werden. Also müßte man wenigstens teilweise den Puffer im Arbeitsspeicher vorhalten.
Die (Audio-)Eingabedaten kommen von einem Audiointerface in schneller Folge in den Puffer. Die Daten werden von einem Server-Prozess aus dem Puffer herausgeholt und an einen Client ausgeliefert, der per Wlan verbunden ist. Diese Verbindung kann sehr gut sein - in dem Fall würden wohl nur einige MB des Ringpuffers belegt sein. Die Verbindung kann aber auch sehr schlecht sein und gelegentlich unterbrochen werden. Für genau diesen Fall muß der Puffer sehr groß sein, um sicherzugehen, dass keine Daten verloren gehen. (Dass die Audiolatenz dann enorm ist, ist richtig, spielt aber bei meinem Anwendungszweck keine Rolle).

Mich würden eure Gedanken dazu interessieren. Ist das mit den SD-Karten immer noch so? Gibt es bereits vorhandene Ansätze für irgendwie geartete zweistufige Ringpuffer, die teils im Ram, teils auf dem Dateisystem agieren?
 

Thallius

Top Contributor
Ich frage mich wie du auf 5GB kommst. Das sind ja fast 20 Stunden unkomprimiertes Audio in CD Qualität..... So schlecht kann die Lazenz ja wohl gar nicht sein....
 
G

Gelöschtes Mitglied 9001

Gast
6 Kanäle, 24bit, 96 kHz. 5GB sind da ca. 51 Minuten. Da ich den Aufnahmeprozess nicht überwachen kann, da ich selbst spiele, muss das System einen ausreichend großen Puffer haben für den Fall, dass unbemerkt die Verbindung abbrach, was bei einer Entfernung von 30m durchaus passieren kann.
Der Raspi hat 1 GB Ram, der natürlich dem Programm nicht in Gänze zur Verfügung steht, da ja auch noch andere Programme laufen. Gehen wir mal von 500MB benutzbarem Speicher aus, sind das dann nur noch 5 Minuten Puffer. Für den Ernstfall zu wenig, wenn z.B. das aufzunehmende Stück 12 Minuten dauert und die Verbindung nach 4 Minuten unbemerkt abbrach.
Daher suche ich also eine effiziente Möglichkeit, einen Ringpuffer teilweise auf der SD-Karte liegen zu haben.
 
G

Gelöschtes Mitglied 9001

Gast
Ja, ich brauche unbedingt raw.
Ich würd mich wirklich gerne eher über das Thema Ringpuffer unterhalten als über Sinn und Zweck, warum und wieso ich meine Tonaufnahme mache.
 

LimDul

Top Contributor
Was du probieren könntest, anstelle das Problem in Java zu lösen - einfach 10 GB Swap Space anlegen und der JVM entsprechend RAM zur Verfügung zu stellen. Dann löst das OS das Problem für dich..
 

LimDul

Top Contributor
Naja, ich kann die Anforderung schon verstehen, dass man die RAW-Daten übertragen möchte. Und 5 GB sind jetzt auch nicht viele Daten.

Wenn man es in Java umsetzen würde, würde ich es wie folgt machen:

* Einen Ringpuffer der tatsächlich komplett über FileChannel geht.
* Da eine CachedRingpuffer drum wrappen, der einen Cache von X Megabyte hat und wie folgt arbeitet:

Beim Schreiben
- Wenn der FileChannelPuffer nicht leer ist => FileChannel Schreiben
- Wenn der FileChannelPuffer leer ist und Platz im Cache => In den Cache hinten anhängen
- Wenn der FileChannelPuffer leer ist und zuwenig Platz im Cache => FileChannel Schreiben

Beim Lesen
* Aus dem Cache lesen
* Danach, wenn der FileChannelPuffer nicht leer ist, den Cache aus dem FileChannelPuffer wieder auffüllen bis entweder Cache voll oder FileChannelPuffer leer

Etwas aufpassen muss man mit MultiThreading, dass das klappt. Ggf. muss man da mit einer gemeinsamen Semaphore arbeiten.
 
G

Gelöschtes Mitglied 9001

Gast
Was du probieren könntest, anstelle das Problem in Java zu lösen - einfach 10 GB Swap Space anlegen und der JVM entsprechend RAM zur Verfügung zu stellen. Dann löst das OS das Problem für dich..
Ja, darüber habe ich nachgedacht. Jedoch: Gängige Ringpufferimplementationen arbeiten ja auf einem linearen Speicher und wandern durch den von vorn bis hinten durch. Selbst wenn die Nutzdaten nur einen Bruchteil der Kapazität des Speichers betragen, wird so der gesamte Speicher genutzt, was dazu führt, dass das Betriebssystem permanent auch die ungenutzten Daten zwischen Harddisk und Ram hin und herschaufeln wird. Ich glaube nicht, dass das effizient sein wird.
 

LimDul

Top Contributor
Ja, darüber habe ich nachgedacht. Jedoch: Gängige Ringpufferimplementationen arbeiten ja auf einem linearen Speicher und wandern durch den von vorn bis hinten durch. Selbst wenn die Nutzdaten nur einen Bruchteil der Kapazität des Speichers betragen, wird so der gesamte Speicher genutzt, was dazu führt, dass das Betriebssystem permanent auch die ungenutzten Daten zwischen Harddisk und Ram hin und herschaufeln wird. Ich glaube nicht, dass das effizient sein wird.
Stimmt, du bräuchtest dann eine Implementierung, die den Speicher dynamisch verwaltet z.B. in Form einer doppelt verketteten Liste (damit man hinten anhängen kann und vorne wegnehmen kann). Das wäre dann allerdings kein Ringpuffer mehr sondern ein potentiell unendlich großer Puffer.
 
G

Gelöschtes Mitglied 9001

Gast
* Einen Ringpuffer der tatsächlich komplett über FileChannel geht.
* Da eine CachedRingpuffer drum wrappen, der einen Cache von X Megabyte hat und wie folgt arbeitet:

Beim Schreiben
- Wenn der FileChannelPuffer nicht leer ist => FileChannel Schreiben
- Wenn der FileChannelPuffer leer ist und Platz im Cache => In den Cache hinten anhängen
- Wenn der FileChannelPuffer leer ist und zuwenig Platz im Cache => FileChannel Schreiben

Beim Lesen
* Aus dem Cache lesen
* Danach, wenn der FileChannelPuffer nicht leer ist, den Cache aus dem FileChannelPuffer wieder auffüllen bis entweder Cache voll oder FileChannelPuffer leer
Das klingt vielversprechend! Werde ich ausprobieren.
 
G

Gelöschtes Mitglied 9001

Gast
Stimmt, du bräuchtest dann eine Implementierung, die den Speicher dynamisch verwaltet z.B. in Form einer doppelt verketteten Liste (damit man hinten anhängen kann und vorne wegnehmen kann). Das wäre dann allerdings kein Ringpuffer mehr sondern ein potentiell unendlich großer Puffer.
Das würde gehen. Man müßte die ankommenden Daten in Blöcke aufteilen, die nicht zu groß und nicht zu klein sind. Und damit das ganze nicht ins Unendliche wächst, die Menge mit einem Zähler überwachen und ggf. Datenblöcke verwerfen. Oder man fragt den verfügbaren Speicher ab, das könnte aber evtl. etwas teurer sein.
 
G

Gelöschtes Mitglied 9001

Gast
Praktischerweise überläßt man das Auslagern, wie du schon schriebst, dem Betriebssystem oder aber man lagert die frischsten Blöcke manuell aus, wenn der Speicher knapp wird, vermerkt im Block den Verweis und holt die Daten wieder ein, wenn sie gelesen werden sollen.
 
G

Gelöschtes Mitglied 9001

Gast
Gerade festgestellt: man kann beim Starten eines Java-Programmes den Heap-Speicher nicht auf einen größeren Wert einstellen als physikalisch vorhanden ist. Also muss man das Auslagern selbst übernehmen.
 
G

Gelöschtes Mitglied 9001

Gast
Es geht hier um eine professionelle Tonaufnahme mit 6 Mikrofonen = 6 Kanäle in 24bit und 96kHz Auflösung. MP3 hat im professionellen Umfeld nichts zu suchen und ist vom Fraunhofer Institut (=Erfinder von MP3) schon lange als veraltet bezeichnet worden. Bei Tonaufnahmen wird einzig und allein unkomprimierter Ton verwendet.
 
K

kneitzel

Gast
Nur einmal ganz kurz als Anmerkung ohne viel Text:
MP3 (mpeg-1/2 Audio Layer 3) ist eine verlustbehaftete Komprimierung.

Verlustbehaftete Komprimierungen haben im professionellen Bereich generell nie etwas verloren.

Man könnte sich maximal überlegen, da statt raw eine verlustfrei Komprimierung zu verwenden. Aber ich bezweifle, dass der PI da 6 Kanäle gleichzeitig ver/entschlüsseln kann.

Generell würde ich da die Hardwarebasis in Frage stellen. Was spricht gegen einen kleinen PC? NuCs und Co lassen grüßen. Da hast du dann problemlos 8GB Speicher und deutlich mehr Performance.
Kosten sind auch nicht so wild - zur Not holt man sich Leasing Rückläufig denn 2-3 Jahre alte Geräte dürften dem pi überlegen sein ...
 
G

Gelöschtes Mitglied 9001

Gast
Ich würde gerne beim Thema Puffer bleiben und hier nicht weiter über Audiotechnik diskutieren. Algorithmen zur Pufferung können ja auch in anderen Bereich verwendet werden. Das Thema Ringpuffer ist also unabhängig von Einsatzzweck interessant.

Wenn jemand hier im Forum was zum Thema Ringpuffer sucht und diesen Thread anklickt, würde er dann hier auf einen Thread zum Thema Audio stoßen, das wäre nicht sehr hilfreich. Da bitte ich alle Diskussionsteilnehmer um Verständnis.

Mein derzeitiger RAM-only Ringpuffer funktioniert einwandfrei und ich bekomme die Daten per Wlan ohne weitere Probleme. Die eingangs gestellte Fragestellung lautete, wie man einen effizienten Puffer erstellt, der deutlich größer als der verfügbare RAM ist.

Einfach auf den Swap-Mechanismus des OS vertrauen funktioniert nicht, wie schon dargestellt. LimDul hat hier bereits zwei gute Impulse geliefert.
 

Meniskusschaden

Top Contributor
Ich würde gerne beim Thema Puffer bleiben und hier nicht weiter über Audiotechnik diskutieren. Algorithmen zur Pufferung können ja auch in anderen Bereich verwendet werden. Das Thema Ringpuffer ist also unabhängig von Einsatzzweck interessant.

Wenn jemand hier im Forum was zum Thema Ringpuffer sucht und diesen Thread anklickt, würde er dann hier auf einen Thread zum Thema Audio stoßen, das wäre nicht sehr hilfreich. Da bitte ich alle Diskussionsteilnehmer um Verständnis.
Diese Bemerkungen finde ich schon etwas seltsam, zumal du das Thema Audiotechnik selbst im Thread eingeführt hast, und zwar bereits im Eröffnungsposting. Ist doch logisch, dass man darauf eingeht. Wer später mal auf diesen Thread stößt, könnte auch durchaus an den Lösungsalternativen interessiert sein.
Zudem betonst du einerseits den professionellen Anspruch, stellst aber einen schlappen Raspi in's Zentrum des Ganzen, an dem nun alles hängt. Da ist es ja nicht allzu abwegig, hier ein XY-Problem als mögliche Ursache in Betracht zu ziehen.
 
G

Gelöschtes Mitglied 9001

Gast
Im Zentrum steht - siehe Threadtitel - ein Ringpuffer und nicht der Raspi, auch keine Kodierung, und auch das Thema Audio habe ich nur beispielhaft erwähnt.
Ich bitte einen Moderator, den Thread zu schließen, da der Thread vom Thema abgekommen ist.
 

temi

Top Contributor
Sorry, aber du löst ein leichtes kopfschüttelndes Unverständnis bei mir aus.

Natürlich ist das Thema der Ringpuffer, aber genauso ist es häufig so, dass der Lösungssuchende für sein konkretes Problem einen ungünstigen Weg eingeschlagen hat. Deshalb ist es durchaus angebracht und hier auch üblich, an dieser Stelle einmal nachzufragen, um ggf. eine bessere Lösung zu finden. Und vielleicht ist auch ein Vorschlag dabei, den du bisher noch nicht in Betracht gezogen hattest. Das du dir schon viele Gedanken darüber gemacht hast und deine Lösung vielleicht auch schon die beste ist, sei dir da unbenommen.

Die Art und Weise, wie du hier kommunizierst finde ich, sagen wir mal, gewöhnungsbedürftig.
 

mihe7

Top Contributor
Mal zum Ringbuffer: ich verstehe das Problem ehrlich gesagt nicht. Im Endeffekt brauchst Du doch nur einen Ringbuffer auf Platte. Je nachdem könnte man sich überlegen, das intern als Ringbuffer von Ringbuffern zu realisieren, wobei jeder persistente Ringbuffer dann z. B. durch ein Memory Mapped File realisiert wird. Aber grundsätzlich sehe ich da keinen Unterschied zum In-Memory-Ringbuffer.
 
G

Gelöschtes Mitglied 9001

Gast
Man kann sich als Programmierer die Bedingungen nicht immer aussuchen. Wenn die Deutsche Bahn einen Java-Programmierer um einen Fahrplanalgorithmus bittet, kann dieser schlecht antworten: Schienenverkehr ist generell ungeeignet, nehmt selbstfahrende Autos.
 

temi

Top Contributor
Man kann sich als Programmierer die Bedingungen nicht immer aussuchen.
Damit hast du völlig Recht, aber das Eine hat mit dem Anderen nichts zu tun, weil wir nur Vorschläge machen und Ideen äußern können, aber nicht wissen, ob und welche Vorgaben du hast. Du kannst das ja einfach verwerfen, wenn es für dich nicht in Frage kommt.
 

LimDul

Top Contributor
Umgekehrt gilt aber auch - man sollte nicht alles blind akzeptieren, was gefordert wird. Den oft kommt der Auftraggeber (hier du) mit einer Lösungsidee (hier Ringpuffer) an, obwohl eigentlich eine andere Lösung (hier Intel NUC) besser ist. Und da ist es durchaus sinnvoll drauf hinzuweisen. Das unterscheidet einen fähigen Software-Entwickler von einem einfachen Programmierer. Er hinterfragt die Anforderungen des Kunden und bietet Alternativen.
 
K

kneitzel

Gast
Man kann sich als Programmierer die Bedingungen nicht immer aussuchen. Wenn die Deutsche Bahn einen Java-Programmierer um einen Fahrplanalgorithmus bittet, kann dieser schlecht antworten: Schienenverkehr ist generell ungeeignet, nehmt selbstfahrende Autos.
Der Vergleich hinkt total! In der Praxis ist es leider mehr als notwendig, das man Anforderungen auch überprüft. Und das ist leider oft genug notwendig und Kunden freuen sich über kompetente Beratung.

Wie wurde das genannt? XY Problem? Du hast das Problem X, bist dann auf Y als Lösung gekommen und hast damit Probleme? Y ist aber absoluter Quatsch und nicht wirklich eine Lösung für X!

Du hast selbst schon erkannt, dass der PI da schlicht ungeeignet ist um Deine Anforderungen zu erfüllen. Denn sowohl die Pufferung rein im Hauptspeicher funktioniert nicht und Puffern auf SD Karte beim PI? Also eine SD Karte ist diesbezüglich extrem ungeeignet. Sowohl die Schreib/Lesegeschwindigkeit ist schon durchaus kritisch aber auch die Anzahl der Schreibzyklen pro Speicherzelle ist zu gering aus meiner Sicht.

Und natürlich ist ein Wechsel auf eine alternative Hardware möglich. Denn einen Pi durch einen anderen Rechner zu ersetzen ist ein minimaler Aufwand (<200€).

Aber wenn man sich das eigentliche Problem X von Dir anschauen würde und nicht auf Y rumreiten würde:
Wer verarbeitet denn die Daten? Sicher, das man da das nicht mit integrieren kann? So eine Pufferung ist 08/15 und findet an mehreren Stellen im Betriebssystem statt. Das Betriebssystem kann also sehr wohl Daten empfangen auch wenn eine Applikation da nicht hinterher kommt. Und dann hätte man da ggf. genug Speicher oder eben entsprechende Plattensysteme.
 

insert2020

Aktives Mitglied
MP3 hat im professionellen Umfeld nichts zu suchen und ist vom Fraunhofer Institut (=Erfinder von MP3) schon lange als veraltet bezeichnet worden
Ich könnte dir MP3 und Flac vorspielen und du würdest den Unterschied nicht einmal merken. So viel zu "veraltet". Weiterhin bedeutet Kompression nicht gleich Informationsverlust ... Also überleg einfach ein bisschen was du schreibst. ;)
 

LimDul

Top Contributor
Ich könnte dir MP3 und Flac vorspielen und du würdest den Unterschied nicht einmal merken. So viel zu "veraltet". Weiterhin bedeutet Kompression nicht gleich Informationsverlust ... Also überleg einfach ein bisschen was du schreibst. ;)
Wenn es um Aufnahmen aus einem Tonstudio geht ist MP3 Schwachsinn. Es ist verlustbehaftet und man will die Originaldaten behalten - zur Weiterverarbeitung und Co. Sorry, MP3 ist bei der Anforderung schlicht Unfug.
 
G

Gelöschtes Mitglied 9001

Gast
Mir gefallen die Ausgangsbedingungen auch nicht, aber sie sind nunmal gegeben und ich kann an denen leider nichts ändern. Meine Aufgabe ist es, das System so stabil wie möglich gegen Datenverlust zu machen. Wer der Meinung ist, dass das mit den Bedingungen grundsätzlich nicht geht, ok. Wer noch Vorschläge für Algorithmen hat - ich freue mich über fachlichen Austausch.
 

insert2020

Aktives Mitglied
Wenn es um Aufnahmen aus einem Tonstudio geht ist MP3 Schwachsinn. Es ist verlustbehaftet und man will die Originaldaten behalten - zur Weiterverarbeitung und Co. Sorry, MP3 ist bei der Anforderung schlicht Unfug.
A wenn es um Tonstudioaufnahmen geht, wieso setzt man dann Raspi ein?
B wie ich schon geschrieben habe gibt es auch verlustfreie Komprimierungsformate...
 
K

kneitzel

Gast
Die Anforderung selbst ist bisher noch nicht im Detail erläutert worden. Es fallen Daten aus 6 Quellen an, die dann über einen pi laufen sollen?

Pi ist in meinen Augen eine reine Frickellösung. Zu Basteln nett und billig aber im professionellen Bereich? Da sehe ich den pi nicht.

Was für ein System nimmt die Daten entgegen? Über welchen Weg? Da würde ich ggf. ansetzen um es zu optimieren. Betriebssysteme lassen sich oft für so Dinge optimieren und/oder eben der höher priorisierte Prozess, der das dann macht. Dann braucht man keinen pi.

Und wenn pi / kleineres embedded Gerät: da wäre mein Ansatz eher ein RTOS mit c/c++ Lösung. Sonst hast du das Risiko, das andere Dinge, die du nicht brauchst, dir dazwischen funken...
 
G

Gelöschtes Mitglied 9001

Gast
Das Programm holt sich die Daten von einem Audiointerface und puffert sie (der Puffer der drunterliegenden Schicht ist definitiv zu klein: 1 Sekunde). Ein Serverprozeß liefert die Daten an einen Client aus, der per Wlan verbunden ist. Da der Client in einer Entfernung von 10-30m steht, ist die Verbindung potenziell schwach, daher ist ein sehr großer Puffer notwendig. Das funktioniert alles bislang einwandfrei. Puffergröße aktuell ca. 5min. Das Betriebssystem ist bereits auf ein Minimum reduziert. Die Geschwindigkeit des Computers ist kein Problem und reicht aus.
 
Zuletzt bearbeitet von einem Moderator:
G

Gelöschtes Mitglied 9001

Gast
Damit hast du völlig Recht, aber das Eine hat mit dem Anderen nichts zu tun, weil wir nur Vorschläge machen und Ideen äußern können, aber nicht wissen, ob und welche Vorgaben du hast. Du kannst das ja einfach verwerfen, wenn es für dich nicht in Frage kommt.
Die Vorgaben stehen im Eingangspost.
 

temi

Top Contributor
Nachteil des PI ist halt immer noch der kleine Speicher. Muss es der PI sein, dann ist es halt so, aber es gibt zig Boards mit Onboard-CPU mit sehr kleinem Formfaktor, die sowohl größeren Speicher, als auch eine SATA-Schnittstelle bieten und für um die 50€ zu haben sind.

Aber wie gesagt, wenn der PI als absolut gesetzt ist, dann soll es so sein.
 

temi

Top Contributor
Das Programm holt sich die Daten von einem Audiointerface und puffert sie (der Puffer der drunterliegenden Schicht ist definitiv zu klein: 1 Sekunde). Ein Serverprozeß liefert die Daten an einen Client aus, der per Wlan verbunden ist. Da der Client in einer Entfernung von 10-30m steht, ist die Verbindung potenziell schwach, daher ist ein sehr großer Puffer notwendig. Das funktioniert alles bislang einwandfrei. Puffergröße aktuell ca. 5min. Das Betriebssystem ist bereits auf ein Minimum reduziert. Die Geschwindigkeit des Computers ist kein Problem und reicht aus.
Das Problem ist also die zu kleine Puffergröße von 5 min? Der Rest scheint ja zu passen.

Und die WLAN-Verbindung ist offenbar zwingend erforderlich und der Grund für den PI in der beschriebenen Funktion?

Auslagern auf eine USB-Platte anstatt SD-Karte?
 
G

Gelöschtes Mitglied 9001

Gast
Ja, ich hätte gerne einen deutlich größeren Puffer. Wlan ist deshalb zwingend, weil das Setup portabel sein muss und es extrem unpraktikabel ist, jedesmal 30m Kabel ab- und aufzuwickeln.

Vielleicht ist es gut, das Thema doch abstrakter zu betrachten, so wie ich mir das eigentlich erhofft hatte:
Ein Ringpuffer soll auf zwei Medien agieren. Eines ist klein und schnell, eines groß aber langsam. Nach Möglichkeit soll hauptsächlich der kleine schnelle verwendet werden. Wenn aber mehr Daten gepuffert werden müssen, der langsame. Wie schon beschrieben ist des Betriebssystems Swapping nicht hilfreich.
Gefragt ist nun ein Algorithmus, der möglichst selten den langsamen Speicher berührt.
 

temi

Top Contributor
Evtl. solltest du doch über ein verlustfreie Audiokomprimierung nachdenken, so dass der schnelle Speicher ausreicht. Die Daten können ja vielleicht auch in der komprimierten Form an den Client weitergegeben werden (und nötigenfalls dort wieder dekomprimiert werden). Fragt sich halt, ob die Leistung des PI dafür ausreicht.

Hier mal ein Link, aber ich nehme an, dass du davon eh mehr Ahnung hast als ich.

EDIT: Ich möchte auch noch erwähnen, dass der Raspberry 4 mit 8 GB RAM erhältlich ist.
 
Zuletzt bearbeitet:

insert2020

Aktives Mitglied
Das sollte eigentlich funktionieren, wenn nicht noch "gravierende" Fehler drin sind:
Java:
import java.nio.ByteBuffer;

public class MyBuffer {
	private static final int size_extern = 25;
	private static final int size_intern = 10;
	private ByteBuffer buffer_intern = ByteBuffer.allocate((int) size_intern);
	private ByteBuffer buffer_extern = ByteBuffer.allocateDirect((int) size_extern);
	private int i1 = 0;
	private int i2 = 0;

	public synchronized void write(byte b) {
		if (i1 == size_intern) {
			for (int i = 0; i < size_intern; i++) {
				if (i2 == size_extern) {
					i2 = 0;
				}
				buffer_extern.put(i2, buffer_intern.get(i));
				i2++;
			}
			buffer_intern.clear();
			i1 = 0;
		}
		buffer_intern.put(i1, b);
		i1++;
	}

	public synchronized byte read() {
		if (i1 == 0) {
			for (int i = 0; i < size_intern; i++) {
				if (i2 == 0) {
					i2 = size_extern;
				}
				i1++;
				i2--;
				buffer_intern.put(size_intern - i1, buffer_extern.get(i2));
			}
		}
		i1--;
		return buffer_intern.get(i1);
	}

	public static void main(String[] args) {
		MyBuffer buffer = new MyBuffer();
		for (int i = 0; i <= 35; i++) {
			buffer.write((byte) i);
			System.out.println((byte) i);
		}
		System.out.println(buffer.buffer_intern);
		System.out.println(buffer.buffer_extern);
		for (int i = 0; i <= 35; i++) {
			System.out.println(buffer.read());
		}
		System.out.println();
		for (int i = 0; i <= 10; i++) {
			buffer.write((byte) i);
			System.out.println((byte) i);
		}
		System.out.println(buffer.buffer_intern);
		System.out.println(buffer.buffer_extern);
		for (int i = 0; i <= 10; i++) {
			System.out.println(buffer.read());
		}
	}
}
Mir ist jetzt beim Testen kein Fehler aufgefallen.
statt 25 und 10 wählst du eben 5 GB... und wenn mehrere Byte auf einmal hinzugefügt werden sollen, dann würde ich noch zwei weitere Methoden dafür schreiben...
 

temi

Top Contributor
Evtl. solltest du doch über ein verlustfreie Audiokomprimierung nachdenken, so dass der schnelle Speicher ausreicht. Die Daten können ja vielleicht auch in der komprimierten Form an den Client weitergegeben werden (und nötigenfalls dort wieder dekomprimiert werden). Fragt sich halt, ob die Leistung des PI dafür ausreicht.
Falls es nicht sowieso schon offensichtlich ist: Dadurch reduziert sich gleichzeitig auch das Datenvolumen auf der WLAN-Verbindung, was sich ja durchaus positiv auswirken würde.
 

httpdigest

Top Contributor
Kurzer Hinweis noch: Du solltest nicht einen API Aufruf pro individuellem Byte tun (Hint: die NIO Buffer API ist sehr ineffizient, was API Aufrufe angeht, aufgrund der Indexrange-Checks bei jedem Aufruf). Du solltest lieber die Bulk-Operationen put(ByteBuffer) bzw. get(ByteBuffer) nutzen und dann entsprechend die Bereiche, aus denen im Buffer gelesen/geschrieben wird, per limit()/remaining()/position() steuern.
Die API ergibt sich dann eigentlich daraus, wie sie genutzt wird. Er wird ja auch nicht Byte für Byte aus der Quelle erhalten, sondern chunkweise mehrere Kilobytes oder Megabytes.
 

insert2020

Aktives Mitglied
So... da ist nämlich doch noch ein Fehler, die Buffer-Größe ist nicht zu jedem Zeitpunkt konstant 25+10=35:
Java:
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Random;

public class MyBuffer {
	private static final int size_extern = 25;
	private static final int size_intern = 10;
	private ByteBuffer buffer_intern = ByteBuffer.allocate((int) size_intern);
	private ByteBuffer buffer_extern = ByteBuffer.allocateDirect((int) size_extern);
	private int i1 = 0;
	private int i2 = 0;

	public synchronized void write(byte b) {
		if (i1 == size_intern) {
			for (int i = 0; i < size_intern; i++) {
				if (i2 == size_extern) {
					i2 = 0;
				}
				buffer_extern.put(i2, buffer_intern.get(i));
				i2++;
			}
			i1 = 0;
		}
		buffer_intern.put(i1, b);
		i1++;
	}

	public synchronized byte read() {
		if (i1 == 0) {
			for (int i = 0; i < size_intern; i++) {
				if (i2 == 0) {
					i2 = size_extern;
				}
				i1++;
				i2--;
				buffer_intern.put(size_intern - i1, buffer_extern.get(i2));
			}
		}
		i1--;
		return buffer_intern.get(i1);
	}

	public static void main(String[] args) {
		Random r = new Random(0);
		MyBuffer buffer = new MyBuffer();
		for (int i = 0; i < 10; i++) {
			int s = r.nextInt(36);
			ArrayList<Byte> l1 = new ArrayList<>();
			ArrayList<Byte> l2 = new ArrayList<>();
			for (int j = 0; j < s; j++) {
				System.out.println((byte) j);
				buffer.write((byte) j);
				l1.add((byte) j);
			}
			System.out.println(buffer.buffer_intern);
			System.out.println(buffer.buffer_extern);
			for (int j = 0; j < s; j++) {
				byte b = buffer.read();
				System.out.println(b);
				l2.add(b);
			}
			Collections.reverse(l2);
			System.out.println(l1.equals(l2));
			System.out.println();
			if (!l1.equals(l2)) {
				return;
			}
		}
	}
}
Code:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
java.nio.HeapByteBuffer[pos=0 lim=10 cap=10]
java.nio.DirectByteBuffer[pos=0 lim=25 cap=25]
23
22
21
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
true

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
java.nio.HeapByteBuffer[pos=0 lim=10 cap=10]
java.nio.DirectByteBuffer[pos=0 lim=25 cap=25]
15
14
13
12
11
10
9
8
7
6
5
4
3
2
1
0
true

0
1
2
3
4
5
6
7
8
9
10
11
12
java.nio.HeapByteBuffer[pos=0 lim=10 cap=10]
java.nio.DirectByteBuffer[pos=0 lim=25 cap=25]
12
11
10
9
8
7
6
5
4
3
2
1
0
true

0
1
2
3
4
5
6
7
8
9
10
java.nio.HeapByteBuffer[pos=0 lim=10 cap=10]
java.nio.DirectByteBuffer[pos=0 lim=25 cap=25]
10
9
8
7
6
5
4
3
2
1
0
true

0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
java.nio.HeapByteBuffer[pos=0 lim=10 cap=10]
java.nio.DirectByteBuffer[pos=0 lim=25 cap=25]
34
33
32
31
30
29
28
27
26
25
24
23
22
21
20
19
18
17
16
15
14
13
12
11
10
9
8
7
6
5
29
28
27
26
25
false
Vielleicht hat jemand dazu eine Lösung.

@httpdigest Danke für die Hinweise.
 

temi

Top Contributor
Was bewirkt denn ByteBuffer.allocateDirect()?

Die Doku sagt dazu nur:
Given a direct byte buffer, the Java virtual machine will make a best effort to perform native I/O operations directly upon it. That is, it will attempt to avoid copying the buffer's content to (or from) an intermediate buffer before (or after) each invocation of one of the underlying operating system's native I/O operations.
und
The contents of direct buffers may reside outside of the normal garbage-collected heap, and so their impact upon the memory footprint of an application might not be obvious.
Aber das ist doch alles noch im RAM und löst damit das Problem nicht, oder?

Was hier gesucht ist, wäre doch eher das Mapping auf ein File.

Hier vielleicht ein paar Infos dazu:
http://www.kdgregory.com/index.php?page=java.byteBuffer
 

Oben