GStreamer Java Binding cleanup issue after playback from AppSrc - java-gstreamer

I'm trying to use GStreamer Java Binding on Raspberry Pi to play some dynamic audio data which is Opus encoded. I'm almost done. My final issue is I cannot have GStreamer clean up nicely when the data reaching the end. My testing code is as below.
package org.freedesktop.gstreamer.examples;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.swing.JFrame;
import org.freedesktop.gstreamer.Bin;
import org.freedesktop.gstreamer.Buffer;
import org.freedesktop.gstreamer.Bus;
import org.freedesktop.gstreamer.Element;
import org.freedesktop.gstreamer.ElementFactory;
import org.freedesktop.gstreamer.FlowReturn;
import org.freedesktop.gstreamer.Gst;
import org.freedesktop.gstreamer.GstObject;
import org.freedesktop.gstreamer.Message;
import org.freedesktop.gstreamer.Pad;
import org.freedesktop.gstreamer.PadLinkReturn;
import org.freedesktop.gstreamer.Pipeline;
import org.freedesktop.gstreamer.State;
import org.freedesktop.gstreamer.elements.AppSrc;
import org.freedesktop.gstreamer.lowlevel.MainLoop;
/**
*
* #author Superrei
*/
public class AudioTest {
//private static final int BUFFER_SIZE = 4096;
private static byte[] soundBytes = null;
private static int pointer = 0;
private static String filename = null;
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
Gst.init("AudioTest", args);
filename = args[0];
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
File soundFile = new File(filename);
FileInputStream inStream = null;
if (soundFile.exists()){
try {
System.out.println("Read media file.");
long fileSize = soundFile.length();
soundBytes = new byte[(int)fileSize];
inStream = new FileInputStream(soundFile);
int byteCount = inStream.read(soundBytes);
System.out.println("Number of byte read: " + byteCount);
} catch (IOException e) {
e.printStackTrace();
return;
}
}
final MainLoop loop = new MainLoop();
AppSrc source = (AppSrc)ElementFactory.make("appsrc", "app-source");
Element demuxer = ElementFactory.make("oggdemux", "ogg-demuxer");
final Element decoder = ElementFactory.make("opusdec", "opus-decoder");
Element conv = ElementFactory.make("audioconvert", "converter");
Element sink = ElementFactory.make("autoaudiosink", "audio-output");
//source.set("location", "/home/pi/gstJavaTest/transcript.ogg");
Pipeline pipe = new Pipeline();
Bus bus = pipe.getBus();
bus.connect(new Bus.EOS() {
#Override
public void endOfStream(GstObject source) {
loop.quit();
}
});
bus.connect(new Bus.ERROR() {
#Override
public void errorMessage(GstObject source, int code, String message) {
System.out.println("Error detected");
System.out.println("Error source: " + source.getName());
System.out.println("Error code: " + code);
System.out.println("Message: " + message);
loop.quit();
}
});
pipe.addMany(source, demuxer, decoder, conv, sink);
source.link(demuxer);
source.set("emit-signals", true);
source.connect(new AppSrc.NEED_DATA() {
private ByteBuffer bb = ByteBuffer.wrap(soundBytes);
#Override
public void needData(AppSrc elem, int size) {
if (bb.hasRemaining()) {
// TODO Auto-generated method stub
System.out.println("needData: size = " + size);
byte[] tempBuffer;
Buffer buf;
if (bb.remaining() > size) {
tempBuffer = new byte[size];
buf = new Buffer(size);
} else {
tempBuffer = new byte[bb.remaining()];
buf = new Buffer(bb.remaining());
}
//System.out.println("Buffer size: " + buf.map(true).remaining());
//System.arraycopy(soundBytes, pointer, tempBuffer, 0, size);
bb.get(tempBuffer);
System.out.println("Temp Buffer remaining bytes: " + bb.remaining());
buf.map(true).put(ByteBuffer.wrap(tempBuffer));
elem.pushBuffer(buf);
} else {
elem.emit("end-of-stream", elem);
}
//pointer += size;
}
});
source.connect(new AppSrc.ENOUGH_DATA() {
#Override
public void enoughData(AppSrc elem) {
System.out.println("enoughData: " + elem.toString());
}
});
source.connect(new AppSrc.END_OF_STREAM() {
#Override
public FlowReturn endOfStream(AppSrc elem) {
// TODO Auto-generated method stub
return FlowReturn.OK;
}
});
Element.linkMany(decoder, conv, sink);
demuxer.connect(new Element.PAD_ADDED() {
#Override
public void padAdded(Element element, Pad pad) {
System.out.println("Dynamic pad created, linking demuxer/decoder");
System.out.println("Pad name: " + pad.getName());
System.out.println("Pad type: " + pad.getTypeName());
Pad sinkPad = decoder.getStaticPad("sink");
//boolean linked = element.link(decoder);
PadLinkReturn ret = pad.link(sinkPad);
if (ret.equals(PadLinkReturn.OK)){
System.out.println("Pad linked.");
} else {
System.out.println("Pad link failed");
}
//System.out.println("Pad Link Return: " + ret.toString());
}
});
System.out.println("Now Playing...");
pipe.play();
System.out.println("Running...");
loop.run();
System.out.println("Returned, stopping playback");
pipe.stop();
}
});
}
}
I don't use playbin since the audio data will come in byte stream finally.
The test runs well until the end. When I reach the end of file. I get error messages and follow by JVM crush. The error message is like this:
(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed
(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed Returned, stopping playback
(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_ref: assertion 'G_IS_OBJECT (object)' failed
(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed
(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_ref: assertion 'G_IS_OBJECT (object)' failed
(AudioTest:4643): GLib-GObject-CRITICAL **: g_object_unref: assertion 'G_IS_OBJECT (object)' failed
(AudioTest:4643): GLib-GObject-CRITICAL **: g_value_set_object: assertion 'G_IS_OBJECT (v_object)' failed
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x63d8b8ec, pid=4643, tid=1658819680
#
# JRE version: Java(TM) SE Runtime Environment (8.0_65-b17) (build
1.8.0_65-b17)
# Java VM: Java HotSpot(TM) Client VM (25.65-b01 mixed mode linux-arm )
# Problematic frame:
# C [libglib-2.0.so.0+0x928ec] g_rec_mutex_lock+0x8
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/pi/gstJavaTest/hs_err_pid4643.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
# Aborted
I cannot find any example on using AppSrc to play something with an end. Any help will be appreciated.

I fixed the problem. The solution is using AppSrc.endOfStream() method rather than emitting a signal. Also I removed the callback for AppSrc.END_OF_STREAM, since it is not necessary. So my callback for needData is like this:
#Override
public void needData(AppSrc elem, int size) {
if (bb.hasRemaining()) {
System.out.println("needData: size = " + size);
byte[] tempBuffer;
Buffer buf;
int copyLength = (bb.remaining() >= size) ? size : bb.remaining();
tempBuffer = new byte[copyLength];
buf = new Buffer(copyLength);
//System.arraycopy(soundBytes, pointer, tempBuffer, 0, copyLength);
System.out.println("Buffer size: " + buf.map(true).remaining());
bb.get(tempBuffer);
System.out.println("Temp Buffer remaining bytes: " + bb.remaining());
buf.map(true).put(ByteBuffer.wrap(tempBuffer));
elem.pushBuffer(buf);
//pointer += size;
} else {
elem.endOfStream();
}
}

Related

GTK4 Problem setting image from pixbuf with a GtkDropTarget

I am testing a gtk4 widget which is GtkDropTarget. I plan on setting an image which is dragged to the window as the image of the window itself. But errors come up as soon as I drag an image file. To be clear, this is the code in vala:
int main (string[] args) {
var app = new App();
return app.run(args);
}
public class App : Gtk.Application {
public App () {
Object (
application_id: "com.github.ea",
flags: ApplicationFlags.FLAGS_NONE
);
}
public override void activate () {
var window = new Window (this);
add_window (window);
}
}
public class Window : Gtk.ApplicationWindow {
public Window (Gtk.Application app) {
Object (application: app);
}
construct {
title = "Drag";
set_default_size (640, 480);
var drag_source = new DragSource ();
set_child (drag_source.self);
show ();
}
}
public class DragSource {
public Gtk.Image self;
public DragSource () {
self = new Gtk.Image ();
var drag_controller = new Gtk.DropTarget (GLib.Type.INVALID, Gdk.DragAction.COPY);
drag_controller.set_gtypes ({typeof(File)});
self.add_controller (drag_controller);
drag_controller.on_drop.connect (on_drop);
}
private bool on_drop (GLib.Value val, double x, double y) {
File filename = (File) val;
var file_path = filename.get_path ();
if (val.holds(typeof(File)) == true) {
print ("The dragged object is a file.\n");
if ("png" in file_path || "jpg" in file_path) {
print ("The dragged object is an image.\n");
self.set_from_pixbuf (pixbuf(file_path));
}
else {
print ("The dragged object is NOT an image.\n");
}
}
else {
print ("The dragged object is NOT a file.\n");
return false;
}
return true;
}
private Gdk.Pixbuf pixbuf (string file) {
try {
return new Gdk.Pixbuf.from_file (file);
} catch (Error e) {
error ("%s", e.message);
}
}
}
This compiles and runs. But as soon as I drag an image file to the window, error occurs and the image is not displayed. This are the pictures of what happens. What should happen is, when I drag a png file from my file manager, the dragged image should be the image showing in the GtkImage, which is the main widget of the window.
On my first drag of an image file from my pc, this error shows up:
The dragged object is a file.
The dragged object is an image.
(v:3891): Gtk-CRITICAL **: 08:52:28.861: gtk_image_set_from_pixbuf: assertion 'GTK_IS_IMAGE (image)' failed
On the second drag, this shows up:
(v:3891): Gdk-CRITICAL **: 08:53:33.388: gdk_drop_set_actions: assertion 'priv->state == GDK_DROP_STATE_NONE' failed
The dragged object is a file.
The dragged object is an image.
(v:3891): Gtk-CRITICAL **: 08:53:33.973: gtk_image_set_from_pixbuf: assertion 'GTK_IS_IMAGE (image)' failed
I would really appreciate a help. Thank You!
This is how I would implement your intention
int main (string[] args) {
var app = new App ();
return app.run (args);
}
public class App : Gtk.Application {
public App () {
Object (
application_id: "com.github.ea",
flags : ApplicationFlags.FLAGS_NONE
);
}
public override void activate () {
var window = new Window (this);
window.present ();
}
}
public class Window : Gtk.ApplicationWindow {
public Window (Gtk.Application app) {
Object (application: app);
}
construct {
title = "Drag an Image!";
set_default_size (640, 480);
var image = new Gtk.Image ();
image.vexpand = image.hexpand = true;
var controller = new Gtk.DropTarget (typeof (GLib.File), Gdk.DragAction.COPY);
controller.on_drop.connect ((target, value, x, y) => {
var file = (GLib.File) value;
var filename = file.get_path ();
if (GLib.ContentType.guess (filename, null, null).contains ("image")) {
image.set_from_file (filename);
}
});
image.add_controller (controller);
set_child (image);
}
}

How To Use CompUtil To Parse With Plugin

When using the Alloy API to perform parsing on the following string:
Module mod = CompUtil.parseEverything_fromString("run {} for 5")
I receive the following error:
Fatal error:
Parser Exception
at edu.mit.csail.sdg.alloy4compiler.parser.CompParser.alloy_parseStream(CompParser.java:2260)
at edu.mit.csail.sdg.alloy4compiler.parser.CompUtil.parseRecursively(CompUtil.java:178)
at edu.mit.csail.sdg.alloy4compiler.parser.CompUtil.parseEverything_fromFile(CompUtil.java:280)
at edu.mit.csail.sdg.alloy4compiler.parser.CompUtil.parseEverything_fromString(CompUtil.java:333)
at edu.mit.csail.sdg.alloy4compiler.parser.CompUtil$parseEverything_fromString.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:47)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:136)
at MyOM.MyOMPlugin.Modularize(MyOMPlugin.groovy:107)
...
--------------------------------------------------------------------------
class file:
package MyOM
class MyOMPlugin extends Plugin{
void Modularize() throws Err{
//line 107 is the only line in the method and is below
Module mod = CompUtil.parseEverything_fromString("run {} for 5")
}
}
I am performing this task in a groovy class file within a groovy project. The code works fine until I run it in conjunction with the plugin I am using.
EDIT:
The parse function is what causes the parse exception and the code for that method is included below for reference:
#Override public Symbol parse() throws java.lang.Exception {
int act; // current action code
Symbol lhs_sym = null; // the Symbol/stack element returned by a reduce
short handle_size, lhs_sym_num; // information about production being reduced with
boolean logging = "yes".equals(System.getProperty("debug"));
production_tab = production_table();
action_tab = action_table();
reduce_tab = reduce_table();
init_actions();
user_init();
// start
cur_token = scan();
stack.removeAllElements();
stack.push(getSymbolFactory().startSymbol("START", 0, start_state()));
tos = 0;
for (_done_parsing = false; !_done_parsing; ) {
act = get_action(((Symbol)stack.peek()).parse_state, cur_token.sym);
if (act > 0) { // "shift"; thus, we shift to the encoded state by pushing it on the stack
if (logging) System.out.println("shift " + cur_token.sym);
cur_token.parse_state = act-1;
stack.push(cur_token);
tos++;
cur_token = scan();
} else if (act<0) { // "reduce"
if (logging) System.out.println("reduce " + ((-act)-1));
lhs_sym = do_action((-act)-1, this, stack, tos);
lhs_sym_num = production_tab[(-act)-1][0];
handle_size = production_tab[(-act)-1][1];
for (int i = 0; i < handle_size; i++) { stack.pop(); tos--; }
act = get_reduce(((Symbol)stack.peek()).parse_state, lhs_sym_num);
lhs_sym.parse_state = act;
stack.push(lhs_sym);
tos++;
} else { // "error"
if (logging) System.out.println("error");
syntax_error(cur_token);
done_parsing();
}
}
return lhs_sym;
}

How to create multiple containers with jade

I want to create 2 containers but the agent of my second container shows a problem
ERROR: Agent robot10 died without being properly terminated !!!
when i delete the second container it works
Runtime Instance = Runtime.instance(); Instance.setCloseVM(true);
ProfileImpl Profile = new ProfileImpl(true);
Profile.setParameter(Profile.CONTAINER_NAME, "Pacman");
Profile.setParameter(Profile.MAIN_HOST, "localhost");
AgentContainer Conteneur = Instance.createAgentContainer(Profile);
for (int i = 1; i <= n; i++) {
AgentController Agent = Conteneur.createNewAgent("robot" + String.valueOf(i), "package1.robot", Parametres1);
Agent.start();
}
AgentContainer Conteneur1 = Instance.createAgentContainer(Profile);
AgentController Agent = Conteneur1.createNewAgent("robot10" , "package1.robot", new Object[] {});
Agent.start();
It is still showing errors
Here is the code
package package1;
import jade.Boot;
import jade.core.AID;
import jade.core.Agent;
import jade.core.Profile;
import static jade.core.Profile.PLATFORM_ID;
import jade.core.ProfileImpl;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAException;
import jade.lang.acl.ACLMessage;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import jade.wrapper.ContainerController;
import jade.wrapper.StaleProxyException;
import javax.swing.UIManager;
public class launch extends Agent {
static DFAgentDescription agentDescription;private static AID aid;
static ACLMessage message1, message2;
launch() throws FIPAException{
agentDescription = new DFAgentDescription();
agentDescription.setName(getAID());
DFService.register(this, agentDescription);
DFService.register(this, agentDescription);
}
public static void main(String[] args) throws StaleProxyException {
try {
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
} catch (Exception e) {
}
try {
String[] arg = { "-gui","ClusteringAgent:multi.agent_clustering.ClusteringAgent" };
Boot.main(arg);
} catch (Exception e) {
e.printStackTrace();
}
jade.core.Runtime rt = jade.core.Runtime.instance(); rt.setCloseVM(true);
String containerName="Mycontainer1";
ProfileImpl pContainer = new ProfileImpl(true);
pContainer.setParameter(Profile.CONTAINER_NAME,containerName);
System.out.println("Launching container "+pContainer);
ContainerController containerRef = rt.createAgentContainer(pContainer);
AgentController Agent = containerRef.createNewAgent("robot" + String.valueOf(1), "package1.launch", new Object[] { 2});
Agent.start();
//create container2
containerName="Mycontainer2";
pContainer = new ProfileImpl( true);
pContainer.setParameter(Profile.CONTAINER_NAME,containerName);
System.out.println("Launching container "+pContainer);
containerRef = rt.createAgentContainer(pContainer);
AgentController Agent1 = containerRef.createNewAgent("robot" + String.valueOf(2), "package1.launch", new Object[] {2});
Agent.start();
}
}
the error showing is :
Exception in thread "main" jade.wrapper.StaleProxyException: Illegal access exception in createAgent() [nested java.lang.IllegalAccessException: Class jade.core.management.AgentManagementService$CommandTargetSink can not access a member of class package1.launch with modifiers ""]
at jade.wrapper.ContainerController.createNewAgent(Unknown Source)
There is an error in your code, you do not update the Profile of your containers and use the same Name for 2 different containers, which is wrong.
//create container1
String containerName="Mycontainer1";
ProfileImpl pContainer = new ProfileImpl(PLATFORM_IP, PLATFORM_PORT, PLATFORM_ID);
pContainer.setParameter(Profile.CONTAINER_NAME,containerName);
System.out.println("Launching container "+pContainer);
ContainerController containerRef = rt.createAgentContainer(pContainer);
//create container2
containerName="Mycontainer2";
pContainer = new ProfileImpl(PLATFORM_IP, PLATFORM_PORT, PLATFORM_ID);
pContainer.setParameter(Profile.CONTAINER_NAME,containerName);
System.out.println("Launching container "+pContainer);
containerRef = rt.createAgentContainer(pContainer);
For a running example with 3 containers, see : https://gitlab.com/startjade/startJade

Dart web audio noteOn internal error

I'm trying to get dart to play an audio, but everytime I try to play the Audio I get the following error:
Internal error: 'dart:_blink': error: line 248: native function 'AudioBufferSourceNode_noteOn_Callback_RESOLVER_STRING_1_double' (2 arguments) cannot be found
Native_AudioBufferSourceNode_noteOn_Callback(mthis, when) native "AudioBufferSourceNode_noteOn_Callback_RESOLVER_STRING_1_double";
This is the my Audio class:
class Audio {
static List<Audio> _loadQueue = new List<Audio>();
String _url;
bool loaded = false;
AudioBufferSourceNode _source;
Audio(this._url) {
if (audioContext == null) {
_loadQueue.add(this);
}
else {
load();
}
}
void load() {
print("Loading sound: " + _url);
HttpRequest req = new HttpRequest();
req.open("GET", _url);
req.responseType = "arraybuffer";
req.onLoad.listen((e) {
_source = audioContext.createBufferSource();
print("Found sound: " + _url + ". Decoding...");
audioContext.decodeAudioData(req.response).then((buffer) {
_source.buffer = buffer;
_source.connectNode(gainNode);
_source.connectNode(audioContext.destination);
loaded = true;
});
});
req.send();
}
void play() {
if (!loaded) { return; }
_source.noteOn(0);
}
void stop() {
if (!loaded) return;
_source.noteOff(0);
}
static void loadAll() {
_loadQueue.forEach((e) {e.load();});
}
}
The audio context and gain node is created in another class like this:
audioContext = new AudioContext();
gainNode = audioContext.createGain();
gainNode.connectNode(audioContext.destination);
Audio.loadAll();
I don't know what the problem is, especially since it says it's internal, and that it's missing arguments, but the noteOn function only takes one argument.
I was facing the same issue using dart 1.6. It seems noteOn has been replaced by start in the latest spec/implementation.
The AudioBufferSourceNode Interface (http://webaudio.github.io/web-audio-api/#the-audiobuffersourcenode-interface)
Porting notes (https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Porting_webkitAudioContext_code_to_standards_based_AudioContext#Changes_to_methods_used_to_start.2Fstop_AudioBufferSourceNode_and_OscillatorNode)

J2ME XML Parsing

I have another question about a "JDWP Error: 21" logged: Unexpected JDWP Error 21
I am trying to parse some XML I gather from a servlet into a J2ME MIDlet with the code below. So far unsuccessfully, I think due to the JDWP error on my HttpConnection how ever the InputStream is filled with XML and once parsed everything inside the Document is null.
Has anyone got and ideas about the JDWP error, and also does that code look like it should work?
In MIDlet I am using JSR-172 API javax.xml.parsers.*.
if(d==form1 && c==okCommand)
{
// Display Webpage
webPage = new TextBox(txtField.getString(),
"",
100000,
TextField.ANY
);
Display.getDisplay(this).setCurrent(webPage);
try
{
HttpConnection conn = (HttpConnection)Connector.open("http://localhost:8080/Blogging_Home/Interface?Page=Bloggers&Action=VIEW&Type=XML");
conn.setRequestMethod(HttpConnection.GET);
int rc = conn.getResponseCode();
getConnectionInformation(conn, webPage);
webPage.setString(webPage.getString() + "Starting....");
String methodString = getStringFromURL("");
if (rc == HttpConnection.HTTP_OK)
{
InputStream is = null;
is = createInputStream(methodString);
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
Document document;
try
{
builder = factory.newDocumentBuilder();
document = builder.parse(is);
} catch (Exception e) {
e.printStackTrace();
}
}
else
{
webPage.setString(webPage.getString() + "ERROR:" + rc);
}
}
catch(Exception ex)
{
// Handle here
webPage.setString("Error" + ex.toString());
}

Resources