/*
* 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;
}
}