Classpath Eclipse - Library hinzufügen (NativeBass)

Joew0815

Bekanntes Mitglied
Hallo,

Ich würde gerne die NativeBass-Library zu Eclipse hinzufügen. Habs inzwischen auch schon geschafft, ein Example auszuführen (in Eclipse natürlich 🙂), aber sobald ich das ganze als JAR exportiere, funktioniert es nicht mehr.
Das eigentliche Problem ist es, die dll-Dateien hinzuzufügen. Die Library ist im Buildpath und funktioniert auch, aber das Programm findet die bass.dll dann nicht. Ich hab dann den win64 Ordner (was ja auch dumm ist, da es dann eben nur hier läuft, aber anders funktionierte es nicht) bei "Native Library Location" eingetragen und dann konnte ich das Beispiel starten, aber nach dem exportieren funktioniert das eben nicht mehr.

Vielen Dank schonmal
Mit freundlichen Grüßen
 
Man kann eine DLL nicht ohne weiteres in eine JAR packen. (D.h. das kann man natürlich, aber sie kann nicht aus der JAR heraus geladen werden 😀 ). Es ist üblich, die DLL "neben" der JAR auszuliefern. Dann muss der Benutzer sich selbst drum kümmern, und ggf. bei sich dann "Native Library Location" setzen oder so.


Man kann die DLL mit in die JAR packen, und mit einer eigenen Klasse (also nicht mit einem einfachen System.loadLibrary, sondern etwas fummeliger) die DLL (oder .SO oder .DYLIB) aus der JAR heraus entpacken (z.B. ins "temp"-Verzeichnis des Benutzers), und diese Datei dann mit System.load (ohne "Library") laden. Ich hatte das mal in https://github.com/gpu/JOCL/blob/e9...77f6fd7d/src/main/java/org/jocl/LibUtils.java gemacht, aber ... man sollte sich das genau überlegen. Speziell bei BASS gibt es ja viele DLLs, die geladen werden müssen, und abhängigkeiten zueinander haben. Die müßte man dann ja erstens alle in die JAR packen (für alle Betriebssysteme, das wären ein paar MB), und auch alle wieder auspacken, wenn sie geladen werden sollen...
 
OK, wenn die DLL bei der JAR ist geht es. Aber das ist doch auch doof, dann müsste ich ja 5 Versionen anbieten, oder der Benutzer muss die richtige Datei selbst einfügen. Mit dem Workaround geht das ja auch nicht, da ich die DLL-Dateien dafür umbenennen muss. Bei der NativeBass-Library gibt es auch irgendeinen Libloader, lustigerweise fehlt davon die Source, aber ich nehme mal an, dass darin der Name der DLL-Dateien steht. Hast du sonst noch irgendeine Idee?
Btw. funktionieren die Beispielapplikationen bei jemanden? Bei mir kommt da immer ein Fehler, egal ob als Applikation oder Applet... (hab Java7u5)
 
Ja, die erste sagt bei mir auch "Libraries not loaded ! Use Init.loadLibraries() before using NativeBass.". Es gibt (abgesehen von der Methode, die ich beschrieben habe) vielleicht (!) noch eine weitere. Zumindest schafft lwjgl.org - Home of the Lightweight Java Game Library es auch in Webstart, native libs nachzuladen. Aber vielleicht verwenden die intern auch die Methode mit dem manuellen Auspacken, das müßte man sich näher ansehen.

Ansonsten ist es, wie gesagt, üblich dass man die native libs "neben" der JAR liegen, und ja, der Benutzer muss sich dann selbst darum kümmern, sofern der Entwickler sich nicht die Arbeit macht, die notwendige Infrastruktur dafür bereitszustellen. (Ob und wie das bei NativeBass überhaupt gehen würde, müßte man sich genauer ansehen oder ausprobieren - dort kommen noch ein paar potentielle Stolperfallen dazu, aber es könnte schon gehen...)

Vielleicht hat noch jemand anderes irgendwelche kreativen Ideen, die mir jetzt nicht einfallen...?
 
So, ich weiß jetzt wo ich den Dateinamen ändern kann 😀

Jetzt hab ich ein anderes Problem. >,<
Wie bekomme ich die .Java Datei in die Library? Hab versucht die Datei als JAR zu exportieren, dann die neue .class mit der aus der Library zu ersetzen und dann das ganze neu zu packen und zu signieren, ich bekomme aber noch immer einen Fehler.

Falls es jemanden interessieren sollte:
BassInit.java
Java:
	public static void loadLibraries() throws BassException {
		final String[] libs = new String[] {"bass", "NativeBass"};
		final boolean[] libLoaderFirst = new boolean[] {true, false};
		
		final String lib = "lib";
		final String dll = ".dll";
		final String so = ".so";
		final String dylib = ".dylib";
		final String jnilib = ".jnilib";
		
		LibLoader.DEBUG = DEBUG;
		for(int i = 0; i < libs.length; i++) {
			final String libName = libs[i];
			final boolean libLoader = libLoaderFirst[i];

			//final String x64 = (i == 1) ? "64" : ""; 
			final String x64 = "64"; //Nun werden beide DLL-Dateien mit einem 64 versehen...
			final String macLib = (i == 0) ? dylib : jnilib;
			
			final LibraryConfig libConfig = new LibraryConfig();
			libConfig.windowsLibraries = new PlatformLibrary(libName, libName+dll);
			libConfig.windows64Libraries = new PlatformLibrary(libName+x64, libName+x64+dll);
			libConfig.linuxLibraries = new PlatformLibrary(libName, lib+libName+so);
			libConfig.linux64Libraries = new PlatformLibrary(libName+x64, lib+libName+x64+so);
			libConfig.macLibraries = new PlatformLibrary(libName, lib+libName+macLib);
			
			if(!LibLoader.loadLibrary(libConfig, libLoader)) {
				throw new BassException("no "+libName+" in java.library.path or org.lwjgl.librarypath");
			}
			printlnDebug(libName+" successfully loaded");
		}
		
		//Attach callbacks
		if(!attachJavaVM()) {
			throw new BassException("JVM not attached");
		}
		
		librariesLoaded = true;
	}
 
Der Fehler:
Code:
Exception in thread "AWT-EventQueue-0" java.lang.SecurityException: SHA-256 digest error for jouvieje/bass/BassInit.class

Also ich hab eben diese Zeile geändert und dann die Datei als JAR exportiert. Dann habe ich die JAR mit Winrar geöffnet und die BassInit.class extrahiert. Danach habe ich die BassInit.class in die Library geschoben und somit die alte ersetzt. Der Fehler scheint laut Google etwas mit der Signierung zu tun haben, deshalb hab ich die ganze Library mit unpack200 neu gepackt und dann mit dem Jarsigner signiert. Das hat aber nicht wirklich was gebracht. Wenn ich nun "Jarsigner -verify" mache kommt jetzt folgender Fehler:
Code:
jarsigner: java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
.
 
Zuletzt bearbeitet:
Ehrlich gesagt kenne ich mich mit den Interna vom Signieren nicht so aus... eine der Intentionen sollte ja aber sein, dass man eben gerade nicht eine andere .class dort reinpfuschen kann, die einem beim Start die Festplatte formatiert 😉 Aber einen Grund, warum man das ganze nicht komplett neu signieren können sollte, sehe ich nicht. Außer, wenn du die alten Dateien aus dem META-INF-Verzeichnis beibehalten hast...

EDIT: Welche "Zeile" hast du wie geändert?
 
Ich hab
Java:
final String x64 = (i == 1) ? "64" : "";
in
Java:
final String x64 = "64";
geändert. (siehe Quellcode oben)
Wenn ich das richtig verstanden hab, würde er dann bei mir nach der base64.dll und der NativeBass64.dll gesucht und somit wäre das Problem mit dem manuellen DLL-Einfügen gelöst.

Und da waren tatsächlich irgendwelche Dateien in dem META-INF-Verzeichnis, die den Fehler verursachten. Ein Fehler beseitigt, aber der nächste folgt sofort.. :'(
Code:
# A fatal error has been detected by the Java Runtime Environment:
#
#  Internal Error (os_windows_x86.cpp:149), pid=14920, tid=17124
#  guarantee(result == EXCEPTION_CONTINUE_EXECUTION) failed: Unexpected result from topLevelExceptionFilter
#
# JRE version: 7.0_05-b05
# Java VM: Java HotSpot(TM) 64-Bit Server VM (23.1-b03 mixed mode windows-amd64 compressed oops)
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# D:\Program Files\Eclipse\Workspace\Radio\hs_err_pid14920.log
#
# If you would like to submit a bug report, please visit:
#   [url=http://bugreport.sun.com/bugreport/crash.jsp]HotSpot Virtual Machine Error Reporting Page[/url]
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

Man wenn ich gewusst hätte, dass ich nach 2 Tagen noch immer an dem Beispielcode von dem Internetradio sitze... xD Aber ich hab auch keine andere Lib für Musikstreams gefunden.
 
Zuletzt bearbeitet:
Ja, in der hs_err_pid14920.log steht vielleicht ein bißchen was interessantes.

Aber... diese Änderung mit dem "64" macht ja keinen Sinn: Auch bei der 64bit-Variante heißt die Datei ja nur "bass.dll" ???:L
 
Wieso nicht? Wenn ich das richtig verstanden habe, lädt das jetzt bei einem 64Bit-System die Bass64.dll und bei einem 32Bit-System die bass.dll. Also könnte ich die bass.dll für Windows x64 in bass64.dll umbenennen und sie zur JAR kopieren. Das müsste doch theoretisch funktionieren.
log:
Code:
---------------  T H R E A D  ---------------

Current thread (0x000000000ac34800):  JavaThread "Thread-1" [_thread_in_native, id=17124, stack(0x000000000f8f0000,0x000000000f9f0000)]

Stack: [0x000000000f8f0000,0x000000000f9f0000]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  jouvieje.bass.BassJNI.Bass_BASS_GetVersion()I+0
j  jouvieje.bass.Bass.BASS_GetVersion()I+0
j  tools.NetRadio.run()V+8
j  java.lang.Thread.run()V+11
v  ~StubRoutines::call_stub

---------------  P R O C E S S  ---------------

Java Threads: ( => current thread )
  0x00000000021cd000 JavaThread "DestroyJavaVM" [_thread_blocked, id=6676, stack(0x0000000002530000,0x0000000002630000)]
=>0x000000000ac34800 JavaThread "Thread-1" [_thread_in_native, id=17124, stack(0x000000000f8f0000,0x000000000f9f0000)]
  0x000000000ac2a800 JavaThread "D3D Screen Updater" daemon [_thread_blocked, id=6604, stack(0x000000000afc0000,0x000000000b0c0000)]
  0x000000000abb5800 JavaThread "AWT-EventQueue-0" [_thread_blocked, id=15836, stack(0x000000000e060000,0x000000000e160000)]
  0x000000000a8d1000 JavaThread "AWT-Windows" daemon [_thread_in_native, id=8708, stack(0x0000000009f40000,0x000000000a040000)]
  0x0000000008c23800 JavaThread "AWT-Shutdown" [_thread_blocked, id=9892, stack(0x000000000ad10000,0x000000000ae10000)]
  0x000000000a98d800 JavaThread "Java2D Disposer" daemon [_thread_blocked, id=10464, stack(0x000000000a560000,0x000000000a660000)]
  0x0000000008bd2800 JavaThread "Service Thread" daemon [_thread_blocked, id=9820, stack(0x000000000a6a0000,0x000000000a7a0000)]
  0x0000000008bd0000 JavaThread "C2 CompilerThread1" daemon [_thread_blocked, id=12380, stack(0x000000000a400000,0x000000000a500000)]
  0x0000000008bcb000 JavaThread "C2 CompilerThread0" daemon [_thread_blocked, id=17772, stack(0x000000000a2b0000,0x000000000a3b0000)]
  0x0000000008bca000 JavaThread "Attach Listener" daemon [_thread_blocked, id=9044, stack(0x0000000009cd0000,0x0000000009dd0000)]
  0x0000000008bc3000 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=7540, stack(0x000000000a150000,0x000000000a250000)]
  0x00000000020da000 JavaThread "Finalizer" daemon [_thread_blocked, id=9944, stack(0x000000000a040000,0x000000000a140000)]
  0x00000000020d3000 JavaThread "Reference Handler" daemon [_thread_blocked, id=6856, stack(0x0000000009e00000,0x0000000009f00000)]

Other Threads:
  0x0000000008b42800 VMThread [stack: 0x0000000009b60000,0x0000000009c60000] [id=15288]
  0x0000000008be5800 WatcherThread [stack: 0x000000000a7c0000,0x000000000a8c0000] [id=15040]

VM state:not at safepoint (normal execution)

VM Mutex/Monitor currently owned by a thread: None

Heap
 PSYoungGen      total 19008K, used 5566K [0x00000000eacb0000, 0x00000000ec1e0000, 0x0000000000000000)
  eden space 16320K, 34% used [0x00000000eacb0000,0x00000000eb21fa20,0x00000000ebca0000)
  from space 2688K, 0% used [0x00000000ebf40000,0x00000000ebf40000,0x00000000ec1e0000)
  to   space 2688K, 0% used [0x00000000ebca0000,0x00000000ebca0000,0x00000000ebf40000)
 ParOldGen       total 43392K, used 0K [0x00000000c0600000, 0x00000000c3060000, 0x00000000eacb0000)
  object space 43392K, 0% used [0x00000000c0600000,0x00000000c0600000,0x00000000c3060000)
 PSPermGen       total 21248K, used 9538K [0x00000000bb400000, 0x00000000bc8c0000, 0x00000000c0600000)
  object space 21248K, 44% used [0x00000000bb400000,0x00000000bbd50a20,0x00000000bc8c0000)

Code Cache  [0x0000000002630000, 0x00000000028a0000, 0x0000000005630000)
 total_blobs=487 nmethods=19 adapters=420 free_code_cache=48586Kb largest_free_block=49751360

Compilation events (10 events):
Event: 0.393 Thread 0x0000000008bd0000 nmethod 15 0x00000000026b1d90 code [0x00000000026b1ec0, 0x00000000026b1f18]
Event: 0.394 Thread 0x0000000008bcb000 nmethod 14 0x00000000026b66d0 code [0x00000000026b6820, 0x00000000026b6a98]
Event: 0.400 Thread 0x0000000008bd0000   16             sun.nio.cs.UTF_8$Encoder::encode (361 bytes)
Event: 0.404 Thread 0x0000000008bd0000 nmethod 16 0x00000000026b5d90 code [0x00000000026b5ee0, 0x00000000026b63c8]
Event: 0.411 Thread 0x0000000008bcb000   17             java.lang.String::replace (142 bytes)
Event: 0.415 Thread 0x0000000008bd0000   18             java.lang.String::lastIndexOf (68 bytes)
Event: 0.417 Thread 0x0000000008bd0000 nmethod 18 0x00000000026b5990 code [0x00000000026b5ae0, 0x00000000026b5c88]
Event: 0.417 Thread 0x0000000008bd0000   19             java.lang.String::startsWith (78 bytes)
Event: 0.419 Thread 0x0000000008bd0000 nmethod 19 0x00000000026b5610 code [0x00000000026b5740, 0x00000000026b58d8]
Event: 0.419 Thread 0x0000000008bcb000 nmethod 17 0x00000000026b3c50 code [0x00000000026b3da0, 0x00000000026b42d8]

GC Heap History (0 events):
No events

Deoptimization events (0 events):
No events

Internal exceptions (10 events):
Event: 0.418 Thread 0x000000000ac34800 Threw 0x00000000eb1d2df0 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166
Event: 0.418 Thread 0x000000000ac34800 Threw 0x00000000eb1d5a80 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166
Event: 0.419 Thread 0x000000000ac34800 Threw 0x00000000eb1d99b0 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166
Event: 0.419 Thread 0x000000000ac34800 Threw 0x00000000eb1df470 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166
Event: 0.420 Thread 0x000000000ac34800 Threw 0x00000000eb1e35c0 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166
Event: 0.420 Thread 0x000000000ac34800 Threw 0x00000000eb1e7260 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166
Event: 0.421 Thread 0x000000000ac34800 Threw 0x00000000eb1e9e58 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166
Event: 0.421 Thread 0x000000000ac34800 Threw 0x00000000eb1ed138 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166
Event: 0.422 Thread 0x000000000ac34800 Threw 0x00000000eb1efbf8 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166
Event: 0.423 Thread 0x000000000ac34800 Threw 0x00000000eb1f2600 at C:\jdk7u1_64p\jdk7u5\hotspot\src\share\vm\prims\jvm.cpp:1166

Events (10 events):
Event: 0.422 loading class 0x000000000abc7170
Event: 0.422 loading class 0x000000000abc7170 done
Event: 0.422 loading class 0x000000000ac282f0
Event: 0.422 loading class 0x000000000ac282f0 done
Event: 0.422 loading class 0x0000000008bb0b90
Event: 0.422 loading class 0x000000000abdebe0
Event: 0.422 loading class 0x000000000abdebe0 done
Event: 0.423 loading class 0x0000000008bb0b90 done
Event: 0.423 loading class 0x00000000101f01f0
Event: 0.423 loading class 0x00000000101f01f0 done

VM Arguments:
jvm_args: -Dfile.encoding=Cp1252 
java_command: tools.NetRadio
Launcher Type: SUN_STANDARD

Edit: Ähm irgendwie greift das Programm trotzdem auf die bass.dll zu. Warum jetzt auf einmal deshalb ein "Fatal Error" kommt verstehe ich zwar nicht ganz, aber ist ja auch nicht so wichtig^^.
 
Zuletzt bearbeitet:
OK, daran sieht man jetzt weniger als gedacht...

Aber ... dies 64bit-Sache: Man kann nicht einfach eine DLL umbenennen und hoffen, dass es geht. Wer sagt denn, dass nicht z.B. die NativeBass64.dll erwartet, dass eine bass.dll (für 64bit, aber ohne "64" im Namen!) existiert? Zumindest würde ich erstmal davon ausgehen...
 
Mch dir ne jar wo alle ddls drinnen sind, dann erkenne das os und die bitzahl und entpacke idr ichtige ins working directory, danach noch per loadLibrary laden und das solltes sein.
 
So ich hab jetzt einfach die DLLs in einen Unterordner gegeben und die richtigen werden dann beim Start zur JAR kopiert. Und es funktioniert sogar :O.
Beim Umbenennen hast du natürlich recht. Das erklärt auch den Fehler den ich bekommen hab (# The crash happened outside the Java Virtual Machine in native code.). 🙂
Eine kleine Frage hätte ich aber noch. Wieso kann man nicht alle Optionen für das Frame benutzen? Also z.B. setSize() geht, aber dispose() oder setDefaultCloseOperation() nicht.

Source von TestNr2000.java:
Java:
import static jouvieje.bass.Bass.*;
import static jouvieje.bass.defines.BASS_CONFIG.BASS_CONFIG_NET_PLAYLIST;
import static jouvieje.bass.defines.BASS_CONFIG.BASS_CONFIG_NET_PREBUF;
import static jouvieje.bass.defines.BASS_CONFIG_NET.BASS_CONFIG_NET_PROXY;
import static jouvieje.bass.defines.BASS_FILEPOS.BASS_FILEPOS_BUFFER;
import static jouvieje.bass.defines.BASS_FILEPOS.BASS_FILEPOS_CONNECTED;
import static jouvieje.bass.defines.BASS_FILEPOS.BASS_FILEPOS_END;
import static jouvieje.bass.defines.BASS_STREAM.BASS_STREAM_AUTOFREE;
import static jouvieje.bass.defines.BASS_STREAM.BASS_STREAM_BLOCK;
import static jouvieje.bass.defines.BASS_STREAM.BASS_STREAM_STATUS;
import static jouvieje.bass.defines.BASS_SYNC.BASS_SYNC_END;
import static jouvieje.bass.defines.BASS_SYNC.BASS_SYNC_META;
import static jouvieje.bass.defines.BASS_SYNC.BASS_SYNC_OGG_CHANGE;
import static jouvieje.bass.examples.util.Device.forceFrequency;
import static jouvieje.bass.examples.util.Device.forceNoSoundDevice;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.nio.ByteBuffer;

import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.Timer;

import jouvieje.bass.BassInit;
import jouvieje.bass.callbacks.DOWNLOADPROC;
import jouvieje.bass.callbacks.SYNCPROC;
import jouvieje.bass.examples.util.GraphicalGui;
import jouvieje.bass.exceptions.BassException;
import jouvieje.bass.structures.HSTREAM;
import jouvieje.bass.structures.HSYNC;
import jouvieje.bass.utils.Pointer;

public class TestNr2000 extends GraphicalGui {
	private static final long serialVersionUID = 1L;
	
	/* display error messages */
	private final void error(String text) {
		JOptionPane.showMessageDialog(TestNr2000.this, "<html><body>"+text+"<BR>(error code: "+BASS_ErrorGetCode()+")</body></html>");
	}
	private final void printfExit(String format, Object... args) {
		String s = String.format(format, args);
		JOptionPane.showMessageDialog(this, s);
		stop();
	}
	
	private boolean init   = false;
	private boolean deinit = false;
	private HSTREAM chan = null;
	JComboBox comboBox;
	
	private Timer timer = new Timer(50, new ActionListener(){
		@Override
		public void actionPerformed(ActionEvent e) {
			//Monitor prebuffering progress
			int progress = (int)(BASS_StreamGetFilePosition(chan, BASS_FILEPOS_BUFFER) * 100 / BASS_StreamGetFilePosition(chan, BASS_FILEPOS_END));	// percentage of buffer filled
			
			if(progress > 75 || BASS_StreamGetFilePosition(chan, BASS_FILEPOS_CONNECTED) != 0) { // over 75% full (or end of download)
				timer.stop(); //Finished prebuffering, stop monitoring
				//Get the stream title and set sync for subsequent titles
//				DoMeta();
				BASS_ChannelSetSync(chan.asInt(), BASS_SYNC_META, 0, metaSync, null);
				BASS_ChannelSetSync(chan.asInt(), BASS_SYNC_OGG_CHANGE, 0, metaSync, null);
				//Set sync for end of stream
				BASS_ChannelSetSync(chan.asInt(), BASS_SYNC_END, 0, endSync, null);
				//Play it!
				BASS_ChannelPlay(chan.asInt(), false);
			}
		}
	});
	
	private Thread thread = null;
	
	private DOWNLOADPROC statusProc = new DOWNLOADPROC(){
		@Override
		public void DOWNLOADPROC(ByteBuffer buffer, int length, Pointer user) {
		}
	};
	
	private SYNCPROC metaSync = new SYNCPROC(){
		@Override
		public void SYNCPROC(HSYNC handle, int channel, int data, Pointer user) {
//			DoMeta(data);	//FIXME
		}
	};
	private SYNCPROC endSync = new SYNCPROC(){
		@Override
		public void SYNCPROC(HSYNC handle, int channel, int data, Pointer user) {

		}
	};
	
	private void openURL(final String url) {
		if(thread != null) {
			return;
		}
		thread = new Thread(){
			public synchronized void start() {
				timer.stop();				//Stop prebuffer monitoring
				BASS_StreamFree(chan);	//Close old stream
				chan = BASS_StreamCreateURL(url, 0, BASS_STREAM_BLOCK | BASS_STREAM_STATUS | BASS_STREAM_AUTOFREE, statusProc, null);
				if(chan == null) {
					error("Can't play the stream");
				}
				else {
					timer.start();			//Start prebuffer monitoring
				}
				
				thread = null;
			}
		};
		thread.start();
	}


	public void init() {

		try {
			BassInit.loadLibraries();
		} catch(BassException e) {
			printfExit("NativeBass error! %s\n", e.getMessage());
			return;
		}
		
		/*
		 * Checking NativeBass version
		 */
		if(BassInit.NATIVEBASS_LIBRARY_VERSION() != BassInit.NATIVEBASS_JAR_VERSION()) {
			printfExit("Error!  NativeBass library version (%08x) is different to jar version (%08x)\n",
					BassInit.NATIVEBASS_LIBRARY_VERSION(), BassInit.NATIVEBASS_JAR_VERSION());
			return;
		}
	    
		init = true;
	}

	public void run() {
		if(!init) {
			return;
		}
		
		if(((BASS_GetVersion() & 0xFFFF0000) >> 16) != BassInit.BASSVERSION()) {
			printfExit("An incorrect version of BASS.DLL was loaded");
			return;
		}
		
		if (!BASS_Init(forceNoSoundDevice(-1), forceFrequency(44100), 0, null, null)) {
			error("Can't initialize device");
			stop();
		}
		BASS_SetConfig(BASS_CONFIG_NET_PLAYLIST, 1);	//Enable playlist processing
		BASS_SetConfig(BASS_CONFIG_NET_PREBUF, 0);		//Minimize automatic pre-buffering, so we can do it (and display it) instead
		BASS_SetConfigPtr(BASS_CONFIG_NET_PROXY, null);
	}

	public boolean isRunning() { return deinit; }

	public void stop() {
		if(!init || deinit) {
			return;
		}
		deinit = true;
		
		BASS_Free();
	}


	public JPanel getPanel() { return this; }
	
	public String getTitle() { return "Radio"; }
	private JButton presetUserB = null;
	
	public TestNr2000() {
		super();
		initialize();
	}

	private void initialize() {
		
		this.setSize(new Dimension(285, 115));
		this.setPreferredSize(new Dimension(285, 115));
		
		comboBox = new JComboBox();
		comboBox.setModel(new DefaultComboBoxModel(new String[] {"test", "2"}));
		comboBox.setToolTipText("");
		
		JSlider slider = new JSlider();
		slider.setPaintTicks(true);
		slider.setMinorTickSpacing(2);
		slider.setMajorTickSpacing(10);
		
		JButton btnStop = new JButton("Stop");
		btnStop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				stop();
			}
		});
		GroupLayout groupLayout = new GroupLayout(this);
		groupLayout.setHorizontalGroup(
			groupLayout.createParallelGroup(Alignment.LEADING)
				.addGroup(groupLayout.createSequentialGroup()
					.addContainerGap()
					.addGroup(groupLayout.createParallelGroup(Alignment.TRAILING)
						.addGroup(groupLayout.createSequentialGroup()
							.addComponent(btnStop, GroupLayout.PREFERRED_SIZE, 61, GroupLayout.PREFERRED_SIZE)
							.addPreferredGap(ComponentPlacement.RELATED)
							.addComponent(comboBox, GroupLayout.PREFERRED_SIZE, 117, GroupLayout.PREFERRED_SIZE)
							.addPreferredGap(ComponentPlacement.RELATED)
							.addComponent(getPresetUserB()))
						.addComponent(slider, GroupLayout.PREFERRED_SIZE, 249, GroupLayout.PREFERRED_SIZE))
					.addContainerGap(36, Short.MAX_VALUE))
		);
		groupLayout.setVerticalGroup(
			groupLayout.createParallelGroup(Alignment.LEADING)
				.addGroup(groupLayout.createSequentialGroup()
					.addContainerGap()
					.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
						.addComponent(getPresetUserB())
						.addComponent(comboBox, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
						.addComponent(btnStop))
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(slider, GroupLayout.PREFERRED_SIZE, 31, GroupLayout.PREFERRED_SIZE)
					.addContainerGap(17, Short.MAX_VALUE))
		);
		setLayout(groupLayout);
	}
	private JButton getPresetUserB() {
		if(presetUserB == null) {
			presetUserB = new JButton();
			presetUserB.setText("Start");
			presetUserB.addActionListener(new ActionListener(){
				public void actionPerformed(ActionEvent e) {
					if (comboBox.getSelectedIndex() == 0) {
						openURL("http://bassdrive.com/v2/streams/BassDrive.m3u");
					}
					if (comboBox.getSelectedIndex() == 1) {
						openURL("http://www.sky.fm/mp3/altrock.pls");
					}
				}
			});
		}
		return presetUserB;
	}
}
Und die BassExample.java
Java:
package jouvieje.bass.examples.util;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

import jouvieje.bass.examples.util.End;
import jouvieje.bass.examples.util.BassExample;

public class BassExampleFrame extends JFrame implements End {
	private static final long serialVersionUID = 1L;
	private final BassExample example;
	private final Thread thread;

	public BassExampleFrame(BassExample example) {
		super();
		this.example = example;
		this.thread = new Thread(example);
		
		initialize();
		this.setVisible(true);

		example.setEnd(this);
		this.example.init();
		this.thread.start();
	}

	protected void initialize() {
		this.setTitle(example.getTitle());
		this.setSize(example.getPanel().getSize());
		this.setLocationRelativeTo(null);
		this.setContentPane(example.getPanel());
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.addWindowListener(new WindowAdapter(){
			@Override
			public void windowClosing(WindowEvent e) {
				new Thread() {	//Avoid to freeze the GUI
					@Override
					public void run() {
						stopExample();
					}
				};
			}
		});
	}
	
	private void stopExample() {
		//Attempt to stop the thread if running
		if(thread != null) {
			while(thread.isAlive()) {
				example.sendStopCommand();
			}
		}
		example.stop();
	}
	
	@Override
	public void end() {
		try {
			System.exit(0);
		} catch(SecurityException e) {}
	}
}
 
Ja, ging mir vor allem um dispose.^^ Wenn ich auf Stop drücke und danach Start kommt nämlich eine Fehlermeldung. Sender wechseln geht aber, also könnte man das Fenster sofort schließen.
 
Wie wenig Kreativität ist notwendig, um auf die Idee zu kommen, die Fehlermeldung zu posten :noe: (oder allgemein das Problem genauer zu beschreiben...)
 
Es geht mir ja primär darum, warum ich nicht dispose() benutzen kann. Ist zwar keine gute Lösung aber naja.
Wenn ich den Stream starte, stoppe und dann wieder starte kommt die Meldung "Can't play the stream. Error Code 8". Da scheint wohl irgendwas bei der Stop-Methode zu fehlen, in der javadoc steht allerdings überhaupt nichts sinnvolles (z.B. was BASS_Free() macht). Wie gesagt ist dispose zwar sicher nicht die sauberste Lösung, aber sie wäre einfach und es würde funktionieren.
 
So ganz ist mir noch nicht klar, was du meinst. Den Frame mit dispose() zu killen und einen neuen aufzumachen dürfte nichts an eventuellen BASS-Problemen ändern. Die Doku zu BASS findet man übrigens unter Un4seen Developments - BASS Documentation , aber.... SHER umfangreich und kompliziert (ich tendiere da auch eher dazu, mich wenn möglich an Beispielen entlangzuhangeln, aber ... das geht nicht immer, und manchmal muss man sich auch die Doku antun...)
 
Doch das funktioniert so halbwegs. Ich hab ja jetzt DISPOSE_ON_CLOSE eingestellt und es kommt keine Fehlermeldung, wenn ich stoppe, das Fenster schließe und neu starte. Gibt zwar trotzdem Bugs, wenn man das Fenster ohne auf Stop zu klicken schließt, aber das ignoriere ich mal 🙂.
Und die Doku ist echt super, aber leider funktioniert die Hälfte nicht in der Java Variante 🙁. In der Doku werden 4 Möglichkeiten beschrieben die Lautstärke zu verändern, 3 davon existieren erst gar nicht und BASS_SetVolume will nicht funktionieren (wird auch umgestellt, wenn man es mit GetVolume prüft, aber den Unterschied hört man nicht). Werde dann wohl die Windows-Lautstärke verändern.

Edit: Ups das mit SetVolume war mein Fehler. Hatte im Hintergrund ein Programm laufen, das die Lautstärke anpasst.
icon11.gif
 
Zuletzt bearbeitet:
An manchen Stellen braucht's etwas... ... ... Kreativität, um die Doku nach Java zu übersetzen, aber zusammen mit Google und den Beispielen geht es (auch wenn ich auch gerade erst damit angefangen habe...)
 
Ok die Doku bringt schon ein bisschen was. 😀 Statt BASS_Free() musste ich BASS_StreamFree() verwenden. So, jetzt hab ich aber erstmal genug von der Lib.^^
Danke nochmal
MfG
 
Gibt zwar trotzdem Bugs, wenn man das Fenster ohne auf Stop zu klicken schließt, aber das ignoriere ich mal 🙂.

Das kann man abfangen. Etwa so sieht das bei mir aus:

Java:
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.addWindowListener(new MyWindowListener(logic));
Java:
public class MyWindowListenerimplements WindowListener {

    private Logic logic;

    public MyWindowListener(Logic logic) {
        this.logic = logic;
    }

    @Override
    public void windowActivated(WindowEvent arg0) {
    }

    @Override
    public void windowClosed(WindowEvent arg0) {
    }

    @Override
    public void windowClosing(WindowEvent arg0) {
        logic.quitProgram();
    }

    @Override
    public void windowDeactivated(WindowEvent arg0) {
    }

    @Override
    public void windowDeiconified(WindowEvent arg0) {
    }

    @Override
    public void windowIconified(WindowEvent arg0) {
    }

    @Override
    public void windowOpened(WindowEvent arg0) {
    }

}
 

Zurück
Oben