controlling VLC via rc from java

Microsoft Windows specific usage questions
Forum rules
Please post only Windows specific questions in this forum category. If you don't know where to post, please read the different forums' rules. Thanks.
tdelbruck
New Cone
New Cone
Posts: 2
Joined: 15 Dec 2010 15:27

controlling VLC via rc from java

Postby tdelbruck » 15 Dec 2010 17:32

We're developing a demo here and wanted to use VLC to show the results of a gesture recognition system. We wanted to be able to control VLC by pausing, rewinding, changing volume, etc. from a separate java program. I couldn't find any directly usable classes so I wrote one that might be useful for others. See below for two classes, VLCControl and VLCControlApp. VLCControl uses the apache commons net library (v2.2) and VLCControlApp uses netbeans layout libraries.

To use VLCControl, you construct a new instance and call sendCommand(String s), e.g. control.sendCommand("pause"). The connection is automatically opened on the first call. Calling disconnect() sends the "quit" command to clean up the VLC side. The stuff sent back from VLC is logged and can be captured by registering a PropertyChangeListener for CLIENT_MESSAGE to the VLCControl. VLC must be set up so that it opens a telnet rc control on port 4444.

Here is the code for VLCControl. It is closely based on the TelnetClientExample from Apache commons.

Code: Select all

package vlccontrol; import java.beans.PropertyChangeSupport; import java.io.*; import java.io.IOException; import java.nio.CharBuffer; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.net.telnet.*; import org.apache.commons.net.telnet.TelnetClient; /** * Exposes control of VLC media player (videolan.org) from java. VLC must be set up to open a telnet control on localhost:4444. * <p> * For VLC 1.1.5, use the following setup to expose the remote control (rc) interrface for telnet control: * <p> * This setting is in VLC Tools/Preferences/Show settings (All)/Interface/Main interfaces. Select the "Remote Control Interface" and replace "oldrc" with "rc" in the text field. * In VLC Tools/Preferences/Show settings (All)/Interface/Main interfaces/RC/TCP command input, put the string "localhost:4444" in the text field. * * @author Tobi */ public class VLCControl extends TelnetClient implements Runnable, TelnetNotificationHandler { /** VLC should be started with as "vlc --rc-host=localhost:4444" */ public static final int VLC_PORT = 4444; static final Logger log = Logger.getLogger("VLCControl"); private CharBuffer cbuf = CharBuffer.allocate(1024); private static VLCControl staticInstance = null; // used to communicate among instances the active client private PropertyChangeSupport support=new PropertyChangeSupport(this); // listeners get informed by output from VLC strings public VLCControl() { } @Override public void disconnect() throws IOException { sendCommand("quit"); super.disconnect(); } public void connect() throws IOException { staticInstance = this; // used by reader to get input stream try { staticInstance.connect("localhost", VLC_PORT); Thread thread = new Thread(new VLCControl()); // starts the thread to get the text sent back from VLC thread.start(); staticInstance.registerNotifHandler(this); // notifications call back to logger Runtime.getRuntime().addShutdownHook(new Thread() { // shutdown hook here makes sure to disconnect cleanly, as long as we are not terminated @Override public void run() { try { if (isConnected()) { disconnect(); } } catch (IOException ex) { log.warning(ex.toString()); } } }); } catch (IOException e) { log.warning("couldn't connect to VLC - you may need to start VLC with command line \"vlc --rc-host=localhost:4444\""); throw new IOException(e); } } /** Sends a string command. Commands do not need to be terminated with a newline. <p> <pre> +----[ Remote control commands ] | add XYZ . . . . . . . . . . . . . . . . . . . . add XYZ to playlist | enqueue XYZ . . . . . . . . . . . . . . . . . queue XYZ to playlist | playlist . . . . . . . . . . . . . .show items currently in playlist | search [string] . . search for items in playlist (or reset search) | sort key . . . . . . . . . . . . . . . . . . . . . sort the playlist | sd [sd] . . . . . . . . . . . . . show services discovery or toggle | play . . . . . . . . . . . . . . . . . . . . . . . . . . play stream | stop . . . . . . . . . . . . . . . . . . . . . . . . . . stop stream | next . . . . . . . . . . . . . . . . . . . . . . next playlist item | prev . . . . . . . . . . . . . . . . . . . . previous playlist item | goto . . . . . . . . . . . . . . . . . . . . . . goto item at index | repeat [on|off] . . . . . . . . . . . . . . toggle playlist repeat | loop [on|off] . . . . . . . . . . . . . . . . toggle playlist loop | random [on|off] . . . . . . . . . . . . . . toggle playlist random | clear . . . . . . . . . . . . . . . . . . . . . .clear the playlist | status . . . . . . . . . . . . . . . . . . . current playlist status | title [X] . . . . . . . . . . . . . . set/get title in current item | title_n . . . . . . . . . . . . . . . . next title in current item | title_p . . . . . . . . . . . . . . previous title in current item | chapter [X] . . . . . . . . . . . . set/get chapter in current item | chapter_n . . . . . . . . . . . . . . next chapter in current item | chapter_p . . . . . . . . . . . . previous chapter in current item | | seek X . . . . . . . . . . . seek in seconds, for instance `seek 12' | pause . . . . . . . . . . . . . . . . . . . . . . . . toggle pause | fastforward . . . . . . . . . . . . . . . . . . set to maximum rate | rewind . . . . . . . . . . . . . . . . . . . . . set to minimum rate | faster . . . . . . . . . . . . . . . . . . faster playing of stream | slower . . . . . . . . . . . . . . . . . . slower playing of stream | normal . . . . . . . . . . . . . . . . . . normal playing of stream | rate [playback rate] . . . . . . . . . . set playback rate to value | frame . . . . . . . . . . . . . . . . . . . . . play frame by frame | fullscreen, f, F [on|off] . . . . . . . . . . . . toggle fullscreen | info . . . . . . . . . . . . . .information about the current stream | stats . . . . . . . . . . . . . . . . show statistical information | get_time . . . . . . . . . .seconds elapsed since stream's beginning | is_playing . . . . . . . . . . . . 1 if a stream plays, 0 otherwise | get_title . . . . . . . . . . . . . the title of the current stream | get_length . . . . . . . . . . . . the length of the current stream | | volume [X] . . . . . . . . . . . . . . . . . . set/get audio volume | volup [X] . . . . . . . . . . . . . . . .raise audio volume X steps | voldown [X] . . . . . . . . . . . . . . lower audio volume X steps | adev [X] . . . . . . . . . . . . . . . . . . . .set/get audio device | achan [X] . . . . . . . . . . . . . . . . . .set/get audio channels | atrack [X] . . . . . . . . . . . . . . . . . . . set/get audio track | vtrack [X] . . . . . . . . . . . . . . . . . . . set/get video track | vratio [X] . . . . . . . . . . . . . . . .set/get video aspect ratio | vcrop, crop [X] . . . . . . . . . . . . . . . . set/get video crop | vzoom, zoom [X] . . . . . . . . . . . . . . . . set/get video zoom | snapshot . . . . . . . . . . . . . . . . . . . . take video snapshot | strack [X] . . . . . . . . . . . . . . . . . set/get subtitles track | hotkey, key [hotkey name] . . . . . . . . . . simulate hotkey press | menu [on|off|up|down|left|right|select] . . . . . . . . . .use menu | | set [var [value]] . . . . . . . . . . . . . . . . . set/get env var | save_env . . . . . . . . . . . . save env vars (for future clients) | alias [cmd] . . . . . . . . . . . . . . . . set/get command aliases | description . . . . . . . . . . . . . . . . . .describe this module | license . . . . . . . . . . . . . . . . print VLC's license message | help, ? [pattern] . . . . . . . . . . . . . . . . . .a help message | longhelp [pattern] . . . . . . . . . . . . . . a longer help message | logout . . . . . . . . . . . . . . exit (if in a socket connection) | quit . . . . . . . . quit VLC (or logout if in a socket connection) | shutdown . . . . . . . . . . . . . . . . . . . . . . . .shutdown VLC +----[ end of help ] </pre> */ public String sendCommand(String s) throws IOException { if (!isConnected()) { connect(); } if (s == null) { return null; } if (!s.endsWith("\n")) { s = s + "\n"; } getOutputStream().write(s.getBytes()); getOutputStream().flush(); return s; } public static String PAUSE="pause", PLAY="play", STOP="stop", NEXT="next", PREV="prev", VOLUP="volup 1", VOLDOWN = "voldown 1"; public static final String CLIENT_MESSAGE="ClientMessage"; /*** * Reader thread. * Reads lines from the TelnetClient and echoes them * on the logger. * PropertyChangeListeners are called with CLIENT_MESSAGE and String sent from VLC. ***/ @Override public void run() { InputStream instr = staticInstance.getInputStream(); byte[] buff = new byte[1024]; int ret_read = 0; try { do { ret_read = instr.read(buff); if (ret_read > 0) { String s=new String(buff, 0, ret_read); log.info(s); staticInstance.getSupport().firePropertyChange(CLIENT_MESSAGE, null, s); // listener on static instance that actually is connected gets the message } } while (ret_read >= 0); } catch (Exception e) { log.log(Level.WARNING, "Reader ending - Exception while reading socket:{0}", e.getMessage()); } } /*** * Callback method called when TelnetClient receives an option * negotiation command. * <p> * @param negotiation_code - type of negotiation command received * (RECEIVED_DO, RECEIVED_DONT, RECEIVED_WILL, RECEIVED_WONT) * <p> * @param option_code - code of the option negotiated * <p> ***/ @Override public void receivedNegotiation(int negotiation_code, int option_code) { String command = null; if (negotiation_code == TelnetNotificationHandler.RECEIVED_DO) { command = "DO"; } else if (negotiation_code == TelnetNotificationHandler.RECEIVED_DONT) { command = "DONT"; } else if (negotiation_code == TelnetNotificationHandler.RECEIVED_WILL) { command = "WILL"; } else if (negotiation_code == TelnetNotificationHandler.RECEIVED_WONT) { command = "WONT"; } log.log(Level.INFO, "Received {0} for option code {1}", new Object[]{command, option_code}); } /** * @return the support. Listeners can get the stuff sent back from VLC with CLIENT_MESSAGE events. */ public PropertyChangeSupport getSupport() { return support; } }
Here is VLCControlApp to demonstrate how it works:

Code: Select all

package vlccontrol; /* * VLCControlApp.java * * Created on Dec 15, 2010, 10:04:22 AM */ import java.beans.*; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; /** * Demo of controlling VLC from jAER project. * @author Tobi */ public class VLCControlApp extends javax.swing.JFrame implements PropertyChangeListener{ VLCControl vlc=new VLCControl(); public VLCControl getVLCControl(){return vlc;} static Logger log=Logger.getLogger("VLCControlApp"); /** Creates new form VLCControlApp */ public VLCControlApp() { initComponents(); vlc.getSupport().addPropertyChangeListener(this); } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code"> private void initComponents() { commandTF = new javax.swing.JTextField(); jScrollPane1 = new javax.swing.JScrollPane(); responseTA = new javax.swing.JTextArea(); connectButton = new javax.swing.JButton(); disconnectButton = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setTitle("VLCControl"); commandTF.setToolTipText("enter text commands here, e.g. pause, fastforward, rewind"); commandTF.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { commandTFActionPerformed(evt); } }); responseTA.setColumns(20); responseTA.setEditable(false); responseTA.setRows(5); responseTA.setToolTipText("shows the output from vlc here"); jScrollPane1.setViewportView(responseTA); connectButton.setText("Connect"); connectButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { connectButtonActionPerformed(evt); } }); disconnectButton.setText("Disconnect"); disconnectButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { disconnectButtonActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addComponent(connectButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(disconnectButton)) .addComponent(commandTF, javax.swing.GroupLayout.PREFERRED_SIZE, 202, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(connectButton) .addComponent(disconnectButton)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(commandTF, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 223, Short.MAX_VALUE) .addContainerGap()) ); pack(); }// </editor-fold> private void connectButtonActionPerformed(java.awt.event.ActionEvent evt) { if(vlc.isConnected()){ return; } try { vlc.connect(); } catch (IOException ex) { Logger.getLogger(VLCControlApp.class.getName()).log(Level.SEVERE, null, ex); responseTA.append(ex.toString()+"\n"); } } private void disconnectButtonActionPerformed(java.awt.event.ActionEvent evt) { try { if(vlc.isConnected()) vlc.disconnect(); } catch (IOException ex) { log.warning(ex.toString()); responseTA.append(ex.toString()+"\n"); } } private void commandTFActionPerformed(java.awt.event.ActionEvent evt) { try { vlc.sendCommand(commandTF.getText()); } catch (IOException ex) { log.warning(ex.toString()); responseTA.append(ex.toString()+"\n"); } } /** * @param args the command line arguments */ public static void main(String args[]) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new VLCControlApp().setVisible(true); } }); } // Variables declaration - do not modify private javax.swing.JTextField commandTF; private javax.swing.JButton connectButton; private javax.swing.JButton disconnectButton; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JTextArea responseTA; // End of variables declaration @Override public void propertyChange(PropertyChangeEvent evt) { if(evt.getPropertyName()==VLCControl.CLIENT_MESSAGE){ if(evt.getNewValue()!=null){ String s=(String)evt.getNewValue(); responseTA.append(s); responseTA.setCaretPosition(responseTA.getText().length()); } } } }

VLC_help
Mega Cone Master
Mega Cone Master
Posts: 25661
Joined: 13 Sep 2006 14:16

Re: controlling VLC via rc from java

Postby VLC_help » 15 Dec 2010 20:29

Could you add these to VLC wiki? http://wiki.videolan.org/Developers_Corner

tdelbruck
New Cone
New Cone
Posts: 2
Joined: 15 Dec 2010 15:27

Re: controlling VLC via rc from java

Postby tdelbruck » 15 Dec 2010 23:39

Sure, sorry for posting here which I realize is not the right place. I also forgot the .form file for the GUI. But I can't see where to post to the wiki since there is no existing developers page for rc or java interfacing. Also, even after i signed up for wiki login I could not store an edit. BTW, the source code is in project jaer here: http://sourceforge.net/apps/trac/jaer/b ... vlccontrol

VLC_help
Mega Cone Master
Mega Cone Master
Posts: 25661
Joined: 13 Sep 2006 14:16

Re: controlling VLC via rc from java

Postby VLC_help » 16 Dec 2010 18:13

You can create new page for it. And if your wiki username is missing some rights, tell the username here and I will try to get you more authority.


Return to “VLC media player for Windows Troubleshooting”

Who is online

Users browsing this forum: Google [Bot] and 14 guests