1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | package org.chromium.media; |
6 | |
7 | import android.Manifest.permission; |
8 | import android.content.Context; |
9 | import android.content.pm.PackageManager; |
10 | import android.media.AudioManager; |
11 | import android.media.MediaPlayer; |
12 | |
13 | import org.chromium.base.CalledByNative; |
14 | import org.chromium.base.JNINamespace; |
15 | |
16 | // This class implements all the listener interface for android mediaplayer. |
17 | // Callbacks will be sent to the native class for processing. |
18 | @JNINamespace("media") |
19 | class MediaPlayerListener implements MediaPlayer.OnPreparedListener, |
20 | MediaPlayer.OnCompletionListener, |
21 | MediaPlayer.OnBufferingUpdateListener, |
22 | MediaPlayer.OnSeekCompleteListener, |
23 | MediaPlayer.OnVideoSizeChangedListener, |
24 | MediaPlayer.OnErrorListener, |
25 | AudioManager.OnAudioFocusChangeListener { |
26 | // These values are mirrored as enums in media/base/android/media_player_bridge.h. |
27 | // Please ensure they stay in sync. |
28 | private static final int MEDIA_ERROR_FORMAT = 0; |
29 | private static final int MEDIA_ERROR_DECODE = 1; |
30 | private static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 2; |
31 | private static final int MEDIA_ERROR_INVALID_CODE = 3; |
32 | |
33 | // These values are copied from android media player. |
34 | public static final int MEDIA_ERROR_MALFORMED = -1007; |
35 | public static final int MEDIA_ERROR_TIMED_OUT = -110; |
36 | |
37 | // Used to determine the class instance to dispatch the native call to. |
38 | private int mNativeMediaPlayerListener = 0; |
39 | private final Context mContext; |
40 | |
41 | private MediaPlayerListener(int nativeMediaPlayerListener, Context context) { |
42 | mNativeMediaPlayerListener = nativeMediaPlayerListener; |
43 | mContext = context; |
44 | } |
45 | |
46 | @Override |
47 | public boolean onError(MediaPlayer mp, int what, int extra) { |
48 | int errorType; |
49 | switch (what) { |
50 | case MediaPlayer.MEDIA_ERROR_UNKNOWN: |
51 | switch (extra) { |
52 | case MEDIA_ERROR_MALFORMED: |
53 | errorType = MEDIA_ERROR_DECODE; |
54 | break; |
55 | case MEDIA_ERROR_TIMED_OUT: |
56 | errorType = MEDIA_ERROR_INVALID_CODE; |
57 | break; |
58 | default: |
59 | errorType = MEDIA_ERROR_FORMAT; |
60 | break; |
61 | } |
62 | break; |
63 | case MediaPlayer.MEDIA_ERROR_SERVER_DIED: |
64 | errorType = MEDIA_ERROR_DECODE; |
65 | break; |
66 | case MediaPlayer.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK: |
67 | errorType = MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK; |
68 | break; |
69 | default: |
70 | // There are some undocumented error codes for android media player. |
71 | // For example, when surfaceTexture got deleted before we setVideoSuface |
72 | // to NULL, mediaplayer will report error -38. These errors should be ignored |
73 | // and not be treated as an error to webkit. |
74 | errorType = MEDIA_ERROR_INVALID_CODE; |
75 | break; |
76 | } |
77 | nativeOnMediaError(mNativeMediaPlayerListener, errorType); |
78 | return true; |
79 | } |
80 | |
81 | @Override |
82 | public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { |
83 | nativeOnVideoSizeChanged(mNativeMediaPlayerListener, width, height); |
84 | } |
85 | |
86 | @Override |
87 | public void onSeekComplete(MediaPlayer mp) { |
88 | nativeOnSeekComplete(mNativeMediaPlayerListener); |
89 | } |
90 | |
91 | @Override |
92 | public void onBufferingUpdate(MediaPlayer mp, int percent) { |
93 | nativeOnBufferingUpdate(mNativeMediaPlayerListener, percent); |
94 | } |
95 | |
96 | @Override |
97 | public void onCompletion(MediaPlayer mp) { |
98 | nativeOnPlaybackComplete(mNativeMediaPlayerListener); |
99 | } |
100 | |
101 | @Override |
102 | public void onPrepared(MediaPlayer mp) { |
103 | nativeOnMediaPrepared(mNativeMediaPlayerListener); |
104 | } |
105 | |
106 | @Override |
107 | public void onAudioFocusChange(int focusChange) { |
108 | if (focusChange == AudioManager.AUDIOFOCUS_LOSS || |
109 | focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) { |
110 | nativeOnMediaInterrupted(mNativeMediaPlayerListener); |
111 | } |
112 | } |
113 | |
114 | @CalledByNative |
115 | public void releaseResources() { |
116 | if (mContext != null) { |
117 | // Unregister the wish for audio focus. |
118 | AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); |
119 | if (am != null) { |
120 | am.abandonAudioFocus(this); |
121 | } |
122 | } |
123 | } |
124 | |
125 | @CalledByNative |
126 | private static MediaPlayerListener create(int nativeMediaPlayerListener, |
127 | Context context, MediaPlayerBridge mediaPlayerBridge) { |
128 | final MediaPlayerListener listener = |
129 | new MediaPlayerListener(nativeMediaPlayerListener, context); |
130 | mediaPlayerBridge.setOnBufferingUpdateListener(listener); |
131 | mediaPlayerBridge.setOnCompletionListener(listener); |
132 | mediaPlayerBridge.setOnErrorListener(listener); |
133 | mediaPlayerBridge.setOnPreparedListener(listener); |
134 | mediaPlayerBridge.setOnSeekCompleteListener(listener); |
135 | mediaPlayerBridge.setOnVideoSizeChangedListener(listener); |
136 | |
137 | AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); |
138 | am.requestAudioFocus( |
139 | listener, |
140 | AudioManager.STREAM_MUSIC, |
141 | |
142 | // Request permanent focus. |
143 | AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK); |
144 | return listener; |
145 | } |
146 | |
147 | /** |
148 | * See media/base/android/media_player_listener.cc for all the following functions. |
149 | */ |
150 | private native void nativeOnMediaError( |
151 | int nativeMediaPlayerListener, |
152 | int errorType); |
153 | |
154 | private native void nativeOnVideoSizeChanged( |
155 | int nativeMediaPlayerListener, |
156 | int width, int height); |
157 | |
158 | private native void nativeOnBufferingUpdate( |
159 | int nativeMediaPlayerListener, |
160 | int percent); |
161 | |
162 | private native void nativeOnMediaPrepared(int nativeMediaPlayerListener); |
163 | |
164 | private native void nativeOnPlaybackComplete(int nativeMediaPlayerListener); |
165 | |
166 | private native void nativeOnSeekComplete(int nativeMediaPlayerListener); |
167 | |
168 | private native void nativeOnMediaInterrupted(int nativeMediaPlayerListener); |
169 | } |