javauis/mmapi_akn/baseline/javasrc.emc/com/nokia/microedition/media/ManagerImpl.java
branchRCL_3
changeset 19 04becd199f91
child 71 d5e927d5853b
equal deleted inserted replaced
16:f5050f1da672 19:04becd199f91
       
     1 /*
       
     2 * Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 package com.nokia.microedition.media;
       
    19 
       
    20 import java.io.IOException;
       
    21 import java.io.InputStream;
       
    22 import java.util.Vector;
       
    23 import java.util.Enumeration;
       
    24 import javax.microedition.media.protocol.DataSource;
       
    25 import javax.microedition.media.TimeBase;
       
    26 import javax.microedition.media.Player;
       
    27 import javax.microedition.media.MediaException;
       
    28 import com.nokia.mj.impl.rt.legacy.MIDEventServer;
       
    29 import com.nokia.mj.impl.rt.legacy.ToolkitInvoker;
       
    30 import com.nokia.mj.impl.rt.legacy.ToolkitObserver;
       
    31 import com.nokia.mj.impl.rt.legacy.NativeError;
       
    32 import com.nokia.microedition.media.protocol.ProtocolFactory;
       
    33 import com.nokia.microedition.media.tone.PlayToneImpl;
       
    34 import com.nokia.microedition.volumekeys.ForegroundListener;
       
    35 import com.nokia.mj.impl.rt.support.Finalizer;
       
    36 
       
    37 /**
       
    38  * ManagerImpl implements the functionality specified in
       
    39  * javax.microedition.media.Manager class.
       
    40  * This class is a singleton and instance can be got with getInstance method.
       
    41  */
       
    42 public class ManagerImpl implements PlugIn
       
    43 {
       
    44     // ManagerImpl native instance
       
    45     private static int sManagerHandle;
       
    46 
       
    47     // CMMAEventSource
       
    48     private static int sEventSourceHandle;
       
    49 
       
    50     // Static instance, can be got with getInstace method
       
    51     private static ManagerImpl sManager;
       
    52 
       
    53     private final TimeBase iSystemTimeBase = new SystemTimeBase();
       
    54     private final MIDEventServer iEventServer;
       
    55     private final Vector iPlugIns = new Vector();
       
    56     private final ProtocolFactory iProtocolFactory = new ProtocolFactory();
       
    57     private final ForegroundListener iForegroundListener;
       
    58 
       
    59     private Finalizer mFinalizer = new Finalizer()
       
    60     {
       
    61         public void finalizeImpl()
       
    62         {
       
    63             doFinalize();
       
    64         }
       
    65     };
       
    66 
       
    67     // Play tone implementation
       
    68     private PlayToneImpl iPlayToneImpl = new PlayToneImpl();
       
    69 
       
    70     static
       
    71     {
       
    72         // This is called when class is loaded for the first time
       
    73         sManager = new ManagerImpl();
       
    74 
       
    75         try
       
    76         {
       
    77             // Invoke external components
       
    78             Setup.setup(sEventSourceHandle);
       
    79         }
       
    80         catch (OutOfMemoryError oome)
       
    81         {
       
    82             // External setup failed clean MMA native resources and throw oome
       
    83             sManager.registeredFinalize();
       
    84             throw oome;
       
    85         }
       
    86     }
       
    87 
       
    88     /**
       
    89      * This private constructor can be called only from staic block.
       
    90      */
       
    91     private ManagerImpl()
       
    92     {
       
    93         com.nokia.mj.impl.rt.support.Jvm.loadSystemLibrary("javamobilemedia");
       
    94 
       
    95         // Event server contructor needs new String object,
       
    96         // otherwise it don't work..
       
    97         iEventServer = new MIDEventServer(new String("java-mma"));
       
    98         sEventSourceHandle = _createEventSource(iEventServer.getHandle());
       
    99         if (sEventSourceHandle < NativeError.KErrNone)
       
   100         {
       
   101             throw new OutOfMemoryError("SymbianOS error: " + sEventSourceHandle);
       
   102         }
       
   103         // Suite UID was fetched using deprecated MIDletSuiteAMS.getMIDletSuiteId.
       
   104         // Using hard coded value in here since MMAPI doesn't really use the
       
   105         // suite id even if it passes it to native.
       
   106         final int midletSuiteId = 1;
       
   107         sManagerHandle = _createManager(sEventSourceHandle, midletSuiteId);
       
   108         if (sManagerHandle < NativeError.KErrNone)
       
   109         {
       
   110             throw new OutOfMemoryError();
       
   111         }
       
   112 
       
   113         ToolkitInvoker ti = ToolkitInvoker.getToolkitInvoker();
       
   114         // register for destroy event
       
   115         ti.addObserver(ti.getToolkit(),  new ToolkitObserver()
       
   116         {
       
   117             public final void destroyNotify()
       
   118             {
       
   119                 release();
       
   120             }
       
   121         });
       
   122 
       
   123         // ManagerImpl is also a PlugIn that getAllSupportedContentTypes,
       
   124         // getAllSupportedProtocols and createPlayer methods can be used
       
   125         // through PlugIn interface.
       
   126         iPlugIns.addElement(this);
       
   127 
       
   128         // support for device://tone and jts
       
   129         iPlugIns.addElement(
       
   130             new com.nokia.microedition.media.protocol.device.tone.Protocol());
       
   131 
       
   132         // Create foreground listener which listens the state of the midlet
       
   133         // This feature is a part of the media keys feature so it is flagged
       
   134         iForegroundListener = new ForegroundListener(sEventSourceHandle);
       
   135     }
       
   136 
       
   137     /**
       
   138      * Returns MMA event source handle
       
   139      */
       
   140     public static int getEventSource()
       
   141     {
       
   142         return sEventSourceHandle;
       
   143     }
       
   144     /**
       
   145      * Returns native handle to Manager
       
   146      */
       
   147     public static int getHandle()
       
   148     {
       
   149         return sManagerHandle;
       
   150     }
       
   151 
       
   152     /**
       
   153      * Return ManagerImpl instance
       
   154      */
       
   155     public static ManagerImpl getInstance()
       
   156     {
       
   157         return sManager;
       
   158     }
       
   159 
       
   160     /**
       
   161      * Adds new PlugIn to PlugIns array.
       
   162      * @param aPlugIn New PlugIn.
       
   163      */
       
   164     public void addPlugIn(PlugIn aPlugIn)
       
   165     {
       
   166         iPlugIns.addElement(aPlugIn);
       
   167     }
       
   168 
       
   169     private void doFinalize()
       
   170     {
       
   171         if (mFinalizer != null)
       
   172         {
       
   173             registeredFinalize();
       
   174             mFinalizer = null;
       
   175         }
       
   176     }
       
   177 
       
   178     /**
       
   179      * This will be called when object is finalized.
       
   180      */
       
   181     synchronized final void registeredFinalize()
       
   182     {
       
   183         _dispose(sEventSourceHandle);
       
   184         sEventSourceHandle = 0;
       
   185     }
       
   186 
       
   187     /**
       
   188      * This method is called in Toolkit's destroyNotify call.
       
   189      * This will release convenient native resources. All native resource
       
   190      * will be deleted in registeredFinalize() method.
       
   191      */
       
   192     synchronized final void release()
       
   193     {
       
   194         _release(sEventSourceHandle);
       
   195     }
       
   196 
       
   197     /**
       
   198      * Create String array from Vector and remove String duplicates.
       
   199      * @param aVector Vector containing String objects.
       
   200      */
       
   201     private String[] createStringArray(Vector aVector)
       
   202     {
       
   203         // remove all duplicates from the vector
       
   204         for (int i = 0; i < aVector.size(); i++)
       
   205         {
       
   206             String element = (String)aVector.elementAt(i);
       
   207             for (int j = i + 1; j < aVector.size();)
       
   208             {
       
   209                 if (element.equals((String)aVector.elementAt(j)))
       
   210                 {
       
   211                     aVector.removeElementAt(j);
       
   212                 }
       
   213                 else
       
   214                 {
       
   215                     j++;
       
   216                 }
       
   217             }
       
   218         }
       
   219 
       
   220         // Create new array for vector elements and copy elements
       
   221         String[] s = new String[ aVector.size()];
       
   222         aVector.copyInto(s);
       
   223         return s;
       
   224     }
       
   225 
       
   226     /**
       
   227      * Return the list of supported content types for the given protocol.
       
   228      * <p>
       
   229      * See <a href="#content-type">content types</a> for the syntax
       
   230      * of the content types returned.
       
   231      * See <a href="#media-protocol">protocol name</a> for the syntax
       
   232      * of the protocol used.
       
   233      * <p>
       
   234      * For example, if the given <code>protocol</code>
       
   235      * is <code>"http"</code>,
       
   236      * then the supported content types that can be played back
       
   237      * with the <code>http</code> protocol will be returned.
       
   238      * <p>
       
   239      * If <code>null</code> is passed in as the <code>protocol</code>,
       
   240      * all the supported content types for this implementation
       
   241      * will be returned.  The returned array must be non-empty.
       
   242      * <p>
       
   243      * If the given <code>protocol</code> is an invalid or
       
   244      * unsupported protocol, then an empty array will be returned.
       
   245      *
       
   246      * @param aProtocol The input protocol for the supported content types.
       
   247      * @return The list of supported content types for the given protocol.
       
   248      */
       
   249     public String[] getAllSupportedContentTypes(String aProtocol)
       
   250     {
       
   251         if ((aProtocol != null) && (aProtocol.length() == 0))
       
   252         {
       
   253             // No supported types for 0 length string.
       
   254             return new String[ 0 ];
       
   255         }
       
   256         Vector contentTypes = new Vector();
       
   257 
       
   258         Enumeration plugIns = iPlugIns.elements();
       
   259 
       
   260         // go through all plugins and get content types
       
   261         while (plugIns.hasMoreElements())
       
   262         {
       
   263             PlugIn plugIn = (PlugIn)plugIns.nextElement();
       
   264             String[] types = plugIn.getSupportedContentTypes(aProtocol);
       
   265 
       
   266             // Add all types to vector
       
   267             for (int i = 0; i < types.length; i++)
       
   268             {
       
   269                 contentTypes.addElement(types[ i ]);
       
   270             }
       
   271         }
       
   272         return createStringArray(contentTypes);
       
   273     }
       
   274 
       
   275     /**
       
   276      * Return the list of supported protocols given the content
       
   277      * type.  The protocols are returned
       
   278      * as strings which identify what locators can be used for creating
       
   279      * <code>Player</code>'s.
       
   280      * <p>
       
   281      * See <a href="#media-protocol">protocol name</a> for the syntax
       
   282      * of the protocols returned.
       
   283      * See <a href="#content-type">content types</a> for the syntax
       
   284      * of the content type used.
       
   285      * <p>
       
   286      * For example, if the given <code>content_type</code>
       
   287      * is <code>"audio/x-wav"</code>, then the supported protocols
       
   288      * that can be used to play back <code>audio/x-wav</code>
       
   289      * will be returned.
       
   290      * <p>
       
   291      * If <code>null</code> is passed in as the
       
   292      * <code>content_type</code>,
       
   293      * all the supported protocols for this implementation
       
   294      * will be returned.  The returned array must be non-empty.
       
   295      * <p>
       
   296      * If the given <code>content_type</code> is an invalid or
       
   297      * unsupported content type, then an empty array will be returned.
       
   298      *
       
   299      * @param aContentType The content type for the supported protocols.
       
   300      * @return The list of supported protocols for the given content type.
       
   301      */
       
   302     public String[] getAllSupportedProtocols(String aContentType)
       
   303     {
       
   304         String contentType = aContentType;
       
   305         if ((contentType != null) &&  contentType.equals(""))
       
   306         {
       
   307             return new String[ 0 ];
       
   308         }
       
   309 
       
   310         Vector protocols = new Vector();
       
   311         Enumeration plugIns = iPlugIns.elements();
       
   312         while (plugIns.hasMoreElements())
       
   313         {
       
   314             PlugIn plugIn = (PlugIn)plugIns.nextElement();
       
   315             String[] types = plugIn.getSupportedProtocols(aContentType);
       
   316             for (int i = 0; i < types.length; i++)
       
   317             {
       
   318                 protocols.addElement(types[ i ]);
       
   319             }
       
   320         }
       
   321         return createStringArray(protocols);
       
   322     }
       
   323 
       
   324     /**
       
   325      * From PlugIn. Get MMA supported protocols.
       
   326      */
       
   327     public String[] getSupportedProtocols(String aContentType)
       
   328     {
       
   329         String[] protocols = _getSupportedProtocols(sEventSourceHandle,
       
   330                              sManagerHandle,
       
   331                              aContentType);
       
   332         NativeError.checkOOM(protocols);
       
   333         return protocols;
       
   334     }
       
   335 
       
   336     /**
       
   337      * From PlugIn. Get MMA supported types.
       
   338      */
       
   339     public String[] getSupportedContentTypes(String aProtocol)
       
   340     {
       
   341         String[] types = _getSupportedContentTypes(sEventSourceHandle,
       
   342                          sManagerHandle,
       
   343                          aProtocol);
       
   344         NativeError.checkOOM(types);
       
   345         return types;
       
   346     }
       
   347 
       
   348     /**
       
   349      * From PlugIn.
       
   350      */
       
   351     public InternalPlayer createPlayer(DataSource aSource)
       
   352     throws MediaException, IOException
       
   353     {
       
   354         InternalPlayer player = null;
       
   355         if (aSource.getContentType() != null)
       
   356         {
       
   357             // Create player from content type
       
   358             if (isValidContentType(aSource.getContentType()))
       
   359             {
       
   360                 player = NativePlayerFactory.createPlayer(aSource.getContentType(),
       
   361                          aSource);
       
   362             }
       
   363             else
       
   364             {
       
   365                 throw new MediaException(
       
   366                     "Content type not supported: " + aSource.getContentType());
       
   367             }
       
   368         }
       
   369 
       
   370         if ((player == null) &&
       
   371                 (aSource.getLocator() != null))
       
   372         {
       
   373             // Create player from locator
       
   374             player = NativePlayerFactory.createPlayer(
       
   375                          new Locator(aSource.getLocator()),
       
   376                          aSource);
       
   377         }
       
   378 
       
   379         if (player == null)
       
   380         {
       
   381             // Could not create player from content-type or locator,
       
   382             // try to create player from header data
       
   383             player = NativePlayerFactory.createPlayer(
       
   384                          ((BufferDataSource)aSource).getHeader(),
       
   385                          aSource);
       
   386         }
       
   387 
       
   388         return player;
       
   389     }
       
   390 
       
   391     /**
       
   392      * From PlugIn. Empty implemation.
       
   393      */
       
   394     public void preparePlayer(InternalPlayer aPlayer) throws MediaException
       
   395     {
       
   396     }
       
   397 
       
   398     /**
       
   399      * This method calls preparePlayer to all PlugIns.
       
   400      */
       
   401     private void pluginsPreparePlayer(InternalPlayer aPlayer)
       
   402     throws MediaException
       
   403     {
       
   404         // Call preparePlayer to all plugins
       
   405         Enumeration plugins = iPlugIns.elements();
       
   406         while (plugins.hasMoreElements())
       
   407         {
       
   408             ((PlugIn)plugins.nextElement()).preparePlayer(aPlayer);
       
   409         }
       
   410     }
       
   411 
       
   412     /**
       
   413      * Create a <code>Player</code> from an input locator.
       
   414      *
       
   415      * @param aLocator A locator string in URI syntax that describes
       
   416      * the media content.
       
   417      * @return A new <code>Player</code>.
       
   418      * @exception IllegalArgumentException Thrown if <code>locator</code>
       
   419      * is <code>null</code>.
       
   420      * @exception MediaException Thrown if a <code>Player</code> cannot
       
   421      * be created for the given locator.
       
   422      * @exception IOException Thrown if there was a problem connecting
       
   423      * with the source pointed to by the <code>locator</code>.
       
   424      * @exception SecurityException Thrown if the caller does not
       
   425      * have security permission to create the <code>Player</code>.
       
   426      */
       
   427     public Player createPlayer(String aLocator)
       
   428     throws IOException, MediaException
       
   429     {
       
   430         if (aLocator == null)
       
   431         {
       
   432             throw new IllegalArgumentException("Locator is null.");
       
   433         }
       
   434         InternalPlayer player = iProtocolFactory.createPlayer(
       
   435                                     new Locator(aLocator));
       
   436         if (player == null)
       
   437         {
       
   438             throw new MediaException("Locator not supported: " +
       
   439                                      aLocator);
       
   440         }
       
   441         pluginsPreparePlayer(player);
       
   442         return player;
       
   443     }
       
   444 
       
   445     /**
       
   446      * Create a <code>InternalPlayer</code> for a <code>DataSource</code>.
       
   447      */
       
   448     public InternalPlayer createInternalPlayer(DataSource aSource)
       
   449     throws IOException, MediaException
       
   450     {
       
   451         // Throw IllegalArgumentException if source  is null.
       
   452         if (aSource == null)
       
   453         {
       
   454             throw new IllegalArgumentException("DataSource is null.");
       
   455         }
       
   456         aSource.connect(); // Ensure that external source is connected.
       
   457         if (aSource.getStreams() == null ||
       
   458                 aSource.getStreams().length == 0)
       
   459         {
       
   460             // There must be atleast one stream in the DataSource
       
   461             throw new MediaException(
       
   462                 "There must be at least one stream in datasource");
       
   463         }
       
   464 
       
   465         BufferDataSource bdc = null;
       
   466         if (aSource instanceof BufferDataSource)
       
   467         {
       
   468             bdc = (BufferDataSource)aSource;
       
   469         }
       
   470         else
       
   471         {
       
   472             bdc = new BufferDataSource(aSource);
       
   473         }
       
   474 
       
   475         InternalPlayer player = null;
       
   476         Enumeration plugins = iPlugIns.elements();
       
   477         // Loop through all plugins, stop if player was created
       
   478         while (plugins.hasMoreElements() &&
       
   479                 (player == null))
       
   480         {
       
   481             PlugIn tmp = (PlugIn)plugins.nextElement();
       
   482             player = tmp.createPlayer(bdc);
       
   483         }
       
   484 
       
   485         if (player == null)
       
   486         {
       
   487             // MMA or plugins could not create player
       
   488             bdc.disconnect();
       
   489 
       
   490             throw new MediaException("Could not create player.");
       
   491         }
       
   492 
       
   493         return player;
       
   494     }
       
   495 
       
   496     /**
       
   497      * Create a <code>Player</code> to play back media from an
       
   498      * <code>InputStream</code>.
       
   499      * <p>
       
   500      * The <code>type</code> argument
       
   501      * specifies the content-type of the input media.  If
       
   502      * <code>null</code> is given, <code>Manager</code> will
       
   503      * attempt to determine the type.  However, since determining
       
   504      * the media type is non-trivial for some media types, it
       
   505      * may not be feasible in some cases.  The
       
   506      * <code>Manager</code> may throw a <code>MediaException</code>
       
   507      * to indicate that.
       
   508      *
       
   509      * @param aStream The <code>InputStream</code> that delivers the
       
   510      * input media.
       
   511      * @param aType The <code>ContentType</code> of the media.
       
   512      * @return A new <code>Player</code>.
       
   513      * @exception IllegalArgumentException Thrown if <code>stream</code>
       
   514      * is <code>null</code>.
       
   515      * @exception MediaException Thrown if a <code>Player</code> cannot
       
   516      * be created for the given stream and type.
       
   517      * @exception IOException Thrown if there was a problem reading data
       
   518      * from the <code>InputStream</code>.
       
   519      * @exception SecurityException Thrown if the caller does not
       
   520      * have security permission to create the <code>Player</code>.
       
   521      */
       
   522     public Player createPlayer(InputStream aStream, String aType)
       
   523     throws IOException, MediaException
       
   524     {
       
   525         if (aStream == null)
       
   526         {
       
   527             throw new IllegalArgumentException("InputStream is null.");
       
   528         }
       
   529 
       
   530         InputStreamSourceStream sourceStream =
       
   531             new InputStreamSourceStream(aStream);
       
   532 
       
   533         // Create data source without locator.
       
   534         DataSource dataSource = new InputStreamDataSource(sourceStream,
       
   535                 aType);
       
   536         InternalPlayer player = createInternalPlayer(dataSource);
       
   537 
       
   538         if (player != null)
       
   539         {
       
   540             // Call preparePlayer to all plugins
       
   541             pluginsPreparePlayer(player);
       
   542         }
       
   543 
       
   544         return player;
       
   545     }
       
   546 
       
   547     /**
       
   548      * Play back a tone as specified by a note and its duration.
       
   549      * A note is given in the range of 0 to 127 inclusive.  The frequency
       
   550      * of the note can be calculated from the following formula:
       
   551      * <pre>
       
   552      *     SEMITONE_CONST = 17.31234049066755 = 1/(ln(2^(1/12)))
       
   553      *     note = ln(freq/8.176)*SEMITONE_CONST
       
   554      *     The musical note A = MIDI note 69 (0x45) = 440 Hz.
       
   555      * </pre>
       
   556      * This call is a non-blocking call. Notice that this method may
       
   557      * utilize CPU resources significantly on devices that don't
       
   558      * have hardware support for tone generation.
       
   559      *
       
   560      * @param aNote Defines the tone of the note as specified by the
       
   561      * above formula.
       
   562      * @param aDuration The duration of the tone in milli-seconds.
       
   563      * Duration must be positive.
       
   564      * @param aVolume Audio volume range from 0 to 100.  100 represents
       
   565      * the maximum
       
   566      * volume at the current hardware level.  Setting the volume to a
       
   567      * value less
       
   568      * than 0 will set the volume to 0.  Setting the volume to greater than
       
   569      * 100 will set the volume to 100.
       
   570      *
       
   571      * @exception IllegalArgumentException Thrown if the given note or
       
   572      * duration is out of range.
       
   573      * @exception MediaException Thrown if the tone cannot be played
       
   574      * due to a device-related problem.
       
   575      */
       
   576     public void playTone(int aNote, int aDuration, int aVolume)
       
   577     throws MediaException
       
   578     {
       
   579         iPlayToneImpl.playTone(aNote, aDuration, aVolume);
       
   580     }
       
   581 
       
   582     /**
       
   583      * Get the time-base object for the system.
       
   584      * @return The system time base.
       
   585      */
       
   586     public TimeBase getSystemTimeBase()
       
   587     {
       
   588         return iSystemTimeBase;
       
   589     }
       
   590 
       
   591     public boolean isValidContentType(String contentType)
       
   592     {
       
   593         for (int i=0; i < contentType.length(); i++)
       
   594         {
       
   595             if ((contentType.charAt(i) >= 0 && contentType.charAt(i) <= 31) || contentType.charAt(i) == 127)
       
   596                 return false;
       
   597         }
       
   598         return true;
       
   599     }
       
   600 
       
   601     private native int _createManager(int aEventSourceHandle,
       
   602                                       int aMIDletSuiteID);
       
   603     private native int _createEventSource(int aEventServerHandle);
       
   604     private native void _dispose(int aEventSourceHandle);
       
   605 
       
   606     /**
       
   607      * Releases native resources.
       
   608      * @param aEventSourceHandle Handle to native CMMAEventSource instance.
       
   609      */
       
   610     private native void _release(int aEventSourceHandle);
       
   611 
       
   612     private static native String[] _getSupportedContentTypes(int aEventSourceHandle,
       
   613             int aManagerHandle,
       
   614             String aContentType);
       
   615 
       
   616     private static native String[] _getSupportedProtocols(int aEventSourceHandle,
       
   617             int aManagerHandle,
       
   618             String aProtocol);
       
   619 }
       
   620 
       
   621 // End of File