javauis/nokiasound/javasrc/com/nokia/mid/sound/Sound.java
branchRCL_3
changeset 83 26b2b12093af
parent 77 7cee158cb8cd
child 84 0553e2305d00
equal deleted inserted replaced
77:7cee158cb8cd 83:26b2b12093af
     1 /*
       
     2 * Copyright (c) 2006 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:  Provides Sound API for playing tones and digitized audio.
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 package com.nokia.mid.sound;
       
    20 
       
    21 import com.nokia.mj.impl.rt.support.Finalizer;
       
    22 import java.util.Vector;
       
    23 import com.nokia.mj.impl.utils.Logger;
       
    24 import java.lang.Thread;
       
    25 
       
    26 /**
       
    27  * <p>
       
    28  * Provides simple Sound API for playing tones and digitized audio.
       
    29  * </p><p>
       
    30  * Since MIDP doesn't have any Sound API for games there is a need
       
    31  * for proprietary sound extension to support devices audio
       
    32  * capabilities. Every implementation has capability to produce tone
       
    33  * sounds (e.g. ringing tones), this is the minimum support. Currently
       
    34  * some products support or will support also digitized audio formats.
       
    35  * The Game sound API will support both buzzer and digitized audio.
       
    36  * Buzzer must be supported by all implementations. If implementation
       
    37  * doesn't have buzzer the buzzer tones are emulated.
       
    38  * </p>
       
    39  * Since implementations have different audio capabilities,
       
    40  * application can query which audio formats are supported by
       
    41  * implementation by calling {@link #getSupportedFormats()}.
       
    42  * <p>
       
    43  * All implementations need to support at least tone based sounds
       
    44  * (type FORMAT_TONE) via {@link #Sound(int freq, long duration)} and
       
    45  * {@link #init(int freq, long duration)}. In addition all implementations
       
    46  * must support Smart messaging ringingtone format (type FORMAT_TONE)
       
    47  * via {@link #Sound(byte[] data, int type)} and
       
    48  * {@link #init(byte[] data, int type) }.
       
    49  * <p>
       
    50  * Note that there is also work going on with Multimedia API that
       
    51  * is done in JCP as
       
    52  * <a href="http://www.jcp.org/jsr/detail/135.jsp">JSR 135</a>.
       
    53  * The standard Multimedia API
       
    54  * will replace the proprietary Game Sound API when it is ready. However
       
    55  * Sound API will be supported also later on but probably it will be
       
    56  * stated as deprecated.
       
    57  * </p>
       
    58  * @version 1.1
       
    59  * @see com.nokia.mid.ui.DeviceControl
       
    60  * @since 1.0
       
    61  */
       
    62 
       
    63 public class Sound
       
    64 {
       
    65 
       
    66     /**
       
    67      * Tone based format is used.
       
    68      *
       
    69      * init(int freq, int duration) puts sound into this format.
       
    70      * @since 1.0
       
    71      *
       
    72      */
       
    73     public static final int FORMAT_TONE = 1;
       
    74 
       
    75     /**
       
    76      * Content is in WAV format.
       
    77      * @since 1.0
       
    78      *
       
    79      */
       
    80     public static final int FORMAT_WAV = 5;
       
    81 
       
    82     /**
       
    83      * Sound is playing.
       
    84      * @since 1.0
       
    85      *
       
    86      */
       
    87     public static final int SOUND_PLAYING = 0;
       
    88 
       
    89     /**
       
    90      * Sound is stopped.
       
    91      * @since 1.0
       
    92      *
       
    93      */
       
    94     public static final int SOUND_STOPPED = 1;
       
    95 
       
    96     /**
       
    97      * Sound is uninitialized (released).
       
    98      * @since 1.0
       
    99      */
       
   100     public static final int SOUND_UNINITIALIZED = 3;
       
   101 
       
   102     /**
       
   103      * Sound is reinitialising
       
   104      */
       
   105     private static final int SOUND_REINITIALISING = 4;
       
   106 
       
   107     private static final int FORMAT_BEEP = 2;
       
   108     private static final int NOT_SUPPORTED_ERROR = 3;
       
   109 
       
   110     private static final int ERR_NOT_READY = -18;
       
   111     private static final int ERR_ARGUMENT  = -6;
       
   112 
       
   113     private int iHandle;
       
   114 
       
   115     private Finalizer iFinalizer;
       
   116     private int iCurrentType;
       
   117     private int iState;
       
   118     private int iGain = -1;
       
   119 
       
   120     Vector iSoundListeners = new Vector();
       
   121 
       
   122     private static Sound iPlayingSound;
       
   123 
       
   124     static
       
   125     {
       
   126         com.nokia.mj.impl.rt.support.Jvm.loadSystemLibrary("javanokiasound");
       
   127     }
       
   128 
       
   129     /**
       
   130      * Constructors initialize the Sound object so that it is ready for
       
   131      * playback. This constructor is used for initializing Sound
       
   132      * object based on byte array data. The data should contain the data
       
   133      * presented in the data format specified by type parameter. The Sound
       
   134      * class defines also generally supported types as constants.
       
   135      * <p>
       
   136      * All implementations need to support at least Nokia
       
   137      * Smart Messaging, Over the Air (OTA) ringingtone format.
       
   138      * The type of this format is FORMAT_TONE.
       
   139      * <p>
       
   140      * Note: some implementations can't throw exceptions about
       
   141      * sound data being corrupted or illegal during construction.
       
   142      * This will result that IllagalArgumentException is delayed until
       
   143      * play(int loop) method is called. Applications thus need to except
       
   144      * that IllegalArgumentException is thrown in this method or during
       
   145      * play method call.
       
   146      * <p>
       
   147      * @throws java.lang.IllegalArgumentException if the data can not be
       
   148      recognized to
       
   149      * given type or the type is unsupported or unknown
       
   150      * @throws java.lang.NullPointerException if the data is null
       
   151      * @since 1.0
       
   152      *
       
   153      */
       
   154     public Sound(byte[] data, int type)
       
   155     {
       
   156         Logger.LOG(Logger.EJavaUI, Logger.EInfo, "Sound Constructor");
       
   157         iFinalizer = registerForFinalization();
       
   158 
       
   159         iHandle = _create();
       
   160 
       
   161         iState = SOUND_UNINITIALIZED;
       
   162 
       
   163         init(data, type);
       
   164     }
       
   165 
       
   166     /**
       
   167      * Constructors initialize the Sound object so that it is ready for
       
   168      * playback. Sound is initialized as a simple tone based sound.
       
   169      * <p>
       
   170      * See method {@link #init(int freq, long duration)} for
       
   171      * freq value descriptions. See also a note on exceptions semantics in
       
   172      * {@link #init(int freq, long duration)}.
       
   173      *
       
   174      * @param freq a frequency value
       
   175      * @param duration the duration of the tone in milliseconds
       
   176      * @throws java.lang.IllegalArgumentException if parameter values are
       
   177      * illegal, freq is not in given range or duration is negative or zero
       
   178      * @since 1.0
       
   179      */
       
   180     public Sound(int freq, long duration)
       
   181     {
       
   182 
       
   183         iFinalizer = registerForFinalization();
       
   184         iHandle = _create();
       
   185 
       
   186         iState = SOUND_UNINITIALIZED;
       
   187 
       
   188         init(freq, duration);
       
   189     }
       
   190 
       
   191     /**
       
   192       * Called when this object is finalized, frees native resources
       
   193       */
       
   194 
       
   195     public Finalizer registerForFinalization()
       
   196     {
       
   197 
       
   198         return new Finalizer()
       
   199         {
       
   200             public void finalizeImpl()
       
   201             {
       
   202                 doFinalize();
       
   203             }
       
   204         };
       
   205     }
       
   206 
       
   207     void doFinalize()
       
   208     {
       
   209 
       
   210         if (iFinalizer == null)
       
   211         {
       
   212             return;
       
   213         }
       
   214         iFinalizer = null;
       
   215 
       
   216         if (iHandle > 0)
       
   217         {
       
   218             _dispose(iHandle);
       
   219         }
       
   220     }
       
   221 
       
   222     /**
       
   223      * Releases audio resources reserved by this object. After object
       
   224      * is released it goes to uninitialized state. This method should
       
   225      * be called when Sound object is not needed anymore.
       
   226      * @since 1.0
       
   227      */
       
   228     public void release()
       
   229     {
       
   230         if ((iState != SOUND_UNINITIALIZED) &&
       
   231                 (iState != SOUND_REINITIALISING))
       
   232         {
       
   233             iState = SOUND_REINITIALISING;
       
   234             soundStateChanged(SOUND_UNINITIALIZED);
       
   235         }
       
   236 
       
   237         _release(iHandle);
       
   238 
       
   239         iState = SOUND_UNINITIALIZED;
       
   240 
       
   241     }
       
   242 
       
   243     /**
       
   244      * Initializes Sound to play a simple beep.
       
   245      * <p>
       
   246      * Note: some implementations may not support the full frequency
       
   247      * scale defined in table below. They will throw
       
   248      * IllegalArgumentException instead for unsupported values. The
       
   249      * exception may also be delayed
       
   250      * until the play(int loop) method is called.
       
   251      * <p>
       
   252      * Following table describes some freq argument
       
   253      * values:
       
   254      * <pre>
       
   255      * Description            Frequency
       
   256      * Freq off               0
       
   257      * Ring freq A0           220
       
   258      * Ring freq B0b          233
       
   259      * Ring freq B0           247
       
   260      * Ring freq C0           262
       
   261      * Ring freq D0b          277
       
   262      * Ring freq D0           294
       
   263      * Ring freq E0b          311
       
   264      * Ring freq E0           330
       
   265      * Ring freq F0           349
       
   266      * Ring freq G0b          370
       
   267      * Ring freq G0           392
       
   268      * Ring freq A1b          416
       
   269      * Ring freq A1           440
       
   270      * Ring freq B1b          466
       
   271      * Ring freq B1           494
       
   272      * Ring freq C1           523
       
   273      * Ring freq D1b          554
       
   274      * Ring freq D1           587
       
   275      * Ring freq E1b          622
       
   276      * Ring freq E1           659
       
   277      * Ring freq F1           698
       
   278      * Ring freq G1b          740
       
   279      * Ring freq G1           784
       
   280      * Ring freq A2b          831
       
   281      * Ring freq A2           880
       
   282      * Ring freq B2b          932
       
   283      * Ring freq B2           988
       
   284      * Ring freq C2           1047
       
   285      * Ring freq D2b          1109
       
   286      * Ring freq D2           1175
       
   287      * Ring freq E2b          1245
       
   288      * Ring freq E2           1319
       
   289      * Ring freq F2           1397
       
   290      * Ring freq G2b          1480
       
   291      * Ring freq G2           1568
       
   292      * Ring freq A3b          1661
       
   293      * Ring freq A3           1760
       
   294      * Ring freq B3b          1865
       
   295      * Ring freq B3           1976
       
   296      * Ring freq C3           2093
       
   297      * Ring freq D3b          2217
       
   298      * Ring freq D3           2349
       
   299      * Ring freq E3b          2489
       
   300      * Ring freq E3           2637
       
   301      * Ring freq F3           2794
       
   302      * Ring freq G3b          2960
       
   303      * Ring freq G3           3136
       
   304      * Ring freq A4b          3322
       
   305      * Ring freq A4           3520
       
   306      * Ring freq B4b          3729
       
   307      * Ring freq B4           3951
       
   308      * Ring freq C4           4186
       
   309      * Ring freq D4b          4434
       
   310      * Ring freq D4           4698
       
   311      * Ring freq E4b          4978
       
   312      * Ring freq E4           5274
       
   313      * Ring freq F4           5588
       
   314      * Ring freq G4b          5920
       
   315      * Ring freq G4           6272
       
   316      * Ring freq A5b          6644
       
   317      * Ring freq A5           7040
       
   318      * Ring freq B5b          7458
       
   319      * Ring freq B5           7902
       
   320      * Ring freq C5           8372
       
   321      * Ring freq D5b          8870
       
   322      * Ring freq D5           9396
       
   323      * Ring freq E5b          9956
       
   324      * Ring freq E5           10548
       
   325      * Ring freq F5           11176
       
   326      * Ring freq G5b          11840
       
   327      * Ring freq G5           12544
       
   328      * Ring freq A6b          13288
       
   329      *
       
   330      * </pre>
       
   331      *
       
   332      * @param duration length of the beep in milliseconds
       
   333      * @param freq frequency to be played
       
   334      * @throws java.lang.IllegalArgumentException if parameter values are
       
   335      * illegal, freq is not in given range or duration is negative or zero
       
   336      * @since 1.0
       
   337      */
       
   338     public void init(int freq, long duration)
       
   339     {
       
   340         if (duration < 1 || duration > 10000000)
       
   341         {
       
   342             throw(new IllegalArgumentException(
       
   343                       "Bad duration value, must be 1-10000000"));
       
   344         }
       
   345         if (freq < 0 || freq > 15000)
       
   346         {
       
   347             throw(new IllegalArgumentException(
       
   348                       "Bad frequency value, must be 0-15000"));
       
   349         }
       
   350         // if the uninitialised event is sent from native side, it reaches
       
   351         // listener too late in TCK test sound8004, thus we send the event
       
   352         // already here
       
   353         if ((iState != SOUND_UNINITIALIZED) &&
       
   354                 (iState != SOUND_REINITIALISING))
       
   355         {
       
   356             iState = SOUND_REINITIALISING;
       
   357             soundStateChanged(SOUND_UNINITIALIZED);
       
   358         } // end of if (iState != SOUND_UNINITIALIZED)
       
   359 
       
   360         iCurrentType = FORMAT_BEEP;
       
   361         int err = _init(iHandle, iCurrentType, null, freq, duration);
       
   362         if (err == ERR_NOT_READY)
       
   363         {
       
   364             throw new RuntimeException(Integer.toString(err));
       
   365         }
       
   366         else if (err == ERR_ARGUMENT)
       
   367         {
       
   368             throw new IllegalArgumentException("Data is invalid");            
       
   369         }
       
   370         iState = SOUND_STOPPED;
       
   371     }
       
   372 
       
   373     /**
       
   374      * Initializes Sound object based on byte
       
   375      * array data. The data should contain the data presented in the data
       
   376      * format specified by type parameter. The Sound class defines also
       
   377      * generally supported types as constants.
       
   378      * <p>
       
   379      * All implementations need to support at least Nokia
       
   380      * Smart Messaging, Over the Air (OTA) ringingtone format.
       
   381      * The type of this format is FORMAT_TONE.
       
   382      * <p>
       
   383      * Note: some implementations can't throw exceptions about
       
   384      * sound data being corrupted or illegal during this method call.
       
   385      * This will result that IllagalArgumentException is delayed until
       
   386      * play(int loop) method is called. Applications thus need to except
       
   387      * that IllegalArgumentException is thrown in this method or during
       
   388      * play method call.
       
   389      * <p>
       
   390      * @param data a byte array containing the data to be played
       
   391      * @param type type of the audio
       
   392      * @throws java.lang.IllegalArgumentException if the data can not be
       
   393      recognized to
       
   394      * given type or the type is unsupported or unknown
       
   395      * @throws java.lang.NullPointerException if the data is null
       
   396      * @since 1.0
       
   397      */
       
   398     public void init(byte[] data, int type)
       
   399     {
       
   400         if (!(type == FORMAT_WAV || type == FORMAT_TONE))
       
   401         {
       
   402             throw(new IllegalArgumentException("Type is not supported"));
       
   403         }
       
   404         if (data == null)
       
   405         {
       
   406             throw(new NullPointerException("Data is null"));
       
   407         }
       
   408 
       
   409         if ((iState != SOUND_UNINITIALIZED) &&
       
   410                 (iState != SOUND_REINITIALISING))
       
   411         {
       
   412             iState = SOUND_REINITIALISING;
       
   413             soundStateChanged(SOUND_UNINITIALIZED);
       
   414         } // end of if (iState != SOUND_UNINITIALIZED)
       
   415 
       
   416         iCurrentType = type;
       
   417         int err = _init(iHandle, iCurrentType, data, 0, 0);
       
   418         if (err == ERR_NOT_READY || err == ERR_ARGUMENT )
       
   419         {
       
   420             throw new IllegalArgumentException("Data is invalid");
       
   421         }
       
   422 
       
   423         iState = SOUND_STOPPED;
       
   424     }
       
   425 
       
   426 
       
   427     /**
       
   428      * Get the current state of the Sound object.
       
   429      *
       
   430      * @return current state, SOUND_PLAYING, SOUND_STOPPED or
       
   431      SOUND_UNINITIALIZED
       
   432      * @since 1.0
       
   433      *
       
   434      */
       
   435     public int getState()
       
   436     {
       
   437         if (iState == SOUND_REINITIALISING)
       
   438         {
       
   439             return SOUND_UNINITIALIZED;
       
   440         }
       
   441 
       
   442         iState = _getState(iHandle);
       
   443         switch (iState)
       
   444         {
       
   445         case(0):  // ENotReady
       
   446         case(4):  // EInitialising
       
   447             iState = SOUND_UNINITIALIZED;
       
   448             break;
       
   449         case(1):  // EReadyToPlay
       
   450             iState = SOUND_STOPPED;
       
   451             break;
       
   452         case(2):  // EPlaying
       
   453             iState = SOUND_PLAYING;
       
   454             break;
       
   455         default:
       
   456         }
       
   457         return iState;
       
   458     }
       
   459 
       
   460     /**
       
   461      * This method is used for starting the playback from the beginning of a
       
   462      * sound object. The loop parameter defined the loop count for playback.
       
   463      * Argument zero (0) means continuos looping. For uninitialized sound the
       
   464      * play method doesn't do anything and silently returns. For stopped and
       
   465      * playing sounds the playback starts from beginning of the sound with new
       
   466      * looping information.
       
   467      * <p>
       
   468      * This method will throw IllegalStateException if playback cannot be
       
   469      * started since all channels are in use, or playback is not possible
       
   470      * because there is more higher priority system sounds being played.
       
   471      * <p>
       
   472      * If Sound playback is possible this method will return immediately and
       
   473      * thus will not block the calling thread during the playback. If any error
       
   474      * that prevents the playback is encountered during the playback, the
       
   475      * playback is silently stopped as if called to the stop method.
       
   476      *
       
   477      * @param number number of times audio is played. Value 0 plays audio in
       
   478      * continous loop.
       
   479      * @throws java.lang.IllegalStateException if the sound object cannot be
       
   480      * played because all the channels are already in use.
       
   481      * @throws java.lang.IllegalArgumentException if the loop value is negative,
       
   482      * or if sound values/date is illegal or corrupted.
       
   483      * @since 1.0
       
   484      *
       
   485      */
       
   486     public void play(int loop) throws IllegalArgumentException
       
   487     {
       
   488         if (loop < 0)
       
   489         {
       
   490             throw(new IllegalArgumentException("Negative loop value"));
       
   491         }
       
   492         if (iState == SOUND_REINITIALISING)
       
   493         {
       
   494             return;
       
   495         } // end of if (iState == SOUND_REINITIALISING)
       
   496 
       
   497         if (iPlayingSound != null)
       
   498         {
       
   499             if (iPlayingSound.getState() == SOUND_PLAYING)
       
   500             {
       
   501                 iPlayingSound.stop();
       
   502             }
       
   503         } // end of if (iPlayingSound != null)
       
   504 
       
   505         int error = _play(iHandle, loop);
       
   506         if ((error == NOT_SUPPORTED_ERROR))
       
   507         {
       
   508             throw(new IllegalArgumentException("Sound is not supported"));
       
   509         }
       
   510         iPlayingSound = this;
       
   511     }
       
   512 
       
   513     /**
       
   514      *  The method will stop the sound playback, storing the current position.
       
   515      *  For sound that has never been started (may be uninitialized), or is
       
   516      *  currently being stopped the method call doesn't do anything and returns
       
   517      *  silently.
       
   518      *
       
   519      *  Note that for tone based sounds it is not possible to resume from
       
   520      *  position the sound was stopped at, to be specific, stop will reset
       
   521      *  the position to the beginning of the sound.
       
   522      *  @since 1.0
       
   523      */
       
   524     public void stop()
       
   525     {
       
   526         if (iState == SOUND_REINITIALISING)
       
   527         {
       
   528             return;
       
   529         } // end of if (iState == SOUND_REINITIALISING)
       
   530         _stop(iHandle);
       
   531     }
       
   532 
       
   533     /**
       
   534      *  The method will continue the stopped sound object from the position it
       
   535      *  was stopped to. For sound that has never been started (may be
       
   536      *  uninitialized), or is currently being played the method call doesn't
       
   537      *  do anything.
       
   538      *  <p>
       
   539      *  Note: For tone based sounds the resume starts the sound from the
       
   540      *  beginning of the sound clip.
       
   541      *  @since 1.0
       
   542      *
       
   543      */
       
   544     public void resume()
       
   545     {
       
   546         if (iState == SOUND_REINITIALISING)
       
   547         {
       
   548             return;
       
   549         } // end of if (iState == SOUND_REINITIALISING)
       
   550         _resume(iHandle);
       
   551     }
       
   552 
       
   553     /**
       
   554      * Sets the gain for the sound object. The gain is a value between
       
   555      * 0 and 255. Implementation scales the gain value to the limits it
       
   556      * supports. Notice that any gain value > 0 should result a gain
       
   557      * value > 0. If the gain is smaller than this minimum value then
       
   558      * gain is set to 0, if the gain greater than this maximum value
       
   559      * then the gain is set to maximum value (255).
       
   560      *
       
   561      * @param gain gain value: 0 - 255
       
   562      * @throws java.lang.IllegalArgumentException if the gain not 0 - 255
       
   563      * @since 1.0
       
   564      */
       
   565     public void setGain(int gain)
       
   566     {
       
   567         if (iState == SOUND_REINITIALISING)
       
   568         {
       
   569             return;
       
   570         } // end of if (iState == SOUND_REINITIALISING)
       
   571         if (gain < 0)
       
   572         {
       
   573             gain = 0;
       
   574         }
       
   575         else if (gain > 255)
       
   576         {
       
   577             gain = 255;
       
   578         }
       
   579         iGain = gain;
       
   580         _setVolume(iHandle, iGain);
       
   581     }
       
   582 
       
   583     /**
       
   584      * Get the gain (or volume) of Sound object. The gain is a value
       
   585      * between 0 and 255. System returns a scaled value based on the
       
   586      * limits it supports. Notice that any system gain value > 0 should
       
   587      * return a gain value > 0.
       
   588      *
       
   589      * @return gain value 0 - 255
       
   590      * @since 1.0
       
   591      *
       
   592      */
       
   593     public int getGain()
       
   594     {
       
   595         if (iGain == -1)
       
   596         {
       
   597             return _volume(iHandle);
       
   598         }
       
   599         // we have previously set gain
       
   600         return iGain;
       
   601     }
       
   602 
       
   603     /**
       
   604      * Returns number of concurrent sounds the device can play for
       
   605      * specific audio type. Returns 1 if only one sound can be played
       
   606      * at a time. Notice that most types use same channel resources.
       
   607      * @return total number of available channels.
       
   608      * @param type the media type
       
   609      * @throws java.lang.IllegalArgumentException if the type is unsupported
       
   610      * or unknown
       
   611      * @since 1.0
       
   612      */
       
   613     public static int getConcurrentSoundCount(int type)
       
   614     {
       
   615         if ((type != FORMAT_TONE) && (type != FORMAT_WAV))
       
   616         {
       
   617             throw(new IllegalArgumentException("Type is not supported"));
       
   618         }
       
   619 
       
   620         return 1;
       
   621     }
       
   622 
       
   623     /**
       
   624      *  Returns the supported audio formats as an int array.
       
   625      *
       
   626      *  @return an array containing supported audio formats as
       
   627      *  int values (e.g. FORMAT_TONE, FORMAT_WAV),
       
   628      *  or an empty array if no audio formats are supported.
       
   629      *  @since 1.0
       
   630      */
       
   631     static public int[] getSupportedFormats()
       
   632     {
       
   633         return(new int[] { FORMAT_TONE, FORMAT_WAV });
       
   634     }
       
   635 
       
   636     /**
       
   637      *  Registeres a listener for playback state notifications.
       
   638      *  @see com.nokia.mid.sound.SoundListener
       
   639      *  @param listener a listener that is notified when state
       
   640      *  changes occur or null if listener is to be
       
   641      *  removed.
       
   642      *  @since 1.0
       
   643      *
       
   644      */
       
   645     public void setSoundListener(SoundListener listener)
       
   646     {
       
   647         iSoundListeners.addElement(listener);
       
   648     }
       
   649 
       
   650     /**
       
   651      * Callback method when sound state changes
       
   652      *
       
   653      */
       
   654     public void soundStateChanged(final int event)
       
   655     {
       
   656         /*
       
   657         for(int i = 0; i < iSoundListeners.size(); i++)
       
   658         {
       
   659           ((SoundListener)iSoundListeners.elementAt(i)).soundStateChanged(this, event);
       
   660         }
       
   661         */
       
   662         //Notify SoundState Listeners in a separate thread, so that application doesn't
       
   663         //block main thread
       
   664         new Thread(new Runnable()
       
   665         {
       
   666             public void run()
       
   667             {
       
   668                 notifySoundStateListeners(event);
       
   669             }
       
   670         }).start();
       
   671     }
       
   672 
       
   673     /**
       
   674      * Notify Sound State Listeners
       
   675      */
       
   676     public synchronized void notifySoundStateListeners(int event)
       
   677     {
       
   678         for (int i = 0; i < iSoundListeners.size(); i++)
       
   679         {
       
   680             ((SoundListener)iSoundListeners.elementAt(i)).soundStateChanged(this, event);
       
   681         }
       
   682     }
       
   683 
       
   684     private native void _dispose(int aHandle);
       
   685     private native int _create();
       
   686     private native int _init(int aHandle, int aType,
       
   687                              byte[] aData,
       
   688                              int aFrequency, long aDuration);
       
   689     private native void _release(int aHandle);
       
   690     private native int _play(int aHandle, int aLoop);
       
   691     private native void _stop(int aHandle);
       
   692     private native void _resume(int aHandle);
       
   693     private native void _setVolume(int aHandle, int aVolume);
       
   694     private native int _volume(int aHandle);
       
   695     private native int _getState(int aHandle);
       
   696 
       
   697 } //End of Sound class
       
   698