content: /*
   * Copyright (C) 2006 Bilibili
   * Copyright (C) 2006 The Android Open Source Project
   * Copyright (C) 2013 Zhang Rui <bbcallen@gmail.com>
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package tv.danmaku.ijk.media.player;
  
  import android.annotation.TargetApi;
  import android.content.Context;
  import android.media.AudioManager;
  import android.media.MediaDataSource;
  import android.media.MediaPlayer;
  import android.media.TimedText;
  import android.net.Uri;
  import android.os.Build;
  import android.text.TextUtils;
  import android.view.Surface;
  import android.view.SurfaceHolder;
  
  import java.io.FileDescriptor;
  import java.io.IOException;
  import java.lang.ref.WeakReference;
  import java.util.Map;
  
  import tv.danmaku.ijk.media.player.misc.AndroidTrackInfo;
  import tv.danmaku.ijk.media.player.misc.IMediaDataSource;
  import tv.danmaku.ijk.media.player.misc.ITrackInfo;
  import tv.danmaku.ijk.media.player.pragma.DebugLog;
  
  public class AndroidMediaPlayer extends AbstractMediaPlayer {
      private final MediaPlayer mInternalMediaPlayer;
      private final AndroidMediaPlayerListenerHolder mInternalListenerAdapter;
      private String mDataSource;
      private MediaDataSource mMediaDataSource;
  
      private final Object mInitLock = new Object();
      private boolean mIsReleased;
  
      private static MediaInfo sMediaInfo;
  
      public AndroidMediaPlayer() {
          synchronized (mInitLock) {
              mInternalMediaPlayer = new MediaPlayer();
          }
          mInternalMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
          mInternalListenerAdapter = new AndroidMediaPlayerListenerHolder(this);
          attachInternalListeners();
      }
  
      public MediaPlayer getInternalMediaPlayer() {
          return mInternalMediaPlayer;
      }
  
      @Override
      public void setDisplay(SurfaceHolder sh) {
          synchronized (mInitLock) {
              if (!mIsReleased) {
                  mInternalMediaPlayer.setDisplay(sh);
              }
          }
      }
  
      @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
      @Override
      public void setSurface(Surface surface) {
          mInternalMediaPlayer.setSurface(surface);
      }
  
      @Override
      public void setDataSource(Context context, Uri uri)
              throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
          mInternalMediaPlayer.setDataSource(context, uri);
      }
  
      @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
      @Override
      public void setDataSource(Context context, Uri uri, Map<String, String> headers)
              throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
          mInternalMediaPlayer.setDataSource(context, uri, headers);
      }
  
      @Override
      public void setDataSource(FileDescriptor fd)
              throws IOException, IllegalArgumentException, IllegalStateException {
          mInternalMediaPlayer.setDataSource(fd);
      }
  
      @Override
      public void setDataSource(String path) throws IOException,
              IllegalArgumentException, SecurityException, IllegalStateException {
          mDataSource = path;
  
          Uri uri = Uri.parse(path);
          String scheme = uri.getScheme();
          if (!TextUtils.isEmpty(scheme) && scheme.equalsIgnoreCase("file")) {
              mInternalMediaPlayer.setDataSource(uri.getPath());
          } else {
              mInternalMediaPlayer.setDataSource(path);
          }
      }
  
      @TargetApi(Build.VERSION_CODES.M)
      @Override
      public void setDataSource(IMediaDataSource mediaDataSource) {
          releaseMediaDataSource();
  
          mMediaDataSource = new MediaDataSourceProxy(mediaDataSource);
          mInternalMediaPlayer.setDataSource(mMediaDataSource);
      }
  
      @TargetApi(Build.VERSION_CODES.M)
      private static class MediaDataSourceProxy extends MediaDataSource {
          private final IMediaDataSource mMediaDataSource;
  
          public MediaDataSourceProxy(IMediaDataSource mediaDataSource) {
              mMediaDataSource = mediaDataSource;
          }
  
          @Override
          public int readAt(long position, byte[] buffer, int offset, int size) throws IOException {
              return mMediaDataSource.readAt(position, buffer, offset, size);
          }
  
          @Override
          public long getSize() throws IOException {
              return mMediaDataSource.getSize();
          }
  
          @Override
          public void close() throws IOException {
              mMediaDataSource.close();
          }
      }
  
      @Override
      public String getDataSource() {
          return mDataSource;
      }
  
      private void releaseMediaDataSource() {
          if (mMediaDataSource != null) {
              try {
                  mMediaDataSource.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
              mMediaDataSource = null;
          }
      }
  
      @Override
      public void prepareAsync() throws IllegalStateException {
          mInternalMediaPlayer.prepareAsync();
      }
  
      @Override
      public void start() throws IllegalStateException {
          mInternalMediaPlayer.start();
      }
  
      @Override
      public void stop() throws IllegalStateException {
          mInternalMediaPlayer.stop();
      }
  
      @Override
      public void pause() throws IllegalStateException {
          mInternalMediaPlayer.pause();
      }
  
      @Override
      public void setScreenOnWhilePlaying(boolean screenOn) {
          mInternalMediaPlayer.setScreenOnWhilePlaying(screenOn);
      }
  
      @Override
      public ITrackInfo[] getTrackInfo() {
          return AndroidTrackInfo.fromMediaPlayer(mInternalMediaPlayer);
      }
  
      @Override
      public int getVideoWidth() {
          return mInternalMediaPlayer.getVideoWidth();
      }
  
      @Override
      public int getVideoHeight() {
          return mInternalMediaPlayer.getVideoHeight();
      }
  
      @Override
      public int getVideoSarNum() {
          return 1;
      }
  
      @Override
      public int getVideoSarDen() {
          return 1;
      }
  
      @Override
      public boolean isPlaying() {
          try {
              return mInternalMediaPlayer.isPlaying();
          } catch (IllegalStateException e) {
              DebugLog.printStackTrace(e);
              return false;
          }
      }
  
      @Override
      public void seekTo(long msec) throws IllegalStateException {
          mInternalMediaPlayer.seekTo((int) msec);
      }
  
      @Override
      public long getCurrentPosition() {
          try {
              return mInternalMediaPlayer.getCurrentPosition();
          } catch (IllegalStateException e) {
              DebugLog.printStackTrace(e);
              return 0;
          }
      }
  
      @Override
      public long getDuration() {
          try {
              return mInternalMediaPlayer.getDuration();
          } catch (IllegalStateException e) {
              DebugLog.printStackTrace(e);
              return 0;
          }
      }
  
      @Override
      public void release() {
          mIsReleased = true;
          mInternalMediaPlayer.release();
          releaseMediaDataSource();
          resetListeners();
          attachInternalListeners();
      }
  
      @Override
      public void reset() {
          try {
              mInternalMediaPlayer.reset();
          } catch (IllegalStateException e) {
              DebugLog.printStackTrace(e);
          }
          releaseMediaDataSource();
          resetListeners();
          attachInternalListeners();
      }
  
      @Override
      public void setLooping(boolean looping) {
          mInternalMediaPlayer.setLooping(looping);
      }
  
      @Override
      public boolean isLooping() {
          return mInternalMediaPlayer.isLooping();
      }
  
      @Override
      public void setVolume(float leftVolume, float rightVolume) {
          mInternalMediaPlayer.setVolume(leftVolume, rightVolume);
      }
  
      @Override
      public int getAudioSessionId() {
          return mInternalMediaPlayer.getAudioSessionId();
      }
  
      @Override
      public MediaInfo getMediaInfo() {
          if (sMediaInfo == null) {
              MediaInfo module = new MediaInfo();
  
              module.mVideoDecoder = "android";
              module.mVideoDecoderImpl = "HW";
  
              module.mAudioDecoder = "android";
              module.mAudioDecoderImpl = "HW";
  
              sMediaInfo = module;
          }
  
          return sMediaInfo;
      }
  
      @Override
      public void setLogEnabled(boolean enable) {
      }
  
      @Override
      public boolean isPlayable() {
          return true;
      }
  
      /*--------------------
       * misc
       */
      @Override
      public void setWakeMode(Context context, int mode) {
          mInternalMediaPlayer.setWakeMode(context, mode);
      }
  
      @Override
      public void setAudioStreamType(int streamtype) {
          mInternalMediaPlayer.setAudioStreamType(streamtype);
      }
  
      @Override
      public void setKeepInBackground(boolean keepInBackground) {
      }
  
      /*--------------------
       * Listeners adapter
       */
      private void attachInternalListeners() {
          mInternalMediaPlayer.setOnPreparedListener(mInternalListenerAdapter);
          mInternalMediaPlayer
                  .setOnBufferingUpdateListener(mInternalListenerAdapter);
          mInternalMediaPlayer.setOnCompletionListener(mInternalListenerAdapter);
          mInternalMediaPlayer
                  .setOnSeekCompleteListener(mInternalListenerAdapter);
          mInternalMediaPlayer
                  .setOnVideoSizeChangedListener(mInternalListenerAdapter);
          mInternalMediaPlayer.setOnErrorListener(mInternalListenerAdapter);
          mInternalMediaPlayer.setOnInfoListener(mInternalListenerAdapter);
          mInternalMediaPlayer.setOnTimedTextListener(mInternalListenerAdapter);
      }
  
      private class AndroidMediaPlayerListenerHolder implements
              MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener,
              MediaPlayer.OnBufferingUpdateListener,
              MediaPlayer.OnSeekCompleteListener,
              MediaPlayer.OnVideoSizeChangedListener,
              MediaPlayer.OnErrorListener, MediaPlayer.OnInfoListener,
              MediaPlayer.OnTimedTextListener {
          public final WeakReference<AndroidMediaPlayer> mWeakMediaPlayer;
  
          public AndroidMediaPlayerListenerHolder(AndroidMediaPlayer mp) {
              mWeakMediaPlayer = new WeakReference<AndroidMediaPlayer>(mp);
          }
  
          @Override
          public boolean onInfo(MediaPlayer mp, int what, int extra) {
              AndroidMediaPlayer self = mWeakMediaPlayer.get();
              return self != null && notifyOnInfo(what, extra);
  
          }
  
          @Override
          public boolean onError(MediaPlayer mp, int what, int extra) {
              AndroidMediaPlayer self = mWeakMediaPlayer.get();
              return self != null && notifyOnError(what, extra);
  
          }
  
          @Override
          public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
              AndroidMediaPlayer self = mWeakMediaPlayer.get();
              if (self == null)
                  return;
  
              notifyOnVideoSizeChanged(width, height, 1, 1);
          }
  
          @Override
          public void onSeekComplete(MediaPlayer mp) {
              AndroidMediaPlayer self = mWeakMediaPlayer.get();
              if (self == null)
                  return;
  
              notifyOnSeekComplete();
          }
  
          @Override
          public void onBufferingUpdate(MediaPlayer mp, int percent) {
              AndroidMediaPlayer self = mWeakMediaPlayer.get();
              if (self == null)
                  return;
  
              notifyOnBufferingUpdate(percent);
          }
  
          @Override
          public void onCompletion(MediaPlayer mp) {
              AndroidMediaPlayer self = mWeakMediaPlayer.get();
              if (self == null)
                  return;
  
              notifyOnCompletion();
          }
  
          @Override
          public void onPrepared(MediaPlayer mp) {
              AndroidMediaPlayer self = mWeakMediaPlayer.get();
              if (self == null)
                  return;
  
              notifyOnPrepared();
          }
  
          @Override
          public void onTimedText(MediaPlayer mp, TimedText text) {
              AndroidMediaPlayer self = mWeakMediaPlayer.get();
              if (self == null)
                  return;
  
              IjkTimedText ijkText = null;
  
              if (text != null) {
                  ijkText = new IjkTimedText(text.getBounds(), text.getText());
              }
  
              notifyOnTimedText(ijkText);
          }
      }
  }
  