/* * File : AudioBuffer.java * Created : 17-sep-2001 13:47 * 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.Constants; import edu.xtec.jclic.PlayStation; import edu.xtec.jclic.boxes.ActiveBox; import java.awt.Component; import java.awt.Cursor; /** * The abtract class <code>AudioBuffer</code> supplies sound * recording and playing services. Audio data is discarded * when the <code>AudioBuffer</code> object is destroyed. * @author Francesc Busquets (fbusquets@xtec.cat) * @version 13.08.28 * @see JavaSoundAudioBuffer */ public abstract class AudioBuffer { /** * Default maximum length of recordings (in seconds). */ public static final int MAX_RECORD_LENGTH=20; /** * Maximum recording length, in seconds. */ protected int m_seconds; /** * Cursor displayed when recording. */ protected static Cursor recCursor; /** * Currently running <code>AudioBuffer</code> (static object, because only one can be * running). */ protected static AudioBuffer activeAudioBuffer; /** * Owner of the active <code>AudioBuffer</code>. */ protected static Component owner; /** * Original <code>Cursor</code> used by the active <code>AudioBuffer</code>. */ protected static Cursor backOwnerCursor; /** * Main owner (usually a {@link java.awt.Frame}) of the active <code>AudioBuffer</code>. */ protected static Component mainOwner; /** * Original {@link java.awt.Cursor} of the main owner of the * active <code>AudioBuffer</code>. */ protected static Cursor backMainOwnerCursor; /** * Creates new AudioBuffer * @param seconds Maximum amount of seconds allowed for recording * @throws Exception If something goes wrong... */ public AudioBuffer(int seconds) throws Exception{ if(seconds<=0 || seconds>MAX_RECORD_LENGTH) throw new Exception("Error: Audio buffer length can't exceed "+MAX_RECORD_LENGTH+" seconds"); m_seconds=seconds; } /** * Plays the recorded audio data, if any. * @throws Exception If something goes wrong */ public abstract void play() throws Exception; /** * Stops playing or recording, if running. */ public abstract void stop(); /** * Performs cleanup of recorded audio data. */ protected abstract void clear(); /** * Performs explicit cleanup of recorded audio data before * destroying the object. * @throws Throwable Throwed by <CODE>Object#finalize</CODE> */ @Override protected void finalize() throws Throwable{ clear(); super.finalize(); } /** * Checks if the <CODE>AudioBuffer</CODE> is currently recording * or playing sound. * @return <CODE>true</CODE> if recording or playing, <CODE>false</CODE> otherwise. */ public static boolean busy(){ return activeAudioBuffer!=null; } /** * Only one <CODE>AudioBuffer</CODE> can be "active", because the * sound recording hardware cannot be shared between processes. * This method returns the currently active <CODE>AudioBuffer</CODE>, if any. * @return The currently active <CODE>AudioBuffer</CODE>, or <CODE>null</CODE> * if none is active. */ protected static AudioBuffer getActiveAudioBuffer(){ return activeAudioBuffer; } /** * Starts sound recording with visual indications: the mouse cursor switchs a * microphone. * @param ps A valid {@link PlayStation}, used to retrieve the recording cursor image and to * determine the main component associated to this <CODE>AudioBuffer</CODE>. * @param bx The {@link ActiveBox} associated to this recording. If <CODE>null</CODE>, the * default {@link Component} for the provided {@link PlayStation} will be used. * @throws Exception If someting goes wrong */ public void record(PlayStation ps, ActiveBox bx) throws Exception{ forceStop(); recCursor=ps.getCustomCursor(Constants.REC_CURSOR); owner=(bx==null ? null : bx.getContainerResolve()); mainOwner=javax.swing.JOptionPane.getFrameForComponent(ps.getComponent()); showRecordingCursor(); record(); } /** * Starts the recording of sound, without any visual indication. Subclasses of * <CODE>AudioBuffer</CODE> must implement this method. * @throws Exception If something goes wrong. */ protected abstract void record() throws Exception; /** * The usual way to stop the recording or playnig processes is to place a flag in * their thread and wait to next cycle. This method allows to force an abrupt end * of this threads. * @throws Exception If something goes wrong */ protected static void forceStop() throws Exception{ if(busy()){ getActiveAudioBuffer().stop(); Thread.yield(); if(busy()) throw new Exception("Unable to stop recorder!"); } } /** * Displays the recording cursor. Prior to call this method, the associated * Component must be specified. */ protected static void showRecordingCursor(){ if(recCursor!=null){ if(owner!=null){ backOwnerCursor=owner.getCursor(); if(backOwnerCursor==Cursor.getDefaultCursor()) backOwnerCursor=null; owner.setCursor(recCursor); } if(mainOwner!=null){ backMainOwnerCursor=mainOwner.getCursor(); if(backMainOwnerCursor==Cursor.getDefaultCursor()) backMainOwnerCursor=null; mainOwner.setCursor(recCursor); } } } /** * Resets the mouse cursor to its original state. */ protected static void hideRecordingCursor(){ if(owner!=null){ owner.setCursor(backOwnerCursor); owner=null; } if(mainOwner!=null){ mainOwner.setCursor(backMainOwnerCursor); mainOwner=null; } } }