接上篇博文: 基于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去了解吧
Github下载页:https://github.com/geniusgithub/MediaRender
DLNA开发文档链接:http://download.csdn.net/detail/geniuseoe2012/4969961
关于SO库的具体C++实现可参考这篇博文:
http://blog.csdn.net/lancees/article/details/9178385
DMS的实现请参考这篇博文:基于Platinum库的DMS实现(android)
more brilliant,Please pay attention to my CSDN blog -->http://blog.csdn.net/geniuseoe2012