随着智能手机越来越流行,多屏互动在家庭里面多个设备之间分享视频,音乐,图片,变得很实用。现在市场上盒子这种产品很多,都是基于手机 + 盒子 + 电视,是将手机视频投射到电视上观看。其中产品有,百度影(百度视频apk + 百度影棒 到电视),小米盒子,还有Lavod(呐活)。
盒子这种产品用到的技术为DLNA,Wifi Display或Miracast。
先说说DLNA,关于DLNA相关内容有一个很好的博客,感谢博主的无私奉献精神.
http://blog.csdn.net/lancees/article/details/8477513
http://www.plutinosoft.com/platinum/
一. DLNA协议使用.
DLNA分为几大功能模块:DMS, DMR, DMC, DMP。蓝斯的博客里面有DMS, DMR, DMP的开源代码,要指出的是DMS模块代码中存在不识别Unicode编码问题,所以分享视频,音乐和图片给DMP模块时,字符名称要为ASCII码。
关于DLNA的使用,一个包含DMC模块功能的A设备,一个包含DMR模块功能的B设备,两个同时连接到一个无线路由器C上,进行控制分享,没什么问题。但是将DMR的B设备设置为wifi热点,DMC的A设备连接到B上,发现这是DMR功能打不开,这里可能是ip地址引起的,使用测试是用MediaRender apk测试的。
二. Miracast使用.
1. 从设置显示--->无线显示打开流程.
a. WifiDisplaySettings中获得DisplayManager
mDisplayManager = (DisplayManager)getActivity().getSystemService(Context.DISPLAY_SERVICE); //获得DisplayManager对象
mDisplayManager.connectWifiDisplay(display.getDeviceAddress());//连接设备
b. DisplayManager.java
public void connectWifiDisplay(String deviceAddress) {
mGlobal.connectWifiDisplay(deviceAddress);
}
c. DisplayManagerGlobal.java
public void connectWifiDisplay(String deviceAddress) {
if (deviceAddress == null) {
throw new IllegalArgumentException("deviceAddress must not be null");
}
try {
mDm.connectWifiDisplay(deviceAddress);
} catch (RemoteException ex) {
Log.e(TAG, "Failed to connect to Wifi display " + deviceAddress + ".", ex);
}
}
d. DisplayManagerService.java
public void connectWifiDisplay(String address) {
if (address == null) {
throw new IllegalArgumentException("address must not be null");
}
final boolean trusted = canCallerConfigureWifiDisplay();
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
if (mWifiDisplayAdapter != null) {
mWifiDisplayAdapter.requestConnectLocked(address, trusted);
}
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
e. WifiDisplayAdapter.java
public void requestConnectLocked(final String address, final boolean trusted) {
if (DEBUG) {
Slog.d(TAG, "requestConnectLocked: address=" + address + ", trusted=" + trusted);
}
if (!trusted) {
synchronized (getSyncRoot()) {
if (!isRememberedDisplayLocked(address)) {
Slog.w(TAG, "Ignoring request by an untrusted client to connect to "
+ "an unknown wifi display: " + address);
return;
}
}
}
getHandler().post(new Runnable() {
@Override
public void run() {
if (mDisplayController != null) {
mDisplayController.requestConnect(address);
}
}
});
}
f. WifiDisplayController.java
requestConnect(), connect(), updateConnection()
2. 刷新流程
a. WindowManagerService.java中updateRotationUncheckedLocked();
mDisplayManagerService.performTraversalInTransactionFromWindowManager()
b. DisplayManagerService.java
performTraversalInTransactionLocked();
mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT);
case MSG_UPDATE_VIEWPORT:
c. InputManagerService.java
setDisplayViewport(boolean external, DisplayViewport viewport);
d. com_android_server_input_InputManagerService.cpp
nativeSetDisplayViewport();
e. PointerController.cpp
void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation);