/*
* File : ActiveMediaPlayer.java
* Created : 27-may-2002 18:43
* By : fbusquets
*
* JClic - Authoring and playing system for educational activities
*
* Copyright (C) 2000 - 2005 Francesc Busquets & Departament
* d'Educacio de la Generalitat de Catalunya
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details (see the LICENSE file).
*/
package edu.xtec.jclic.media;
import edu.xtec.jclic.*;
import edu.xtec.jclic.bags.MediaBag;
import edu.xtec.jclic.boxes.ActiveBox;
import edu.xtec.util.GlobalMouseAdapter;
import edu.xtec.util.Options;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.Rectangle;
/**
*
* @author Francesc Busquets (fbusquets@xtec.cat)
* @version 13.08.28
*/
public abstract class ActiveMediaPlayer {
public static final int AUDIO_BUFFERS=10;
protected static final AudioBuffer[] audioBuffer=new AudioBuffer[AUDIO_BUFFERS];
MediaContent mc;
PlayStation ps;
ActiveBox bx;
Component visualComponent;
GlobalMouseAdapter mouseAdapter;
boolean useAudioBuffer;
public static ActiveMediaPlayer createActiveMediaPlayer(MediaContent mc, MediaBag mb, PlayStation ps){
ActiveMediaPlayer result=null;
String playerClassName=null;
String ms=ps.getOptions().getString(Constants.MEDIA_SYSTEM);
switch(mc.mediaType){
case MediaContent.RECORD_AUDIO:
case MediaContent.PLAY_RECORDED_AUDIO:
if(ps.getOptions().getBoolean(Options.MAC)){
if(Constants.QT61.equals(ms)){
playerClassName="edu.xtec.jclic.media.QT61ActiveMediaPlayer";
break;
}
// 27-Nov-2007: QuickTime 6.0 is no longer supported in JClic
//else if(Constants.QT.equals(ms)){
// playerClassName="edu.xtec.jclic.media.QTActiveMediaPlayer";
// break;
//}
}
case MediaContent.PLAY_AUDIO:
case MediaContent.PLAY_MIDI:
playerClassName="edu.xtec.jclic.media.JavaSoundActiveMediaPlayer";
break;
default:
if(Constants.QT61.equals(ms))
playerClassName="edu.xtec.jclic.media.QT61ActiveMediaPlayer";
//else if(Constants.QT.equals(ms))
// playerClassName="edu.xtec.jclic.media.QTActiveMediaPlayer";
else if(Constants.JMF.equals(ms))
playerClassName="edu.xtec.jclic.media.JMFActiveMediaPlayer";
else
CheckMediaSystem.warn(ps.getOptions());
break;
}
if(playerClassName!=null){
try{
Class<?> c=Class.forName(playerClassName);
java.lang.reflect.Constructor<?> cons=c.getConstructor(new Class<?>[]{edu.xtec.jclic.media.MediaContent.class, edu.xtec.jclic.bags.MediaBag.class, edu.xtec.jclic.PlayStation.class});
result=(ActiveMediaPlayer)cons.newInstance(new Object[]{mc, mb, ps});
} catch(Exception ex){
System.err.println("Error building media player:\n"+ex);
}
}
return result;
}
/** Creates new MediaContentPlayer */
protected ActiveMediaPlayer(MediaContent mc, MediaBag mb, PlayStation ps) {
this.mc=mc;
this.ps=ps;
bx=null;
visualComponent=null;
mouseAdapter=null;
useAudioBuffer=false;
try{
switch(mc.mediaType){
case MediaContent.RECORD_AUDIO:
clearAudioBuffer(mc.recBuffer);
audioBuffer[mc.recBuffer]=createAudioBuffer(mc.length);
case MediaContent.PLAY_RECORDED_AUDIO:
useAudioBuffer=true;
break;
default:
break;
}
} catch(Exception ex){
System.err.println("Error:\n"+ex);
}
}
public abstract AudioBuffer createAudioBuffer(int seconds) throws Exception;
public abstract void realize();
public void play(final edu.xtec.jclic.boxes.ActiveBox setBx){
javax.swing.SwingUtilities.invokeLater(new Runnable(){
public void run(){
stopAllAudioBuffers();
playNow(setBx);
}
});
}
protected void playNow(edu.xtec.jclic.boxes.ActiveBox setBx){
try{
switch(mc.mediaType){
case MediaContent.RECORD_AUDIO:
if(audioBuffer[mc.recBuffer]!=null){
audioBuffer[mc.recBuffer].record(ps, setBx);
}
break;
case MediaContent.PLAY_RECORDED_AUDIO:
if(audioBuffer[mc.recBuffer]!=null)
audioBuffer[mc.recBuffer].play();
break;
default:
break;
}
} catch(Exception e){
System.err.println("Error playing media \""+mc.mediaFileName+"\":\n"+e);
}
}
public void stop(){
if(useAudioBuffer)
stopAudioBuffer(mc.recBuffer);
}
@Override
protected void finalize() throws Throwable{
clear();
super.finalize();
}
public void clear(){
stop();
if(useAudioBuffer)
clearAudioBuffer(mc.recBuffer);
}
protected abstract void setTimeRanges();
public static void clearAudioBuffer(int buffer){
if(buffer>=0 && buffer<AUDIO_BUFFERS && audioBuffer[buffer]!=null){
audioBuffer[buffer].clear();
audioBuffer[buffer]=null;
}
}
public static void clearAllAudioBuffers(){
for(int i=0; i<AUDIO_BUFFERS; i++)
clearAudioBuffer(i);
}
public static int countActiveBuffers(){
int c=0;
for(AudioBuffer ab : audioBuffer)
if(ab!=null)
c++;
return c;
}
public static void stopAllAudioBuffers(){
for(AudioBuffer ab : audioBuffer)
if(ab!=null)
ab.stop();
}
public static void stopAudioBuffer(int buffer){
if(buffer>=0 && buffer<AUDIO_BUFFERS && audioBuffer[buffer]!=null)
audioBuffer[buffer].stop();
}
public void checkVisualComponentBounds(ActiveBox bxi){
if(visualComponent==null)
return;
Rectangle enclosingRect=new Rectangle();
if(!mc.free)
enclosingRect.setBounds(bxi.getBounds());
else
enclosingRect.setBounds(ps.getComponent().getBounds());
Point offset=new Point();
Dimension dim=new Dimension(visualComponent.getPreferredSize());
if(mc.absLocation!=null){
offset.setLocation(mc.absLocation);
if(offset.x+dim.width>enclosingRect.width)
offset.x=enclosingRect.width-dim.width;
if(offset.y+dim.height>enclosingRect.height)
offset.y=enclosingRect.height-dim.height;
}
if(mc.stretch){
int extraW=enclosingRect.width-offset.x-dim.width;
if(extraW<0){
dim.width=enclosingRect.width-offset.x;
extraW=0;
}
int extraH=enclosingRect.height-offset.y-dim.height;
if(extraH<0){
dim.height=enclosingRect.height-offset.y;
extraH=0;
}
if(mc.absLocation==null){
offset.x+=extraW/2;
offset.y+=extraH/2;
}
}
Rectangle vRect=new Rectangle(enclosingRect.x+offset.x, enclosingRect.y+offset.y, dim.width, dim.height);
visualComponent.setSize(dim);
visualComponent.setLocation(vRect.getLocation());
visualComponent.setBounds(vRect);
}
public void setVisualComponentVisible(boolean state){
if(visualComponent!=null)
visualComponent.setVisible(state);
}
protected abstract java.awt.Component getVisualComponent();
public void attachVisualComponent(){
if(mc.mediaType!=MediaContent.PLAY_VIDEO || bx==null)
return;
visualComponent=getVisualComponent();
if(visualComponent==null)
return;
visualComponent.setVisible(false);
Container cnt=bx.getContainerResolve();
if(mc.free)
cnt=ps.getComponent();
if(cnt!=visualComponent.getParent()){
cnt.add(visualComponent);
}
if(mouseAdapter==null && mc.catchMouseEvents==false){
mouseAdapter=new GlobalMouseAdapter(cnt);
mouseAdapter.attachTo(visualComponent, true);
}
checkVisualComponentBounds(bx);
//bx.addActiveBoxListener(this);
visualComponent.setVisible(true);
}
protected void destroyVisualComponent(){
if(mouseAdapter!=null){
mouseAdapter.detach(visualComponent);
mouseAdapter=null;
}
if(visualComponent!=null){
visualComponent.setVisible(false);
stop();
visualComponent=null;
}
}
public void linkTo(ActiveBox setBx){
if(bx!=null && bx!=setBx){
bx.setHostedMediaPlayer(null);
destroyVisualComponent();
}
bx=setBx;
if(bx!=null)
bx.setHostedMediaPlayer(this);
else{
destroyVisualComponent();
}
}
public MediaContent getMediaContent() {
return mc;
}
}