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