接上篇博文: 基于CyberGarage库的dlna开发(android)
文章讲述了用CyberGarage库的DMP实现
部分童鞋想知道DMR是如何实现的
网上似乎也没看到相关的android code
在下不才,自个儿捣鼓了project并上传至github
今与诸君共赏
本例所采用的upnp框架是Platinum SDK
官方网址是http://www.plutinosoft.com/platinum
该库是一个跨平台的C++库,利用该库,可以很容易就构建出DLNA/UPnP控制点 (DLNA/UPnP Control Point)和DLNA/UPnP设备(DLNA/UPnP Device),其中包括有UPnP AV Media Server, Media Render & Control Point的例子
该库稳定强大,被很多知名产品所沿用,口碑较好自然也为楼主所青睐
关于该库如何编译,请参考这篇博文:NDK下 将Platinum SDK 编译成so库
下面给出运行效果图:
JNI接口文件:
public class PlatinumJniProxy {
static {
System.loadLibrary("git-platinum");
}
public static native int startMediaRender(byte[] friendname ,byte[] uuid);
public static native int stopMediaRender();
public static native boolean responseGenaEvent(int cmd, byte[] value ,byte[] data);
public static native boolean enableLogPrint(boolean flag);
public static int startMediaRender(String friendname ,String uuid){
if (friendname == null)friendname = "";
if (uuid == null)uuid = "";
int ret = -1;
try {
ret = startMediaRender(friendname.getBytes("utf-8"), uuid.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return ret;
}
public static boolean responseGenaEvent(int cmd, String value, String data){
if (value == null)value = "";
if (data == null)data = "";
boolean ret = false;
try {
ret = responseGenaEvent(cmd, value.getBytes("utf-8"), data.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return ret;
}
}
反射类:
public class PlatinumReflection {
private static final CommonLog log = LogFactory.createLog();
private static final int MEDIA_RENDER_CTL_MSG_BASE = 0x100;
/*----------------------------------------------------------------*/
public static final int MEDIA_RENDER_CTL_MSG_SET_AV_URL = (MEDIA_RENDER_CTL_MSG_BASE+0);
public static final int MEDIA_RENDER_CTL_MSG_STOP = (MEDIA_RENDER_CTL_MSG_BASE+1);
public static final int MEDIA_RENDER_CTL_MSG_PLAY = (MEDIA_RENDER_CTL_MSG_BASE+2);
public static final int MEDIA_RENDER_CTL_MSG_PAUSE = (MEDIA_RENDER_CTL_MSG_BASE+3);
public static final int MEDIA_RENDER_CTL_MSG_SEEK = (MEDIA_RENDER_CTL_MSG_BASE+4);
public static final int MEDIA_RENDER_CTL_MSG_SETVOLUME = (MEDIA_RENDER_CTL_MSG_BASE+5);
public static final int MEDIA_RENDER_CTL_MSG_SETMUTE = (MEDIA_RENDER_CTL_MSG_BASE+6);
public static final int MEDIA_RENDER_CTL_MSG_SETPLAYMODE = (MEDIA_RENDER_CTL_MSG_BASE+7);
public static final int MEDIA_RENDER_CTL_MSG_PRE = (MEDIA_RENDER_CTL_MSG_BASE+8);
public static final int MEDIA_RENDER_CTL_MSG_NEXT = (MEDIA_RENDER_CTL_MSG_BASE+9);
/*----------------------------------------------------------------*/
/*----------------------------------------------------------------*/
/*
*
*
* */
public static final int MEDIA_RENDER_TOCONTRPOINT_SET_MEDIA_DURATION = (MEDIA_RENDER_CTL_MSG_BASE+0);
public static final int MEDIA_RENDER_TOCONTRPOINT_SET_MEDIA_POSITION = (MEDIA_RENDER_CTL_MSG_BASE+1);
public static final int MEDIA_RENDER_TOCONTRPOINT_SET_MEDIA_PLAYINGSTATE = (MEDIA_RENDER_CTL_MSG_BASE+2);
/*----------------------------------------------------------------*/
public static final String RENDERER_TOCONTRPOINT_CMD_INTENT_NAME="com.geniusgithub.platinum.tocontrolpointer.cmd.intent";
public static final String GET_RENDERER_TOCONTRPOINT_CMD="get_dlna_renderer_tocontrolpointer.cmd";
public static final String GET_PARAM_MEDIA_DURATION="get_param_media_duration";
public static final String GET_PARAM_MEDIA_POSITION="get_param_media_position";
public static final String GET_PARAM_MEDIA_PLAYINGSTATE="get_param_media_playingstate";
/*----------------------------------------------------------------*/
public static final String MEDIA_PLAYINGSTATE_STOP="STOPPED";
public static final String MEDIA_PLAYINGSTATE_PAUSE="PAUSED_PLAYBACK";
public static final String MEDIA_PLAYINGSTATE_PLAYING="PLAYING";
public static final String MEDIA_PLAYINGSTATE_TRANSTION="TRANSITIONING";
public static final String MEDIA_PLAYINGSTATE_NOMEDIA="NO_MEDIA_PRESENT";
/*----------------------------------------------------------------*/
public static final String MEDIA_SEEK_TIME_TYPE_REL_TIME="REL_TIME";
public static final String MEDIA_SEEK_TIME_TYPE_TRACK_NR="TRACK_NR";
public static interface ActionReflectionListener{
public void onActionInvoke(int cmd,String value,String data);
}
private static ActionReflectionListener mListener;
public static void onActionReflection(int cmd,String value,String data){
if (mListener != null){
mListener.onActionInvoke(cmd, value, data);
}
}
public static void setActionInvokeListener(ActionReflectionListener listener){
mListener = listener;
}
}
工作线程 DMRWorkThread
public class DMRWorkThread extends Thread implements IBaseEngine{
private static final CommonLog log = LogFactory.createLog();
private static final int CHECK_INTERVAL = 30 * 1000;
private Context mContext = null;
private boolean mStartSuccess = false;
private boolean mExitFlag = false;
private String mFriendName = "";
private String mUUID = "";
private RenderApplication mApplication;
public DMRWorkThread(Context context){
mContext = context;
mApplication = RenderApplication.getInstance();
}
public void setFlag(boolean flag){
mStartSuccess = flag;
}
public void setParam(String friendName, String uuid){
mFriendName = friendName;
mUUID = uuid;
mApplication.updateDevInfo(mFriendName, mUUID);
}
public void awakeThread(){
synchronized (this) {
notifyAll();
}
}
public void exit(){
mExitFlag = true;
awakeThread();
}
@Override
public void run() {
log.e("DMRWorkThread run...");
while(true)
{
if (mExitFlag){
stopEngine();
break;
}
refreshNotify();
synchronized(this)
{
try
{
wait(CHECK_INTERVAL);
}
catch(Exception e)
{
e.printStackTrace();
}
}
if (mExitFlag){
stopEngine();
break;
}
}
log.e("DMRWorkThread over...");
}
public void refreshNotify(){
if (!CommonUtil.checkNetworkState(mContext)){
return ;
}
if (!mStartSuccess){
stopEngine();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
boolean ret = startEngine();
if (ret){
mStartSuccess = true;
}
}
}
@Override
public boolean startEngine() {
if (mFriendName.length() == 0){
return false;
}
int ret = PlatinumJniProxy.startMediaRender(mFriendName, mUUID);
boolean result = (ret == 0 ? true : false);
mApplication.setDevStatus(result);
return result;
}
@Override
public boolean stopEngine() {
PlatinumJniProxy.stopMediaRender();
mApplication.setDevStatus(false);
return true;
}
@Override
public boolean restartEngine() {
setFlag(false);
awakeThread();
return true;
}
}
通过startMediaRender开启设备后就可以被外界所发现,控制点发送控制信息后
动作action的回调通过反射类PlatinumReflection的静态方法onActionReflection执行
GENA事件则通过PlatinumJniProxy类的responseGenaEvent传递
详情大家down code去了解吧