PageRenderTime 89ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 0ms

/frameworks/base/media/java/android/media/AsyncPlayer.java

https://gitlab.com/brian0218/rk3066_r-box_android4.2.2_sdk
Java | 242 lines | 152 code | 23 blank | 67 comment | 30 complexity | f9721c634232582714ed59d2ae7011eb MD5 | raw file
  1. /*
  2. * Copyright (C) 2008 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package android.media;
  17. import android.content.Context;
  18. import android.net.Uri;
  19. import android.os.PowerManager;
  20. import android.os.SystemClock;
  21. import android.util.Log;
  22. import java.io.IOException;
  23. import java.lang.IllegalStateException;
  24. import java.util.LinkedList;
  25. /**
  26. * Plays a series of audio URIs, but does all the hard work on another thread
  27. * so that any slowness with preparing or loading doesn't block the calling thread.
  28. */
  29. public class AsyncPlayer {
  30. private static final int PLAY = 1;
  31. private static final int STOP = 2;
  32. private static final boolean mDebug = false;
  33. private static final class Command {
  34. int code;
  35. Context context;
  36. Uri uri;
  37. boolean looping;
  38. int stream;
  39. long requestTime;
  40. public String toString() {
  41. return "{ code=" + code + " looping=" + looping + " stream=" + stream
  42. + " uri=" + uri + " }";
  43. }
  44. }
  45. private final LinkedList<Command> mCmdQueue = new LinkedList();
  46. private void startSound(Command cmd) {
  47. // Preparing can be slow, so if there is something else
  48. // is playing, let it continue until we're done, so there
  49. // is less of a glitch.
  50. try {
  51. if (mDebug) Log.d(mTag, "Starting playback");
  52. MediaPlayer player = new MediaPlayer();
  53. player.setAudioStreamType(cmd.stream);
  54. player.setDataSource(cmd.context, cmd.uri);
  55. player.setLooping(cmd.looping);
  56. player.prepare();
  57. player.start();
  58. if (mPlayer != null) {
  59. mPlayer.release();
  60. }
  61. mPlayer = player;
  62. long delay = SystemClock.uptimeMillis() - cmd.requestTime;
  63. if (delay > 1000) {
  64. Log.w(mTag, "Notification sound delayed by " + delay + "msecs");
  65. }
  66. }
  67. catch (Exception e) {
  68. Log.w(mTag, "error loading sound for " + cmd.uri, e);
  69. }
  70. }
  71. private final class Thread extends java.lang.Thread {
  72. Thread() {
  73. super("AsyncPlayer-" + mTag);
  74. }
  75. public void run() {
  76. while (true) {
  77. Command cmd = null;
  78. synchronized (mCmdQueue) {
  79. if (mDebug) Log.d(mTag, "RemoveFirst");
  80. cmd = mCmdQueue.removeFirst();
  81. }
  82. switch (cmd.code) {
  83. case PLAY:
  84. if (mDebug) Log.d(mTag, "PLAY");
  85. startSound(cmd);
  86. break;
  87. case STOP:
  88. if (mDebug) Log.d(mTag, "STOP");
  89. if (mPlayer != null) {
  90. long delay = SystemClock.uptimeMillis() - cmd.requestTime;
  91. if (delay > 1000) {
  92. Log.w(mTag, "Notification stop delayed by " + delay + "msecs");
  93. }
  94. mPlayer.stop();
  95. mPlayer.release();
  96. mPlayer = null;
  97. } else {
  98. Log.w(mTag, "STOP command without a player");
  99. }
  100. break;
  101. }
  102. synchronized (mCmdQueue) {
  103. if (mCmdQueue.size() == 0) {
  104. // nothing left to do, quit
  105. // doing this check after we're done prevents the case where they
  106. // added it during the operation from spawning two threads and
  107. // trying to do them in parallel.
  108. mThread = null;
  109. releaseWakeLock();
  110. return;
  111. }
  112. }
  113. }
  114. }
  115. }
  116. private String mTag;
  117. private Thread mThread;
  118. private MediaPlayer mPlayer;
  119. private PowerManager.WakeLock mWakeLock;
  120. // The current state according to the caller. Reality lags behind
  121. // because of the asynchronous nature of this class.
  122. private int mState = STOP;
  123. /**
  124. * Construct an AsyncPlayer object.
  125. *
  126. * @param tag a string to use for debugging
  127. */
  128. public AsyncPlayer(String tag) {
  129. if (tag != null) {
  130. mTag = tag;
  131. } else {
  132. mTag = "AsyncPlayer";
  133. }
  134. }
  135. /**
  136. * Start playing the sound. It will actually start playing at some
  137. * point in the future. There are no guarantees about latency here.
  138. * Calling this before another audio file is done playing will stop
  139. * that one and start the new one.
  140. *
  141. * @param context Your application's context.
  142. * @param uri The URI to play. (see {@link MediaPlayer#setDataSource(Context, Uri)})
  143. * @param looping Whether the audio should loop forever.
  144. * (see {@link MediaPlayer#setLooping(boolean)})
  145. * @param stream the AudioStream to use.
  146. * (see {@link MediaPlayer#setAudioStreamType(int)})
  147. */
  148. public void play(Context context, Uri uri, boolean looping, int stream) {
  149. Command cmd = new Command();
  150. cmd.requestTime = SystemClock.uptimeMillis();
  151. cmd.code = PLAY;
  152. cmd.context = context;
  153. cmd.uri = uri;
  154. cmd.looping = looping;
  155. cmd.stream = stream;
  156. synchronized (mCmdQueue) {
  157. enqueueLocked(cmd);
  158. mState = PLAY;
  159. }
  160. }
  161. /**
  162. * Stop a previously played sound. It can't be played again or unpaused
  163. * at this point. Calling this multiple times has no ill effects.
  164. */
  165. public void stop() {
  166. synchronized (mCmdQueue) {
  167. // This check allows stop to be called multiple times without starting
  168. // a thread that ends up doing nothing.
  169. if (mState != STOP) {
  170. Command cmd = new Command();
  171. cmd.requestTime = SystemClock.uptimeMillis();
  172. cmd.code = STOP;
  173. enqueueLocked(cmd);
  174. mState = STOP;
  175. }
  176. }
  177. }
  178. private void enqueueLocked(Command cmd) {
  179. mCmdQueue.add(cmd);
  180. if (mThread == null) {
  181. acquireWakeLock();
  182. mThread = new Thread();
  183. mThread.start();
  184. }
  185. }
  186. /**
  187. * We want to hold a wake lock while we do the prepare and play. The stop probably is
  188. * optional, but it won't hurt to have it too. The problem is that if you start a sound
  189. * while you're holding a wake lock (e.g. an alarm starting a notification), you want the
  190. * sound to play, but if the CPU turns off before mThread gets to work, it won't. The
  191. * simplest way to deal with this is to make it so there is a wake lock held while the
  192. * thread is starting or running. You're going to need the WAKE_LOCK permission if you're
  193. * going to call this.
  194. *
  195. * This must be called before the first time play is called.
  196. *
  197. * @hide
  198. */
  199. public void setUsesWakeLock(Context context) {
  200. if (mWakeLock != null || mThread != null) {
  201. // if either of these has happened, we've already played something.
  202. // and our releases will be out of sync.
  203. throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock
  204. + " mThread=" + mThread);
  205. }
  206. PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
  207. mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
  208. }
  209. private void acquireWakeLock() {
  210. if (mWakeLock != null) {
  211. mWakeLock.acquire();
  212. }
  213. }
  214. private void releaseWakeLock() {
  215. if (mWakeLock != null) {
  216. mWakeLock.release();
  217. }
  218. }
  219. }