/uikit/src/main/java/cn/wildfire/chat/kit/voip/AsyncPlayer.java

https://github.com/wildfirechat/android-chat · Java · 185 lines · 152 code · 27 blank · 6 comment · 25 complexity · 9157fbabe1cb9f5ab6b8ca2526680cac MD5 · raw file

  1. /*
  2. * Copyright (c) 2020 WildFireChat. All rights reserved.
  3. */
  4. package cn.wildfire.chat.kit.voip;
  5. /**
  6. * Created by heavyrainlee on 24/02/2018.
  7. */
  8. import android.content.Context;
  9. import android.media.AudioAttributes;
  10. import android.media.MediaPlayer;
  11. import android.net.Uri;
  12. import android.os.Build;
  13. import android.os.PowerManager;
  14. import android.os.SystemClock;
  15. import android.util.Log;
  16. import java.io.IOException;
  17. import java.util.LinkedList;
  18. public class AsyncPlayer {
  19. private static final int PLAY = 1;
  20. private static final int STOP = 2;
  21. private static final boolean mDebug = false;
  22. private static final class Command {
  23. int code;
  24. Context context;
  25. Uri uri;
  26. boolean looping;
  27. int stream;
  28. long requestTime;
  29. public String toString() {
  30. return "{ code=" + code + " looping=" + looping + " stream=" + stream + " uri=" + uri + " }";
  31. }
  32. }
  33. private LinkedList mCmdQueue = new LinkedList();
  34. private void startSound(Command cmd) {
  35. try {
  36. MediaPlayer player = new MediaPlayer();
  37. player.setAudioStreamType(cmd.stream);
  38. player.setDataSource(cmd.context, cmd.uri);
  39. player.setLooping(cmd.looping);
  40. if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
  41. player.setAudioAttributes(new AudioAttributes.Builder()
  42. .setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST)
  43. .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
  44. .build()
  45. );
  46. }
  47. player.prepare();
  48. player.start();
  49. if (mPlayer != null) {
  50. mPlayer.stop();
  51. mPlayer.release();
  52. }
  53. mPlayer = player;
  54. } catch (IOException e) {
  55. Log.w(mTag, "error loading sound for " + cmd.uri, e);
  56. } catch (IllegalStateException e) {
  57. Log.w(mTag, "IllegalStateException (content provider died?) " + cmd.uri, e);
  58. }
  59. }
  60. private final class Thread extends java.lang.Thread {
  61. Thread() {
  62. super("AsyncPlayer-" + mTag);
  63. }
  64. public void run() {
  65. while (true) {
  66. Command cmd = null;
  67. synchronized (mCmdQueue) {
  68. cmd = (Command) mCmdQueue.removeFirst();
  69. }
  70. switch (cmd.code) {
  71. case PLAY:
  72. startSound(cmd);
  73. break;
  74. case STOP:
  75. Log.e(mTag, "STOP CMD");
  76. if (mPlayer != null) {
  77. Log.e("AsyncPlayer", "mediaPlayer stop & release");
  78. mPlayer.stop();
  79. mPlayer.release();
  80. mPlayer = null;
  81. } else {
  82. Log.w(mTag, "STOP command without a player");
  83. }
  84. break;
  85. }
  86. synchronized (mCmdQueue) {
  87. if (mCmdQueue.size() == 0) {
  88. mThread = null;
  89. releaseWakeLock();
  90. return;
  91. }
  92. }
  93. }
  94. }
  95. }
  96. private String mTag;
  97. private Thread mThread;
  98. private MediaPlayer mPlayer;
  99. private PowerManager.WakeLock mWakeLock;
  100. private int mState = STOP;
  101. public AsyncPlayer(String tag) {
  102. if (tag != null) {
  103. mTag = tag;
  104. } else {
  105. mTag = "AsyncPlayer";
  106. }
  107. }
  108. public void play(Context context, Uri uri, boolean looping, int stream) {
  109. Command cmd = new Command();
  110. cmd.requestTime = SystemClock.uptimeMillis();
  111. cmd.code = PLAY;
  112. cmd.context = context;
  113. cmd.uri = uri;
  114. cmd.looping = looping;
  115. cmd.stream = stream;
  116. synchronized (mCmdQueue) {
  117. enqueueLocked(cmd);
  118. mState = PLAY;
  119. }
  120. }
  121. public void stop() {
  122. Log.e(mTag, "stop");
  123. synchronized (mCmdQueue) {
  124. if (mState != STOP) {
  125. Command cmd = new Command();
  126. cmd.requestTime = SystemClock.uptimeMillis();
  127. cmd.code = STOP;
  128. enqueueLocked(cmd);
  129. mState = STOP;
  130. }
  131. }
  132. }
  133. private void enqueueLocked(Command cmd) {
  134. mCmdQueue.add(cmd);
  135. if (mThread == null) {
  136. acquireWakeLock();
  137. mThread = new Thread();
  138. mThread.start();
  139. }
  140. }
  141. public void setUsesWakeLock(Context context) {
  142. if (mWakeLock != null || mThread != null) {
  143. throw new RuntimeException("assertion failed mWakeLock=" + mWakeLock + " mThread=" + mThread);
  144. }
  145. PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
  146. mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, mTag);
  147. }
  148. private void acquireWakeLock() {
  149. if (mWakeLock != null) {
  150. mWakeLock.acquire();
  151. }
  152. }
  153. private void releaseWakeLock() {
  154. if (mWakeLock != null) {
  155. mWakeLock.release();
  156. }
  157. }
  158. }