在做智能电视应用的时候,最头疼的就是焦点问题,特别是对于个人开发者,没有设备这是最最头疼的事情了,在没有设备的情况下,怎么实现智能电视应用呢,接下来我是用TV程序来做演示的,所以接下来的所有操作是在有网络的情况下,TV链接到一个路由器上面,做过开发的人都知道Socket编程分为两种一个是可靠传输的TCP,另一个是不可靠传输的UDP,TCP需要知道对方的IP才能实现,UDP虽然不可靠,但是它可以实现广播来进行通信,从而得知对方的IP地址,然后就可以TCP通信了,对于智能电视的TV开发,如果你没有设备,则可以利用UDP的这个特性来实现手机操控电视,建立通信协议,然后TV端Server接收广播,手机端作为Client发送广播,所有的操作放在手机端来实现,TV只接收并处理相应的命令。

一、UDP实现

首先就是实现UDP的广播通信,下面就是UDP的Server和Client代码:
Server:为了实现能够长时间的接收客户端的信息,所以要把Server端放在线程里面如下:

[java] view plaincopy print?
  1. /**
  2. * 实现后台监听广播
  3. * @author jwzhangjie
  4. */
  5. private class UdpServerRunable implements  Runnable {
  6. @Override
  7. public void run() {
  8. byte[] data = new byte[256];
  9. DatagramPacket udpPacket = new DatagramPacket(data, 256);
  10. try {
  11. udpSocket = new DatagramSocket(43708);
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. }
  15. while (!isStop) {
  16. try {
  17. udpSocket.receive(udpPacket);
  18. if (udpPacket.getLength() != 0) {
  19. Url = new String(data, 0, udpPacket.getLength());
  20. Log.e(TAG, Url);
  21. if (onUdpServerCallBackListener != null) {
  22. onUdpServerCallBackListener.onPlayUrl(Url);
  23. }
  24. }
  25. } catch (Exception e) {
  26. }
  27. }
  28. }
  29. };

为了测试方便我先阶段是Client放在PC端来实现的,为了实现循环测试,我也是把客户端放在一个线程里面,代码如下:

[java] view plaincopy print?
  1. public class Test_UDP_Client{
  2. public static void main(String[] args){
  3. new Thread(new Runnable() {
  4. int i = 0;
  5. private byte[] buffer = new byte[40];
  6. @Override
  7. public void run() {
  8. DatagramPacket dataPacket = null;
  9. DatagramSocket udpSocket = null;
  10. List<String> listData = new ArrayList<String>();
  11. listData.add("http://live.gslb.letv.com/gslb?stream_id=hunan&tag=live&ext=m3u8&sign=live_tv");
  12. <span style="white-space:pre">              </span>listData.add("http://play.api.pptv.com/web-m3u8-300161.m3u8?type=m3u8.web.pad");
  13. try {
  14. udpSocket = new DatagramSocket(43708);
  15. dataPacket = new DatagramPacket(buffer, 40);
  16. dataPacket.setPort(43708);
  17. InetAddress broadcastAddr;
  18. broadcastAddr = InetAddress.getByName("255.255.255.255");
  19. dataPacket.setAddress(broadcastAddr);
  20. } catch (Exception e) {
  21. }
  22. while (i < 30) {
  23. i++;
  24. try {
  25. byte[] data = (listData.get(i%2)).getBytes();
  26. dataPacket.setData( data );
  27. dataPacket.setLength( data.length );
  28. udpSocket.send(dataPacket);
  29. Thread.sleep(20000);
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. }
  34. udpSocket.close();
  35. }
  36. }).start();
  37. }
  38. }

二、Service启动Server的线程

线程是不可控的,如果Activity突然的挂掉,那么这个线程还是在后台运行的,所以我们要把Server放在Service里面,通过Service来启动服务端,代码如下:

[java] view plaincopy print?
  1. package com.jwzhangjie.smart_tv.server;
  2. import java.net.DatagramPacket;
  3. import java.net.DatagramSocket;
  4. import com.jwzhangjie.smart_tv.interfaces.UdpServerCallBackListener;
  5. import android.app.Service;
  6. import android.content.Intent;
  7. import android.os.Binder;
  8. import android.os.IBinder;
  9. import android.util.Log;
  10. public class CommandServer extends Service{
  11. private static String TAG = CommandServer.class.getName();
  12. public static boolean isStop = false;
  13. private DatagramSocket udpSocket = null;
  14. private Thread udpServerThread;
  15. private String Url;
  16. /**
  17. * 设置视频连接的回调接口
  18. */
  19. private UdpServerCallBackListener onUdpServerCallBackListener;
  20. @Override
  21. public IBinder onBind(Intent intent) {
  22. Log.e(TAG, "onBind");
  23. startListener();
  24. return new LocalBinder();
  25. }
  26. /**
  27. * 注册回调接口的方法,供外部调用
  28. * @param onUdpServerCallBackListener
  29. */
  30. public void setOnUdpServerCallBackListener(UdpServerCallBackListener onUdpServerCallBackListener){
  31. this.onUdpServerCallBackListener = onUdpServerCallBackListener;
  32. }
  33. @Override
  34. public void onCreate() {
  35. Log.e(TAG, "onCreate");
  36. super.onCreate();
  37. }
  38. @Override
  39. public int onStartCommand(Intent intent, int flags, int startId) {
  40. Log.e(TAG, "onStartCommand");
  41. startListener();
  42. return super.onStartCommand(intent, flags, startId);
  43. }
  44. @Override
  45. public void onDestroy() {
  46. Log.e(TAG, "onDestroy");
  47. isStop = true;
  48. udpSocket.disconnect();
  49. udpSocket.close();
  50. udpServerThread.interrupt();
  51. udpServerThread = null;
  52. super.onDestroy();
  53. }
  54. @Override
  55. public boolean onUnbind(Intent intent) {
  56. Log.e(TAG, "onUnbind");
  57. return super.onUnbind(intent);
  58. }
  59. /**
  60. * 开始监听广播
  61. */
  62. private void startListener(){
  63. if (udpServerThread == null) {
  64. Log.e(TAG, "run");
  65. udpServerThread = new Thread(new UdpServerRunable());
  66. udpServerThread.start();
  67. }
  68. }
  69. /**
  70. * 实现后台监听广播
  71. * @author pig_video
  72. */
  73. private class UdpServerRunable implements  Runnable {
  74. @Override
  75. public void run() {
  76. byte[] data = new byte[256];
  77. DatagramPacket udpPacket = new DatagramPacket(data, 256);
  78. try {
  79. udpSocket = new DatagramSocket(43708);
  80. } catch (Exception e) {
  81. e.printStackTrace();
  82. }
  83. while (!isStop) {
  84. try {
  85. udpSocket.receive(udpPacket);
  86. if (udpPacket.getLength() != 0) {
  87. Url = new String(data, 0, udpPacket.getLength());
  88. Log.e(TAG, Url);
  89. if (onUdpServerCallBackListener != null) {
  90. onUdpServerCallBackListener.onPlayUrl(Url);
  91. }
  92. }
  93. } catch (Exception e) {
  94. }
  95. }
  96. }
  97. };
  98. //定义内部类继承Binder
  99. public class LocalBinder extends Binder{
  100. //返回本地服务
  101. public CommandServer getService(){
  102. return CommandServer.this;
  103. }
  104. }
  105. }

3.Activity与Service的绑定

我这里启动Service的方式是通过Activity的onBind来启动的,当Activity关闭的时候,也将Service关闭同时关闭Server的线程,当然常驻后台也行,不过用户可能不太喜欢,毕竟需要资源,播放器我选用的是免费的Vitamio主要是他们把上层应用的代码也提供出来了,非常省事。

[java] view plaincopy print?
  1. package com.jwzhangjie.smart_tv.player;
  2. import io.vov.vitamio.LibsChecker;
  3. import io.vov.vitamio.MediaPlayer;
  4. import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener;
  5. import io.vov.vitamio.MediaPlayer.OnErrorListener;
  6. import io.vov.vitamio.MediaPlayer.OnInfoListener;
  7. import io.vov.vitamio.MediaPlayer.OnTimedTextListener;
  8. import io.vov.vitamio.widget.MediaController;
  9. import io.vov.vitamio.widget.VideoView;
  10. import com.jwzhangjie.smart_tv.R;
  11. import com.jwzhangjie.smart_tv.dialog.JWDialogLoading;
  12. import com.jwzhangjie.smart_tv.interfaces.UdpServerCallBackListener;
  13. import com.jwzhangjie.smart_tv.server.CommandServer;
  14. import android.os.Bundle;
  15. import android.os.IBinder;
  16. import android.util.Log;
  17. import android.view.View;
  18. import android.widget.TextView;
  19. import android.widget.Toast;
  20. import android.app.Activity;
  21. import android.content.ComponentName;
  22. import android.content.Context;
  23. import android.content.Intent;
  24. import android.content.ServiceConnection;
  25. public class SmartTV_Server extends Activity implements OnInfoListener, OnBufferingUpdateListener{
  26. private static final String TAG = SmartTV_Server.class.getName();
  27. private String path = "http://live.gslb.letv.com/gslb?stream_id=guangdong&tag=live&ext=m3u8";
  28. private String subtitle_path = "";
  29. private VideoView mVideoView;
  30. private TextView mSubtitleView;
  31. private long mPosition = 0;
  32. private int mVideoLayout = 0;
  33. private JWDialogLoading mDialogLoading;
  34. private CommandServer pigBackServices;
  35. private boolean isFirst = true;
  36. @Override
  37. protected void onCreate(Bundle savedInstanceState) {
  38. super.onCreate(savedInstanceState);
  39. if (!LibsChecker.checkVitamioLibs(this))
  40. return;
  41. setContentView(R.layout.subtitle2);
  42. mDialogLoading = new JWDialogLoading(this, R.style.dialog);
  43. //绑定后台接收视频连接的Service
  44. Intent intent = new Intent(SmartTV_Server.this, CommandServer.class);
  45. bindService(intent, conn, Context.BIND_AUTO_CREATE);
  46. mVideoView = (VideoView) findViewById(R.id.surface_view);
  47. mSubtitleView = (TextView) findViewById(R.id.subtitle_view);
  48. if (path == "") {
  49. // Tell the user to provide a media file URL/path.
  50. Toast.makeText(SmartTV_Server.this, "Please select video, and set path" + " variable to your media file URL/path", Toast.LENGTH_LONG).show();
  51. return;
  52. } else {
  53. /*
  54. * Alternatively,for streaming media you can use
  55. * mVideoView.setVideoURI(Uri.parse(URLstring));
  56. */
  57. isFirst = false;
  58. mVideoView.setVideoPath(path);
  59. mVideoView.setMediaController(new MediaController(this));
  60. mVideoView.requestFocus();
  61. mVideoView.setOnErrorListener(new OnErrorListener() {
  62. @Override
  63. public boolean onError(MediaPlayer mp, int what, int extra) {
  64. return true;
  65. }
  66. });
  67. mVideoView.setOnInfoListener(this);
  68. mVideoView.setOnBufferingUpdateListener(this);
  69. mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  70. @Override
  71. public void onPrepared(MediaPlayer mediaPlayer) {
  72. // optional need Vitamio 4.0
  73. mediaPlayer.setPlaybackSpeed(1.0f);
  74. mVideoView.addTimedTextSource(subtitle_path);
  75. mVideoView.setTimedTextShown(true);
  76. }
  77. });
  78. mVideoView.setOnTimedTextListener(new OnTimedTextListener() {
  79. @Override
  80. public void onTimedText(String text) {
  81. mSubtitleView.setText(text);
  82. }
  83. @Override
  84. public void onTimedTextUpdate(byte[] pixels, int width, int height) {
  85. }
  86. });
  87. }
  88. }
  89. @Override
  90. protected void onPause() {
  91. mPosition = mVideoView.getCurrentPosition();
  92. mVideoView.stopPlayback();
  93. super.onPause();
  94. }
  95. @Override
  96. protected void onResume() {
  97. if (mPosition > 0) {
  98. mVideoView.seekTo(mPosition);
  99. mPosition = 0;
  100. }
  101. super.onResume();
  102. mVideoView.start();
  103. }
  104. public void changeLayout(View view) {
  105. mVideoLayout++;
  106. if (mVideoLayout == 4) {
  107. mVideoLayout = 0;
  108. }
  109. switch (mVideoLayout) {
  110. case 0:
  111. mVideoLayout = VideoView.VIDEO_LAYOUT_ORIGIN;
  112. view.setBackgroundResource(R.drawable.mediacontroller_sreen_size_100);
  113. break;
  114. case 1:
  115. mVideoLayout = VideoView.VIDEO_LAYOUT_SCALE;
  116. view.setBackgroundResource(R.drawable.mediacontroller_screen_fit);
  117. break;
  118. case 2:
  119. mVideoLayout = VideoView.VIDEO_LAYOUT_STRETCH;
  120. view.setBackgroundResource(R.drawable.mediacontroller_screen_size);
  121. break;
  122. case 3:
  123. mVideoLayout = VideoView.VIDEO_LAYOUT_ZOOM;
  124. view.setBackgroundResource(R.drawable.mediacontroller_sreen_size_crop);
  125. break;
  126. }
  127. mVideoView.setVideoLayout(mVideoLayout, 0);
  128. }
  129. ServiceConnection conn = new ServiceConnection() {
  130. @Override
  131. public void onServiceDisconnected(ComponentName name) {
  132. pigBackServices = null;
  133. }
  134. @Override
  135. public void onServiceConnected(ComponentName name, IBinder service) {
  136. pigBackServices = ((CommandServer.LocalBinder)service).getService();
  137. pigBackServices.setOnUdpServerCallBackListener(new UdpServerCallBackListener() {
  138. @Override
  139. public void onPlayUrl(String url) {
  140. path = url;
  141. if (isFirst) {
  142. isFirst = false;
  143. mVideoView.setVideoPath(url);
  144. mVideoView.setMediaController(new MediaController(SmartTV_Server.this));
  145. mVideoView.requestFocus();
  146. mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
  147. @Override
  148. public void onPrepared(MediaPlayer mediaPlayer) {
  149. // optional need Vitamio 4.0
  150. mediaPlayer.setPlaybackSpeed(1.0f);
  151. mVideoView.addTimedTextSource(subtitle_path);
  152. mVideoView.setTimedTextShown(true);
  153. }
  154. });
  155. mVideoView.setOnTimedTextListener(new OnTimedTextListener() {
  156. @Override
  157. public void onTimedText(String text) {
  158. mSubtitleView.setText(text);
  159. }
  160. @Override
  161. public void onTimedTextUpdate(byte[] pixels, int width, int height) {
  162. }
  163. });
  164. }else{
  165. if (mVideoView.isPlaying()) {
  166. mVideoView.stopPlayback();
  167. }
  168. mVideoView.setVideoPath(url);
  169. }
  170. Log.e(TAG, url);
  171. }
  172. });
  173. }
  174. };
  175. @Override
  176. protected void onDestroy() {
  177. if (pigBackServices != null) {
  178. unbindService(conn);
  179. }
  180. super.onDestroy();
  181. }
  182. @Override
  183. public void onBufferingUpdate(MediaPlayer mp, int percent) {
  184. mDialogLoading.setProgreess(percent);
  185. }
  186. private boolean isStart;
  187. @Override
  188. public boolean onInfo(MediaPlayer mp, int what, int extra) {
  189. switch (what) {
  190. case MediaPlayer.MEDIA_INFO_BUFFERING_START:
  191. if (mVideoView.isPlaying()) {
  192. mVideoView.pause();
  193. isStart = true;
  194. if (!mDialogLoading.isShowing()) {
  195. mDialogLoading.show();
  196. }
  197. }
  198. break;
  199. case MediaPlayer.MEDIA_INFO_BUFFERING_END:
  200. if (isStart) {
  201. mVideoView.start();
  202. if (mDialogLoading.isShowing()) {
  203. mDialogLoading.dismiss();
  204. }
  205. }
  206. break;
  207. case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED:
  208. mDialogLoading.setValue("" + extra + "kb/s" + "  ");
  209. break;
  210. }
  211. return true;
  212. }
  213. }

4.加载进度

可能你在上面的播放器代码里面会看到JWDialogLoading,这个是一个网上的环形进度框,能够提示视频的记载进度和下载速度,不过你要覆写Vitamio里面的OnInfoListener, OnBufferingUpdateListener这两个接口才行。

[java] view plaincopy print?
  1. package com.jwzhangjie.smart_tv.dialog;
  2. import android.app.Activity;
  3. import android.app.Dialog;
  4. import android.os.Bundle;
  5. import android.view.Display;
  6. import android.view.Window;
  7. import android.view.WindowManager.LayoutParams;
  8. import android.widget.LinearLayout;
  9. public class JWDialogLoading extends Dialog{
  10. private RadialProgressWidget mProgressWidget;
  11. private Activity context;
  12. public JWDialogLoading(Activity context) {
  13. super(context);
  14. this.context = context;
  15. mProgressWidget = new RadialProgressWidget(context);
  16. }
  17. public JWDialogLoading(Activity context, int style) {
  18. super(context, style);
  19. this.context = context;
  20. mProgressWidget = new RadialProgressWidget(context);
  21. }
  22. @SuppressWarnings("deprecation")
  23. @Override
  24. protected void onCreate(Bundle savedInstanceState) {
  25. super.onCreate(savedInstanceState);
  26. LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
  27. setContentView(mProgressWidget, param);
  28. mProgressWidget.setSecondaryText("Loading...");
  29. mProgressWidget.setTouchEnabled(false);
  30. Window window = getWindow();
  31. LayoutParams params = window.getAttributes();
  32. Display display = context.getWindowManager().getDefaultDisplay();
  33. params.height = (int)(display.getWidth()*0.3);
  34. params.width = (int)(display.getWidth()*0.3);
  35. params.alpha = 1.0f;
  36. window.setAttributes(params);
  37. }
  38. public void setProgreess(int value){
  39. mProgressWidget.setCurrentValue(value);
  40. mProgressWidget.invalidate();
  41. if (value == 100) {
  42. dismiss();
  43. }
  44. }
  45. public void setValue(String content){
  46. mProgressWidget.setSecondaryText("Loading...  "+content);
  47. }
  48. }

5.效果图如下:

android 智能电视视频播放器UDP通信相关推荐

  1. 智能android电视更换播放器,GitHub - qfwc258/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...

    TvPlayer 1,android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现 2,测试的源地址可能失效,如需测试可以自己更换播放源.HttpUtils.getOfflin ...

  2. 智能android电视更换播放器,GitHub - kaigeLove/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...

    TvPlayer 1,android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现 2,测试的源地址可能失效,如需测试可以自己更换播放源.HttpUtils.getOfflin ...

  3. 智能android电视更换播放器,GitHub - xioxu/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...

    TvPlayer 1,android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现 2,测试的源地址可能失效,如需测试可以自己更换播放源.HttpUtils.getOfflin ...

  4. Android智能电视应用程序开发浅谈(二)

    Android应用程序的布局有两种,一种是在res/layout下面的xml文件里布局,一种是直接在java代码里布局,而Android智能电视有多种分辨率,我们可以建立多个适应不同分辨率的资源文件, ...

  5. android 智能电视 电视盒子 安卓嵌入式硬件LAN压力测试

    android 智能电视 电视盒子 安卓嵌入式硬件LAN压力测试 android 智能电视 电视盒子 安卓嵌入式硬件LAN压力测试 android环境下部分必须用到的查询命令 操作命令 LAN口使用a ...

  6. Android开发之视频播放器

    Android开发之视频播放器 一.效果图 二.build.gradle中导入依赖 三.主布局文件(activity_video) 四.布局文件(video_item) 五.布局文件(activity ...

  7. android 浏览器 遥控器 光标,论Android智能电视盒子必装应用之——飞视浏览器

    原标题:论Android智能电视&盒子必装应用之--飞视浏览器 安卓智能电视的浏览器一般都有个跟随系统预装好的基础版本,不仅功能受限,而且使用不便,地址栏输入和保存页面书签是唯一可以用的.那么 ...

  8. 开源安卓Android流媒体音视频播放器实现声音自动停止、恢复、一键静音功能源码

    本文转自EasyDarwin团队John的博客:http://blog.csdn.net/jyt0551/article/details/60802145 我们在开发安卓Android流媒体音视频播放 ...

  9. Android智能电视应用程序开发浅谈(一)

    最近新出的一些智能电视,都是基于Android系统,而本人最近也一直在从事Android智能电视的应用开发,想和大家分享下经验. Android智能电视是什么呢?它与我们平时用的移动设备有什么区别呢? ...

最新文章

  1. 搭建redis给mysql做缓存
  2. 安装 Linux -Mplayer 播放器
  3. Linux下时间戳格式和标准时间格式的转换
  4. vivo手机解锁_关于手机“解锁”的话题,vivo屏幕指纹技术很有话语权
  5. Python数据分析笔记——Numpy、Pandas库
  6. 如何使用facenet详解_如何使用冰箱更节能 使用冰箱节能技巧介绍【详解】
  7. Node.JS——NodeJS引用路径的小问题
  8. rocketmq 两个线程同时消费一个消息
  9. 5分钟了解什么是自然语言处理技术
  10. IRedMail卸载升级
  11. libcef和js交互
  12. 上汽拿下国内首张道路测试用牌照
  13. 计算机仿真塞曼效应实验报告,塞曼效应实验报告[完整版].doc
  14. 集群服务器中定时任务多次执行的解决方案
  15. html5 状态栏颜色怎么改,iOS 修改状态栏颜色的3种方式
  16. platfrom设备驱动框架
  17. 用sql查询姓名和身份证_查询,更新和身份
  18. 50例源码Python scipy.stats.norm 模块,pdf()
  19. aspx网页背景图片设置代码_Vue+CSS3制作双螺旋DNA动画:代码详解和基础知识复习
  20. docker 批量删除images

热门文章

  1. python报错1-'int' object is not iterable('int'对象不可迭代)
  2. 蘑菇云【行空板Python入门教程】第三课:多功能提醒器
  3. 修改注册表(修改键盘按键)
  4. 第一次嵌入式裸机应用设计——秒表器
  5. 知识图谱创新FinTech,一览群智携手浪潮力推智能反洗钱
  6. RT-Thread_rt_kprintf()打印浮点数(解决方法1:rt_vsnprintf替换为vsnprinitf)
  7. 日系小清新PPT模板
  8. 自动判断QQ是否在线,并显示在线状态
  9. 北京第二次面试录音总结
  10. 安装matlab2020a ,解决打开错误error8