/* * This file is modified by Ivan Maidanski <ivmai@ivmaisoft.com> * Project name: JCGO-SUNAWT (http://www.ivmaisoft.com/jcgo/) */ /* * @(#)MixerThread.java 1.24 03/01/23 * * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package com.sun.media.sound; import java.util.Vector; import java.lang.reflect.Method; import java.lang.reflect.Constructor; /** * Thread to manage the inner loop of the audio engine. * * @version 1.24 03/01/23 * @author David Rivas, Chris Schardt, Kara Kytle */ class MixerThread extends Thread { // STATIC VARIABLES /** * Vector of all created instances of this class. */ private static Vector threadObjects = new Vector(); private static ThreadGroup topmostThreadGroup = null; private static final String threadName = "Headspace mixer frame proc thread"; // Variables needed for Security private static JSSecurity jsSecurity = null; private static boolean securityPrivilege = false; /* private Method m[] = new Method[1]; private Class cl[] = new Class[1]; private Object args[][] = new Object[1][0]; */ // INSTANCE VARIABLES /** * True after runNative() returns. * False if the thread is running in the native code. * When true, causes this thread to repeatedly call wait(), just after runNative(). */ private boolean paused; private long frameProc; // Get our security class in the static{} block static { /* Method m[] = new Method[1]; Class cl[] = new Class[1]; Object args[][] = new Object[1][0]; securityPrivilege = true; if(Printer.debug)Printer.debug("MixerThread.static: securityPrivilege = " + securityPrivilege); try { jsSecurity = JSSecurityManager.getJSSecurity(); if( (jsSecurity != null) && !(jsSecurity instanceof DisabledSecurity) ) { jsSecurity.requestPermission(m, cl, args, JSSecurity.THREAD_GROUP); m[0].invoke(cl[0],args[0]); } // $$jb: with no exception, we can assume we're running locally // as an application, so securityPrivilege remains true // even if jsSecurity is null. } catch (Exception e) { if(Printer.debug)Printer.debug("Exception caught: " + e); if(Printer.debug)Printer.debug("Setting securityPrivilege to false"); securityPrivilege = false; } if (securityPrivilege) { if(Printer.debug)Printer.debug("MixerThread.java: getting the real topmost thread group"); if( (jsSecurity!=null) && (jsSecurity instanceof DisabledSecurity) ) { // do nothing } else if( (jsSecurity!=null) && (jsSecurity.getName().startsWith("JDK12") )) { try { // invoke the privileged action using 1.2 security Constructor cons = JDK12TopmostThreadGroupAction.cons; topmostThreadGroup = (ThreadGroup) JDK12.doPrivM.invoke( JDK12.ac, new Object[] { cons.newInstance( new Object[0] ) }); if(Printer.debug)Printer.debug("Got topmost thread group with 1.2 style security"); } catch (Exception e) { if(Printer.debug)Printer.debug("Exception getting topmost thread group with 1.2 style security"); // try without using 1.2 style topmostThreadGroup = getTopmostThreadGroup(); } } else */ { // not JDK 1.2 style, assume we already have permission topmostThreadGroup = getTopmostThreadGroup(); } /* } else { if(Printer.debug)Printer.debug("MixerThread.java: no securityPrivilege, settling for current threadgroup"); topmostThreadGroup = Thread.currentThread().getThreadGroup(); } */ } /** * Private constructor, invoked by our getNewThreadObject method */ // $$jb:06.24.99: taking the frameProc argument out of this constructor // to simplify the 1.2 security privileged block in getNewThreadObject. // private MixerThread() { protected MixerThread() { // we use the top parent thread group. super(topmostThreadGroup, ""); if(Printer.trace)Printer.trace(">> MixerThread() CONSTRUCTOR"); //this.frameProc = frameProc; /* if( (jsSecurity!=null) && (jsSecurity instanceof DisabledSecurity)) { // do nothing } else if( (jsSecurity!=null) && (jsSecurity.getName().startsWith("JDK12") )) { try { if(Printer.debug)Printer.debug("Configuring thread with 1.2 style security"); // run privileged code with 1.2-style security // invoke the privileged action using 1.2 security Constructor cons = JDK12ConfigureThreadAction.cons; JDK12.doPrivM.invoke( JDK12.ac, new Object[] { cons.newInstance( new Object[] { this, threadName }) }); if(Printer.debug)Printer.debug("Configured thread with 1.2 style security"); } catch (Exception e) { if(Printer.debug)Printer.debug("Exception configuring thread with 1.2 style security"); // try without using 1.2 style configureThread(); } } else */ { // not JDK 1.2 style, assume we already have permission configureThread(); } paused = false; if(Printer.trace)Printer.trace(">> MixerThread() CONSTRUCTOR completed"); } /* * private setter - $$jb:06.24.99: was an argument to private constructor, * but I split it to simplify the 1.2 security privileged block in * getNewThreadObject */ private void setFrameProc( long frameProc ) { this.frameProc = frameProc; } private static MixerThread getExistingThreadObject(long frameProc) { if(Printer.trace)Printer.trace(">> MixerThread: getExistingThreadObject(" + frameProc + ")"); MixerThread currentThreadObject; synchronized(threadObjects) { for (int i = 0; i < threadObjects.size(); i++) { currentThreadObject = (MixerThread)threadObjects.elementAt(i); if (currentThreadObject.frameProc == frameProc) { if(Printer.trace)Printer.trace("<< MixerThread: getExistingThreadObject() returning existing object: " + currentThreadObject); return currentThreadObject; } } } return null; } private static MixerThread getNewThreadObject(long frameProc) { /* Method m[] = new Method[1]; Class cl[] = new Class[1]; Object args[][] = new Object[1][0]; */ MixerThread newThreadObject = null; if(Printer.trace)Printer.trace(">> MixerThread: getNewThreadObject(" + frameProc + ")"); // $$jb: 05.03.99: // get THREAD and THREAD_GROUP permissions here ... they // will be needed in the private constructor if(Printer.debug)Printer.debug("MixerThread.getNewThreadObject: asking for permissions"); /* if( securityPrivilege && (jsSecurity != null) ) { if( jsSecurity.getName().startsWith("JDK12") ) { try { // invoke the privileged action using 1.2 security Constructor cons = JDK12NewMixerThreadAction.cons; newThreadObject = (MixerThread) JDK12.doPrivM.invoke( JDK12.ac, new Object[] { cons.newInstance( new Object[0] ) }); if(Printer.debug)Printer.debug("Got mixer thread object with 1.2 style security"); } catch (Exception e) { if(Printer.debug)Printer.debug("Exception getting mixer thread object with 1.2 style security"); // try without using 1.2 style newThreadObject = new MixerThread(); newThreadObject.setFrameProc( frameProc ); } newThreadObject.setFrameProc( frameProc ); } else { try { jsSecurity.requestPermission(m, cl, args, JSSecurity.THREAD); m[0].invoke(cl[0], args[0]); jsSecurity.requestPermission(m, cl, args, JSSecurity.THREAD_GROUP); m[0].invoke(cl[0], args[0]); if(Printer.debug)Printer.debug("MixerThread.getNewThreadObject: got THREAD, THREAD_GROUP permissions"); } catch (Exception e) { if(Printer.debug)Printer.debug("MixerThread.getNewThreadObject: could not get THREAD, THREAD_GROUP permissions"); } newThreadObject = new MixerThread(); newThreadObject.setFrameProc( frameProc ); } } else */ { if(Printer.debug)Printer.debug("MixerThread.getNewThreadObject: no securityPrivilege or jsSecurity=null, not using security"); newThreadObject = new MixerThread(); newThreadObject.setFrameProc( frameProc ); } threadObjects.addElement(newThreadObject); return newThreadObject; } private void configureThread() { if(Printer.trace)Printer.trace(">> MixerThread: configureThread()"); setDaemon(true); setPriority(Thread.MAX_PRIORITY); setName(threadName); if(Printer.trace)Printer.trace("<< MixerThread: configureThread() completed"); } private static ThreadGroup getTopmostThreadGroup() { if(Printer.trace)Printer.trace(">> MixerThread: getTopmostThreadGroup()"); ThreadGroup g = currentThread().getThreadGroup(); while ((g.getParent() != null) && (g.getParent().getParent() != null)) { g = g.getParent(); } if(Printer.trace)Printer.trace("<< MixerThread: getTopmostThreadGroup() completed"); return g; } public void run() { if(Printer.trace)Printer.trace(">> MixerThread: run()"); while (true) { if(Printer.debug)Printer.debug("MixerThread: run(): calling runNative()"); runNative(frameProc); if(Printer.debug)Printer.debug("MixerThread: run(): runNative() returned"); synchronized(this) { paused = true; // repeatedly call wait() until a call to unpause() while (paused) { try { if(Printer.debug)Printer.debug("MixerThread: run(): calling wait()"); wait(); // paused gets cleared here if(Printer.debug)Printer.debug("MixerThread: run(): returned from wait()"); } catch(InterruptedException e) { if(Printer.debug)Printer.debug("MixerThread: run(): wait() interrupted"); } } if(Printer.debug)Printer.debug("MixerThread: run(): exited while(paused)"); } if(Printer.debug)Printer.debug("MixerThread: run(): exited synchronized block"); } } // Causes the while loop above to continue by returning from its wait() call private synchronized void unpause() { if(Printer.trace)Printer.trace(">> MixerThread: unpause() called, notifying..."); paused = false; notify(); if(Printer.trace)Printer.trace("<< MixerThread: unpause() completed"); } // Processes frames of audio data // Returns after HAE_ReleaseAudioCard() is called // native private void runNative(); native private void runNative(long frameProc); }