Musikstream lib

Moin,

ich weiß (vielleicht ändert sich das mit JDK 8 oder JavaFX auch?) das Java keine gute Audiounterstützung bietet.
Mein Vorhaben:
Ich will einen 24/7 stream aufzeichnen und in verschiedene Dateien splitten. Der Stream hat einen einfaches MP3 format.
Das Problem. Es gibt keine Titel angaben bzw länge eines einzelnen Titels(diese Beziehe ich aus einer anderen Quelle).
Ich brauche praktisch eine Lib oder einen Weg den Internetstream aufzueichnen und alle x Minuten in eine andere Datei zu speichern.

Habt ihr da Erfahrung mit Libs?

Edit: Das sollte Lib heißen und nicht lin. Das Thema kann man anscheinend nicht bearbeiten.

(Edit von Tomate_Salat: hab den Titel entsprechend angepasst)

Hast du schon probiert den Stream erstmal in einen Buffer zu schreiben und diesen dann ab Größe N in ein File zu schreiben? Die Größe ist abhängig von x und der Bitrate die du hast. Das sollte so sofort funktionieren wenn dem SO-Post hier zu trauen ist.

Ah logisch sind ja auch nur Bytes die da übertragen werden. Diese einfach nehmen und in eine andere Datei übertragen. Nur mein Problem, eine MP3 hat ja einen bestimmten Header. Diesen müsste ich zu jeder Datei hinzugenerieren.

Ich habe gerade mal die Streamdatei geöffnet in Notepad++:

[playlist]
NumberOfEntries=3
File1=http://listen.housetime.fm/tunein-mp3-pls
Title1=HouseTime.FM - MP3 192k - High Quality - (DSL/Cable)
Length1=-1
File2=http://listen.housetime.fm/tunein-aacplus-pls
Title2=HouseTime.FM - AACplus 96k - Very High Quality - (DSL/Cable)
Length2=-1
File3=http://listen.housetime.fm/tunein-aacisdn-pls
Title3=HouseTime.FM - AACplus 40k - Low Quality - (ISDN)
Length3=-1
Version=2

Für File einfach das File in dem ich den Stream speichere. Length anzahl Bytes? und Title natürlich der Name des Liedes.

Was genau meinst du? Wenn du die Länge des jeweiligen Tracks in Minuten und Sekunden hast musst du das in Byte umrechnen. Im Falle der MP3-Version sind das 192Kbps. Das bedeuted du musst 1000 (oder 1024?) * 192 * Sekunden des Tracks Bits abspeichern.

Ob’s jetzt 1000 oder 1024 sind weiß ich allerdings nicht. Da wirst du dich ein bisschen herumspielen müssen. Testweise kannst du ja mal 192.000 bit speichern und prüfen ob das dann tatsächlich eine Sekunde ist oder weniger. Falls es weniger sind musst du 192 * 1024 bit speichern pro Sekunde.

Oder wolltest du was anderes wissen?

ja sind kbits gerade gesehen.
http://en.wikipedia.org/wiki/MP3

*** Edit ***

Soo hab mal etwas kleines geschrieben.
Ich hoffe das ist so plausible. Komme leider erstmal nicht zum testen.

Handler:

public class StreamHandler {

	private final ConnectionInfo connInfo;
	private final InputStream in;
	/**
	 * Might be a security risk. Long overflow
	 * 
	 */
	private volatile long numberOfTotalBytesRead;

	public StreamHandler(ConnectionInfo connectionInfo) throws IOException {
		this.connInfo = connectionInfo;
		in = connectionInfo.getInputStream();
	}

	public void nextSingle(String name, int numberOfSeconds)
			throws FileNotFoundException {
		long numberOfBytes = calculateNumberOfBytes(numberOfSeconds);
		long byteCounter = 0;

		File file = new File(connInfo.getPathToSave() + File.pathSeparator
				+ name + ".mp3");

		if (file.canWrite()) {
			try {
				file.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		} else {
			closeStream(in);
			return;
		}

		FileOutputStream out = new FileOutputStream(file);

		byte buff[] = new byte[125];
		while (byteCounter >= numberOfBytes) {

			try {
				in.read(buff);
				out.write(buff);
				out.flush();
			} catch (IOException e) {
				e.printStackTrace();
				return;
			} finally {
				closeStream(in);
				closeStream(out);

			}

			byteCounter += buff.length;
		}

		numberOfBytes += byteCounter;
		closeStream(out);
	}

	

	private long calculateNumberOfBytes(int numberOfSecs) {
		return connInfo.getBitsPerSecond() * 1000 * 8 * numberOfSecs;
	}

	public long getNumberOfTotalBytesRead() {
		return numberOfTotalBytesRead;
	}
	
	public static void closeStream(InputStream stream) {
		try {
			stream.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public static void closeStream(OutputStream stream) {
		try {
			stream.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

ConnectionInfo

public class ConnectionInfo {

	private final URL url;
	private final File file;
	private final File pathToSave;
	private final int bytesPerSecond;  

	public ConnectionInfo(URL url, File pathToSave, int bytesPerSecond) {
		this.url = url;
		this.file = null;
		this.pathToSave = pathToSave;
		this.bytesPerSecond = bytesPerSecond;
	}

	public ConnectionInfo(File file, File pathToSave, int bytesPerSecond) {
		this.file = file;
		this.url = null;
		this.pathToSave = pathToSave;
		this.bytesPerSecond = bytesPerSecond;
	}

	public InputStream getInputStream() throws IOException {
		if (url != null) {
			return url.openStream();
		}

		return Files.newInputStream(file.toPath(), StandardOpenOption.READ);
	}

	public File getPathToSave() {
		return pathToSave;
	}

	public int getBitsPerSecond() {
		return bytesPerSecond;
	}

}
  1. Es sind n * 1000 bps. Aber so wie du das berechnest, kannst du es vergessen. :wink:
  2. Woher weisst du, dass in dem Stream nicht hin und wieder mal ein ID3-Tag vorkommt? Viele Online-Radios senden einen solchen nämlich manchmal zwischen jedem Titel mit, damit er im Player angezeigt werden kann.
  3. Wie dem auch sei. Man kann im Stream (wie normal) jeden einzelnen Frameheader synchronisieren, den Header und die Seiteninformationen (insbesondere den Wert MainDataBegin) lesen. Sobald der Wert MainDataBegin 0 ist, kann eine Datei sicher geschlossen werden, weil der vorhergehende Frame dann garantiert mehr keine Daten mehr vom folgenden Frame beinhaltet.
  4. Soweit ich weiss, bietet JavaZoom auch die Möglichkeit Streams zu dekodieren und in eine Datei statt in eine DataLine zu spoolen. Aber wenn du MP3-Dateien ohne Mithören spoolen willst, musst du dir einen ensprechenden Spooler wohl selber basteln. So schwierig ist das nicht, zumal du dir ja den Decoding-Kram sparen kannst. Hier mal ein Link zum Dateiformat. http://swlab.et.fh-duesseldorf.de/pc_pool/lernmodule/multimediadateien/Kapitel32.htm
  1. Woher weisst du, dass in dem Stream nicht hin und wieder mal ein ID3-Tag vorkommt? Viele Online-Radios senden einen solchen nämlich manchmal zwischen jedem Titel mit, damit er im Player angezeigt werden kann.

Das ist ein Problem das ich gerade zu lösen Versuche. VLC z.B zeigt mir nur Stumpf HouseTime.FM - MP3 192k - High Quality - (DSL/Cable) an.
Das kann man schon mal ausschließen.

Das andere ist ich bekomme den Namen des Liedes nur wenn ich eine Internetseite parse. Die Daten sind eigentlich immer recht schnell geupdatet (vielleicht mit 1 Sekunde verzögerung OHNE Längenagabe).

Das heißt er muss solange Mitschneiden bis irgendein Callback was anderes sagt. (Theoretisch solange bis die Internetseite ihren Inhalt ändert) Ich glaube das kann keine Lib.

Punkt 3 verstehe ich leider nicht genau. Vielleicht könntest du diesen konkretisieren.

Also die Idee mit dem Callback von der Internet-Seite scheint mir keine so gute zu sein, zumal der Stream selber Unterbrechungsmarkierungen liefert und zwar wenn besagter Wert MainDataBegin 0 ist, das war er bei diversen MP3-Dateien jeweils immer nur 2 mal am Anfang einer solchen Datei (wenn man ID3-Tags mal ausschliesst). Um an diesen zu kommen, muss man den Stream zunächst Scannen, bis man auf einen Header-Sync (ACHTUNG! seit MP3 V2.5 besteht dieser nur noch aus 11 gesetzten Bits. Das freigewordene Bit signalisiert nun V2.5) stösst. Diesen Header musst du auslesen und gemäss Tabelle (siehe Link) auswerten. Daraus errechnest du die Länge des folgenden Frames. Dann liest du bei MP3 V1 die nächsten 8 und bei MP3 V2 und V2.5 die nächsten 9 Bits (MainDataBegin). Sind diese 0, beginnt ein neuer Titel und man kann das aktuelle File schliessen und einen neues erstellen. So kannst du den Stream frameweise lesen, dazu ists allerdings notwendig, dass du dich mit dem MP3-Format auseinandersetzt. Das ist einfacher, als es aussieht. :wink:

Also doch mehr als eine Fingerübung :S

Naja danke werds mir mal durchlesen.