javauis/mmapi_qt/baseline/javasrc/com/nokia/microedition/media/protocol/SourceStreamReader.java
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 14 May 2010 15:47:24 +0300
changeset 23 98ccebc37403
child 26 dc7c549001d5
permissions -rw-r--r--
Revision: v2.1.24 Kit: 201019

/*
* 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