# auf einem PC kein mp3 unter Java



## Cottonwood (18. Apr 2011)

Mein Java-Programm spielt mp3 eigentlich einwandfrei ab. Auf einem PC gibt es aber einen Fehler:

```
javax.media.ResourceUnavailableEvent[source=com.sun.media.content.unknown.Handler@fd54d6,
message=Failed to realize: input media not supported: mpeglayer3 audio]
```

Die mp3-Datei kann ich aber problemlos mit Winamp abspielen und sie ist auch 100% identisch mit der Datei, die auf dem anderen PC mit demselben Programm einwandfrei abgespielt werden kann.

Zunächst habe ich das mp3-Codec vom Fraunhofer-Institut installiert. Konnte natürlich nichts bringen.

Auch dieser Vorschlag führte zu nichts. 
Die Zeile "java com.sun.media.codec.audio.mp3.JavaDecoder" wurde nicht akzeptiert.

Was bitte ist zu tun? Die jmfregistry zeigt mir identische Codecs auf beiden PCs (siehe Anhang).


----------



## Cottonwood (19. Apr 2011)

Inzwischen bin ich etwas weiter (verwirrter). Da mein Programm ja auf einem PC läuft (ich nenne ihn mal Notebook), wollte ich es dort mit Excelsior compilieren und dann auf dem anderen (den nenne ich Tower) laufen lassen. Nun bekam ich einen Hinweis auf mein Problem: Das laufende compilierte Programm meldete jetzt bereits auf dem Notebook eine fehlende Klasse (javax.media.Manager).

Ich muss wohl auch erzählen, dass ich das Programm auf dem Notebook mit Eclipse bearbeite, von dort ein jar erzeuge (mit "Extract required libraries into generated jar") und dieses mittels Inno Setup 5 in ein Installationspaket packe. Dieses wurde bisher dann verteilt. Und das damit installierte jar lief dann einwandfrei auf dem Notebook, nicht aber auf dem Tower.

Ich habe nun also in Eclipse jmf.jar in den Build path eingefügt. Das Ergebnis ist jetzt, dass mein Programm jetzt auch auf dem Notebook keine mp3's mehr abspielt, wenn ich das jar starte. Unter Eclipse gestartet läuft es immer noch einwandfrei. Es kommt weiterhin die Fehlermeldung:


```
javax.media.ResourceUnavailableEvent[source=com.sun.media.content.unknown.Handler@141fab6,
message=Failed to realize: input media not supported: mpeglayer3 audio], 
Thread=JMF thread: SendEventQueue: com.sun.media.content.unknown.Handler
```

Dieses Verhalten ist mit demselben jar jetzt auf dem Notebook und dem Tower identisch. Das ist ja schon mal was. Es hat also wohl wirklich etwas mit der Klasse javax.media.Manager zu tun. Nur war es wohl nicht der richtige Weg, sie in Eclipse hinzuzufügen.

Vielleicht ist die richtige Frage jetzt: Wie muss ich diese Klasse einbinden, damit das Programm überall läuft? Wie gesagt, ohne läuft es auf dem Notebook problemlos. Aber eben nicht auf dem Tower.

Was müsst ihr noch wissen, um mir helfen zu können?

*//Edit:*
Ich habe gerade in meinem programmeigenen Protokoll die ersten Unterschiede zwischen jar und Eclipse-Version gesucht und gefunden:

jar-Version:

```
v1.5.032 JukeSound:229 0 transition event (player1), Thread=JMF thread: SendEventQueue: com.sun.media.content.unknown.Handler
v1.5.032 JukeSound:245 0 player1-event: realizing, Thread=JMF thread: SendEventQueue: com.sun.media.content.unknown.Handler
```

Eclipse-Version:

```
v1.5.032 JukeSound:229 0 transition event (player1), Thread=JMF thread: SendEventQueue: com.sun.media.content.audio.mpeg.Handler
v1.5.032 JukeSound:245 0 player1-event: realizing, Thread=JMF thread: SendEventQueue: com.sun.media.content.audio.mpeg.Handler
```

Der Unterschied liegt im Namen des Threads, der den ControllerAdapter abhandelt (unknown.Handler/audio.mpeg.Handler). 

Hier noch der Code, der das Ereignis ausgibt:

[java=176]    player1.addControllerListener(new ControllerAdapter() {
        public void configureComplete(ConfigureCompleteEvent e) {
            ErrorWindow.errorMsg("v1.5.032 JukeSound:178 "+S.t()+" configure complete event (player1)");
        }
        public void controllerError(ControllerErrorEvent e) {
            ErrorWindow.errorMsg("v1.5.032 JukeSound:181 "+S.t()+" controller error event (player1) "+e.toString());
            ErrorWindow.errorMsg("v1.5.032 JukeSound:182 "+S.t()+" controller error event (player1) "+e.getMessage());
            mp3SoundIsPlaying=false;
            if (isServer) TastaturInput.displayTitle("Juke2010 "+"v1.5.032 ");
            player1.stop();
            player1.close();
        }
[/code]

*//Edit:*
Ich habe hier etwas gefunden, was in die gleiche Richtung gehen könnte. Allerdings bezieht sich das wohl nur auf Streaming


```
Format input1 = new AudioFormat(AudioFormat.MPEGLAYER3);
    Format input2 = new AudioFormat(AudioFormat.MPEG);
    Format output = new AudioFormat(AudioFormat.LINEAR);
    PlugInManager.addPlugIn(
        "com.sun.media.codec.audio.mp3.JavaDecoder",
        new Format[]{input1, input2},
        new Format[]{output},
        PlugInManager.CODEC
    );
```

Kann oder muss ich so etwas auch einsetzen? Wenn ja, wie bzw. wo? Oder: Wo ist das beschrieben?


----------



## Cottonwood (20. Apr 2011)

Ich habe jetzt mal alle die Zeilen aus dem Programm extrahiert, die unbedingt erforderlich sind, um den Fehler zu reproduzieren. Dabei ist folgendes rausgekommen:


```
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;

import javax.media.ConfigureCompleteEvent;
import javax.media.ControllerAdapter;
import javax.media.ControllerClosedEvent;
import javax.media.ControllerErrorEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.DeallocateEvent;
import javax.media.EndOfMediaEvent;
import javax.media.InternalErrorEvent;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.MediaTimeSetEvent;
import javax.media.NoPlayerException;
import javax.media.Player;
import javax.media.PrefetchCompleteEvent;
import javax.media.Processor;
import javax.media.RealizeCompleteEvent;
import javax.media.RestartingEvent;
import javax.media.SizeChangeEvent;
import javax.media.StartEvent;
import javax.media.StopEvent;
import javax.media.TransitionEvent;
import javax.media.control.FormatControl;
import javax.media.format.FormatChangeEvent;

public class WindowTester {

	private static String userPath=System.getProperty("user.home")+System.getProperty("file.separator");
	public static Player player1=null;
	private static String playerState;

	public static void main(String[] args)
	{
		try {
			player1 = Manager.createPlayer(new MediaLocator(new File(userPath+"temporary1.mp3").toURI().toURL()));
		} catch (NoPlayerException e) {e.printStackTrace();
		} catch (MalformedURLException e) {e.printStackTrace();
		} catch (IOException e) {e.printStackTrace();
		}
		System.out.println("player1=Manager.createPlayer");
		player1.addControllerListener(new ControllerListener() {
			public void controllerUpdate(ControllerEvent event) {
				if(event instanceof EndOfMediaEvent) {
					player1.stop();
					player1.close();
				}
			}
		});
		player1.addControllerListener(new ControllerAdapter() {
			public void configureComplete(ConfigureCompleteEvent e) {
				System.out.println("configure complete event (player1)");
			}
			public void controllerError(ControllerErrorEvent e) {
				System.out.println("controller error event (player1) "+e.toString());
				System.out.println("controller error event (player1) "+e.getMessage());
				player1.stop();
				player1.close();
			}
			public void controllerClosed(ControllerClosedEvent e) {
				System.out.println("controller closed event (player1)");
			}
			public void deallocate(DeallocateEvent e) {
				System.out.println("deallocate event (player1)");
			}
			public void endOfMedia(EndOfMediaEvent e) {
				System.out.println("end of media event (player1)");
			}
			public void formatChange(FormatChangeEvent e) {
				System.out.println("format change event (player1)");
			}
			public void internalError(InternalErrorEvent e) {
				System.out.println("internal error event (player1)");
			}
			public void mediaTimeSet(MediaTimeSetEvent e) {
				System.out.println("media time set event (player1)");
			}
			public void prefetchComplete(PrefetchCompleteEvent e) {
				System.out.println("prefetch complete event (player1)");
			}
			public void realizeComplete(RealizeCompleteEvent e) {
				System.out.println("realize complete event (player1)");
				FormatControl formatControl = (FormatControl)
				player1.getControl("javax.media.control.FormatControl");
				if (formatControl == null) 
					System.out.println("player1-event: no format control");
			}
			public void restarting(RestartingEvent e) {
				System.out.println("restarting event (player1)");
			}
			public void sizeChange(SizeChangeEvent e) {
				System.out.println("size change event (player1)");
			}
			public void start(StartEvent e) {
				System.out.println("start event (player1)");
			}
			public void stop(StopEvent e) {
				System.out.println("stop event (player1)");
			}
			public void transition(TransitionEvent e) {
				System.out.println("transition event (player1)");
				int state = e.getCurrentState();
				switch (state) {
				case Processor.Configuring:
					System.out.println("player1-event: configuring");
					break;
				case Processor.Configured:
					System.out.println("player1-event: configured");
					break;
				case Processor.Prefetching:
					System.out.println("player1-event: prefetching");
					break;
				case Processor.Prefetched:
					System.out.println("player1-event: prefetched");
					break;
				case Processor.Realizing:
					System.out.println("player1-event: realizing");
					break;
				case Processor.Realized:
					System.out.println("player1-event: realized");
					break;
				case Processor.Unrealized:
					System.out.println("player1-event: unrealized");
					break;
				case Processor.Started:
					System.out.println("player1-event: started");
					break;
				}
			}
		});
		System.out.println("player1.addControllerListener");
		player1.realize();
		System.out.println("nach player1.realize(); "); printPlayerState1();
		int count=0;
		//while ((player1.getState()!=Player.Realized)&&(count<50))
		while ((player1.getState()>Player.Unrealized)&&(count<50))
		{
			try{Thread.sleep(50);}catch(InterruptedException e){}
			System.out.println("Loop1 count="+count+" "); printPlayerState1();
			count++;
		}
		System.out.println("player start");
		player1.start();
		System.out.println("player1.start();");
		count=0;
		while ((player1.getState()!=Player.Started)&(count<50)) {
			try{Thread.sleep(50);}catch(InterruptedException e){}
			System.out.println("Loop3 count="+count+" ");
			printPlayerState1();
			count++;
		}
		try{Thread.sleep(5000);}catch(InterruptedException e){}
	}
	private static void printPlayerState1(){
		playerState="player1 player state=";
		int i=player1.getState();
		switch (i){
		case Player.Prefetched: playerState=playerState + "Prefetched";printPlayerState(i);break;
		case Player.Prefetching: playerState=playerState + "Prefetching";printPlayerState(i);break;
		case Player.Realized: playerState=playerState + "Realized";printPlayerState(i);break;
		case Player.Realizing: playerState=playerState + "Realizing";printPlayerState(i);break;
		case Player.Started: playerState=playerState + "Started";printPlayerState(i);break;
		case Player.Unrealized: playerState=playerState + "Unrealized";printPlayerState(i);break;
		default: playerState=playerState + "state unknown";printPlayerState(i);break;
		}
	}
	private static void printPlayerState(int state) {
		System.out.println(playerState+"(="+state+")");
	}
}
```

Wenn ich das Programm auf dem Notebook als .jar durch Doppelklick starte, dann läuft es einwandfrei und spielt genau den einen Titel.
Auf dem Tower läuft es aber nicht. Daraufhin habe ich es als jar im DOS-Fenster mit java gestartet:


```
C:\Dokumente und Einstellungen\Claus>C:\WINDOWS\system32\java.exe -Djava.library.path=C:\Programme\Juke2010\lwjgl\dll -jar D:\Java\WindowTester.jar > c:\temp\windowTester.txt
  Unable to handle format: mpeglayer3, 44100.0 Hz, 16-bit, Mono, LittleEndian, S
igned, 16000.0 frame rate, FrameSize=16384 bits
Failed to realize: com.sun.media.PlaybackEngine@eee36c
Error: Unable to realize com.sun.media.PlaybackEngine@eee36c
```

Der java.library.path ist dabei sicher überflüssig. Aber ich wollte es möglichst genau so ablaufen lassen, wie mein ursprüngliches Programm auch gestartet wird, wenn man den Icon doppelklickt.

Darauf habe ich dasselbe auf dem Notebook gemacht. Das Ergebnis war genau derselbe Fehler.

Also habe ich die Classpaths zwischen Notebook und Tower verglichen. Die ja eigentlich uninteressant sein sollten, da das jar ja alles mitbringen sollte. Sie waren nicht gleich. Also habe ich das geändert. Jetzt sind sie gleich. Was für das DOS-Fenster allerdings nichts ändern kann, da es da ja auf dem Tower auch nicht läuft.

Wenn ich jetzt allerdings das jar mit Doppelklick starte, läuft es auch auf dem Tower. Juhu.

Also konnte es jetzt nur noch am java.library.path liegen. Also habe ich den auch im DOS-Fenster rausgenommen. Und es läuft. Das war's. Dachte ich.

Mein eigentliches Programm hat das alles nicht beeindruckt. Das lief ja auch schon mit java.library.path. Allerdings werde ich da heute nicht weiter suchen. Ich melde mich also noch mal. Nix mit juhu.


----------



## HoaX (20. Apr 2011)

Zwar nichts direkt zu dem Problem, aber dennoch: Es ist eine sehr schlechte Idee bei den Fehlermeldungen die Zeilennummer fix einzubauen. Die kann man sicherlich auch einfach aus dem Stacktrace extrahieren. So wie es im moment ist brauchst du oben nur einen neuen Import einfügen, und schon darfst du X Zeilen anpassen weil die Zeilennummer ja nichtmehr stimmt. Dann werde ein paar Zeilen übersehen, irgendeine Logging-Lib spuckt in den Meldungen die korrekten Zeilennummern aus, und dann ist am Ende die Verwirrung groß, wegen widersprüchlicher ausgaben.


----------



## Cottonwood (20. Apr 2011)

Die Klassennamen/Zeilennummern werden durch einen einfachen Precompiler automatisch generiert. Und sie helfen mir enorm.


----------



## Cottonwood (21. Apr 2011)

Um voran zu kommen, habe ich jetzt mal Eclipse auf dem Tower installiert und teste da in der Entwicklungsumgebung weiter. Grundsätzlich läuft das so, wenn das Programm als Server läuft. Wenn das Programm als Client läuft, bekomme ich jetzt an derselben Stelle die Meldung:

Error: Unable to realize com.sun.media.amovie.AMController@1632c2d
Exception in thread "JMF thread: com.sun.media.content.audio.mpeg.Handler@1d4c61c[ com.sun.media.content.audio.mpeg.Handler@1d4c61c ] ( realizeThread)" java.lang.NullPointerException
	at com.sun.media.content.video.mpeg.Handler.getMasterTimeBase(Handler.java:64)
	at com.sun.media.BasicPlayer.completeRealize(BasicPlayer.java:1313)
	at com.sun.media.RealizeWorkThread.completed(BasicController.java:1404)
	at com.sun.media.StateTransitionWorkThread.run(BasicController.java:1344)

Dabei soll er doch bloss MP3 abspielen.

Das MP3 ist in beiden Testfällen dasselbe.


----------



## Cottonwood (1. Mai 2011)

Hat sich erledigt. Der Tower hatte zu wenig Speicher. Danke an alle, die sich Gedanken gemacht haben.


----------

