湖畔镇

封装DLNA开源库

对Cling类库所做的封装

数据结构

BaseDeviceItem

设备基类

1
2
3
4
5
6
7
8
9
10
11
12
13
public class BaseDeviceItem {
// DLNA设备类型
protected int mDlnaType;
// AV服务
public Service mAVservice;
// RC服务
protected Service mRCservice;
// DLNA设备
protected DeviceItem mDeviceItem;
// 模块表
protected HashMap<String, IBaseModule> mModules;
...
}

BaseBindableDeviceItem

有绑定专辑功能的设备,持有一个BaseItemBindableModel

BaseItemBindableModel

绑定专辑模型

1
2
3
4
5
6
//  每个键上绑定的专辑列表
protected HashMap<Integer, AlbumM> mAlbums;
// 名字
protected List<String> mKeyNames;
// 图标
protected List<Integer> mKeyImages;

CommonDevice

支持喜马拉雅协议的通用设备

1
2
3
4
5
6
7
8
9
public abstract class CommonDeviceItem extends BaseBindableDeviceItem {
// PQ服务
protected Service mPQservice;
// MM服务
protected Service mMMservice;
// 当前播放的数据结构
protected BaseCurrentPlayingModel mCurrentPlayingModel = new BaseCurrentPlayingModel();
...
}

BaseCurrentPlayingModel保存当前播放的数据结构,如当前页,当前列表,当前曲目数deng

LinkedDeviceModel

  • 持有一个BaseDeviceItem
  • 管理播放状态:播放、停止
  • 管理音量
  • 透过它获得设备的AV和RC服务

IDlnaController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public interface IDlnaController {
// 基本信息:设备类型、UDN
int getDeviceType();
String[] getCheckedUdn();
boolean isThisDeviceType(BaseDeviceItem deviceItem);

// 设备管理
void addDeivce(BaseDeviceItem myDeviceItem);
boolean removeDeivce(BaseDeviceItem myDeviceItem);
void clearDeivce();
List<BaseDeviceItem> getAllDevices();
boolean isThisDevice(BaseDeviceItem deviceItem);

// 模块管理
void initModules();
IBaseModule getModule(String moduleName);
void setModule(IBaseModule baseModule);

void onCommandFailed(ActionModel model);

// 获取设备信息,如绑定专辑、内置声音
void initDeviceInfo(BaseDeviceItem deviceItem, IActionCallBack callBack);

// 在默认的推送后面加上额外的操作,如订阅更多种类的事件
void tuisongExtra(BasePlayManageController basePlayManageController);

// 播放声音
void playSound(BaseDeviceItem baseDeviceItem, ActionModel model);

// 切换到本地
void change2Bendi(BasePlayManageController basePlayManageController);
}

BaseDlnaController

DLNA控制器基类,实现IDlnaController接口,维护了设备列表、模块表、ControlPoint,功能还需要子类实现

CommonController

实现了通用的功能

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public void tuisongExtra(BasePlayManageController basePlayManageController) {
CommonDeviceItem commonDeviceItem = (CommonDeviceItem) basePlayManageController.getLinkedDeviceModel().getNowDeviceItem();
if (commonDeviceItem.getPQservice() != null) {
basePlayManageController.setPlayQueueSubscriptionCallback(new MyPlaySubscriptionCallback(commonDeviceItem.getPQservice(), 600, basePlayManageController));
getControlPoint().execute(basePlayManageController.getPlayQueueSubscriptionCallback());
}
if (commonDeviceItem.getMMservice() != null) {
basePlayManageController.setMediaManagerSubscriptionCallback(new MyPlaySubscriptionCallback(commonDeviceItem.getMMservice(), 600, basePlayManageController));
getControlPoint().execute(basePlayManageController.getMediaManagerSubscriptionCallback());
}
}

tuisongExtra()里主要订阅了播放列表PQService和媒体管理MMService

1
2
3
4
5
6
7
8
9
10
11
@Override
public void change2Bendi(BasePlayManageController basePlayManageController) {
if (basePlayManageController.getPlayQueueSubscriptionCallback() != null) {
basePlayManageController.getPlayQueueSubscriptionCallback().end();
basePlayManageController.setPlayQueueSubscriptionCallback(null);
}
if (basePlayManageController.getMediaManagerSubscriptionCallback() != null) {
basePlayManageController.getMediaManagerSubscriptionCallback().end();
basePlayManageController.setMediaManagerSubscriptionCallback(null);
}
}

change2Bendi()里进行了退订

1
2
3
4
5
6
7
8
@Override
public void playSound(BaseDeviceItem baseDeviceItem, ActionModel model) {
BaseTuiSongModule tuiSongModule = (BaseTuiSongModule) getModule(BaseTuiSongModule.NAME);
if (tuiSongModule == null) {
return;
}
tuiSongModule.tuisong(baseDeviceItem, model);
}

playSound()通过BaseTuiSongModuletuisong()实现

DlnaControllerFactory

通过这个工厂类生成了控制器

1
2
3
4
5
6
7
8
9
10
public class DlnaControllerFactory {
List<IDlnaControllerCreator> mCreators;
...
// 调用所有构造器的设备添加回调
public void buildController(BaseDeviceItem baseDeviceItem) {
for (int i = 0; i < mCreators.size(); i++) {
mCreators.get(i).onDeviceAdded(baseDeviceItem);
}
}
}

保存了一组控制器的构造器,创建时根据控制器的类型选择合适的构造器构造控制器

IDlnaControllerCreator

控制器构造器接口

1
2
3
4
5
6
7
8
public interface IDlnaControllerCreator {
// 设备添加回调
void onDeviceAdded(BaseDeviceItem baseDeviceItem);
// 创建控制器
void buildController();
// 子类实现,返回控制器类型
int getControllerType();
}

AbsControllerCreator

一个抽象的实现类,构造函数再DlnaManager中添加了一个控制器

1
2
3
4
5
6
7
public abstract class AbsControllerCreator implements IDlnaControllerCreator {
protected Context mContext;
public AbsControllerCreator(Context context) {
DlnaManager.getInstance(context).addControllerCreator(this);
mContext = context;
}
}

CometController

举个Comet设备的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class CometControllerCreator extends AbsControllerCreator {
@Override
public void onDeviceAdded(BaseDeviceItem baseDeviceItem) {
// 获得设备UDN
String udn = baseDeviceItem.getDevice().getIdentity().getUdn().toString();
// 判断UDN是否包含COMET设备的头信息
if (udn.contains(CometController.DEVICE_COMET_HEADER)) {
baseDeviceItem.setDlnaType(DeviceType.comet);
DlnaManager.getInstance(mContext).getController(DeviceType.comet).addDeivce(baseDeviceItem);
}
}
}

@Override
public int getControllerType() {
return DeviceType.comet;
}

BaseDlnaModule

DLNA功能模块基础类
功能的实现都差不多,通过发送的ActionCallback不同来区分

  • BasePlayModule
  • BaseDownloadModule
  • BaseDlnaKeyModule
  • BaseTuisongModule
  • BaseManageTFModule
  • BaseBindModule

DlnaManager

DLNA功能的管理器,持有一个CoreController

1
2
3
4
5
6
7
8
9
10
public class DlnaManager {
// 核心控制器
public CoreController mCoreController;
// 播放事件管理
private PlayManageController mPlayManageController;
private OperationStorageModel mOperationStroageModel;
private HashMap<Integer, IDlnaController> mContrllerMap;
private CopyOnWriteArrayList<OnDeviceChangedListener> mOnDeviceChangedListeners;
private CopyOnWriteArrayList<OnKeyEventListener> mOnkeyEventListeners;
}
  • 设备管理
  • 控制器管理
  • 播放控制

CoreController

核心控制器,BasePlayManageController的子类

绑定服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public void bindService(Context context) {
...
deviceListRegistryListener = new DeviceListRegistryListener();
mIsBind = mContext.bindService(new Intent(mContext, DmcUpnpService.class), serviceConnection, Context.BIND_AUTO_CREATE);
...
}

private ServiceConnection serviceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
...
upnpService = (UpnpServiceBinder) service;
// 为这个服务提供CoreUpnpServiceListener
upnpService.setProcessor(coreUpnpServiceListener);
...
// 在Registry中添加DeviceListRegistryListener
upnpService.getRegistry().addListener(deviceListRegistryListener);
// 移除所有的远端和本地设备
upnpService.getRegistry().removeAllRemoteDevices(true);
upnpService.getRegistry().removeAllLocalDevices();
// 搜索设备
searchDevice();
}

public void onServiceDisconnected(ComponentName className) {
upnpService = null;
}
};

初始化,绑定到DmcUpnpService

CoreUpnpServiceListener

1
2
3
4
5
6
public interface CoreUpnpServiceListener {
void onNetworkChanged(NetworkInterface ni);
void onRouterError(String message);
void onRouterDisabled();
void onRouterEnabled();
}

监听网络状态和路由状态

DeviceListRegistryListener

实现接口RegistryListener,这个接口主要用来通知设备的添加、删除和更新

1
2
3
4
5
6
7
8
9
10
11
public interface RegistryListener {
void remoteDeviceDiscoveryStarted(Registry registry, RemoteDevice device);
void remoteDeviceDiscoveryFailed(Registry registry, RemoteDevice device, Exception ex);
void remoteDeviceAdded(Registry registry, RemoteDevice device);
void remoteDeviceUpdated(Registry registry, RemoteDevice device);
void remoteDeviceRemoved(Registry registry, RemoteDevice device);
void localDeviceAdded(Registry registry, LocalDevice device);
void localDeviceRemoved(Registry registry, LocalDevice device);
void beforeShutdown(Registry registry);
void afterShutdown();
}

搜索设备

通过startScanThread()stopScanThread()方法
创建ScanThread搜索设备,最终调用upnpService.getControlPoint().search()

设备管理

通过removeDevice()removeAllDevices()移除设备
最终调用Registry中的移除设备的方法

按键处理

实现了MyPlaySubscriptionCallback.OnPlayKeyHandler接口
通过BaseDlnaKeyModuleGENASubscription结构转化为KeyEvent,然后调用OnCoreControllerListener.onKeyAciton()

OnCoreControllerListener

1
2
3
4
5
6
public interface OnCoreControllerListener {
void onDeviceAdded(BaseDeviceItem baseDeviceItem);
void onDeviceRemoved(BaseDeviceItem baseDeviceItem);
void onNetworkChanged();
void onKeyAciton(KeyEvent keyEvent);
}

暴露给DlnaManager的接口,处理设备添加、设备删除、网络变化和按键事件

播放控制

包括推送到设备、切换到本地、(继续)播放、上一曲、下一曲、暂停、停止

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public void tuisongDevice(BaseDeviceItem baseDeviceItem) {
if (!isUpnpServiceCanUse()) {
return;
}
// 如果当前没有操作的设备就创建一个
if (mLinkedDeviceModel == null) {
mLinkedDeviceModel = new LinkedDeviceModel();
}
mLinkedDeviceModel.setNowDeviceItem(baseDeviceItem);
// 获得一个控制器
mNowDlnaController = mDlnaManager.getController(baseDeviceItem.getDlnaType());
if (mNowDlnaController == null) {
return;
}
//这里推送需要重新重新新建订阅,两台设备切换的情况,一直只会订阅第一台设备
mPlaySubscriptionCallback = new MyPlaySubscriptionCallback(mLinkedDeviceModel.getAvService(), 600, this);
upnpService.getControlPoint().execute(mPlaySubscriptionCallback);
mNowDlnaController.tuisongExtra(this);
}

首先通过tuisongDevice()确定要操作的设备,获得该设备类型的控制器,然后调用IDlnaController.tuisongExtra()

音量控制

进度条控制

提供了setSeekBar设置进度条,以及PositionThread来周期性获得播放进度

BasePlayManageController

  • 持有一个LinkedDeviceModel,记录正在操作的设备
  • 订阅事件相关处理
  • 实现了MyPlaySubscriptionCallback.OnPlayKeyHandler接口(并没实现,仍需要子类实现)

DmcUpnpService

通过绑定这个服务调用UpnpService提供的功能,返回AndroidUpnpService接口

1
2
3
4
5
6
public interface AndroidUpnpService {
UpnpService get();
UpnpServiceConfiguration getConfiguration();
Registry getRegistry();
ControlPoint getControlPoint();
}

通过createUpnpService()创建一个UPnP服务,提供配置、路由等信息

流程

搜索设备

发送命令

按键事件

分享