/* * Copyright (C) 1996-1997 Intel Corporation * All Rights Reserved * * A royalty-free copyright license to copy, modify and compile this source * code and to distribute it in your own products in source and binary forms * is hereby granted, so long as this copyright notice and this copyright * license appear in all source code copies. No other rights or licenses * are granted. The Intel name or other trademarks may not be used to * endorse or promote products using this header file without Intel's prior * written permission. * * THIS SOURCE CODE IS PROVIDED "AS IS" WITH NO WARRANTIES WHATSOEVER, * INCLUDING ANY WARRANTY OF MERCHANTABILITY, NONINFRINGEMENT, OR FITNESS * FOR ANY PARTICULAR PURPOSE. Intel disclaims all liability, including * liability for infringement of any proprietary rights, relating to use * of this source code. */ package FrameworkTutorial; import java.awt.*; import java.applet.*; import java.util.*; import java.net.*; import java.io.*; import java.media.*; /** * This is an applet that shows simple synchronization between * more than one media player. * * There will be N media players, each playing the same media * file, but starting and stopping at different times. The file * appears to "cascade" down through the N players. The players * are synchronized because: * - they share the same time base * - they all start at an offset from the *same* future time * (see action() method to clarify this) * * In addition to the N synchronized players, there is one * other synchronized player that just plays the audio track, * since the audio device can't currently be deallocated in * advance in a manner similar to setStopTime(). * * The MPlayer class describes a single media player and is * defined below, in this file. */ public class AdvancedPlayer3 extends Applet { /** * How many players to demo? */ private static final int numPlayers = 4; /** * A list of media players. */ private MPlayer playerList[]; /** * One extra player just to play audio. */ private MPlayer audioPlayer; /** * A button to start things off. */ private Button startButton; /** * A panel to hold N media players. */ private Panel mediaPanel; /** * The name of the file to play (comes from MediaFile param). */ private String fileName; /** * The duration of the media file in nanoseconds. */ private long duration; /** * The duration of one player's chunk of the total file. */ private long segmentDuration; public void init() { URL mediaURL = null; // Get a file name to use for all players. if ((fileName = getParameter("MediaFile")) == null) { System.err.println("MediaFile parameter must be specified"); return; } // Get an URL to use for all players. try { mediaURL = new URL(getDocumentBase(), fileName); } catch (MalformedURLException e) { System.err.println("Bad URL for media file: " + e); } // Create the audio player and wait for it to prefetch // before doing anything else. This is a workaround for the // lack of audio mixing in the current version of ActiveMovie. audioPlayer = new MPlayer(mediaURL); while (audioPlayer.isPlayable() == false) { try { Thread.sleep(1000); } catch (Exception e) { System.out.println(e); } } // Create all N players and start each one prefetching. playerList = new MPlayer[numPlayers]; for (int i = 0; i < numPlayers; ++i) { playerList[i] = new MPlayer(mediaURL); } // While the players prefetch, I can do other things. startButton = new Button("Click here to begin"); startButton.disable(); // Make a panel to hold N media players mediaPanel = new Panel(); mediaPanel.setLayout(new GridLayout(numPlayers, 1)); setLayout(new BorderLayout()); add("North", startButton); add("Center", mediaPanel); // Use the already-prefetched audio player to get the media // duration for all the players (since they all play the same file) duration = audioPlayer.player.getDuration(); segmentDuration = duration / numPlayers; // Wait for all players to become realized before their // visual components are available. while (allRealized() == false) { try { Thread.sleep(500); } catch (Exception e) { System.out.println(e); } } // Add each player's visual component to my panel. for (int i = 0; i < numPlayers; ++i) { mediaPanel.add(playerList[i].player.getVisualComponent()); } // Wait for the players to prefetch before doing setTimeBase. while (allPlayable() == false) { try { Thread.sleep(1000); } catch (Exception e) { System.out.println(e); } } // Slave all the players to the same time base for (int i = 0; i < numPlayers; ++i) { try { playerList[i].player.setTimeBase(audioPlayer.player.getTimeBase()); // audioPlayer.player.setTimeBase(playerList[0].player.getTimeBase()); } catch (java.media.IncompatibleTimeBaseException e) { System.err.println(e); } } // Set each player's chunk of the total media. for (int i = 0; i < numPlayers; ++i) { playerList[i].player.setMediaTime(segmentDuration * i); playerList[i].player.setStopTime(segmentDuration * (i + 1)); } } public void start() { startButton.enable(); } public void stop() { System.out.println("In stop"); for (int i = 0; i < numPlayers; ++i) { playerList[i].player.stop(); playerList[i].player.deallocate(); } audioPlayer.player.stop(); audioPlayer.player.deallocate(); } public boolean action(Event e, Object o) { if (e.target == startButton) { startButton.disable(); /* Start all the players at some offset from (now + 1 second), * where one second is arbitrary; long enough to span the * following code N times. */ long futureStartTime = playerList[0].player.getTimeBase().getRefTime(); futureStartTime += 1000000000L; audioPlayer.player.syncStart(futureStartTime); for (int i = 0; i < numPlayers; ++i) { playerList[i].player.syncStart(futureStartTime + (segmentDuration * i)); } return true; } else { return false; } } private boolean allRealized() { for (int i = 0; i < numPlayers; ++i) { if (playerList[i].isRealized() == false) return false; } return true; } private boolean allPlayable() { for (int i = 0; i < numPlayers; ++i) { if (playerList[i].isPlayable() == false) return false; } return true; } } /** * A class to play audio/video with Intel Media for Java. * Note we need a class separate from the applet because each * player needs its own ControllerListener interface. */ class MPlayer implements ControllerListener { /** * Media player */ Player player; /** * Boolean that shows when this player can start playing. */ private boolean playable = false; /** * Boolean that shows when the visual component is available */ private boolean realized = false; private MPlayer() { } MPlayer(URL mediaURL) { try { player = Manager.createPlayer(mediaURL); } catch (IOException e) { System.err.println("IO exception creating player for " + mediaURL); } player.addControllerListener(this); player.prefetch(); } public boolean isRealized() { return realized; } public boolean isPlayable() { return playable; } /** * This controllerUpdate method must be defined in order to implement * a ControllerListener interface. This method will be called whenever * there is a media event. */ public void controllerUpdate(ControllerEvent event) { // Once the player is realized, the visual component is available if (event instanceof RealizeCompleteEvent) { realized = true; } // Once the player has Prefetched, it can be started else if (event instanceof PrefetchCompleteEvent) { playable = true; } } /** * For debugging. Print the Controller state for this player. */ public void printState(int id) { switch(player.getState()) { case Controller.Unrealized: System.out.println("Unrealized"); break; case Controller.Realizing: System.out.println("Realizing"); break; case Controller.Realized: System.out.println("Realized"); break; case Controller.Prefetching: System.out.println("Prefetching"); break; case Controller.Prefetched: System.out.println("Prefetched"); break; case Controller.Started: System.out.println("Started"); break; } } }