/*
* @(#)CloneableSourceStreamAdapter.java 1.8 02/08/21
*
* Copyright (c) 1996-2002 Sun Microsystems, Inc. All rights reserved.
*/
package com.ibm.media.protocol;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.io.*;
import java.util.*;
import java.lang.*;
import javax.media.*;
import javax.media.protocol.*;
import javax.media.format.*;
import com.sun.media.*;
import com.sun.media.util.*;
import com.ms.security.PermissionID;
import com.ms.security.PolicyEngine;
public class CloneableSourceStreamAdapter {
SourceStream master;
SourceStream adapter = null;
Vector slaves = new Vector();
private static JMFSecurity jmfSecurity = null;
private static boolean securityPrivelege=false;
private Method m[] = new Method[1];
private Class cl[] = new Class[1];
private Object args[][] = new Object[1][0];
protected int numTracks = 0;
protected Format [] trackFormats;
static {
try {
jmfSecurity = JMFSecurityManager.getJMFSecurity();
securityPrivelege = true;
} catch (SecurityException e) {
}
}
/**
* Constructor
*/
CloneableSourceStreamAdapter(SourceStream master) {
this.master = master;
// create the matching adapter according to the stream's type
if (master instanceof PullSourceStream)
adapter = new PullSourceStreamAdapter();
if (master instanceof PullBufferStream)
adapter = new PullBufferStreamAdapter();
if (master instanceof PushSourceStream)
adapter = new PushSourceStreamAdapter();
if (master instanceof PushBufferStream)
adapter = new PushBufferStreamAdapter();
}
/**
* Return the stream adapter to be used by the Handler. There is only
* one adapter per stream since there is only one master stream.
*/
SourceStream getAdapter() {
return adapter;
}
/**
* This method should be could only by the <CODE>CloneableDataSource</CODE>.
*
* @return a slave <CODE>SourceStream</CODE> which will either a
* <CODE>PushSourceStream</CODE> or a <CODE>PushBufferStream.
*/
SourceStream createSlave() {
SourceStream slave = null;
if ((master instanceof PullSourceStream) ||
(master instanceof PushSourceStream))
slave = new PushSourceStreamSlave();
if ((master instanceof PullBufferStream) ||
(master instanceof PushBufferStream))
slave = new PushBufferStreamSlave();
slaves.addElement(slave);
return slave;
}
void copyAndRead(Buffer b) throws IOException {
if (master instanceof PullBufferStream)
((PullBufferStream)master).read(b);
if (master instanceof PushBufferStream)
((PushBufferStream)master).read(b);
for (Enumeration e = slaves.elements(); e.hasMoreElements();) {
Object stream = e.nextElement();
((PushBufferStreamSlave)stream).setBuffer((Buffer)b.clone());
Thread.yield();
}
}
int copyAndRead(byte[] buffer, int offset, int length) throws IOException {
int totalRead = 0;
if (master instanceof PullSourceStream)
totalRead = ((PullSourceStream)master).read(buffer, offset, length);
if (master instanceof PushSourceStream)
totalRead = ((PushSourceStream)master).read(buffer, offset, length);
for (Enumeration e = slaves.elements(); e.hasMoreElements();) {
Object stream = e.nextElement();
byte[] copyBuffer = new byte[totalRead];
System.arraycopy(buffer, offset, copyBuffer, 0, totalRead);
((PushSourceStreamSlave)stream).setBuffer(copyBuffer);
}
return totalRead;
}
////////////////////////////
//
// INNER CLASSES
////////////////////////////
class SourceStreamAdapter implements SourceStream {
public ContentDescriptor getContentDescriptor() {
return master.getContentDescriptor();
}
public long getContentLength() {
return master.getContentLength();
}
public boolean endOfStream() {
return master.endOfStream();
}
public Object[] getControls() {
return master.getControls();
}
public Object getControl(String controlType) {
return master.getControl(controlType);
}
}
abstract class PushStreamSlave extends SourceStreamAdapter
implements SourceStreamSlave, Runnable {
MediaThread notifyingThread;
boolean connected = false;
public synchronized void connect() {
if (connected)
return;
connected = true;
if ( /*securityPrivelege && */ (jmfSecurity != null) ) {
String permission = null;
try {
if (jmfSecurity.getName().startsWith("jmf-security")) {
permission = "thread";
jmfSecurity.requestPermission(m, cl, args, JMFSecurity.THREAD);
m[0].invoke(cl[0], args[0]);
permission = "thread group";
jmfSecurity.requestPermission(m, cl, args, JMFSecurity.THREAD_GROUP);
m[0].invoke(cl[0], args[0]);
} else if (jmfSecurity.getName().startsWith("internet")) {
PolicyEngine.checkPermission(PermissionID.THREAD);
PolicyEngine.assertPermission(PermissionID.THREAD);
}
} catch (Throwable e) {
if (JMFSecurityManager.DEBUG) {
System.err.println("Unable to get " + permission +
" privilege " + e);
}
securityPrivelege = false;
// TODO: Do the right thing if permissions cannot
// be obtained.
// User should be notified via an event
}
}
if ( (jmfSecurity != null) && (jmfSecurity.getName().startsWith("jdk12"))) {
try {
Constructor cons = jdk12CreateThreadRunnableAction.cons;
notifyingThread = (MediaThread) jdk12.doPrivM.invoke(
jdk12.ac,
new Object[] {
cons.newInstance(
new Object[] {
MediaThread.class,
this
})});
} catch (Exception e) { }
} else {
notifyingThread = new MediaThread(this);
}
if (notifyingThread != null) {
if (master instanceof PushBufferStream) {
if (((PushBufferStream)master).getFormat() instanceof VideoFormat)
notifyingThread.useVideoPriority();
else
notifyingThread.useAudioPriority();
}
notifyingThread.start(); // You dont need permission for start
}
}
public synchronized void disconnect() {
connected = false;
notifyAll();
}
}
class PushSourceStreamSlave extends PushStreamSlave
implements PushSourceStream, Runnable {
SourceTransferHandler handler;
private byte[] buffer;
/**
* Set the buffer this stream can provide for the next read
*/
synchronized void setBuffer(byte[] buffer) {
this.buffer = buffer;
notifyAll();
}
public synchronized int read(byte[] buffer, int offset, int length)
throws IOException {
if (length + offset > buffer.length)
throw new IOException("buffer is too small");
// block till we have a buffer to read from
while (this.buffer == null && connected) {
try {
wait(50);
}
catch (InterruptedException e) {
System.out.println("Exception: " + e);
}
}
if (!connected)
throw new IOException("DataSource is not connected");
int copyLength = (length > this.buffer.length ? this.buffer.length : length);
System.arraycopy(this.buffer, 0, buffer, offset, copyLength);
this.buffer = null;
return copyLength;
}
public int getMinimumTransferSize() {
return ((PushSourceStream)master).getMinimumTransferSize();
}
public void setTransferHandler(SourceTransferHandler transferHandler) {
handler = transferHandler;
}
SourceTransferHandler getTransferHandler() {
return handler;
}
/**
* Implementation of Runnable inteface.
*/
public void run() {
while (!endOfStream() && connected) {
try {
synchronized(this) {
wait(); // till we will be notified that a read occured
}
} catch (InterruptedException e) {
System.out.println("Exception: " + e);
}
if (connected && handler != null)
handler.transferData((PushSourceStream)this);
}
}
}
class PushBufferStreamSlave extends PushStreamSlave
implements PushBufferStream, Runnable {
BufferTransferHandler handler;
private Buffer b;
/**
* Set the buffer this stream can provide for the next read
*/
synchronized void setBuffer(Buffer b) {
this.b = b;
notifyAll();
}
public javax.media.Format getFormat() {
return ((PushBufferStream)master).getFormat();
}
public synchronized void read(Buffer buffer) throws IOException {
// block till we have a buffer to read from
while (b == null && connected) {
try {
wait(50);
}
catch (InterruptedException e) {
System.out.println("Exception: " + e);
}
}
if (!connected)
throw new IOException("DataSource is not connected");
buffer.copy(b);
b = null;
}
public int getMinimumTransferSize() {
return ((PushSourceStream)master).getMinimumTransferSize();
}
public void setTransferHandler(BufferTransferHandler transferHandler) {
handler = transferHandler;
}
BufferTransferHandler getTransferHandler() {
return handler;
}
/**
* Implementation of Runnable inteface.
*/
public void run() {
while (!endOfStream() && connected) {
try {
synchronized(this) {
wait(); // till we will be notified that a read occured
}
} catch (InterruptedException e) {
System.out.println("Exception: " + e);
}
if (connected && handler != null)
handler.transferData((PushBufferStream)this);
}
}
}
class PullSourceStreamAdapter extends SourceStreamAdapter
implements PullSourceStream {
public boolean willReadBlock() {
return ((PullSourceStream)master).willReadBlock();
}
public int read(byte[] buffer, int offset, int length)
throws IOException {
return copyAndRead(buffer, offset, length);
}
}
class PullBufferStreamAdapter extends SourceStreamAdapter
implements PullBufferStream {
public boolean willReadBlock() {
return ((PullBufferStream)master).willReadBlock();
}
public void read(Buffer buffer)throws IOException {
copyAndRead(buffer);
}
public javax.media.Format getFormat() {
return ((PullBufferStream)master).getFormat();
}
}
class PushSourceStreamAdapter extends SourceStreamAdapter
implements PushSourceStream, SourceTransferHandler {
SourceTransferHandler handler;
public int read(byte[] buffer, int offset, int length) throws IOException {
return copyAndRead(buffer, offset, length);
}
public int getMinimumTransferSize() {
return ((PushSourceStream)master).getMinimumTransferSize();
}
public void setTransferHandler(SourceTransferHandler transferHandler) {
handler = transferHandler;
((PushSourceStream)master).setTransferHandler(this);
}
public void transferData(PushSourceStream stream) {
if (handler != null)
handler.transferData(this);
}
}
class PushBufferStreamAdapter extends SourceStreamAdapter
implements PushBufferStream, BufferTransferHandler {
BufferTransferHandler handler;
public javax.media.Format getFormat() {
return ((PushBufferStream)master).getFormat();
}
public void read(Buffer buffer) throws IOException {
copyAndRead(buffer);
}
public void setTransferHandler(BufferTransferHandler transferHandler) {
handler = transferHandler;
((PushBufferStream)master).setTransferHandler(this);
}
public void transferData(PushBufferStream stream) {
if (handler != null)
handler.transferData(this);
}
}
}
|