接上篇博文:基于Platinum库的DMR实现(android)
文章讲述了如何使用Platinum库实现DMR
今天同样使用该库,来讲解一下DMS的实现
关于该库如何编译,请参考这篇博文: NDK下 将Platinum SDK 编译成so库 (android - upnp)
下面给出运行效果图:
界面很简单,就是一些开关和设备名以及设备运行状态的展现
下面看看代码片段:
JNI接口文件:
public class DMSJniInterface { static { System.loadLibrary("git-platinum"); } public static native int startServer(byte[] rootDir,byte[] name ,byte[] uid); public static native int stopServer(); public static native boolean enableLogPrint(boolean flag); ////////////////////////////////////////////////////////////////////////////////////////// public static int startServer(String rootDir, String name ,String uid){ if (rootDir == null){ rootDir = ""; } if (name == null){ name = ""; } if (uid == null){ uid = ""; } int ret = -1; try { ret = startServer(rootDir.getBytes("utf-8"), name.getBytes("utf-8"), uid.getBytes("utf-8")); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return ret; } }
后台服务:
public class DMSService extends Service implements IBaseEngine{ private static final CommonLog log = LogFactory.createLog(); public static final String START_SERVER_ENGINE = "com.geniusgithub.start.dmsengine"; public static final String RESTART_SERVER_ENGINE = "com.geniusgithub.restart.dmsengine"; private DMSWorkThread mWorkThread; private Handler mHandler; private static final int START_ENGINE_MSG_ID = 0x0001; private static final int RESTART_ENGINE_MSG_ID = 0x0002; private static final int DELAY_TIME = 1000; private MediaStoreCenter mMediaStoreCenter; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); initService(); log.e("MediaServerService onCreate"); } @Override public void onDestroy() { unInitService(); log.e("MediaServerService onDestroy"); super.onDestroy(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { if (intent != null){ String actionString = intent.getAction(); if (actionString != null){ if (actionString.equalsIgnoreCase(START_SERVER_ENGINE)){ delayToSendStartMsg(); }else if (actionString.equalsIgnoreCase(RESTART_SERVER_ENGINE)){ delayToSendRestartMsg(); } } } return super.onStartCommand(intent, flags, startId); } private void initService(){ mWorkThread = new DMSWorkThread(this); mHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch(msg.what){ case START_ENGINE_MSG_ID: startEngine(); break; case RESTART_ENGINE_MSG_ID: restartEngine(); break; } } }; mMediaStoreCenter = MediaStoreCenter.getInstance(); mMediaStoreCenter.clearWebFolder(); mMediaStoreCenter.createWebFolder(); mMediaStoreCenter.doScanMedia(); } private void unInitService(){ stopEngine(); removeStartMsg(); removeRestartMsg(); mMediaStoreCenter.clearAllData(); } private void delayToSendStartMsg(){ removeStartMsg(); mHandler.sendEmptyMessageDelayed(START_ENGINE_MSG_ID, DELAY_TIME); } private void delayToSendRestartMsg(){ removeStartMsg(); removeRestartMsg(); mHandler.sendEmptyMessageDelayed(RESTART_ENGINE_MSG_ID, DELAY_TIME); } private void removeStartMsg(){ mHandler.removeMessages(START_ENGINE_MSG_ID); } private void removeRestartMsg(){ mHandler.removeMessages(RESTART_ENGINE_MSG_ID); } @Override public boolean startEngine() { awakeWorkThread(); return true; } @Override public boolean stopEngine() { mWorkThread.setParam("", "", ""); exitWorkThread(); return true; } @Override public boolean restartEngine() { String friendName = DlnaUtils.getDevName(this); String uuid = DlnaUtils.creat12BitUUID(this); mWorkThread.setParam(mMediaStoreCenter.getRootDir(), friendName, uuid); if (mWorkThread.isAlive()){ mWorkThread.restartEngine(); }else{ mWorkThread.start(); } return true; } private void awakeWorkThread(){ String friendName = DlnaUtils.getDevName(this); String uuid = DlnaUtils.creat12BitUUID(this); mWorkThread.setParam(mMediaStoreCenter.getRootDir(), friendName, uuid); if (mWorkThread.isAlive()){ mWorkThread.awakeThread(); }else{ mWorkThread.start(); } } private void exitWorkThread(){ if (mWorkThread != null && mWorkThread.isAlive()){ mWorkThread.exit(); long time1 = System.currentTimeMillis(); while(mWorkThread.isAlive()){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } long time2 = System.currentTimeMillis(); log.e("exitWorkThread cost time:" + (time2 - time1)); mWorkThread = null; } } }
工作线程:
public class DMSWorkThread extends Thread implements IBaseEngine{ private static final CommonLog log = LogFactory.createLog(); private static final int CHECK_INTERVAL = 30 * 1000; private Context mContext = null; private boolean mStartSuccess = false; private boolean mExitFlag = false; private String mRootdir = ""; private String mFriendName = ""; private String mUUID = ""; private ServerApplication mApplication; public DMSWorkThread(Context context){ mContext = context; mApplication = ServerApplication.getInstance(); } public void setFlag(boolean flag){ mStartSuccess = flag; } public void setParam(String rootDir, String friendName, String uuid){ mRootdir = rootDir; mFriendName = friendName; mUUID = uuid; mApplication.updateDevInfo(mRootdir, mFriendName, mUUID); } public void awakeThread(){ synchronized (this) { notifyAll(); } } public void exit(){ mExitFlag = true; awakeThread(); } @Override public void run() { log.e("DMSWorkThread run..."); while(true) { if (mExitFlag){ stopEngine(); break; } refreshNotify(); synchronized(this) { try { wait(CHECK_INTERVAL); } catch(Exception e) { e.printStackTrace(); } } if (mExitFlag){ stopEngine(); break; } } log.e("DMSWorkThread over..."); } public void refreshNotify(){ if (!CommonUtil.checkNetworkState(mContext)){ return ; } if (!mStartSuccess){ stopEngine(); try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } boolean ret = startEngine(); if (ret){ mStartSuccess = true; } } } @Override public boolean startEngine() { if (mFriendName.length() == 0){ return false; } int ret = DMSJniInterface.startServer(mRootdir, mFriendName, mUUID); boolean result = (ret == 0 ? true : false); mApplication.setDevStatus(result); return result; } @Override public boolean stopEngine() { DMSJniInterface.stopServer(); mApplication.setDevStatus(false); return true; } @Override public boolean restartEngine() { setFlag(false); awakeThread(); return true; } }
多媒体遍历:
public class MediaScannerCenter { private static final CommonLog log = LogFactory.createLog(); public static final int AUDIO_TYPE = 0; public static final int VIDEO_TYPE = 1; public static final int IMAGE_TYPE = 2; String AUDIO_PATH = MediaStore.Audio.AudioColumns.DATA; String AUDIO_DISPLAYHNAME = MediaStore.Audio.AudioColumns.DISPLAY_NAME; String AUDIO_COLUMN_STRS[] = {AUDIO_PATH, AUDIO_DISPLAYHNAME}; String VIDEO_PATH = MediaStore.Video.VideoColumns.DATA; String VIDEO_DISPLAYHNAME = MediaStore.Video.VideoColumns.DISPLAY_NAME; String VIDEO_COLUMN_STRS[] = {VIDEO_PATH, VIDEO_DISPLAYHNAME}; String IMAGE_PATH = MediaStore.Images.ImageColumns.DATA; String IMAGE_DISPLAYHNAME = MediaStore.Images.ImageColumns.DISPLAY_NAME; String IMAGE_COLUMN_STRS[] = {IMAGE_PATH, IMAGE_DISPLAYHNAME}; private static MediaScannerCenter mInstance; private Context mContext; private ScanMediaThread mediaThread; private MediaScannerCenter(Context context) { mContext = context; initData(); } public static synchronized MediaScannerCenter getInstance() { if (mInstance == null){ mInstance = new MediaScannerCenter(ServerApplication.getInstance()); } return mInstance; } private void initData(){ } public synchronized boolean startScanThread(IMediaScanListener listener){ if (mediaThread == null || !mediaThread.isAlive()){ mediaThread = new ScanMediaThread(listener); mediaThread.start(); } return true; } public synchronized void stopScanThread(){ if (mediaThread != null){ if (mediaThread.isAlive()){ mediaThread.exit(); } mediaThread = null; } } public synchronized boolean isThreadOver(){ if (mediaThread != null && mediaThread.isAlive()){ return false; } return true; } private boolean scanMusic(IMediaScanListener listener, ICancelScanMedia cancelObser) throws Exception { Cursor cursor = mContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, AUDIO_COLUMN_STRS, null, null, AUDIO_DISPLAYHNAME); if (cursor != null) { int count = cursor.getCount(); if (count != 0) { int _name_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DISPLAY_NAME); int _dir_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA); if (cursor.moveToFirst()) { do { if (cancelObser.ifCancel()){ return false; } String srcpath = cursor.getString(_dir_index); String name = cursor.getString(_name_index); listener.mediaScan(AUDIO_TYPE, srcpath, name); } while (cursor.moveToNext()); } } cursor.close(); return true; } return false; } private boolean scanVideo(IMediaScanListener listener, ICancelScanMedia cancelObser) throws Exception { Cursor cursor = mContext.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, VIDEO_COLUMN_STRS, null, null, VIDEO_DISPLAYHNAME); if (cursor != null) { int count = cursor.getCount(); if (count != 0) { int _name_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME); int _dir_index = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA); if (cursor.moveToFirst()) { do { if (cancelObser.ifCancel()){ return false; } String srcpath = cursor.getString(_dir_index); String name = cursor.getString(_name_index); listener.mediaScan(VIDEO_TYPE, srcpath, name); } while (cursor.moveToNext()); } } cursor.close(); return true; } return false; } private boolean scanImage(IMediaScanListener listener, ICancelScanMedia cancelObser) throws Exception { Cursor cursor = mContext.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, IMAGE_COLUMN_STRS, null, null, IMAGE_DISPLAYHNAME); if (cursor != null) { int count = cursor.getCount(); if (count != 0) { int _name_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME); int _dir_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); if (cursor.moveToFirst()) { do { if (cancelObser.ifCancel()){ return false; } String srcpath = cursor.getString(_dir_index); String name = cursor.getString(_name_index); listener.mediaScan(IMAGE_TYPE, srcpath, name); } while (cursor.moveToNext()); } } cursor.close(); return true; } return false; } public class ScanMediaThread extends Thread implements ICancelScanMedia{ IMediaScanListener mListener; boolean exitFlag = false; public ScanMediaThread(IMediaScanListener listener){ mListener = listener; } public void exit(){ exitFlag = true; } @Override public void run() { try { scanMusic(mListener, this); scanVideo(mListener, this); scanImage(mListener, this); } catch (Exception e) { e.printStackTrace(); } super.run(); } @Override public boolean ifCancel() { return exitFlag; } } public interface ICancelScanMedia{ public boolean ifCancel(); } }
startServer和stopServer分别对应设备的开启关闭
在startServer需要传入的三个参数分别是根目录,设备名和设备ID
在本地构建好web目录后将根目录路径设置进去
然后开启一个线程来浏览本地多媒体文件并通过创建软链接来映射本地路径和web路径
详看这个类:
public class MediaStoreCenter implements IMediaScanListener{ private static final CommonLog log = LogFactory.createLog(); private static MediaStoreCenter mInstance; private Context mContext; private String mShareRootPath = ""; private String mImageFolderPath = ""; private String mVideoFolderPath = ""; private String mAudioFolderPath = ""; private MediaScannerCenter mMediaScannerCenter; private Map<String, String> mMediaStoreMap = new HashMap<String, String>(); private MediaStoreCenter(Context context) { mContext = context; initData(); } public static synchronized MediaStoreCenter getInstance() { if (mInstance == null){ mInstance = new MediaStoreCenter(ServerApplication.getInstance()); } return mInstance; } private void initData(){ mShareRootPath = mContext.getFilesDir().getAbsolutePath()+"/" + "rootFolder"; mImageFolderPath = mShareRootPath + "/" + "Image"; mVideoFolderPath = mShareRootPath + "/" + "Video"; mAudioFolderPath = mShareRootPath + "/" + "Audio"; mMediaScannerCenter = MediaScannerCenter.getInstance(); } public String getRootDir(){ return mShareRootPath; } public void clearAllData(){ stopScanMedia(); clearMediaCache(); clearWebFolder(); } public boolean createWebFolder(){ boolean ret = FileHelper.createDirectory(mShareRootPath); if (!ret){ return false; } FileHelper.createDirectory(mImageFolderPath); FileHelper.createDirectory(mVideoFolderPath); FileHelper.createDirectory(mAudioFolderPath); return true; } public boolean clearWebFolder(){ long time = System.currentTimeMillis(); boolean ret = FileHelper.deleteDirectory(mShareRootPath); long time1 = System.currentTimeMillis(); log.e("clearWebFolder cost : " + (time1 - time)); return ret; } public void clearMediaCache(){ mMediaStoreMap.clear(); } public void doScanMedia(){ mMediaScannerCenter.startScanThread(this); } public void stopScanMedia(){ mMediaScannerCenter.stopScanThread(); while(!mMediaScannerCenter.isThreadOver()){ try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } @Override public void mediaScan(int mediaType, String mediaPath, String mediaName) { switch (mediaType) { case MediaScannerCenter.AUDIO_TYPE: mapAudio(mediaPath, mediaName); break; case MediaScannerCenter.VIDEO_TYPE: mapVideo(mediaPath, mediaName); break; case MediaScannerCenter.IMAGE_TYPE: mapImage(mediaPath, mediaName); break; default: break; } } private void mapAudio( String mediaPath, String mediaName){ String webPath = mAudioFolderPath + "/" + mediaName; mMediaStoreMap.put(mediaPath, webPath); softLinkMode(mediaPath, webPath); } private void mapVideo( String mediaPath, String mediaName){ String webPath = mVideoFolderPath + "/" + mediaName; mMediaStoreMap.put(mediaPath, webPath); softLinkMode(mediaPath, webPath); } private void mapImage( String mediaPath, String mediaName){ String webPath = mImageFolderPath + "/" + mediaName; mMediaStoreMap.put(mediaPath, webPath); softLinkMode(mediaPath, webPath); } private boolean softLinkMode(String localPath, String webPath){ Process p; int status; try { long time = System.currentTimeMillis(); String cmd = "ln -s " + localPath + " "+ webPath; p = Runtime.getRuntime().exec(cmd); releaseProcessStream(p); status = p.waitFor(); if (status == 0) { return true;//success } else { log.e("status = " + status + ", run ln -s failed !localPath = " + localPath); return false; } }catch (Exception e) { log.e("Catch Exceptino run ln -s failed !localPath = " + localPath); return false; } } private void releaseProcessStream(Process p) throws IOException{ InputStream stderr = p.getErrorStream(); InputStreamReader isr = new InputStreamReader(stderr); BufferedReader br = new BufferedReader(isr); String line = null; while ( (line = br.readLine()) != null) System.out.println(line); } }
这样控制点访问的时候就可以浏览到多媒体文件了
关键代码大都已经贴出来了,详情大家down code去了解吧
Github下载页:https://github.com/geniusgithub/MediaServer
当然关于android上的DMS实现网上已有一个不错的开源项目wireme
下载地址 http://code.google.com/p/wireme/
用的是cling库,下载链接https://github.com/4thline/cling
不过Platinum库在稳定性方面还是要胜过其它java库的,而且效率也高,所以推荐大家使用
DLNA开发文档链接:http://download.csdn.net/detail/geniuseoe2012/4969961
more brilliant,Please pay attention to my CSDN blog -->http://blog.csdn.net/geniuseoe2012