关于dlna的介绍就不多说了,具体可以看这篇博文http://blog.csdn.net/geniuseoe2012/article/details/8230877
或者问百度谷歌
Dlna通讯采用upnp协议,详看这篇博文:http://blog.csdn.net/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;
- }
- }
最后远程播放音视频流,对于图片先下载到本地再显示
具体详情看demo吧
apk下载地址:
https://raw.githubusercontent.com/geniusgithub/MediaPlayer/master/storage/mediaPlayer.apk
附上工程链接:
http://download.csdn.NET/detail/geniuseoe2012/4970066(旧版)
github下载链接:
https://github.com/geniusgithub/MediaPlayer
PS:建议大家上github下载,这样可以更新到最新的代码
文档链接:
http://download.csdn.net/detail/geniuseoe2012/4969961
关于DMR和DMS的实现请参考这两篇博文:
基于Platinum库的DMR实现(android)
more brilliant,Please pay attention to my CSDN blog -->http://blog.csdn.Net/geniuseoe2012