content: /*
   * Created by LuaView.
   * Copyright (c) 2017, Alibaba Group. All rights reserved.
   *
   * This source code is licensed under the MIT.
   * For the full copyright and license information,please view the LICENSE file in the root directory of this source tree.
   */
  
  package com.taobao.luaview.userdata.kit;
  
  import android.content.Context;
  import android.content.res.AssetFileDescriptor;
  import android.media.MediaPlayer;
  import android.os.Handler;
  import android.webkit.URLUtil;
  
  import com.taobao.luaview.userdata.base.BaseCacheUserdata;
  import com.taobao.luaview.util.AssetUtil;
  import com.taobao.luaview.util.LuaUtil;
  
  import org.luaj.vm2.Globals;
  import org.luaj.vm2.LuaFunction;
  import org.luaj.vm2.LuaValue;
  import org.luaj.vm2.Varargs;
  
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  
  /**
   * Audio 用户数据封装
   *
   * @author song
   * @date 15/9/6
   */
  public class UDAudio extends BaseCacheUserdata implements MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
      private MediaPlayer mMediaPlayer;
      private String mUriOrName;
      private Integer mLoopTimes;
      private LuaFunction mCallback;
  
      public UDAudio(Globals globals, LuaValue metatable, Varargs varargs) {
          super(globals, metatable, varargs);
          init();
      }
  
      private void init() {
          if (initParams != null) {
              mUriOrName = LuaUtil.getString(initParams, 1);
              mLoopTimes = LuaUtil.getInt(initParams, 2, 1);
              mCallback = LuaUtil.getFunction(initParams, 3, 2, 1);
          }
      }
  
      public UDAudio setCallback(LuaFunction callback) {
          this.mCallback = callback;
          return this;
      }
  
      public LuaFunction getCallback() {
          return mCallback;
      }
  
      /**
       * create a media player
       *
       * @return
       */
      private synchronized MediaPlayer getMediaPlayer() {
          if (mMediaPlayer == null) {
              mMediaPlayer = new MediaPlayer();
              if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
                  try {
                      final Class<?> cMediaTimeProvider = Class.forName("android.media.MediaTimeProvider");
                      final Class<?> cSubtitleController = Class.forName("android.media.SubtitleController");
                      final Class<?> iSubtitleControllerAnchor = Class.forName("android.media.SubtitleController$Anchor");
                      final Class<?> iSubtitleControllerListener = Class.forName("android.media.SubtitleController$Listener");
  
                      final Constructor constructor = cSubtitleController.getConstructor(new Class[]{Context.class, cMediaTimeProvider, iSubtitleControllerListener});
  
                      final Object subtitleInstance = constructor.newInstance(getContext(), null, null);
  
                      final Field f = cSubtitleController.getDeclaredField("mHandler");
  
                      f.setAccessible(true);
                      try {
                          f.set(subtitleInstance, new Handler());
                      } catch (IllegalAccessException e) {
                          return mMediaPlayer;
                      } finally {
                          f.setAccessible(false);
                      }
  
                      final Method setSubtitleAnchor = mMediaPlayer.getClass().getMethod("setSubtitleAnchor", cSubtitleController, iSubtitleControllerAnchor);
                      setSubtitleAnchor.invoke(mMediaPlayer, subtitleInstance, null);
                  } catch (Exception e) {
                  }
              }
          }
          return mMediaPlayer;
      }
  
      /**
       * start playing audio
       *
       * @param uriOrName
       * @param loopTimes
       * @return
       */
      public synchronized UDAudio play(String uriOrName, Integer loopTimes) {
          stopAndReset();
  
          if (uriOrName != null && uriOrName.equals(this.mUriOrName) == false) {//url 不同
              this.mUriOrName = uriOrName;
          }
  
          if (loopTimes != null) {
              this.mLoopTimes = loopTimes;
          }
  
          if (this.mUriOrName != null) {
              final MediaPlayer player = getMediaPlayer();
              if (player != null && player.isPlaying() == false) {
                  String uri = null;
                  boolean assetFileExist = false;
                  if (URLUtil.isNetworkUrl(this.mUriOrName) || URLUtil.isFileUrl(this.mUriOrName) || URLUtil.isAssetUrl(this.mUriOrName)) {//net & file & asset
                      uri = this.mUriOrName;
                  } else {//plain text, use as file path
                      uri = getLuaResourceFinder().buildFullPathInBundleOrAssets(this.mUriOrName);
                      assetFileExist = AssetUtil.exists(getContext(), uri);
                  }
                  try {
                      if (assetFileExist) {
                          final AssetFileDescriptor descriptor = getContext().getAssets().openFd(uri);
                          player.setDataSource(descriptor.getFileDescriptor(), descriptor.getStartOffset(), descriptor.getLength());
                      } else {
                          player.setDataSource(uri);
                      }
                      player.setOnErrorListener(this);
                      player.setOnCompletionListener(this);
                      player.setOnPreparedListener(this);
                      player.setLooping((this.mLoopTimes != null && this.mLoopTimes > 1) ? true : false);
                      player.prepareAsync();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
  
          return this;
      }
  
      /**
       * pause playing audio
       *
       * @return
       */
      public synchronized UDAudio pause() {
          final MediaPlayer player = getMediaPlayer();
          if (player != null) {
              try {
                  player.pause();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          return this;
      }
  
      /**
       * resume playing
       *
       * @return
       */
      public synchronized UDAudio resume() {
          final MediaPlayer player = getMediaPlayer();
          if (player != null && player.isPlaying() == false) {
              try {
                  if (player.getCurrentPosition() > 0) {
                      player.start();
                  } else {
                      play(mUriOrName, mLoopTimes);
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          return this;
      }
  
      /**
       * seek to position
       *
       * @param position
       * @return
       */
      public synchronized UDAudio seekTo(Integer position) {
          if (position != null) {
              final MediaPlayer player = getMediaPlayer();
              if (player != null) {
                  try {
                      player.seekTo(position);
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
          return this;
      }
  
  
      /**
       * stop playing audio
       *
       * @return
       */
      public synchronized UDAudio stop() {
          final MediaPlayer player = getMediaPlayer();
          if (player != null && player.isPlaying()) {
              try {
                  player.stop();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          return this;
      }
  
      /**
       * reset from error state
       *
       * @return
       */
      public synchronized UDAudio reset() {
          final MediaPlayer player = getMediaPlayer();
          if (player != null) {
              try {
                  player.reset();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          return this;
      }
  
      /**
       * stop playing and reset error state
       *
       * @return
       */
      public synchronized UDAudio stopAndReset() {
          return stop().reset();
      }
  
      /**
       * stop playing and release
       *
       * @return
       */
      public synchronized UDAudio stopAndRelease() {
          return stop().release();
      }
  
      /**
       * release resource
       *
       * @return
       */
      public synchronized UDAudio release() {
          final MediaPlayer player = getMediaPlayer();
          if (player != null) {
              try {
                  player.release();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
          return this;
      }
  
      public boolean isPlaying() {
          return getMediaPlayer() != null && getMediaPlayer().isPlaying();
      }
  
      public boolean isLooping() {
          return getMediaPlayer() != null && getMediaPlayer().isLooping();
      }
  
      public boolean isPause() {
          return getMediaPlayer() != null && getMediaPlayer().isPlaying() == false && getMediaPlayer().getCurrentPosition() > 0;
      }
  
      @Override
      public void onCacheClear() {
          release();
      }
  
  
      //-----------------------------------------listeners--------------------------------------------
  
      @Override
      public void onPrepared(MediaPlayer mp) {
          if (mp != null) {
              synchronized (mp) {
                  try {
                      if (mp.isPlaying() == false) {
                          mp.start();
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
      }
  
      /**
       * @param mp
       */
      @Override
      public void onCompletion(MediaPlayer mp) {
          if (mp != null) {
              synchronized (mp) {
                  try {
                      mp.stop();
                      mp.reset();
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
  
          if (mCallback != null) {
              LuaUtil.callFunction(LuaUtil.getFunction(mCallback, "onComplete", "OnComplete"));
          }
      }
  
      @Override
      public boolean onError(MediaPlayer mp, int what, int extra) {
          if (mCallback != null) {
              LuaUtil.callFunction(mCallback.get("onError"), valueOf(what));
          }
          return false;
      }
  }
  