关于dlna的介绍就不多说了,具体可以看这篇博文http://blog.youkuaiyun.com/geniuseoe2012/article/details/8230877
或者问百度谷歌
Dlna通讯采用upnp协议,详看这篇博文:http://blog.youkuaiyun.com/geniuseoe2012/article/details/8132719
或者问百度谷歌
更多开发资料稍后再末尾附上
我们在做DLNA开发的时候都是用现有的upnp开源框架,upnp官网地址是:
http://upnp.org/
相关SDK地址为http://upnp.org/sdcps-and-certification/resources/sdks/
本文阐述的是基于CyberGarage库的DMP开发,ControlPoint是核心类
关键方法有search();start(),stop(),addDeviceChangeListener(DeviceChangeListener listener)
见名知意
先上几张效果图:
代码里将ControlPoint委托给service,外部通过与service的交互来执行相关操作
- public class DlnaService extends Service implements IBaseEngine,
- DeviceChangeListener,
- ControlCenterWorkThread.ISearchDeviceListener{
- private static final CommonLog log = LogFactory.createLog();
- public static final String SEARCH_DEVICES = "com.geniusgithub.allshare.search_device";
- public static final String RESET_SEARCH_DEVICES = "com.geniusgithub.allshare.reset_search_device";
- private static final int NETWORK_CHANGE = 0x0001;
- private boolean firstReceiveNetworkChangeBR = true;
- private NetworkStatusChangeBR mNetworkStatusChangeBR;
- private ControlPoint mControlPoint;
- private ControlCenterWorkThread mCenterWorkThread;
- private AllShareProxy mAllShareProxy;
- private Handler mHandler;
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- @Override
- public void onCreate() {
- super.onCreate();
- log.e("DlnaService onCreate");
- init();
- }
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- if (intent != null && intent.getAction() != null){
- String action = intent.getAction();
- if (DlnaService.SEARCH_DEVICES.equals(action)) {
- startEngine();
- }else if (DlnaService.RESET_SEARCH_DEVICES.equals(action)){
- restartEngine();
- }
- }else{
- log.e("intent = " + intent);
- }
- return super.onStartCommand(intent, flags, startId);
- }
- @Override
- public void onDestroy() {
- log.e("DlnaService onDestroy");
- unInit();
- super.onDestroy();
- }
- private void init(){
- mAllShareProxy = AllShareProxy.getInstance(this);
- mControlPoint = new ControlPoint();
- AllShareApplication.getInstance().setControlPoint(mControlPoint);
- mControlPoint.addDeviceChangeListener(this);
- mControlPoint.addSearchResponseListener(new SearchResponseListener() {
- public void deviceSearchResponseReceived(SSDPPacket ssdpPacket) {
- }
- });
- mCenterWorkThread = new ControlCenterWorkThread(this, mControlPoint);
- mCenterWorkThread.setSearchListener(this);
- mHandler = new Handler(){
- public void handleMessage(Message msg) {
- switch(msg.what){
- case NETWORK_CHANGE:
- mAllShareProxy.resetSearch();
- break;
- }
- }
- };
- registerNetworkStatusBR();
- }
- private void unInit(){
- unRegisterNetworkStatusBR();
- AllShareApplication.getInstance().setControlPoint(null);
- mCenterWorkThread.setSearchListener(null);
- mCenterWorkThread.exit();
- }
- @Override
- public boolean startEngine() {
- awakeWorkThread();
- return true;
- }
- @Override
- public boolean stopEngine() {
- exitWorkThread();
- return true;
- }
- @Override
- public boolean restartEngine() {
- mCenterWorkThread.reset();
- return true;
- }
- @Override
- public void deviceAdded(Device dev) {
- mAllShareProxy.addDevice(dev);
- }
- @Override
- public void deviceRemoved(Device dev) {
- mAllShareProxy.removeDevice(dev);
- }
- private void awakeWorkThread(){
- if (mCenterWorkThread.isAlive()){
- mCenterWorkThread.awakeThread();
- }else{
- mCenterWorkThread.start();
- }
- }
- private void exitWorkThread(){
- if (mCenterWorkThread != null && mCenterWorkThread.isAlive()){
- mCenterWorkThread.exit();
- long time1 = System.currentTimeMillis();
- while(mCenterWorkThread.isAlive()){
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- long time2 = System.currentTimeMillis();
- log.e("exitCenterWorkThread cost time:" + (time2 - time1));
- mCenterWorkThread = null;
- }
- }
- @Override
- public void onSearchComplete(boolean searchSuccess) {
- if (!searchSuccess){
- sendSearchDeviceFailBrocast(this);
- }
- }
- public static final String SEARCH_DEVICES_FAIL = "com.geniusgithub.allshare.search_devices_fail";
- public static void sendSearchDeviceFailBrocast(Context context){
- log.e("sendSearchDeviceFailBrocast");
- Intent intent = new Intent(SEARCH_DEVICES_FAIL);
- context.sendBroadcast(intent);
- }
- private class NetworkStatusChangeBR extends BroadcastReceiver{
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent != null){
- String action = intent.getAction();
- if (action != null){
- if (action.equalsIgnoreCase(ConnectivityManager.CONNECTIVITY_ACTION)){
- sendNetworkChangeMessage();
- }
- }
- }
- }
- }
- private void registerNetworkStatusBR(){
- if (mNetworkStatusChangeBR == null){
- mNetworkStatusChangeBR = new NetworkStatusChangeBR();
- registerReceiver(mNetworkStatusChangeBR, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
- }
- }
- private void unRegisterNetworkStatusBR(){
- if (mNetworkStatusChangeBR != null){
- unregisterReceiver(mNetworkStatusChangeBR);
- }
- }
- private void sendNetworkChangeMessage(){
- if (firstReceiveNetworkChangeBR){
- log.e("first receive the NetworkChangeMessage, so drop it...");
- firstReceiveNetworkChangeBR = false;
- return ;
- }
- mHandler.removeMessages(NETWORK_CHANGE);
- mHandler.sendEmptyMessageDelayed(NETWORK_CHANGE, 500);
- }
- }
Service内部开启一个线程来执行控制点的搜索,停止等命令
- public class ControlCenterWorkThread extends Thread{
- private static final CommonLog log = LogFactory.createLog();
- private static final int REFRESH_DEVICES_INTERVAL = 30 * 1000;
- public static interface ISearchDeviceListener{
- public void onSearchComplete(boolean searchSuccess);
- }
- private ControlPoint mCP = null;
- private Context mContext = null;
- private boolean mStartComplete = false;
- private boolean mIsExit = false;
- private ISearchDeviceListener mSearchDeviceListener;
- public ControlCenterWorkThread(Context context, ControlPoint controlPoint){
- mContext = context;
- mCP = controlPoint;
- }
- public void setCompleteFlag(boolean flag){
- mStartComplete = flag;
- }
- public void setSearchListener(ISearchDeviceListener listener){
- mSearchDeviceListener = listener;
- }
- public void awakeThread(){
- synchronized (this) {
- notifyAll();
- }
- }
- public void reset(){
- setCompleteFlag(false);
- awakeThread();
- }
- public void exit(){
- mIsExit = true;
- awakeThread();
- }
- @Override
- public void run() {
- log.e("ControlCenterWorkThread run...");
- while(true)
- {
- if (mIsExit){
- mCP.stop();
- break;
- }
- refreshDevices();
- synchronized(this)
- {
- try
- {
- wait(REFRESH_DEVICES_INTERVAL);
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- }
- }
- log.e("ControlCenterWorkThread over...");
- }
- private void refreshDevices(){
- log.e("refreshDevices...");
- if (!CommonUtil.checkNetworkState(mContext)){
- return ;
- }
- try {
- if (mStartComplete){
- boolean searchRet = mCP.search();
- log.e("mCP.search() ret = " + searchRet);
- if (mSearchDeviceListener != null){
- mSearchDeviceListener.onSearchComplete(searchRet);
- }
- }else{
- boolean startRet = mCP.start();
- log.e("mCP.start() ret = " + startRet);
- if (startRet){
- mStartComplete = true;
- }
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
外部类过滤DLNA设备信息保留DMS设备列表,并发出更新广播通知UI
- public class AllShareProxy implements IDeviceOperator,
- IDeviceOperator.IDMSDeviceOperator{
- private static final CommonLog log = LogFactory.createLog();
- private static AllShareProxy instance;
- private Context mContext;
- private AbstractMediaMng dmsMediaMng;
- private AllShareProxy(Context context) {
- mContext = context;
- dmsMediaMng = new MediaServerMng(context);
- }
- public static synchronized AllShareProxy getInstance(Context context) {
- if (instance == null){
- instance = new AllShareProxy(context);
- }
- return instance;
- }
- public void startSearch(){
- mContext.startService(new Intent(DlnaService.SEARCH_DEVICES));
- }
- public void resetSearch(){
- mContext.startService(new Intent(DlnaService.RESET_SEARCH_DEVICES));
- clearDevice();
- }
- public void exitSearch(){
- mContext.stopService(new Intent(mContext, DlnaService.class));
- clearDevice();
- }
- @Override
- public void addDevice(Device d) {
- if (UpnpUtil.isMediaServerDevice(d)){
- dmsMediaMng.addDevice(d);
- }
- }
- @Override
- public void removeDevice(Device d) {
- if (UpnpUtil.isMediaServerDevice(d)){
- dmsMediaMng.removeDevice(d);
- }
- }
- @Override
- public void clearDevice() {
- dmsMediaMng.clear();
- }
- @Override
- public List<Device> getDMSDeviceList() {
- return dmsMediaMng.getDeviceList();
- }
- @Override
- public void setDMSSelectedDevice(Device selectedDevice) {
- dmsMediaMng.setSelectedDevice(selectedDevice);
- }
- @Override
- public Device getDMSSelectedDevice() {
- return dmsMediaMng.getSelectedDevice();
- }
- }<span style="color:#ff0000;">
- </span>
选中浏览设备后通过代理放送控制命令获取xml文件描述并解析得到多媒体文件信息
- public class BrowseDMSProxy {
- public static interface BrowseRequestCallback
- {
- public void onGetItems(final List<MediaItem> list);
- }
- private static final CommonLog log = LogFactory.createLog();
- public static void syncGetDirectory(final Context context, final BrowseRequestCallback callback) {
- Thread thread = new Thread(new Runnable() {
- @Override
- public void run() {
- List<MediaItem> list = null;
- try {
- list = getDirectory(context);
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (callback != null){
- callback.onGetItems(list);
- }
- }
- });
- thread.start();
- }
- public static void syncGetItems(final Context context, final String id,final BrowseRequestCallback callback) {
- Thread thread = new Thread(new Runnable() {
- @Override
- public void run() {
- List<MediaItem> list = null;
- try {
- list = getItems(context, id);
- } catch (Exception e) {
- e.printStackTrace();
- }
- if (callback != null){
- callback.onGetItems(list);
- }
- }
- });
- thread.start();
- }
- public static List<MediaItem> getDirectory(Context context) throws Exception {
- Device selDevice = AllShareProxy.getInstance(context).getDMSSelectedDevice();
- if (selDevice == null) {
- log.e("no selDevice!!!");
- return null;
- }
- // Node selDevNode = selDevice.getDeviceNode();
- // if (selDevNode != null){
- // selDevNode.print();
- // }
- org.cybergarage.upnp.Service service = selDevice
- .getService("urn:schemas-upnp-org:service:ContentDirectory:1");
- if (service == null)
- {
- log.e("no service for ContentDirectory!!!");
- return null;
- }
- // Node serverNode = service.getServiceNode();
- // if (serverNode != null){
- // serverNode.print();
- // }
- Action action = service.getAction("Browse");
- if(action == null)
- {
- log.e("action for Browse is null!!!");
- return null;
- }
- ArgumentList argumentList = action.getArgumentList();
- argumentList.getArgument("ObjectID").setValue(0);
- argumentList.getArgument("BrowseFlag").setValue("BrowseDirectChildren");
- argumentList.getArgument("StartingIndex").setValue("0");
- argumentList.getArgument("RequestedCount").setValue("0");
- argumentList.getArgument("Filter").setValue("*");
- argumentList.getArgument("SortCriteria").setValue("");
- ArgumentList actionInputArgList = action.getInputArgumentList();
- // int size = actionInputArgList.size();
- // for(int i = 0; i < size; i++){
- // Argument argument = (Argument) (actionInputArgList.get(i));
- // argument.getArgumentNode().print();
- // }
- if (action.postControlAction()) {
- ArgumentList outArgList = action.getOutputArgumentList();
- Argument result = outArgList.getArgument("Result");
- log.d("result value = \n" + result.getValue());
- List<MediaItem> items = ParseUtil.parseResult(result);
- return items;
- } else {
- UPnPStatus err = action.getControlStatus();
- log.e("Error Code = " + err.getCode());
- log.e("Error Desc = " + err.getDescription());
- }
- return null;
- }
- public static List<MediaItem> getItems(Context context, String id) throws Exception{
- Device selDevice = AllShareProxy.getInstance(context).getDMSSelectedDevice();
- if (selDevice == null) {
- log.e("no selDevice!!!");
- return null;
- }
- org.cybergarage.upnp.Service service = selDevice
- .getService("urn:schemas-upnp-org:service:ContentDirectory:1");
- if (selDevice == null)
- {
- log.e("no service for ContentDirectory!!!");
- return null;
- }
- Action action = service.getAction("Browse");
- if(action == null)
- {
- log.e("action for Browse is null");
- return null;
- }
- // action.getActionNode().print();
- ArgumentList argumentList = action.getArgumentList();
- argumentList.getArgument("ObjectID").setValue(id);
- argumentList.getArgument("BrowseFlag").setValue("BrowseDirectChildren");
- argumentList.getArgument("StartingIndex").setValue("0");
- argumentList.getArgument("RequestedCount").setValue("0");
- argumentList.getArgument("Filter").setValue("*");
- argumentList.getArgument("SortCriteria").setValue("");
- if (action.postControlAction()) {
- ArgumentList outArgList = action.getOutputArgumentList();
- Argument result = outArgList.getArgument("Result");
- log.d("result value = \n" + result.getValue());
- List<MediaItem> items = ParseUtil.parseResult(result);
- return items;
- } else {
- UPnPStatus err = action.getControlStatus();
- System.out.println("Error Code = " + err.getCode());
- System.out.println("Error Desc = " + err.getDescription());
- }
- return null;
- }
- }
最后远程播放音视频流,对于图片先下载到本地再显示
鉴于CyberGarage库有些许bug,工程里依赖的jar包dlna_framework.jar是经过修改过的
原版cyber库下载地址:https://github.com/cybergarage/CyberLink4Java
dlna_framework下载地址: https://github.com/geniusgithub/dlna_framework
具体详细看demo吧
附上工程链接:
http://download.youkuaiyun.com/detail/geniuseoe2012/4970066(旧版)
github下载链接:
https://github.com/geniusgithub/MediaPlayer
PS:建议大家上github下载,这样可以更新到最新的代码
文档链接:
http://download.youkuaiyun.com/detail/geniuseoe2012/4969961
关于DMR和DMS的实现请参考这两篇博文:
基于Platinum库的DMR实现(android)
more brilliant,Please pay attention to my 优快云 blog -->http://blog.youkuaiyun.com/geniuseoe2012
- <pre name="code" class="cpp"><pre class="java" name="code"><pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- <pre></pre>
- </pre></pre>
-
21楼
pengkun520 2013-10-28 10:53发表
-
-
dlna_framework.jar 在哪里。
-
Re:
蓝斯 2013-10-28 21:17发表
-
- 回复pengkun520:下载地址不都给了么
-
-
20楼
c牧殇c 2013-10-08 14:54发表
-
- 我search不到开启了DLNA的华为手机啊...楼主帮忙...着急啊!~~
-
19楼
c牧殇c 2013-10-08 14:52发表
-
- 请问楼主大大,为什么我用工程代码..然后点击search的时候,找不到我的华为手机的DLNA服务设备 啊???我怎么测试这个工程好不好用呢?
-
18楼
quzhiyong99 2013-09-02 11:46发表
-
- 请问大家,网上下的代码search不到Device,是什么原因?你们是怎么解决的?请教了
-
17楼
dywywh709 2013-08-18 18:34发表
-
-
我再补充一下哈,我把dlna_framework.jar里面class对应的java源代码复制到工程的src文件下,就可以运行了,是你给的dlna_framework有问题呢?还是使用的时候还要注意什么,求指教交流啊
-
Re:
蓝斯 2013-08-21 20:59发表
-
- 回复dywywh709:用github上的mediaplayer和dlna_framework不会有问题的
-
-
16楼
dywywh709 2013-08-18 18:20发表
-
- 不知为何你共享的代码一运行就crash了,我重新编译了dlna_framework.jar,还是没用;打断点调试总是死在mAllShareProxy = AllShareProxy.getInstance(this);这句话上,还请您多多指点
-
15楼
viptmd 2013-08-14 15:28发表
-
-
我搞错了 lz做的是DMP的实现,我想要的是DMC的实现
-
14楼
viptmd 2013-08-13 15:15发表
-
- 用的github上最新的代码,也找不到设备, mirage能发现
-
13楼
hui372405333 2013-08-01 21:11发表
-
-
Allshare怎么没有发现到设备,mirage可以发现分享文件,请问下是库不一样还是那里出现问题,谢谢
-
Re:
蓝斯 2013-08-02 12:31发表
-
-
回复hui372405333:mirage用的是cling库,当然不一样
关于搜索不到的问题,旧版的有bug可能会出现这个问题
建议上github下载最新版代码
https://github.com/geniusgithub/MediaPlayer
-
-
12楼
tkwxty 2013-07-11 22:49发表
-
-
楼主问下啊,你工程链接的那个mirageDLNA能否提供一下源代码借鉴借鉴下呢。本人将不胜感激!
-
Re:
tkwxty 2013-07-12 16:46发表
-
- 试了下那个软件效果还不错
-
Re:
蓝斯 2013-07-12 09:30发表
-
- 回复tkwxty:兄台,那个是第三方软件。。。
-
-
11楼
mingren001 2013-07-04 17:28发表
-
- 很好,正准备研究下这个 的
-
10楼
tianjia125 2013-06-21 08:48发表
-
- 跪求博主,请问怎么让手机端只做lib,像手机上的airplay,,,然后发送到PC或者电视上看?需要怎么实现呀?
-
9楼
laohui110 2013-05-06 17:11发表
-
- 楼主,有DMC相关的资料或者demo么
-
8楼
jasontaondsc 2013-04-25 11:38发表
-
-
网上下的CyberGarage在search就有问题,能否共享下dlna_framework.jar源码? 谢谢
-
Re:
jmq_0000 2013-05-31 17:01发表
-
- 回复jasontaondsc:反编译就可以看见了。
-
Re:
蓝斯 2013-05-02 12:32发表
-
- 回复jasontaondsc:source address:https://github.com/geniusgithub/dlna_framework
-
-
7楼
齐殿天下 2013-03-22 16:43发表
-
- 很好
-
6楼
zmyde2010 2013-03-08 21:13发表
-
-
研究了一下楼主的代码,写的漂亮极了。两个问题 :1) 我看CyberLink库修改了不少东西,能否分享一下;2) DMR/DMS 好像没有实现,有开源例子吗?
-
Re:
蓝斯 2013-03-13 22:15发表
-
-
回复zmyde2010:there is a demo for dms ,but it's used by cling
link:https://github.com/friflaj/wireme
-
Re:
zmyde2010 2013-03-08 21:14发表
-
- 回复zmyde2010:3) DMC好像也没有实现
-
-
5楼
ozh555 2013-03-05 10:24发表
-
-
博住你好!
请问有没有DMR的例子或者开源项目介绍?
-
4楼
拂帘望猪 2013-03-04 22:20发表
-
- 谢谢楼主分享这么好的东西,请问一下,为什么我导入该工程无法搜索到连接在该wifi下的手机,而只能搜索到连接的电脑设备??我跟踪代码发现始终无法addDevice。
-
3楼
zmyde2010 2013-02-28 16:09发表
-
-
同问,楼主libs/下面那几个jar哪里来的
-
Re:
蓝斯 2013-02-28 20:21发表
-
- 回复zmyde2010:网上下载来的,博文中有地址
-
-
2楼
zmyde2010 2013-02-28 16:04发表
-
- 顶
-
1楼
jiangkaibo1987 2013-02-21 16:43发表
-
- 请问下,dlna_framework.jar这个是如何修改的呢