--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/mmapi_qt/baseline/javasrc/com/nokia/microedition/media/protocol/SourceStreamReader.java Tue Aug 31 15:09:22 2010 +0300
@@ -0,0 +1,290 @@
+/*
+* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: SourceStreamReader gets data from java classes and passes
+* stream to CMMASourceStream on C++ side
+*
+*/
+
+
+package com.nokia.microedition.media.protocol;
+
+import java.io.IOException;
+import javax.microedition.media.protocol.SourceStream;
+import javax.microedition.media.Controllable;
+import javax.microedition.media.Control;
+import com.nokia.microedition.media.SeekControl;
+import com.nokia.microedition.media.InputStreamSeekControl;
+import com.nokia.mj.impl.utils.Logger;
+
+public class SourceStreamReader extends Thread
+{
+ Thread t1 = null;
+ // these states are the same in c++ side
+ private static final int NO_ERROR = 0;
+ private static final int ERR_GENERAL = -2; // KErrGeneral
+ private static final int ERR_EOF = -25; // KErrEof
+ private static final int READ_ALL = -1;
+ private static final int MORE_DATA = 3;
+ private static final int COMPLETED = 4;
+ private static final int CLOSED = -45; // KErrSessionClosed
+
+ // size of the buffer (transferred bytes)
+ // MMF currently requests data in 4k blocks
+ private static final int BUFFER_SIZE = 4096;
+
+ private static final String SEEK_CONTROL = "SeekControl";
+
+ private SourceStream iSourceStream;
+ private byte[] iBuffer;
+ private int iLength; // Length of stream c++ requested
+ private int iHandle; // handle to CMMASourceStream
+ private int iStatus = NO_ERROR; // source stream status
+ private int iEventSourceHandle;
+ private boolean iIsActive;
+ private int iPlayerHandle;
+
+ private Object iWaitObject = new Object();
+
+ // DataSource that SourceStream belongs to
+ private Controllable iControllable;
+
+ /**
+ * Constructor
+ *
+ * @param aSourceStream a Stream to be passed to C++ side
+ * @param aEventSourceHandle handle to the event source
+ */
+ public SourceStreamReader(SourceStream aSourceStream,
+ Controllable aControllable,
+ int aEventSourceHandle,
+ int aPlayerHandle)
+ {
+ iSourceStream = aSourceStream;
+ iControllable = aControllable;
+ iEventSourceHandle = aEventSourceHandle;
+ iBuffer = new byte[ BUFFER_SIZE ];
+ iPlayerHandle = aPlayerHandle;
+ }
+
+ /**
+ * Sets handle to CMMASourceStream
+ *
+ * @param aHandle handle to CMMASourceStream
+ */
+ public void setHandle(int aHandle)
+ {
+ iHandle = aHandle;
+ }
+
+ /**
+ * Run method for a thread which writes data to C++
+ */
+ public void run()
+ {
+ int length = 0;
+ do
+ {
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"Source stream reader run()");
+ iStatus = MORE_DATA;
+ try
+ {
+ length = iSourceStream.read(iBuffer, 0, iLength);
+ }
+ catch (IOException ioe)
+ {
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"Source stream reader run(), io exception");
+ ioe.printStackTrace();
+ iStatus = ERR_GENERAL;
+ }
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"Source stream reader run(), length = "+length);
+ if (iStatus == CLOSED)
+ {
+ return;
+ }
+ // no more data because end of file has been reach
+ if (length == -1)
+ {
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"no more data because end of file has been reach");
+ iStatus = COMPLETED;
+ }
+ // synchronized (iWaitObject)
+ // {
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"Source stream reader run(), calling jni _write"+"status =" + iStatus + "length =" + length);
+
+ int err = _write(iHandle,
+ iEventSourceHandle,
+ iBuffer,
+ length,
+ iStatus,
+ iPlayerHandle);
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"Source stream reader run(), calling jni _write ret = "+err);
+ if (err != 0)
+ {
+ // error in writing, closing thread
+ iIsActive = false;
+ iStatus = CLOSED;
+ break;
+ }
+ // wait for next native read
+ // try
+ // {
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"Source stream reader run(), calling wait()");
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"Source stream reader run(), calling wait() thread is =" +Thread.currentThread().getName());
+ // iWaitObject.wait();
+ //}
+ /*catch (InterruptedException ex)
+ {
+ // MIDP's object does not have interrupt
+ }*/
+ // }
+ }
+ while (length>0);
+ }
+
+ /**
+ * Close stops run() thread
+ */
+ public void close()
+ {
+ iIsActive = false;
+ iStatus = CLOSED;
+
+ // If Controllable has SeekControl it must be closed
+ Control control = iControllable.getControl(SEEK_CONTROL);
+ if (control != null)
+ {
+ SeekControl sc = (SeekControl)control;
+ sc.close();
+ }
+
+ synchronized (iWaitObject)
+ {
+ iWaitObject.notify();
+ }
+ }
+
+ /**
+ * Resets streams to point start of the media. Player deallocate needs
+ * this.
+ */
+ public void resetStream()
+ {
+ try
+ {
+ SeekControl control = (SeekControl)iControllable.getControl(SEEK_CONTROL);
+ control.seek(0);
+ }
+ catch (IOException ioe)
+ {
+ // Stream may be broken, we can't do anything for it here.
+ // It will be noticed by the player when changing state from deallocate
+ Logger.ELOG(Logger.EJavaMMAPI,
+ "SourceStreamReader: resetStream: ", ioe);
+ }
+ }
+
+
+ /**
+ * Native side request data from Java with read method.
+ *
+ * @param aBytes native side notifies how many bytes should be sent to it
+ * @param aStatus Status of the stream reading
+ */
+ private void read(int aBytes, int aStatus)
+ {
+ // Try to read but SourceStream is already completed or closed?
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"SourceStreamReader:: read() , callback detected ,iStatus = "+iStatus+" aBytes = "+aBytes);
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"thread id = "+Thread.currentThread().getName());
+ if (iStatus == CLOSED)
+ {
+ // Inform the native object; attempting to read pass the end of the stream
+ _write(iHandle, iEventSourceHandle, new byte[ 0 ], 0, ERR_EOF, iPlayerHandle);
+ return;
+ }
+
+ if (aBytes == READ_ALL)
+ {
+ iLength = BUFFER_SIZE;
+ }
+ else
+ {
+ iLength = aBytes;
+ }
+
+ if (aBytes > iBuffer.length)
+ {
+ // native request larger buffer
+ iBuffer = new byte[ aBytes ];
+ }
+
+ if (iStatus == COMPLETED)
+ {
+ // Stream is already read ones and need to be seeked to start
+ Control control = iControllable.getControl(SEEK_CONTROL);
+ if (control != null)
+ {
+ // start new seak thread, thread will notify iWaitObject
+ // when completed
+ (new SeekThread(iWaitObject,
+ (SeekControl)control)).start();
+ }
+ else
+ {
+ // stream is not seekable, so informing native object
+ _write(iHandle, iEventSourceHandle, new byte[ 0 ], 0,
+ ERR_EOF, iPlayerHandle);
+ }
+ }
+ else if (iIsActive)
+ {
+ // notify to while() write -loop that data is requested
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"SourceStreamReader:: read() before sync(iWaitObjet() ");
+ synchronized (iWaitObject)
+ {
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"SourceStreamReader:: read() notifying iWaitObject");
+ iWaitObject.notify();
+ }
+ }
+ else
+ {
+ Logger.LOG(Logger.EJavaMMAPI, Logger.EInfo,"SourceStreamReader, creating new Thread");
+ iIsActive = true;
+ t1 = new Thread(this);
+ t1.start();
+ // start();
+ }
+
+ }
+
+
+ /**
+ * _write writes data to the C++ side
+ *
+ * @param aHandle Handle
+ * @param aEventSourceHandle EventSourceHandle
+ * @param aData Source stream
+ * @param aBytesRead how many bytes is read
+ * @param aStatus stream status
+ * @return return value
+ */
+ static private native int _write(int aHandle,
+ int aEventSourceHandle,
+ byte[] aData,
+ int aBytesRead,
+ int aStatus,
+ int aPlayerHandle);
+
+}
+
+// end of file