1717import android .content .Context ;
1818import android .content .res .AssetFileDescriptor ;
1919import android .media .AudioManager ;
20+ import android .media .AudioManager .OnAudioFocusChangeListener ;
2021import android .media .MediaPlayer ;
2122import android .net .Uri ;
2223import android .webkit .URLUtil ;
@@ -63,6 +64,8 @@ public class MediaPlayerWrapper
6364
6465 protected KrollProxy proxy ;
6566 protected MediaPlayer mp ;
67+ protected AudioManager am ;
68+ protected Context context ;
6669 protected float volume ;
6770 protected boolean speakerphone ;
6871 protected boolean playOnResume ;
@@ -79,6 +82,9 @@ public MediaPlayerWrapper(KrollProxy proxy) throws IOException
7982 {
8083 this .initialize ();
8184 }
85+
86+ context = proxy .getActivity ().getBaseContext ();
87+ am = (AudioManager ) context .getSystemService (Context .AUDIO_SERVICE );
8288 }
8389
8490 protected void initialize ()
@@ -89,7 +95,6 @@ protected void initialize()
8995 mp = new MediaPlayer ();
9096 String url = TiConvert .toString (proxy .getProperty (TiC .PROPERTY_URL ));
9197 if (URLUtil .isAssetUrl (url )) {
92- Context context = proxy .getActivity ().getApplicationContext ();
9398 String path = url .substring (TiConvert .ASSET_URL .length ());
9499 AssetFileDescriptor afd = null ;
95100 try {
@@ -179,6 +184,8 @@ public void pause()
179184 {
180185 try {
181186 if (mp != null ) {
187+ am .setMode (AudioManager .USE_DEFAULT_STREAM_TYPE );
188+ am .setSpeakerphoneOn (true );
182189 if (mp .isPlaying ()) {
183190 if (DBG ) {
184191 Log .d (LCAT ,"audio is playing, pause" );
@@ -208,6 +215,46 @@ public void play()
208215 if (DBG ) {
209216 Log .d (LCAT , "Play: Volume set to " + volume );
210217 }
218+
219+ OnAudioFocusChangeListener focusChangeListener =
220+ new OnAudioFocusChangeListener () {
221+ public void onAudioFocusChange (int focusChange ) {
222+ switch (focusChange ) {
223+
224+ case (AudioManager .AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK ) :
225+ // Lower the volume while ducking.
226+ mp .setVolume (0.2f , 0.2f );
227+ break ;
228+ case (AudioManager .AUDIOFOCUS_LOSS_TRANSIENT ) :
229+ pause ();
230+ break ;
231+
232+ case (AudioManager .AUDIOFOCUS_LOSS ) :
233+ stop ();
234+ break ;
235+
236+ case (AudioManager .AUDIOFOCUS_GAIN ) :
237+ // Return the volume to normal and resume if paused.
238+ mp .setVolume (1f , 1f );
239+ play ();
240+ break ;
241+
242+ default :
243+ // Nothing
244+ break ;
245+ }
246+ }
247+ };
248+
249+ am .requestAudioFocus (focusChangeListener , (speakerphone ) ? AudioManager .STREAM_MUSIC : AudioManager .STREAM_VOICE_CALL , AudioManager .AUDIOFOCUS_GAIN );
250+
251+ if (!speakerphone ) {
252+ am .setMode (AudioManager .STREAM_VOICE_CALL );
253+ am .setSpeakerphoneOn (false );
254+ } else {
255+ am .setSpeakerphoneOn (true );
256+ }
257+
211258 mp .start ();
212259 setState (STATE_PLAYING );
213260 paused = false ;
@@ -259,8 +306,6 @@ public void release()
259306 * Restore default stream type
260307 */
261308 if (android .os .Build .VERSION .SDK_INT > android .os .Build .VERSION_CODES .KITKAT ) {
262- Context context = proxy .getActivity ().getBaseContext ();
263- AudioManager am = (AudioManager ) context .getSystemService (Context .AUDIO_SERVICE );
264309 am .setMode (AudioManager .USE_DEFAULT_STREAM_TYPE );
265310 am .setSpeakerphoneOn (true );
266311 }
@@ -353,31 +398,30 @@ public void setTime(int position)
353398 proxy .setProperty (TiC .PROPERTY_TIME , position );
354399 }
355400
401+ /**
402+ * Sets the speaker mode. This can only be called once per instance of the player (i.e. when
403+ * it is initializing).
404+ */
356405 public void setSpeakerphoneOn () {
357406 if (mp != null ) {
358407
359- Context context = proxy .getActivity ().getBaseContext ();
360- AudioManager am = (AudioManager ) context .getSystemService (Context .AUDIO_SERVICE );
361-
362408 speakerphone = true ;
363409 if (proxy .hasProperty ("speakerphone" )) {
364410 speakerphone = TiConvert .toBoolean (proxy .getProperty ("speakerphone" ));
365411 }
366412
367- if (speakerphone ) {
413+ if (speakerphone )
414+ {
368415 mp .setAudioStreamType (AudioManager .STREAM_MUSIC );
369- if ( android . os . Build . VERSION . SDK_INT > android . os . Build . VERSION_CODES . KITKAT ) {
370- am .setMode ( AudioManager . STREAM_MUSIC );
371- am . setSpeakerphoneOn ( true );
372- }
373-
374- } else {
416+ am . setMode ( AudioManager . USE_DEFAULT_STREAM_TYPE );
417+ am .setSpeakerphoneOn ( true );
418+ }
419+
420+ else
421+ {
375422 mp .setAudioStreamType (AudioManager .STREAM_VOICE_CALL );
376- if (android .os .Build .VERSION .SDK_INT > android .os .Build .VERSION_CODES .KITKAT ) {
377- am .setMode (AudioManager .MODE_IN_CALL );
378- am .setSpeakerphoneOn (false );
379- }
380-
423+ am .setMode (AudioManager .STREAM_VOICE_CALL );
424+ am .setSpeakerphoneOn (false );
381425 }
382426 }
383427 }
@@ -387,7 +431,8 @@ private void setState(int state)
387431 proxy .setProperty ("state" , state );
388432 String stateDescription = "" ;
389433
390- switch (state ) {
434+ switch (state )
435+ {
391436 case STATE_BUFFERING :
392437 stateDescription = STATE_BUFFERING_DESC ;
393438 break ;
@@ -418,7 +463,8 @@ private void setState(int state)
418463 }
419464
420465 proxy .setProperty ("stateDescription" , stateDescription );
421- if (DBG ) {
466+ if (DBG )
467+ {
422468 Log .d (LCAT , "Audio state changed: " + stateDescription );
423469 }
424470
@@ -431,33 +477,49 @@ private void setState(int state)
431477
432478 public void stop ()
433479 {
434- try {
435- if (mp != null ) {
480+ try
481+ {
482+ if (mp != null )
483+ {
436484
437- if (mp .isPlaying () || isPaused ()) {
438- if (DBG ) {
485+ if (mp .isPlaying () || isPaused ())
486+ {
487+ if (DBG )
488+ {
439489 Log .d (LCAT , "audio is playing, stop()" );
440490 }
441491 setState (STATE_STOPPING );
442492 mp .stop ();
493+
494+ am .setMode (AudioManager .USE_DEFAULT_STREAM_TYPE );
495+ am .setSpeakerphoneOn (true );
496+
443497 setState (STATE_STOPPED );
444498 //if (remote) {
445499 stopProgressTimer ();
446500 //}
447- try {
501+ try
502+ {
448503 mp .prepare ();
449- } catch (IOException e ) {
504+ }
505+ catch (IOException e )
506+ {
450507 Log .e (LCAT ,"Error while preparing audio after stop(). Ignoring." );
451- } catch (IllegalStateException e ) {
508+ }
509+ catch (IllegalStateException e )
510+ {
452511 Log .w (LCAT , "Error while preparing audio after stop(). Ignoring." );
453512 }
454513 }
455514
456- if (isPaused ()) {
515+ if (isPaused ())
516+ {
457517 paused = false ;
458518 }
459519 }
460- } catch (Throwable t ) {
520+ }
521+ catch (Throwable t )
522+ {
461523 Log .e (LCAT , "Error : " , t );
462524 }
463525 }
@@ -466,6 +528,8 @@ public void stop()
466528 public void onCompletion (MediaPlayer mp )
467529 {
468530 proxy .fireEvent (EVENT_COMPLETE , null );
531+ am .setMode (AudioManager .USE_DEFAULT_STREAM_TYPE );
532+ am .setSpeakerphoneOn (true );
469533 stop ();
470534 }
471535
@@ -474,7 +538,8 @@ public boolean onInfo(MediaPlayer mp, int what, int extra)
474538 {
475539 String msg = "OnInfo Unknown media issue." ;
476540
477- switch (what ) {
541+ switch (what )
542+ {
478543 case MediaPlayer .MEDIA_INFO_BAD_INTERLEAVING :
479544 msg = "Stream not interleaved or interleaved improperly." ;
480545 break ;
@@ -506,7 +571,8 @@ public boolean onError(MediaPlayer mp, int what, int extra)
506571 {
507572 int code = 0 ;
508573 String msg = "Unknown media error." ;
509- if (what == MediaPlayer .MEDIA_ERROR_SERVER_DIED ) {
574+ if (what == MediaPlayer .MEDIA_ERROR_SERVER_DIED )
575+ {
510576 msg = "Media server died" ;
511577 }
512578 release ();
@@ -522,7 +588,8 @@ public boolean onError(MediaPlayer mp, int what, int extra)
522588 @ Override
523589 public void onBufferingUpdate (MediaPlayer mp , int percent )
524590 {
525- if (DBG ) {
591+ if (DBG )
592+ {
526593 Log .d (LCAT , "Buffering: " + percent + "%" );
527594 }
528595
@@ -531,31 +598,41 @@ public void onBufferingUpdate(MediaPlayer mp, int percent)
531598 proxy .fireEvent (EVENT_BUFFERING , data );
532599 }
533600
534- public int getCurrentPosition () {
535- if (mp != null ) {
601+ public int getCurrentPosition ()
602+ {
603+ if (mp != null )
604+ {
536605 return mp .getCurrentPosition ();
537- } else {
606+ }
607+ else
608+ {
538609 return 0 ;
539610 }
540611 }
541612
542613
543614 private void startProgressTimer ()
544615 {
545- if (progressTimer == null ) {
616+ if (progressTimer == null )
617+ {
546618 progressTimer = new Timer (true );
547- } else {
619+ }
620+ else
621+ {
548622 progressTimer .cancel ();
549623 progressTimer = new Timer (true );
550624 }
551625
552626 progressTimer .schedule (new TimerTask ()
553627 {
554628 @ Override
555- public void run () {
556- if (mp != null && mp .isPlaying ()) {
629+ public void run ()
630+ {
631+ if (mp != null && mp .isPlaying ())
632+ {
557633 int position = mp .getCurrentPosition ();
558- if (DBG ) {
634+ if (DBG )
635+ {
559636 Log .d (LCAT , "Progress: " + position );
560637 }
561638 KrollDict event = new KrollDict ();
@@ -568,15 +645,17 @@ public void run() {
568645
569646 private void stopProgressTimer ()
570647 {
571- if (progressTimer != null ) {
648+ if (progressTimer != null )
649+ {
572650 progressTimer .cancel ();
573651 progressTimer = null ;
574652 }
575653 }
576654
577655 public void onDestroy ()
578656 {
579- if (mp != null ) {
657+ if (mp != null )
658+ {
580659 mp .release ();
581660 mp = null ;
582661 }
@@ -585,8 +664,10 @@ public void onDestroy()
585664
586665 public void onPause ()
587666 {
588- if (mp != null ) {
589- if (isPlaying ()) {
667+ if (mp != null )
668+ {
669+ if (isPlaying ())
670+ {
590671 pause ();
591672 playOnResume = true ;
592673 }
@@ -595,8 +676,10 @@ public void onPause()
595676
596677 public void onResume ()
597678 {
598- if (mp != null ) {
599- if (playOnResume ) {
679+ if (mp != null )
680+ {
681+ if (playOnResume )
682+ {
600683 play ();
601684 playOnResume = false ;
602685 }
0 commit comments