Javafx and wav files - java

I'm playing around with javafx and I have modified the code of the MediaPleyer demo trying to reproduce a wav file. It doesn't work.
/*
* Copyright (c) 2009, SUN Microsystems, Inc.
* All rights reserved.
*/
package javafx.tools.fxd.demos.mediaplayer;
import javafx.scene.*;
import javafx.scene.media.*;
import javafx.stage.*;
var player = javafx.scene.media.MediaPlayer {
repeatCount: 1
media: Media {
source: "{__DIR__}Door_Open.wav"
};
};
class MyMediaPlayerUI extends MediaPlayerUI {
override protected function contentLoaded() {
super.contentLoaded();
var s = player.media.source;
var i = s.lastIndexOf ("/");
if (i >= 0) {
s = s.substring (i + 1);
}
fileName.content = s;
}
}
var stage : Stage;
var ui = MyMediaPlayerUI {};
var skins = [ "{__DIR__}MediaPlayer1.fxz", "{__DIR__}MediaPlayer2.fxz" ];
var index = 0;
ButtonController {
pressed: bind ui.playPressed
hovered: bind ui.playHovered
normal: bind ui.playNormal
activeArea: bind ui.playActiveArea
action: function () {
player.play ();
}
}
ButtonController {
pressed: bind ui.pausePressed
hovered: bind ui.pauseHovered
normal: bind ui.pauseNormal
activeArea: bind ui.pauseActiveArea
action: function () {
player.pause ();
}
}
ButtonController {
pressed: bind ui.switchPressed
hovered: bind ui.switchHovered
normal: bind ui.switchNormal
activeArea: bind ui.switchActiveArea
action: function () {
index = (index + 1) mod skins.size ();
ui.url = skins[index];
}
}
stage = Stage {
title: "Media Player"
//visible: true
resizable: false
onClose: function() { java.lang.System.exit (0); }
scene: Scene {
content: ui
}
}
The wav file is not reproduced without giving any exception.
If I change the repeatCount property to
repeatCount: javafx.scene.media.MediaPlayer.REPEAT_FOREVER
eventually gives a heap space exception:
Exception in thread "PlayerLoop" java.lang.OutOfMemoryError: Java heap space
There is any problem in the code above? There is a way to reproduce wav files? I think this is essential for javafx since wavs are a very spread audio format.
Thanks.

The JavaFx documentation is strange on that one. On one page it says playing wav files placed in jar files works on another it says it does not work.
For me it does not work like for you. (What works is playing .wav files which are not placed in jar files.)
Here is my solution for the problem (My own audioplayer)
import java.net.URL;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
public class AudioPlayer {
private static final int EXTERNAL_BUFFER_SIZE = 128000;
private URL url_;
public AudioPlayer(URL filename) {
url_ = filename;
}
public void play() throws Exception {
AudioInputStream audioInputStream = null;
audioInputStream = AudioSystem.getAudioInputStream(url_);
AudioFormat audioFormat = audioInputStream.getFormat();
SourceDataLine line = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,
audioFormat);
line = (SourceDataLine) AudioSystem.getLine(info);
line.open(audioFormat);
line.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0) {
line.write(abData, 0, nBytesRead);
}
}
line.drain();
line.close();
}
}
import javafx.async.RunnableFuture;
public class PlayAudioImpl implements RunnableFuture {
private AudioPlayer audio;
public PlayAudioImpl(AudioPlayer audio) {
this.audio = audio;
}
#Override
public void run() throws Exception {
audio.play();
}
}
import javafx.async.JavaTaskBase;
import javafx.async.RunnableFuture;
import java.net.URL;
public class PlayAudio extends JavaTaskBase {
public-init var source:String;
public override function create() : RunnableFuture {
var player = new AudioPlayer(new URL(source));
return new PlayAudioImpl(player);
}
public function play() : Void {
start();
}
}
Play the audio using:
PlayAudio {
source: "{__DIR__}audio/audio.wav"
}.play();

Related

ConnectionNotFoundException j2me

I'have written the following code in j2me but it always throws ConnectionNotFoundException. I have disabled the windows firewall in case it blocks the netbeans network activity.
package networking;
import java.io.IOException;
import java.io.InputStream;
import javax.microedition.io.Connection;
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;
import javax.microedition.midlet.*;
/**
* #author Kanishk
*/
public class Midlet extends MIDlet implements CommandListener{
private Command command;
private Form form;
private Display display;
private String url = "http://www.gzip.org/algorithm.txt";
private String local="http://127.0.0.1:8000";
private HttpConnection c = null;
private InputStream s = null;
private Connection conn;
public void startApp() {
display = Display.getDisplay(this);
form = new Form("Networking");
command = new Command("Exit",Command.EXIT,0);
form.addCommand(command);
try {
//conn = Connector.open(url);
c = (HttpConnection) Connector.open(url);
s = c.openInputStream();
byte[] byteArray = new byte[1024];
StringBuffer sb = new StringBuffer();
int readBytes = 0;
while ((readBytes = s.read(byteArray)) > 0) {
String temp = new String(byteArray, 0, readBytes);
sb.append(temp);
String inData = sb.toString();
System.out.println(inData);
form.append(inData);
c.close();
}
} catch (IOException ex) {
form.append("Connection failed.");
System.out.println("here");
}
// if (s != null) {
// form.append(inData);
// } else if (s == null) {
// form.append("Connection failed.");
// }
form.setCommandListener(this);
display.setCurrent(form);
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
notifyDestroyed();
}
public void commandAction(Command c, Displayable d){
if(c == command)
destroyApp(true);
}
}
The snapshot of output console is as follows:
Installing suite from: file:///C:/Users/Messi/Documents/NetBeansProjects/networking/dist/nbrun3458695790676134373/networking.jad
988830 - ERROR - AMS - 2 - Installation failed: com.sun.midp.midletsuite.MIDletSuiteLockedException
com.sun.midp.midletsuite.MIDletSuiteLockedException
at com.sun.midp.midletsuite.MIDletSuiteImpl.lockMIDletSuite(), bci=0
at com.sun.midp.midletsuite.MIDletSuiteStorage.getMIDletSuite(), bci=12
at com.sun.midp.installer.Installer.checkPreviousVersion(), bci=60
at com.sun.midp.installer.Installer.installStep2(), bci=10
at com.sun.midp.installer.Installer.performInstall(), bci=132
at com.sun.midp.installer.Installer.resumeInstallation(), bci=7
at com.sun.midp.installer.MidpInstaller$StartAction.run(), bci=10
at com.sun.j2me.security.AccessController.doPrivileged(), bci=12
at com.sun.midp.installer.MidpInstaller$InstallThread.run(), bci=9
at java.lang.Thread.run(Thread.java:743)
javacall_lifecycle_state_changed() lifecycle: event is JAVACALL_LIFECYCLE_MIDLET_SHUTDOWN status is JAVACALL_OK
javax.microedition.io.ConnectionNotFoundException: error 10061 in socket::open
at com.sun.midp.io.j2me.socket.Protocol.open0(), bci=0
at com.sun.midp.io.j2me.socket.Protocol.connect(), bci=184
at com.sun.midp.io.j2me.socket.Protocol.open(), bci=216
at com.sun.midp.io.j2me.socket.Protocol.openPrim(), bci=4
at com.sun.midp.io.j2me.http.Protocol.createConnection(), bci=41
at com.sun.midp.io.j2me.http.Protocol.connect(), bci=41
at com.sun.midp.io.j2me.http.Protocol.streamConnect(), bci=164
at com.sun.midp.io.j2me.http.Protocol.startRequest(), bci=7
at com.sun.midp.io.j2me.http.Protocol.sendRequest(), bci=33
at com.sun.midp.io.j2me.http.Protocol.sendRequest(), bci=3
at com.sun.midp.io.j2me.http.Protocol.getResponseCode(), bci=5
- networking.Main.run(Main.java:68)
at java.lang.Thread.run(Thread.java:743)
Any help will be appreciated. Thank You!

Updating parameter in SwingWorker

I need some help, I'm making a program like a file manager. In my program I need to make simultaneous files copies. For that I use SwingWorker to see the progress of the copies in a JProgressbar, but I need to know how to add more files to Copy in the task with the same destination.
This is my class that extends from Swingworker in my principal program I´ll select some files or folders to copy in one destination. What I need is while the Copytask is working I can to add more files to the Copyitem Arraylist.
Please help and sorry about my english.
import java.awt.Dimension;
import java.awt.Toolkit;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import xray.XRAYView;
public class CopyTask extends SwingWorker<Void, Integer>
{
ArrayList<CopyItem>copia;
private long totalBytes = 0L;
private long copiedBytes = 0L;
JProgressBar progressAll;
JProgressBar progressCurrent;
boolean override=true;
boolean overrideall=false;
public CopyTask(ArrayList<CopyItem>copia,JProgressBar progressAll,JProgressBar progressCurrent)
{
this.copia=copia;
this.progressAll=progressAll;
this.progressCurrent=progressCurrent;
progressAll.setValue(0);
progressCurrent.setValue(0);
totalBytes=retrieveTotalBytes(copia);
}
public void AgregarCopia(ArrayList<CopyItem>addcopia)throws Exception{
copia.addAll(copia.size(), addcopia);
totalBytes=retrieveTotalBytes(addcopia)+totalBytes;
System.out.println("AL AGREGAR: "+copia.size()+" Tamaño"+totalBytes);
}
public File getDriveDest(){
File dest=new File(copia.get(0).getOrigen().getPath().split("\\")[0]);
return dest;
}
#Override
public Void doInBackground() throws Exception
{
for(CopyItem cop:copia){
File ori=cop.getOrigen();
File des=new File(cop.getDestino().getPath());
if(!des.exists()){
des.mkdirs();
}
if(!overrideall){
override =true;
}
File para=new File(cop.getDestino().getPath()+"\\"+ori.getName());
copyFiles(ori, para);
}
return null;
}
#Override
public void process(List<Integer> chunks)
{
for(int i : chunks)
{
progressCurrent.setValue(i);
}
}
#Override
public void done()
{
setProgress(100);
}
private long retrieveTotalBytes(ArrayList<CopyItem>fich)
{
long size=0;
for(CopyItem cop: fich)
{
size += cop.getOrigen().length();
}
return size;
}
private void copyFiles(File sourceFile, File targetFile) throws IOException
{
if(overrideall==false){
if(targetFile.exists() && !targetFile.isDirectory()){
String []options={"Si a Todos","Si","No a Ninguno","No"};
int seleccion=JOptionPane.showOptionDialog(null, "El fichero \n"+targetFile+" \n se encuentra en el equipo, \n¿Desea sobreescribirlo?", "Colisión de ficheros", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, null);
switch(seleccion){
case 0:
override=true;
overrideall=true;
break;
case 1:
override=true;
overrideall=false;
break;
case 2:
override =false;
overrideall=true;
break;
case 3:
override =false;
overrideall=false;
break;
}
}
}
if(override || !targetFile.exists()){
FileInputStream LeeOrigen= new FileInputStream(sourceFile);
OutputStream Salida = new FileOutputStream(targetFile);
byte[] buffer = new byte[1024];
int tamaño;
long fileBytes = sourceFile.length();
long totalBytesCopied = 0;
while ((tamaño = LeeOrigen.read(buffer)) > 0) {
Salida.write(buffer, 0, tamaño);
totalBytesCopied += tamaño;
copiedBytes+= tamaño;
setProgress((int)Math.round(((double)copiedBytes++ / (double)totalBytes) * 100));
int progress = (int)Math.round(((double)totalBytesCopied / (double)fileBytes) * 100);
publish(progress);
}
Salida.close();
LeeOrigen.close();
publish(100);
}
}
}
Here is CopyItem class
import java.io.File;
public class CopyItem {
File origen;
File destino;
String root;
public CopyItem(File origen, File destino) {
this.origen = origen;
this.destino = destino;
}
public CopyItem(File origen, File destino, String root) {
this.origen = origen;
this.destino = destino;
this.root = root;
}
public String getRoot() {
return root;
}
public void setRoot(String root) {
this.root = root;
}
public File getOrigen() {
return origen;
}
public void setOrigen(File origen) {
this.origen = origen;
}
public File getDestino() {
return destino;
}
public void setDestino(File destino) {
this.destino = destino;
}
#Override
public String toString() {
return super.toString(); //To change body of generated methods, choose Tools | Templates.
}
}
yes you can add the files directly to source List(the list contains files to be copied ) but you need to synchronize your code because adding more file will be in different thread(UI Thread),another way is to implement (produce/consumer ) using BlockingQueue
Consumer class run in separate Thread or Swingworker coping files is in progress.
Producer class runs UI Thread (selecting more files).
both should have access to BlockingQueue (contains files to be copied)(of course BlockingQueue implementations are thread-safe based on the documentation. ,it has the advantage to block the execution and wait for the files to be added this is very useful if you dont know when the files are added )
I prefer using Thread Pool to manage the threads executions(Optional).

Java - Clipboard modification : Works in Eclipse, but not as JAR

I created a software based on two sources (stated in the code below) which detect HTML copied to the clipboard and change local images to base 64 ones.
This code works perfectly when I run it in Eclipse, but not using a JAR.
Initially, I was not using the method getHtmlDataFlavor, but I added it when I tried the software as a JAR. Then, I had to ensure in HtmlSelection.getTransferData to have if (flavor.getRepresentationClass() == java.io.Reader.class) otherwise it would crash. But using the JAR, I'm only getting the plain text version! Though, it stills works when ran in Eclipse.
Does someone have an idea ?
I am running on Windows 10.
Executing in command line using : java -jar ClipboardImageToBase64-1.0.0-jar-with-dependencies.jar
GitHub project :
https://github.com/djon2003/ClipboardImageToBase64
/**
* Library from HTML parsing : https://jsoup.org
*
* Code based on :
* - http://stackoverflow.com/a/14226456/214898
* - http://elliotth.blogspot.ca/2005/01/copying-html-to-clipboard-from-java.html
*/
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
public class ClipBoardListener extends Thread implements ClipboardOwner {
Clipboard sysClip = Toolkit.getDefaultToolkit().getSystemClipboard();
private static DataFlavor HTML_FLAVOR = new DataFlavor("text/html;class=java.io.Reader", "HTML");
private int nbImagesConverted = 0;
private Transferable currentTransferable;
#Override
public void run() {
Transferable trans = sysClip.getContents(this);
TakeOwnership(trans);
}
#Override
public void lostOwnership(Clipboard c, Transferable t) {
System.out.println("Copy to clipboard detected");
try {
ClipBoardListener.sleep(250); // waiting e.g for loading huge
// elements like word's etc.
} catch (Exception e) {
System.out.println("Exception: " + e);
}
Transferable contents = sysClip.getContents(this);
try {
process_clipboard(contents, c);
} catch (Exception ex) {
Logger.getLogger(ClipBoardListener.class.getName()).log(Level.SEVERE, null, ex);
}
TakeOwnership(currentTransferable);
}
void TakeOwnership(Transferable t) {
sysClip.setContents(t, this);
}
private void getHtmlDataFlavor(Transferable t) {
DataFlavor df = null;
for (DataFlavor tDf : t.getTransferDataFlavors()) {
if (tDf.getMimeType().contains("text/html")) {
if (tDf.getRepresentationClass() == java.io.Reader.class) {
df = tDf;
break;
}
}
}
HTML_FLAVOR = df;
}
public void process_clipboard(Transferable t, Clipboard c) {
String tempText = "";
Transferable trans = t;
currentTransferable = t;
getHtmlDataFlavor(t);
if (HTML_FLAVOR == null) {
System.out.println("No HTML flavor detected");
return;
}
nbImagesConverted = 0;
try {
if (trans != null ? trans.isDataFlavorSupported(HTML_FLAVOR) : false) {
if (trans.isDataFlavorSupported(DataFlavor.stringFlavor)) {
tempText = (String) trans.getTransferData(DataFlavor.stringFlavor);
}
java.io.Reader r = (java.io.Reader) trans.getTransferData(HTML_FLAVOR);
StringBuilder content = getReaderContent(r);
String newHtml = changeImages(content);
currentTransferable = new HtmlSelection(newHtml, tempText);
System.out.println("Converted " + nbImagesConverted + " images");
} else {
System.out.println("Not converted:" + trans.isDataFlavorSupported(HTML_FLAVOR));
System.out.println(trans.getTransferData(HTML_FLAVOR));
/*
for (DataFlavor tt : trans.getTransferDataFlavors()) {
if (tt.getMimeType().contains("text/html")) {
System.out.println("-------");
System.out.println(tt.toString());
}
}
*/
}
} catch (Exception e) {
currentTransferable = t;
System.out.println("Conversion error");
e.printStackTrace();
}
}
private String changeImages(StringBuilder content) throws RuntimeException, IOException {
Document doc = Jsoup.parse(content.toString());
Elements imgs = doc.select("img");
for (Element img : imgs) {
String filePath = img.attr("src");
filePath = filePath.replace("file:///", "");
filePath = filePath.replace("file://", "");
File file = new File(filePath);
if (file.exists()) {
String encoded = Base64.encodeBase64String(FileUtils.readFileToByteArray(file));
String extension = file.getName();
extension = extension.substring(extension.lastIndexOf(".") + 1);
String dataURL = "data:image/" + extension + ";base64," + encoded;
img.attr("src", dataURL); // or whatever
nbImagesConverted++;
}
}
String html = doc.outerHtml();
html = html.replaceAll("(?s)<!--.*?-->", ""); //Remove html comments
return html; // returns the modified HTML
}
private StringBuilder getReaderContent(java.io.Reader r) throws IOException {
char[] arr = new char[8 * 1024];
StringBuilder buffer = new StringBuilder();
int numCharsRead;
while ((numCharsRead = r.read(arr, 0, arr.length)) != -1) {
buffer.append(arr, 0, numCharsRead);
}
r.close();
return buffer;
}
private static class HtmlSelection implements Transferable {
private String html;
private String plainText;
public HtmlSelection(String html, String plainText) {
this.html = html;
this.plainText = plainText;
}
public DataFlavor[] getTransferDataFlavors() {
DataFlavor[] dfs = {HTML_FLAVOR, DataFlavor.stringFlavor};
return dfs;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.getMimeType().contains("text/html") || flavor.getMimeType().contains("text/plain");
}
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException {
if (flavor.getMimeType().contains("text/html")) {
if (flavor.getRepresentationClass() == java.io.Reader.class) {
return new StringReader(html);
} else {
return html;
}
} else {
return plainText;
}
//throw new UnsupportedFlavorException(flavor);
}
}
}
I finally fixed all my problems. I created a GitHub project for those who are interested.
https://github.com/djon2003/ClipboardImageToBase64

Unity WebGl. Load textures from Java server

I have two project, a Java+Spring server and a unity project written in C#.
The unity project will be export into WebGl(it is not a game).
Now here is my problem:
I must load textures from the Java server.
How can i solve this problem?
My current solution, greatly simplified (not work in browser):
Server:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
-
#RestController
public class MyController {
#Autowired
private Loader2 loader2;
#RequestMapping("/skull2")
public ByteObj skull2(#RequestParam(value = "name", defaultValue = "World") String name) {
return loader2.getImages("Skull");
}
}
-
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.stereotype.Controller;
#Controller
public class Loader2 {
String mainPath = "Path to images folder"; // in the future i will load many textures;
public List<String> getFileNameInPath(String foldername) {
List<String> result = new ArrayList<String>();
File folder = new File(mainPath + foldername);
File[] listOfFiles = folder.listFiles();
for (int i = 0; i < listOfFiles.length; i++) {
if (listOfFiles[i].isFile()) {
System.out.println("file " + listOfFiles[i].getName());
result.add(listOfFiles[i].getName());
} else if (listOfFiles[i].isDirectory()) {
System.out.println("Directory " + listOfFiles[i].getName());
}
}
return result;
}
public ByteObj getImages(String folder) {
List<String> images = getFileNameInPath(folder);
for (String string : images) {
try {
File file = new File(mainPath + folder + "//" + string);
FileInputStream imageInFile = new FileInputStream(file);
byte imageData[] = new byte[(int) file.length()];
imageInFile.read(imageData);
// Converting Image byte array into Base64 String
String imageDataString = encodeImage(imageData);
imageInFile.close();
return new ByteObj(imageDataString);
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public String encodeImage(byte[] imageByteArray) {
return Base64.encodeBase64String(imageByteArray);
}
}
-
import java.io.Serializable;
public class ByteObj implements Serializable {
public String obj;
public ByteObj(String obj) {
this.obj = obj;
}
public ByteObj() {
}
}
Client(load from server and decode)
The Unity stage contains a 3D cube and a camera(with script)
// C#
public class ByteObj {
public string obj;
public ByteObj(string obj) {
this.obj = obj;
}
public ByteObj() {
}
}
-
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using System.Text;
public class MyTestClass: MonoBehaviour {
public GameObject cube;
public float speed = 10f;
IEnumerator Start() {
yield return StartCoroutine( UploadImages() );
}
void Update () {
cube.transform.Rotate(Vector3.up, speed * Time.deltaTime);
}
IEnumerator UploadImages()
{
string aux = "";
WWW www = new WWW("http://localhost:8080/skull2");
yield return www;
aux = www.text;
if (www.text == null)
{
Debug.Log("Images not found");
}
else {
ByteObj list = JsonUtility.FromJson<ByteObj>(aux);
var myObject = list.obj;
//instruction.text = list.obj;
string s = myObject.Trim().Replace(" ", "+");
if (s.Length % 4 > 0)
s = s.PadRight(s.Length + 4 - s.Length % 4, '=');
byte[] b64_bytes = System.Convert.FromBase64String(myObject);
var decodedBytes = Convert.FromBase64String(myObject);
var tex = new Texture2D(2, 2);
tex.LoadImage(decodedBytes);
cube.GetComponent<Renderer>().material.mainTexture = tex;
}
}
}
It works as a Desktop app, but after export to WebGl I see only the cube(without textures)
Thank you for your help
PS. Sorry for my english

How to load media resources from the classpath in JMF

I have a Java application that I want to turn into an executable jar. I am using JMF in this application, and I can't seem to get the sound files working right...
I create the jar using
jar cvfm jarname.jar manifest.txt *.class *.gif *.wav
So, all the sound files get put inside the jar, and in the code, I am creating the Players using
Player player = Manager.createPlayer(ClassName.class.getResource("song1.wav"));
The jar is on my desktop, and when I attempt to run it, this exception occurs:
javax.media.NoPlayerException: Cannot find a Player for :jar:file:/C:/Users/Pojo/
Desktop/jarname.jar!/song1.wav
...It's not getting IOExceptions, so it seems to at least be finding the file itself all right.
Also, before I used the getResource, I used to have it like this:
Player player = Manager.createPlayer(new File("song1.wav").toURL());
and it was playing fine, so I know nothing is wrong with the sound file itself.
The reason I am trying to switch to this method instead of the File method is so that the sound files can be packaged inside the jar itself and not have to be its siblings in a directory.
This is a far cry from production code, but this seems resolved any runtime exceptions (though it's not actually wired up to play anything yet):
import javax.media.Manager;
import javax.media.Player;
import javax.media.protocol.URLDataSource;
// ...
URL url = JmfTest.class.getResource("song1.wav");
System.out.println("url: " + url);
URLDataSource uds = new URLDataSource(url);
uds.connect();
Player player = Manager.createPlayer(uds);
New solution:
First, a custom DataSource class that returns a SourceStream that implements Seekable is needed:
package com.ziesemer.test;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.media.Duration;
import javax.media.MediaLocator;
import javax.media.Time;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.PullDataSource;
import javax.media.protocol.PullSourceStream;
import javax.media.protocol.Seekable;
/**
* #author Mark A. Ziesemer
* <www.ziesemer.com>
*/
public class JarDataSource extends PullDataSource{
protected JarURLConnection conn;
protected ContentDescriptor contentType;
protected JarPullSourceStream[] sources;
protected boolean connected;
public JarDataSource(URL url) throws IOException{
setLocator(new MediaLocator(url));
connected = false;
}
#Override
public PullSourceStream[] getStreams(){
return sources;
}
#Override
public void connect() throws IOException{
conn = (JarURLConnection)getLocator().getURL().openConnection();
conn.connect();
connected = true;
JarFile jf = conn.getJarFile();
JarEntry je = jf.getJarEntry(conn.getEntryName());
String mimeType = conn.getContentType();
if(mimeType == null){
mimeType = ContentDescriptor.CONTENT_UNKNOWN;
}
contentType = new ContentDescriptor(ContentDescriptor.mimeTypeToPackageName(mimeType));
sources = new JarPullSourceStream[1];
sources[0] = new JarPullSourceStream(jf, je, contentType);
}
#Override
public String getContentType(){
return contentType.getContentType();
}
#Override
public void disconnect(){
if(connected){
try{
sources[0].close();
}catch(IOException e){
e.printStackTrace();
}
connected = false;
}
}
#Override
public void start() throws IOException{
// Nothing to do.
}
#Override
public void stop() throws IOException{
// Nothing to do.
}
#Override
public Time getDuration(){
return Duration.DURATION_UNKNOWN;
}
#Override
public Object[] getControls(){
return new Object[0];
}
#Override
public Object getControl(String controlName){
return null;
}
protected class JarPullSourceStream implements PullSourceStream, Seekable, Closeable{
protected final JarFile jarFile;
protected final JarEntry jarEntry;
protected final ContentDescriptor type;
protected InputStream stream;
protected long position;
public JarPullSourceStream(JarFile jarFile, JarEntry jarEntry, ContentDescriptor type) throws IOException{
this.jarFile = jarFile;
this.jarEntry = jarEntry;
this.type = type;
this.stream = jarFile.getInputStream(jarEntry);
}
#Override
public ContentDescriptor getContentDescriptor(){
return type;
}
#Override
public long getContentLength(){
return jarEntry.getSize();
}
#Override
public boolean endOfStream(){
return position < getContentLength();
}
#Override
public Object[] getControls(){
return new Object[0];
}
#Override
public Object getControl(String controlType){
return null;
}
#Override
public boolean willReadBlock(){
if(endOfStream()){
return true;
}
try{
return stream.available() == 0;
}catch(IOException e){
return true;
}
}
#Override
public int read(byte[] buffer, int offset, int length) throws IOException{
int read = stream.read(buffer, offset, length);
position += read;
return read;
}
#Override
public long seek(long where){
try{
if(where < position){
stream.close();
stream = jarFile.getInputStream(jarEntry);
position = 0;
}
long skip = where - position;
while(skip > 0){
long skipped = stream.skip(skip);
skip -= skipped;
position += skipped;
}
}catch(IOException ioe){
// Made a best effort.
ioe.printStackTrace();
}
return position;
}
#Override
public long tell(){
return position;
}
#Override
public boolean isRandomAccess(){
return true;
}
#Override
public void close() throws IOException{
try{
stream.close();
}finally{
jarFile.close();
}
}
}
}
Then, the above custom data source is used to create a player, and a ControllerListener is added to cause the player to loop:
package com.ziesemer.test;
import java.net.URL;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.EndOfMediaEvent;
import javax.media.Manager;
import javax.media.Player;
import javax.media.Time;
/**
* #author Mark A. Ziesemer
* <www.ziesemer.com>
*/
public class JmfTest{
public static void main(String[] args) throws Exception{
URL url = JmfTest.class.getResource("Test.wav");
JarDataSource jds = new JarDataSource(url);
jds.connect();
final Player player = Manager.createPlayer(jds);
player.addControllerListener(new ControllerListener(){
#Override
public void controllerUpdate(ControllerEvent ce){
if(ce instanceof EndOfMediaEvent){
player.setMediaTime(new Time(0));
player.start();
}
}
});
player.start();
}
}
Note that without the custom data source, JMF tries repeatedly to seek back to the beginning - but fails, and eventually gives up. This can be seen from debugging the same ControllerListener, which will receive a several events for each attempt.
Or, using the MediaPlayer approach to loop (that you mentioned on my previous answer):
package com.ziesemer.test;
import java.net.URL;
import javax.media.Manager;
import javax.media.Player;
import javax.media.bean.playerbean.MediaPlayer;
/**
* #author Mark A. Ziesemer
* <www.ziesemer.com>
*/
public class JmfTest{
public static void main(String[] args) throws Exception{
URL url = JmfTest.class.getResource("Test.wav");
JarDataSource jds = new JarDataSource(url);
jds.connect();
final Player player = Manager.createPlayer(jds);
MediaPlayer mp = new MediaPlayer();
mp.setPlayer(player);
mp.setPlaybackLoop(true);
mp.start();
}
}
Again, I would not consider this production-ready code (could use some more Javadocs and logging, etc.), but it is tested and working (Java 1.6), and should meet your needs nicely.
Merry Christmas, and happy holidays!
Manager.createPlayer(this.getClass().getResource("/song1.wav"));
That will work if the song1.wav is in the root of a Jar that is on the run-time class-path of the application.

Categories

Resources