Package com.entertailion.java.fling

Source Code of com.entertailion.java.fling.FlingFrame$MySliderUI

/*
* Copyright 2013 ENTERTAILION LLC
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* <http://www.apache.org/licenses/LICENSE-2.0>
*
* Unless required by applicable law or agreed to in writing, software distributed under the License is
* distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and limitations under the License.
*/
package com.entertailion.java.fling;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.URL;
import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.TimeZone;

import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.basic.BasicSliderUI;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

import uk.co.caprica.vlcj.player.MediaPlayer;
import uk.co.caprica.vlcj.player.MediaPlayerEventAdapter;
import uk.co.caprica.vlcj.player.MediaPlayerFactory;

/**
* Main window frame for the Fling application
*
* @author leon_nicholls
*
*/
public class FlingFrame extends JFrame implements ActionListener, BroadcastDiscoveryHandler, ChangeListener, WindowListener {
  private static final String LOG_TAG = "FlingFrame";

  // https://www.gstatic.com/cv/receiver.html?${POST_DATA}
  public static final String CHROMECAST = "ChromeCast";
  // TODO Add your own app id here
  private static final String APP_ID = "YOUR_APP_ID_HERE";

  private static final String HEADER_APPLICATION_URL = "Application-URL";
  private static final String CHROME_CAST_MODEL_NAME = "Eureka Dongle";
  private static final String TRANSCODING_EXTENSIONS = "wmv,avi,mkv,mpg,mpeg,flv,3gp,ogm";
  private static final String TRANSCODING_PARAMETERS = "vcodec=VP80,vb=1000,vfilter=canvas{width=640,height=360},acodec=vorb,ab=128,channels=2,samplerate=44100,threads=2";
  private static final String PROPERTY_TRANSCODING_EXTENSIONS = "transcoding.extensions";
  private static final String PROPERTY_TRANSCODING_PARAMETERS = "transcoding.parameters";
  private static final String PROPERTY_MANUAL_SERVERS = "manual.servers";
  private int port = EmbeddedServer.HTTP_PORT;
  private List<DialServer> servers = new ArrayList<DialServer>();
  private List<DialServer> manualServers = new ArrayList<DialServer>();
  private JComboBox deviceList;
  private JDialog progressDialog;
  private JButton refreshButton, playButton, pauseButton, stopButton, settingsButton;
  private JLabel label;
  private JSlider scrubber;
  private JSlider volume;
  private ResourceBundle resourceBundle;
  private EmbeddedServer embeddedServer;

  private BroadcastDiscoveryClient broadcastClient;
  private Thread broadcastClientThread;
  private TrackedDialServers trackedServers = new TrackedDialServers();
  private RampClient rampClient;

  private MediaPlayerFactory mediaPlayerFactory;
  private MediaPlayer mediaPlayer;

  private String transcodingParameterValues = TRANSCODING_PARAMETERS;
  private String transcodingExtensionValues = TRANSCODING_EXTENSIONS;

  private DialServer selectedDialServer;

  private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");

  private int duration;
  private boolean playbackValueIsAdjusting;
  private boolean isTranscoding;
  private String appId;

  public FlingFrame(String appId) {
    super();
    this.appId = appId;
    rampClient = new RampClient(this);

    addWindowListener(this);

    simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));

    Locale locale = Locale.getDefault();
    resourceBundle = ResourceBundle.getBundle("com/entertailion/java/fling/resources/resources", locale);
    setTitle(MessageFormat.format(resourceBundle.getString("fling.title"), Fling.VERSION));

    JPanel listPane = new JPanel();
    // show list of ChromeCast devices detected on the local network
    listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE_AXIS));
    JPanel devicePane = new JPanel();
    devicePane.setLayout(new BoxLayout(devicePane, BoxLayout.LINE_AXIS));
    deviceList = new JComboBox();
    deviceList.addActionListener(this);
    devicePane.add(deviceList);
    URL url = ClassLoader.getSystemResource("com/entertailion/java/fling/resources/refresh.png");
    ImageIcon icon = new ImageIcon(url, resourceBundle.getString("button.refresh"));
    refreshButton = new JButton(icon);
    refreshButton.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        // refresh the list of devices
        if (deviceList.getItemCount() > 0) {
          deviceList.setSelectedIndex(0);
        }
        discoverDevices();
      }
    });
    refreshButton.setToolTipText(resourceBundle.getString("button.refresh"));
    devicePane.add(refreshButton);
    url = ClassLoader.getSystemResource("com/entertailion/java/fling/resources/settings.png");
    icon = new ImageIcon(url, resourceBundle.getString("settings.title"));
    settingsButton = new JButton(icon);
    settingsButton.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        JTextField transcodingExtensions = new JTextField(50);
        transcodingExtensions.setText(transcodingExtensionValues);
        JTextField transcodingParameters = new JTextField(50);
        transcodingParameters.setText(transcodingParameterValues);

        JPanel myPanel = new JPanel(new BorderLayout());
        JPanel labelPanel = new JPanel(new GridLayout(3, 1));
        JPanel fieldPanel = new JPanel(new GridLayout(3, 1));
        myPanel.add(labelPanel, BorderLayout.WEST);
        myPanel.add(fieldPanel, BorderLayout.CENTER);
        labelPanel.add(new JLabel(resourceBundle.getString("transcoding.extensions"), JLabel.RIGHT));
        fieldPanel.add(transcodingExtensions);
        labelPanel.add(new JLabel(resourceBundle.getString("transcoding.parameters"), JLabel.RIGHT));
        fieldPanel.add(transcodingParameters);
        labelPanel.add(new JLabel(resourceBundle.getString("device.manual"), JLabel.RIGHT));
        JPanel devicePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        final JComboBox manualDeviceList = new JComboBox();
        if (manualServers.size() == 0) {
          manualDeviceList.setVisible(false);
        } else {
          for (DialServer dialServer : manualServers) {
            manualDeviceList.addItem(dialServer);
          }
        }
        devicePanel.add(manualDeviceList);
        JButton addButton = new JButton(resourceBundle.getString("device.manual.add"));
        addButton.setToolTipText(resourceBundle.getString("device.manual.add.tooltip"));
        addButton.addActionListener(new ActionListener() {

          public void actionPerformed(ActionEvent e) {
            JTextField name = new JTextField();
            JTextField ipAddress = new JTextField();
            Object[] message = { resourceBundle.getString("device.manual.name") + ":", name,
                resourceBundle.getString("device.manual.ipaddress") + ":", ipAddress };

            int option = JOptionPane.showConfirmDialog(null, message, resourceBundle.getString("device.manual"), JOptionPane.OK_CANCEL_OPTION);
            if (option == JOptionPane.OK_OPTION) {
              try {
                manualServers.add(new DialServer(name.getText(), InetAddress.getByName(ipAddress.getText())));

                Object selected = deviceList.getSelectedItem();
                int selectedIndex = deviceList.getSelectedIndex();
                deviceList.removeAllItems();
                deviceList.addItem(resourceBundle.getString("devices.select"));
                for (DialServer dialServer : servers) {
                  deviceList.addItem(dialServer);
                }
                for (DialServer dialServer : manualServers) {
                  deviceList.addItem(dialServer);
                }
                deviceList.invalidate();
                if (selectedIndex > 0) {
                  deviceList.setSelectedItem(selected);
                } else {
                  if (deviceList.getItemCount() == 2) {
                    // Automatically select single device
                    deviceList.setSelectedIndex(1);
                  }
                }

                manualDeviceList.removeAllItems();
                for (DialServer dialServer : manualServers) {
                  manualDeviceList.addItem(dialServer);
                }
                manualDeviceList.setVisible(true);
                storeProperties();
              } catch (UnknownHostException e1) {
                Log.e(LOG_TAG, "manual IP address", e1);

                JOptionPane.showMessageDialog(FlingFrame.this, resourceBundle.getString("device.manual.invalidip"));
              }
            }
          }
        });
        devicePanel.add(addButton);
        JButton removeButton = new JButton(resourceBundle.getString("device.manual.remove"));
        removeButton.setToolTipText(resourceBundle.getString("device.manual.remove.tooltip"));
        removeButton.addActionListener(new ActionListener() {

          public void actionPerformed(ActionEvent e) {
            Object selected = manualDeviceList.getSelectedItem();
            manualDeviceList.removeItem(selected);
            if (manualDeviceList.getItemCount() == 0) {
              manualDeviceList.setVisible(false);
            }
            deviceList.removeItem(selected);
            deviceList.invalidate();
            manualServers.remove(selected);
            storeProperties();
          }
        });
        devicePanel.add(removeButton);
        fieldPanel.add(devicePanel);
        int result = JOptionPane.showConfirmDialog(FlingFrame.this, myPanel, resourceBundle.getString("settings.title"), JOptionPane.OK_CANCEL_OPTION);
        if (result == JOptionPane.OK_OPTION) {
          transcodingParameterValues = transcodingParameters.getText();
          transcodingExtensionValues = transcodingExtensions.getText();
          storeProperties();
        }
      }
    });
    settingsButton.setToolTipText(resourceBundle.getString("settings.title"));
    devicePane.add(settingsButton);
    listPane.add(devicePane);

    // TODO
    volume = new JSlider(JSlider.VERTICAL, 0, 100, 0);
    volume.setUI(new MySliderUI(volume));
    volume.setMajorTickSpacing(25);
    // volume.setMinorTickSpacing(5);
    volume.setPaintTicks(true);
    volume.setEnabled(true);
    volume.setValue(100);
    volume.setToolTipText(resourceBundle.getString("volume.title"));
    volume.addChangeListener(new ChangeListener() {

      @Override
      public void stateChanged(ChangeEvent e) {
        JSlider source = (JSlider) e.getSource();
        if (!source.getValueIsAdjusting()) {
          int position = (int) source.getValue();
          rampClient.volume(position / 100.0f);
        }
      }

    });
    JPanel centerPanel = new JPanel(new BorderLayout());
    // centerPanel.add(volume, BorderLayout.WEST);

    centerPanel.add(DragHereIcon.makeUI(this), BorderLayout.CENTER);
    listPane.add(centerPanel);

    scrubber = new JSlider(JSlider.HORIZONTAL, 0, 100, 0);
    scrubber.addChangeListener(this);
    scrubber.setMajorTickSpacing(25);
    scrubber.setMinorTickSpacing(5);
    scrubber.setPaintTicks(true);
    scrubber.setEnabled(false);
    listPane.add(scrubber);

    // panel of playback buttons
    JPanel buttonPane = new JPanel();
    buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS));
    label = new JLabel("00:00:00");
    buttonPane.add(label);
    url = ClassLoader.getSystemResource("com/entertailion/java/fling/resources/play.png");
    icon = new ImageIcon(url, resourceBundle.getString("button.play"));
    playButton = new JButton(icon);
    playButton.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        rampClient.play();
      }
    });
    buttonPane.add(playButton);
    url = ClassLoader.getSystemResource("com/entertailion/java/fling/resources/pause.png");
    icon = new ImageIcon(url, resourceBundle.getString("button.pause"));
    pauseButton = new JButton(icon);
    pauseButton.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        rampClient.pause();
      }
    });
    buttonPane.add(pauseButton);
    url = ClassLoader.getSystemResource("com/entertailion/java/fling/resources/stop.png");
    icon = new ImageIcon(url, resourceBundle.getString("button.stop"));
    stopButton = new JButton(icon);
    stopButton.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        rampClient.stop();
        setDuration(0);
        scrubber.setValue(0);
        scrubber.setEnabled(false);
      }
    });
    buttonPane.add(stopButton);
    listPane.add(buttonPane);
    getContentPane().add(listPane);

    createProgressDialog();
    startWebserver();
    discoverDevices();
  }

  // http://stackoverflow.com/questions/6992633/painting-the-slider-icon-of-jslider
  private static class MySliderUI extends BasicSliderUI {

    private Font font = new Font(Font.SERIF, Font.PLAIN, 12);

    public MySliderUI(JSlider slider) {
      super(slider);
    }

    @Override
    public void paintTrack(Graphics g) {
      Graphics2D g2d = (Graphics2D) g;
      Rectangle t = trackRect;
      g.setColor(Color.darkGray);
      g.drawRect(t.x, t.y, t.width, t.height);

      if (g instanceof Graphics2D) {
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setFont(font);
        int w2 = slider.getFontMetrics(font).stringWidth("Volume") / 2;
        g2.drawString("Volume", t.width / 2 - w2, t.height);
      }
    }

    @Override
    public void paintThumb(Graphics g) {
      Graphics2D g2d = (Graphics2D) g;
      g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
      Rectangle t = thumbRect;
      g2d.setColor(Color.black);
      int tw2 = t.width / 2;
      g2d.drawLine(t.x, t.y, t.x + t.width - 1, t.y);
      g2d.drawLine(t.x, t.y, t.x + tw2, t.y + t.height);
      g2d.drawLine(t.x + t.width - 1, t.y, t.x + tw2, t.y + t.height);
    }
  }

  public void stateChanged(ChangeEvent e) {
    JSlider source = (JSlider) e.getSource();
    if (!source.getValueIsAdjusting() && !playbackValueIsAdjusting) {
      int position = (int) source.getValue();
      if (position == 0) {
        rampClient.play(0);
      } else {
        rampClient.play((int) (position / 100.0f * duration));
      }
    }
  }

  /**
   * Start a web server to serve the videos to the media player on the
   * ChromeCast device
   */
  private void startWebserver() {
    new Thread(new Runnable() {

      @Override
      public void run() {
        boolean started = false;
        while (!started) {
          try {
            embeddedServer = new EmbeddedServer(port);
            Log.d(LOG_TAG, "Started web server on port " + port);
            started = true;
          } catch (IOException ioe) {
            ioe.printStackTrace();
            port++;
          } catch (Exception ex) {
            break;
          }
        }
      }

    }).start();
  }

  /**
   * Discover ChromeCast devices on the local network
   *
   */
  private void discoverDevices() {
    Properties properties = loadProperties();

    broadcastClient = new BroadcastDiscoveryClient(this);
    broadcastClientThread = new Thread(broadcastClient);

    deviceList.removeAllItems();
    // Prompt selection option
    deviceList.addItem(resourceBundle.getString("devices.select"));

    // discovering devices can take time, so do it in a thread
    new Thread(new Runnable() {
      public void run() {
        try {
          showProgressDialog(resourceBundle.getString("progress.discoveringDevices"));
          broadcastClientThread.start();

          // wait a while...
          // TODO do this better
          Thread.sleep(BroadcastDiscoveryClient.PROBE_INTERVAL_MS-1);

          broadcastClient.stop();

          hideProgressDialog();

          Log.d(LOG_TAG, "size=" + trackedServers.size());
          for (DialServer dialServer : trackedServers) {
            deviceList.addItem(dialServer);
            servers.add(dialServer);
          }

          // Now add user's manual servers
          for (DialServer dialServer : manualServers) {
            deviceList.addItem(dialServer);
          }
          deviceList.invalidate();

          if (deviceList.getItemCount() == 1) {
            JOptionPane.showMessageDialog(FlingFrame.this, resourceBundle.getString("device.notfound"));
          } else if (deviceList.getItemCount() == 2) {
            // Automatically select single device
            deviceList.setSelectedIndex(1);
          }

        } catch (InterruptedException e) {
          Log.e(LOG_TAG, "discoverDevices", e);
        }
      }
    }).start();
  }

  public void onBroadcastFound(final BroadcastAdvertisement advert) {
    if (advert.getLocation() != null) {
      new Thread(new Runnable() {
        public void run() {
          Log.d(LOG_TAG, "location=" + advert.getLocation());
          HttpResponse response = new HttpRequestHelper().sendHttpGet(advert.getLocation());
          if (response != null) {
            String appsUrl = null;
            Header header = response.getLastHeader(HEADER_APPLICATION_URL);
            if (header != null) {
              appsUrl = header.getValue();
              if (!appsUrl.endsWith("/")) {
                appsUrl = appsUrl + "/";
              }
              Log.d(LOG_TAG, "appsUrl=" + appsUrl);
            }
            try {
              InputStream inputStream = response.getEntity().getContent();
              BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

              InputSource inStream = new org.xml.sax.InputSource();
              inStream.setCharacterStream(reader);
              SAXParserFactory spf = SAXParserFactory.newInstance();
              SAXParser sp = spf.newSAXParser();
              XMLReader xr = sp.getXMLReader();
              BroadcastHandler broadcastHandler = new BroadcastHandler();
              xr.setContentHandler(broadcastHandler);
              xr.parse(inStream);
              Log.d(LOG_TAG, "modelName=" + broadcastHandler.getDialServer().getModelName());
              // Only handle ChromeCast devices; not other DIAL
              // devices like ChromeCast devices
              if (broadcastHandler.getDialServer().getModelName().equals(CHROME_CAST_MODEL_NAME)) {
                Log.d(LOG_TAG, "ChromeCast device found: " + advert.getIpAddress().getHostAddress());
                DialServer dialServer = new DialServer(advert.getLocation(), advert.getIpAddress(), advert.getPort(), appsUrl, broadcastHandler
                    .getDialServer().getFriendlyName(), broadcastHandler.getDialServer().getUuid(), broadcastHandler.getDialServer()
                    .getManufacturer(), broadcastHandler.getDialServer().getModelName());
                trackedServers.add(dialServer);
              }
            } catch (Exception e) {
              Log.e(LOG_TAG, "parse device description", e);
            }
          }
        }
      }).start();
    }
  }

  private InterfaceAddress getPreferredInetAddress(String prefix) {
    InterfaceAddress selectedInterfaceAddress = null;
    try {
      Enumeration<NetworkInterface> list = NetworkInterface.getNetworkInterfaces();

      while (list.hasMoreElements()) {
        NetworkInterface iface = list.nextElement();
        if (iface == null)
          continue;
        Log.d(LOG_TAG, "interface=" + iface.getName());
        Iterator<InterfaceAddress> it = iface.getInterfaceAddresses().iterator();
        while (it.hasNext()) {
          InterfaceAddress interfaceAddress = it.next();
          if (interfaceAddress == null)
            continue;
          InetAddress address = interfaceAddress.getAddress();
          Log.d(LOG_TAG, "address=" + address);
          if (address instanceof Inet4Address) {
            // Only pick an interface that is likely to be on the
            // same subnet as the selected ChromeCast device
            if (address.getHostAddress().toString().startsWith(prefix)) {
              return interfaceAddress;
            }
          }
        }
      }
    } catch (Exception ex) {
    }
    return selectedInterfaceAddress;
  }

  /**
   * Get the network address.
   *
   * @return
   */
  public Inet4Address getNetworAddress() {
    Inet4Address selectedInetAddress = null;
    try {
      InterfaceAddress interfaceAddress = null;
      if (selectedDialServer != null) {
        String address = selectedDialServer.getIpAddress().getHostAddress();
        String prefix = address.substring(0, address.indexOf('.') + 1);
        Log.d(LOG_TAG, "prefix=" + prefix);
        interfaceAddress = getPreferredInetAddress(prefix);
      } else {
        InterfaceAddress oneNineTwoInetAddress = getPreferredInetAddress("192.");
        if (oneNineTwoInetAddress != null) {
          interfaceAddress = oneNineTwoInetAddress;
        } else {
          InterfaceAddress oneSevenTwoInetAddress = getPreferredInetAddress("172.");
          if (oneSevenTwoInetAddress != null) {
            interfaceAddress = oneSevenTwoInetAddress;
          } else {
            interfaceAddress = getPreferredInetAddress("10.");
          }
        }
      }
      if (interfaceAddress != null) {
        InetAddress networkAddress = interfaceAddress.getAddress();
        Log.d(LOG_TAG, "networkAddress=" + networkAddress);
        if (networkAddress != null) {
          return (Inet4Address) networkAddress;
        }
      }
    } catch (Exception ex) {
    }

    return selectedInetAddress;
  }

  /**
   * Create a progress indicator
   */
  private void createProgressDialog() {
    progressDialog = new JDialog(this, resourceBundle.getString("progress.title"), true);
    JProgressBar progressBar = new JProgressBar(0, 100);
    progressBar.setStringPainted(true);
    progressBar.setIndeterminate(true);
    progressDialog.add(BorderLayout.CENTER, progressBar);
    progressDialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
    progressDialog.setSize(300, 75);
    progressDialog.setLocationRelativeTo(this);
  }

  /**
   * Show the progress indicator with a title message
   *
   * @param message
   */
  private void showProgressDialog(final String message) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        progressDialog.setLocationRelativeTo(FlingFrame.this);
        progressDialog.setTitle(message);
        progressDialog.setVisible(true);
      }
    });
  }

  /**
   * Hide the progress indicator
   */
  private void hideProgressDialog() {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        progressDialog.setVisible(false);
      }
    });
  }

  /**
   * Event handler for device dropdown list selection
   *
   * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
   */
  public void actionPerformed(ActionEvent e) {
    JComboBox cb = (JComboBox) e.getSource();
    int pos = cb.getSelectedIndex();
    // when device is selected, attempt to connect
    if (servers != null && pos > 0) {
      selectedDialServer = (DialServer) cb.getSelectedItem();
    }
  }

  /**
   * Send a uri to the ChromeCast device
   *
   * @param keycode
   */
  protected void sendMediaUrl(String file) {
    if (selectedDialServer == null) {
      JOptionPane.showMessageDialog(this, resourceBundle.getString("device.select"));
      return;
    }
    isTranscoding = false;
    Log.d(LOG_TAG, "sendMediaUrl=" + file);
    if (file != null) {
      duration = 0;
      boolean found = false;
      String[] extensions = transcodingExtensionValues.split(",");
      for (String extension : extensions) {
        if (file.endsWith(extension.trim())) {
          found = true;
          break;
        }
      }
      if (!found) {
        try {
          int pos = file.lastIndexOf('.');
          String extension = "";
          if (pos > -1) {
            extension = file.substring(pos);
          }
          Inet4Address address = getNetworAddress();
          if (address != null) {
            final String url = "http://" + address.getHostAddress() + ":" + port + "/video" + extension;
            if (!rampClient.isClosed()) {
              rampClient.stop();
            }
            rampClient.launchApp(appId==null?APP_ID:appId, selectedDialServer);
            // wait for socket to be ready...
            new Thread(new Runnable() {
              public void run() {
                while (!rampClient.isStarted() && !rampClient.isClosed()) {
                  try {
                    // make less than 3 second ping time
                    Thread.sleep(500);
                  } catch (InterruptedException e) {
                  }
                }
                if (!rampClient.isClosed()) {
                  try {
                    Thread.sleep(500);
                  } catch (InterruptedException e) {
                  }
                  rampClient.load(url);
                }
              }
            }).start();
          } else {
            Log.d(LOG_TAG, "could not find a network interface");
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      } else {
        vlcTranscode(file);
      }

      // TODO
      if (!volume.getValueIsAdjusting()) {
        int position = (int) volume.getValue();
        // rampClient.volume(position / 100.0f);
      }
    }
  }

  protected void vlcTranscode(final String file) {
    // Transcoding does not support jumps
    isTranscoding = true;

    // http://caprica.github.io/vlcj/javadoc/2.1.0/index.html
    try {
      // clean up previous session
      if (mediaPlayer != null) {
        mediaPlayer.release();
      }
      if (mediaPlayerFactory != null) {
        mediaPlayerFactory.release();
      }
      mediaPlayerFactory = new MediaPlayerFactory();
      mediaPlayer = mediaPlayerFactory.newHeadlessMediaPlayer();
      // Add a component to be notified of player events
      mediaPlayer.addMediaPlayerEventListener(new MediaPlayerEventAdapter() {
        public void opening(MediaPlayer mediaPlayer) {
          Log.d(LOG_TAG, "VLC Transcoding: Opening");
        }

        public void buffering(MediaPlayer mediaPlayer, float newCache) {
          Log.d(LOG_TAG, "VLC Transcoding: Buffering");
        }

        public void playing(MediaPlayer mediaPlayer) {
          Log.d(LOG_TAG, "VLC Transcoding: Playing");

          setDuration((int) (mediaPlayer.getLength() / 1000.0f));
          Log.d(LOG_TAG, "duration=" + duration);
        }

        public void paused(MediaPlayer mediaPlayer) {
          Log.d(LOG_TAG, "VLC Transcoding: Paused");
        }

        public void stopped(MediaPlayer mediaPlayer) {
          Log.d(LOG_TAG, "VLC Transcoding: Stopped");
        }

        public void finished(MediaPlayer mediaPlayer) {
          Log.d(LOG_TAG, "VLC Transcoding: Finished");
        }

        public void error(MediaPlayer mediaPlayer) {
          Log.d(LOG_TAG, "VLC Transcoding: Error");
        }

        public void videoOutput(MediaPlayer mediaPlayer, int newCount) {
          Log.d(LOG_TAG, "VLC Transcoding: VideoOutput");
        }
      });

      // Find a port for VLC HTTP server
      boolean started = false;
      int vlcPort = port + 1;
      while (!started) {
        try {
          ServerSocket serverSocket = new ServerSocket(vlcPort);
          Log.d(LOG_TAG, "Available port for VLC: " + vlcPort);
          started = true;
          serverSocket.close();
        } catch (IOException ioe) {
          ioe.printStackTrace();
          vlcPort++;
        } catch (Exception ex) {
          break;
        }
      }

      if (!rampClient.isClosed()) {
        rampClient.stop();
      }
      Inet4Address address = getNetworAddress();
      if (address != null) {
        // Play a particular item, with options if necessary
        final String options[] = { ":sout=#transcode{" + transcodingParameterValues + "}:http{mux=webm,dst=:" + vlcPort + "/cast.webm}", ":sout-keep" };
        // http://192.168.0.8:8087/cast.webm
        final String url = "http://" + address.getHostAddress() + ":" + vlcPort + "/cast.webm";
        Log.d(LOG_TAG, "url=" + url);
        if (true || isChromeCast()) {
          rampClient.launchApp(appId==null?APP_ID:appId, selectedDialServer);
          // wait for socket to be ready...
          new Thread(new Runnable() {
            public void run() {
              while (!rampClient.isStarted() && !rampClient.isClosed()) {
                try {
                  Thread.sleep(500);
                } catch (InterruptedException e) {
                }
              }
              if (!rampClient.isClosed()) {
                mediaPlayer.playMedia(file, options);
                rampClient.load(url);
              }
            }
          }).start();
        } else {
          rampClient.load(url);
        }
      } else {
        Log.d(LOG_TAG, "could not find a network interface");
      }
    } catch (Throwable e) {
      Log.e(LOG_TAG, "vlcTranscode: " + file, e);
    }
  }

  // Store user settings
  private Properties loadProperties() {
    Properties prop = new Properties();
    try {
      prop.load(new FileInputStream("config.properties"));
      transcodingParameterValues = prop.getProperty(PROPERTY_TRANSCODING_PARAMETERS);
      transcodingExtensionValues = prop.getProperty(PROPERTY_TRANSCODING_EXTENSIONS);
      String manual = prop.getProperty(PROPERTY_MANUAL_SERVERS);
      if (manual != null) {
        String[] parts = manual.split(":");
        for (int i = 0; i < parts.length / 2; i++) {
          manualServers.add(new DialServer(parts[i * 2], InetAddress.getByName(parts[i * 2 + 1])));
        }
      }
    } catch (Exception ex) {
    }
    if (transcodingParameterValues == null) {
      transcodingParameterValues = TRANSCODING_PARAMETERS;
    }
    if (transcodingExtensionValues == null) {
      transcodingExtensionValues = TRANSCODING_EXTENSIONS;
    }
    return prop;
  }

  // Restore user settings
  private void storeProperties() {
    Properties prop = new Properties();
    try {
      prop.setProperty(PROPERTY_TRANSCODING_PARAMETERS, transcodingParameterValues);
      prop.setProperty(PROPERTY_TRANSCODING_EXTENSIONS, transcodingExtensionValues);
      String manual = "";
      for (DialServer dialServer : manualServers) {
        if (manual.length() > 0) {
          manual = manual + ":";
        }
        manual = manual + dialServer.getFriendlyName() + ":" + dialServer.getIpAddress().getHostAddress();
      }
      prop.setProperty(PROPERTY_MANUAL_SERVERS, manual);
      prop.store(new FileOutputStream("config.properties"), null);
    } catch (Exception ex) {
    }
  }

  public void updateTime(int time) {
    label.setText(simpleDateFormat.format(new Date(time * 1000)));
    if (duration > 0 && !scrubber.getValueIsAdjusting()) {
      playbackValueIsAdjusting = true;
      scrubber.setValue((int) ((time * 1.0f) / duration * 100));
      playbackValueIsAdjusting = false;
    }
  }

  // Current video duration in seconds
  public int getDuration() {
    return duration;
  }

  // Display the current duration in the slider
  public void setDuration(int duration) {
    this.duration = duration;
    if (duration >= 0) {
      Hashtable labelTable = new Hashtable();
      labelTable.put(new Integer(0), new JLabel("0"));
      labelTable.put(new Integer(100), new JLabel(simpleDateFormat.format(new Date(duration * 1000))));
      scrubber.setLabelTable(labelTable);
      scrubber.setPaintLabels(true);
      if (!isTranscoding) {
        scrubber.setEnabled(true);
      } else {
        scrubber.setEnabled(false);
      }
    }
  }

  @Override
  public void windowActivated(WindowEvent arg0) {
    // TODO Auto-generated method stub

  }

  @Override
  public void windowClosed(WindowEvent arg0) {
    // TODO Auto-generated method stub

  }

  @Override
  public void windowClosing(WindowEvent arg0) {
    // TODO Auto-generated method stub
    if (rampClient != null) {
      rampClient.stop();
    }
  }

  @Override
  public void windowDeactivated(WindowEvent arg0) {
    // TODO Auto-generated method stub

  }

  @Override
  public void windowDeiconified(WindowEvent arg0) {
    // TODO Auto-generated method stub

  }

  @Override
  public void windowIconified(WindowEvent arg0) {
    // TODO Auto-generated method stub

  }

  @Override
  public void windowOpened(WindowEvent arg0) {
    // TODO Auto-generated method stub

  }

  public boolean isChromeCast() {
    String id = appId==null?APP_ID:appId;
    return id.equals(FlingFrame.CHROMECAST);
  }

}
TOP

Related Classes of com.entertailion.java.fling.FlingFrame$MySliderUI

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.