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