转载地址:http://blog.csdn.net/lancees/article/details/8477513
我们在做
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.csdn.net/detail/geniuseoe2012/4970066(旧版)
github下载链接:
https://github.com/geniusgithub/MediaPlayer
PS:建议大家上github下载,这样可以更新到最新的代码
文档链接:
http://download.csdn.net/detail/geniuseoe2012/4969961