android 智能电视视频播放器UDP通信
在做智能电视应用的时候,最头疼的就是焦点问题,特别是对于个人开发者,没有设备这是最最头疼的事情了,在没有设备的情况下,怎么实现智能电视应用呢,接下来我是用TV程序来做演示的,所以接下来的所有操作是在有网络的情况下,TV链接到一个路由器上面,做过开发的人都知道Socket编程分为两种一个是可靠传输的TCP,另一个是不可靠传输的UDP,TCP需要知道对方的IP才能实现,UDP虽然不可靠,但是它可以实现广播来进行通信,从而得知对方的IP地址,然后就可以TCP通信了,对于智能电视的TV开发,如果你没有设备,则可以利用UDP的这个特性来实现手机操控电视,建立通信协议,然后TV端Server接收广播,手机端作为Client发送广播,所有的操作放在手机端来实现,TV只接收并处理相应的命令。
一、UDP实现
首先就是实现UDP的广播通信,下面就是UDP的Server和Client代码:
Server:为了实现能够长时间的接收客户端的信息,所以要把Server端放在线程里面如下:
- /**
- * 实现后台监听广播
- * @author jwzhangjie
- */
- private class UdpServerRunable implements Runnable {
- @Override
- public void run() {
- byte[] data = new byte[256];
- DatagramPacket udpPacket = new DatagramPacket(data, 256);
- try {
- udpSocket = new DatagramSocket(43708);
- } catch (Exception e) {
- e.printStackTrace();
- }
- while (!isStop) {
- try {
- udpSocket.receive(udpPacket);
- if (udpPacket.getLength() != 0) {
- Url = new String(data, 0, udpPacket.getLength());
- Log.e(TAG, Url);
- if (onUdpServerCallBackListener != null) {
- onUdpServerCallBackListener.onPlayUrl(Url);
- }
- }
- } catch (Exception e) {
- }
- }
- }
- };
为了测试方便我先阶段是Client放在PC端来实现的,为了实现循环测试,我也是把客户端放在一个线程里面,代码如下:
- public class Test_UDP_Client{
- public static void main(String[] args){
- new Thread(new Runnable() {
- int i = 0;
- private byte[] buffer = new byte[40];
- @Override
- public void run() {
- DatagramPacket dataPacket = null;
- DatagramSocket udpSocket = null;
- List<String> listData = new ArrayList<String>();
- listData.add("http://live.gslb.letv.com/gslb?stream_id=hunan&tag=live&ext=m3u8&sign=live_tv");
- <span style="white-space:pre"> </span>listData.add("http://play.api.pptv.com/web-m3u8-300161.m3u8?type=m3u8.web.pad");
- try {
- udpSocket = new DatagramSocket(43708);
- dataPacket = new DatagramPacket(buffer, 40);
- dataPacket.setPort(43708);
- InetAddress broadcastAddr;
- broadcastAddr = InetAddress.getByName("255.255.255.255");
- dataPacket.setAddress(broadcastAddr);
- } catch (Exception e) {
- }
- while (i < 30) {
- i++;
- try {
- byte[] data = (listData.get(i%2)).getBytes();
- dataPacket.setData( data );
- dataPacket.setLength( data.length );
- udpSocket.send(dataPacket);
- Thread.sleep(20000);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- udpSocket.close();
- }
- }).start();
- }
- }
二、Service启动Server的线程
线程是不可控的,如果Activity突然的挂掉,那么这个线程还是在后台运行的,所以我们要把Server放在Service里面,通过Service来启动服务端,代码如下:
- package com.jwzhangjie.smart_tv.server;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import com.jwzhangjie.smart_tv.interfaces.UdpServerCallBackListener;
- import android.app.Service;
- import android.content.Intent;
- import android.os.Binder;
- import android.os.IBinder;
- import android.util.Log;
- public class CommandServer extends Service{
- private static String TAG = CommandServer.class.getName();
- public static boolean isStop = false;
- private DatagramSocket udpSocket = null;
- private Thread udpServerThread;
- private String Url;
- /**
- * 设置视频连接的回调接口
- */
- private UdpServerCallBackListener onUdpServerCallBackListener;
- @Override
- public IBinder onBind(Intent intent) {
- Log.e(TAG, "onBind");
- startListener();
- return new LocalBinder();
- }
- /**
- * 注册回调接口的方法,供外部调用
- * @param onUdpServerCallBackListener
- */
- public void setOnUdpServerCallBackListener(UdpServerCallBackListener onUdpServerCallBackListener){
- this.onUdpServerCallBackListener = onUdpServerCallBackListener;
- }
- @Override
- public void onCreate() {
- Log.e(TAG, "onCreate");
- super.onCreate();
- }
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- Log.e(TAG, "onStartCommand");
- startListener();
- return super.onStartCommand(intent, flags, startId);
- }
- @Override
- public void onDestroy() {
- Log.e(TAG, "onDestroy");
- isStop = true;
- udpSocket.disconnect();
- udpSocket.close();
- udpServerThread.interrupt();
- udpServerThread = null;
- super.onDestroy();
- }
- @Override
- public boolean onUnbind(Intent intent) {
- Log.e(TAG, "onUnbind");
- return super.onUnbind(intent);
- }
- /**
- * 开始监听广播
- */
- private void startListener(){
- if (udpServerThread == null) {
- Log.e(TAG, "run");
- udpServerThread = new Thread(new UdpServerRunable());
- udpServerThread.start();
- }
- }
- /**
- * 实现后台监听广播
- * @author pig_video
- */
- private class UdpServerRunable implements Runnable {
- @Override
- public void run() {
- byte[] data = new byte[256];
- DatagramPacket udpPacket = new DatagramPacket(data, 256);
- try {
- udpSocket = new DatagramSocket(43708);
- } catch (Exception e) {
- e.printStackTrace();
- }
- while (!isStop) {
- try {
- udpSocket.receive(udpPacket);
- if (udpPacket.getLength() != 0) {
- Url = new String(data, 0, udpPacket.getLength());
- Log.e(TAG, Url);
- if (onUdpServerCallBackListener != null) {
- onUdpServerCallBackListener.onPlayUrl(Url);
- }
- }
- } catch (Exception e) {
- }
- }
- }
- };
- //定义内部类继承Binder
- public class LocalBinder extends Binder{
- //返回本地服务
- public CommandServer getService(){
- return CommandServer.this;
- }
- }
- }
3.Activity与Service的绑定
我这里启动Service的方式是通过Activity的onBind来启动的,当Activity关闭的时候,也将Service关闭同时关闭Server的线程,当然常驻后台也行,不过用户可能不太喜欢,毕竟需要资源,播放器我选用的是免费的Vitamio主要是他们把上层应用的代码也提供出来了,非常省事。
- package com.jwzhangjie.smart_tv.player;
- import io.vov.vitamio.LibsChecker;
- import io.vov.vitamio.MediaPlayer;
- import io.vov.vitamio.MediaPlayer.OnBufferingUpdateListener;
- import io.vov.vitamio.MediaPlayer.OnErrorListener;
- import io.vov.vitamio.MediaPlayer.OnInfoListener;
- import io.vov.vitamio.MediaPlayer.OnTimedTextListener;
- import io.vov.vitamio.widget.MediaController;
- import io.vov.vitamio.widget.VideoView;
- import com.jwzhangjie.smart_tv.R;
- import com.jwzhangjie.smart_tv.dialog.JWDialogLoading;
- import com.jwzhangjie.smart_tv.interfaces.UdpServerCallBackListener;
- import com.jwzhangjie.smart_tv.server.CommandServer;
- import android.os.Bundle;
- import android.os.IBinder;
- import android.util.Log;
- import android.view.View;
- import android.widget.TextView;
- import android.widget.Toast;
- import android.app.Activity;
- import android.content.ComponentName;
- import android.content.Context;
- import android.content.Intent;
- import android.content.ServiceConnection;
- public class SmartTV_Server extends Activity implements OnInfoListener, OnBufferingUpdateListener{
- private static final String TAG = SmartTV_Server.class.getName();
- private String path = "http://live.gslb.letv.com/gslb?stream_id=guangdong&tag=live&ext=m3u8";
- private String subtitle_path = "";
- private VideoView mVideoView;
- private TextView mSubtitleView;
- private long mPosition = 0;
- private int mVideoLayout = 0;
- private JWDialogLoading mDialogLoading;
- private CommandServer pigBackServices;
- private boolean isFirst = true;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (!LibsChecker.checkVitamioLibs(this))
- return;
- setContentView(R.layout.subtitle2);
- mDialogLoading = new JWDialogLoading(this, R.style.dialog);
- //绑定后台接收视频连接的Service
- Intent intent = new Intent(SmartTV_Server.this, CommandServer.class);
- bindService(intent, conn, Context.BIND_AUTO_CREATE);
- mVideoView = (VideoView) findViewById(R.id.surface_view);
- mSubtitleView = (TextView) findViewById(R.id.subtitle_view);
- if (path == "") {
- // Tell the user to provide a media file URL/path.
- Toast.makeText(SmartTV_Server.this, "Please select video, and set path" + " variable to your media file URL/path", Toast.LENGTH_LONG).show();
- return;
- } else {
- /*
- * Alternatively,for streaming media you can use
- * mVideoView.setVideoURI(Uri.parse(URLstring));
- */
- isFirst = false;
- mVideoView.setVideoPath(path);
- mVideoView.setMediaController(new MediaController(this));
- mVideoView.requestFocus();
- mVideoView.setOnErrorListener(new OnErrorListener() {
- @Override
- public boolean onError(MediaPlayer mp, int what, int extra) {
- return true;
- }
- });
- mVideoView.setOnInfoListener(this);
- mVideoView.setOnBufferingUpdateListener(this);
- mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
- @Override
- public void onPrepared(MediaPlayer mediaPlayer) {
- // optional need Vitamio 4.0
- mediaPlayer.setPlaybackSpeed(1.0f);
- mVideoView.addTimedTextSource(subtitle_path);
- mVideoView.setTimedTextShown(true);
- }
- });
- mVideoView.setOnTimedTextListener(new OnTimedTextListener() {
- @Override
- public void onTimedText(String text) {
- mSubtitleView.setText(text);
- }
- @Override
- public void onTimedTextUpdate(byte[] pixels, int width, int height) {
- }
- });
- }
- }
- @Override
- protected void onPause() {
- mPosition = mVideoView.getCurrentPosition();
- mVideoView.stopPlayback();
- super.onPause();
- }
- @Override
- protected void onResume() {
- if (mPosition > 0) {
- mVideoView.seekTo(mPosition);
- mPosition = 0;
- }
- super.onResume();
- mVideoView.start();
- }
- public void changeLayout(View view) {
- mVideoLayout++;
- if (mVideoLayout == 4) {
- mVideoLayout = 0;
- }
- switch (mVideoLayout) {
- case 0:
- mVideoLayout = VideoView.VIDEO_LAYOUT_ORIGIN;
- view.setBackgroundResource(R.drawable.mediacontroller_sreen_size_100);
- break;
- case 1:
- mVideoLayout = VideoView.VIDEO_LAYOUT_SCALE;
- view.setBackgroundResource(R.drawable.mediacontroller_screen_fit);
- break;
- case 2:
- mVideoLayout = VideoView.VIDEO_LAYOUT_STRETCH;
- view.setBackgroundResource(R.drawable.mediacontroller_screen_size);
- break;
- case 3:
- mVideoLayout = VideoView.VIDEO_LAYOUT_ZOOM;
- view.setBackgroundResource(R.drawable.mediacontroller_sreen_size_crop);
- break;
- }
- mVideoView.setVideoLayout(mVideoLayout, 0);
- }
- ServiceConnection conn = new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- pigBackServices = null;
- }
- @Override
- public void onServiceConnected(ComponentName name, IBinder service) {
- pigBackServices = ((CommandServer.LocalBinder)service).getService();
- pigBackServices.setOnUdpServerCallBackListener(new UdpServerCallBackListener() {
- @Override
- public void onPlayUrl(String url) {
- path = url;
- if (isFirst) {
- isFirst = false;
- mVideoView.setVideoPath(url);
- mVideoView.setMediaController(new MediaController(SmartTV_Server.this));
- mVideoView.requestFocus();
- mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
- @Override
- public void onPrepared(MediaPlayer mediaPlayer) {
- // optional need Vitamio 4.0
- mediaPlayer.setPlaybackSpeed(1.0f);
- mVideoView.addTimedTextSource(subtitle_path);
- mVideoView.setTimedTextShown(true);
- }
- });
- mVideoView.setOnTimedTextListener(new OnTimedTextListener() {
- @Override
- public void onTimedText(String text) {
- mSubtitleView.setText(text);
- }
- @Override
- public void onTimedTextUpdate(byte[] pixels, int width, int height) {
- }
- });
- }else{
- if (mVideoView.isPlaying()) {
- mVideoView.stopPlayback();
- }
- mVideoView.setVideoPath(url);
- }
- Log.e(TAG, url);
- }
- });
- }
- };
- @Override
- protected void onDestroy() {
- if (pigBackServices != null) {
- unbindService(conn);
- }
- super.onDestroy();
- }
- @Override
- public void onBufferingUpdate(MediaPlayer mp, int percent) {
- mDialogLoading.setProgreess(percent);
- }
- private boolean isStart;
- @Override
- public boolean onInfo(MediaPlayer mp, int what, int extra) {
- switch (what) {
- case MediaPlayer.MEDIA_INFO_BUFFERING_START:
- if (mVideoView.isPlaying()) {
- mVideoView.pause();
- isStart = true;
- if (!mDialogLoading.isShowing()) {
- mDialogLoading.show();
- }
- }
- break;
- case MediaPlayer.MEDIA_INFO_BUFFERING_END:
- if (isStart) {
- mVideoView.start();
- if (mDialogLoading.isShowing()) {
- mDialogLoading.dismiss();
- }
- }
- break;
- case MediaPlayer.MEDIA_INFO_DOWNLOAD_RATE_CHANGED:
- mDialogLoading.setValue("" + extra + "kb/s" + " ");
- break;
- }
- return true;
- }
- }
4.加载进度
可能你在上面的播放器代码里面会看到JWDialogLoading,这个是一个网上的环形进度框,能够提示视频的记载进度和下载速度,不过你要覆写Vitamio里面的OnInfoListener, OnBufferingUpdateListener这两个接口才行。
- package com.jwzhangjie.smart_tv.dialog;
- import android.app.Activity;
- import android.app.Dialog;
- import android.os.Bundle;
- import android.view.Display;
- import android.view.Window;
- import android.view.WindowManager.LayoutParams;
- import android.widget.LinearLayout;
- public class JWDialogLoading extends Dialog{
- private RadialProgressWidget mProgressWidget;
- private Activity context;
- public JWDialogLoading(Activity context) {
- super(context);
- this.context = context;
- mProgressWidget = new RadialProgressWidget(context);
- }
- public JWDialogLoading(Activity context, int style) {
- super(context, style);
- this.context = context;
- mProgressWidget = new RadialProgressWidget(context);
- }
- @SuppressWarnings("deprecation")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- setContentView(mProgressWidget, param);
- mProgressWidget.setSecondaryText("Loading...");
- mProgressWidget.setTouchEnabled(false);
- Window window = getWindow();
- LayoutParams params = window.getAttributes();
- Display display = context.getWindowManager().getDefaultDisplay();
- params.height = (int)(display.getWidth()*0.3);
- params.width = (int)(display.getWidth()*0.3);
- params.alpha = 1.0f;
- window.setAttributes(params);
- }
- public void setProgreess(int value){
- mProgressWidget.setCurrentValue(value);
- mProgressWidget.invalidate();
- if (value == 100) {
- dismiss();
- }
- }
- public void setValue(String content){
- mProgressWidget.setSecondaryText("Loading... "+content);
- }
- }
5.效果图如下:
android 智能电视视频播放器UDP通信相关推荐
- 智能android电视更换播放器,GitHub - qfwc258/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...
TvPlayer 1,android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现 2,测试的源地址可能失效,如需测试可以自己更换播放源.HttpUtils.getOfflin ...
- 智能android电视更换播放器,GitHub - kaigeLove/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...
TvPlayer 1,android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现 2,测试的源地址可能失效,如需测试可以自己更换播放源.HttpUtils.getOfflin ...
- 智能android电视更换播放器,GitHub - xioxu/TvPlayer: android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现。...
TvPlayer 1,android智能电视播放器,可以播放各电视台节目,播放基于ijkplayer的实现 2,测试的源地址可能失效,如需测试可以自己更换播放源.HttpUtils.getOfflin ...
- Android智能电视应用程序开发浅谈(二)
Android应用程序的布局有两种,一种是在res/layout下面的xml文件里布局,一种是直接在java代码里布局,而Android智能电视有多种分辨率,我们可以建立多个适应不同分辨率的资源文件, ...
- android 智能电视 电视盒子 安卓嵌入式硬件LAN压力测试
android 智能电视 电视盒子 安卓嵌入式硬件LAN压力测试 android 智能电视 电视盒子 安卓嵌入式硬件LAN压力测试 android环境下部分必须用到的查询命令 操作命令 LAN口使用a ...
- Android开发之视频播放器
Android开发之视频播放器 一.效果图 二.build.gradle中导入依赖 三.主布局文件(activity_video) 四.布局文件(video_item) 五.布局文件(activity ...
- android 浏览器 遥控器 光标,论Android智能电视盒子必装应用之——飞视浏览器
原标题:论Android智能电视&盒子必装应用之--飞视浏览器 安卓智能电视的浏览器一般都有个跟随系统预装好的基础版本,不仅功能受限,而且使用不便,地址栏输入和保存页面书签是唯一可以用的.那么 ...
- 开源安卓Android流媒体音视频播放器实现声音自动停止、恢复、一键静音功能源码
本文转自EasyDarwin团队John的博客:http://blog.csdn.net/jyt0551/article/details/60802145 我们在开发安卓Android流媒体音视频播放 ...
- Android智能电视应用程序开发浅谈(一)
最近新出的一些智能电视,都是基于Android系统,而本人最近也一直在从事Android智能电视的应用开发,想和大家分享下经验. Android智能电视是什么呢?它与我们平时用的移动设备有什么区别呢? ...
最新文章
- 搭建redis给mysql做缓存
- 安装 Linux -Mplayer 播放器
- Linux下时间戳格式和标准时间格式的转换
- vivo手机解锁_关于手机“解锁”的话题,vivo屏幕指纹技术很有话语权
- Python数据分析笔记——Numpy、Pandas库
- 如何使用facenet详解_如何使用冰箱更节能 使用冰箱节能技巧介绍【详解】
- Node.JS——NodeJS引用路径的小问题
- rocketmq 两个线程同时消费一个消息
- 5分钟了解什么是自然语言处理技术
- IRedMail卸载升级
- libcef和js交互
- 上汽拿下国内首张道路测试用牌照
- 计算机仿真塞曼效应实验报告,塞曼效应实验报告[完整版].doc
- 集群服务器中定时任务多次执行的解决方案
- html5 状态栏颜色怎么改,iOS 修改状态栏颜色的3种方式
- platfrom设备驱动框架
- 用sql查询姓名和身份证_查询,更新和身份
- 50例源码Python scipy.stats.norm 模块,pdf()
- aspx网页背景图片设置代码_Vue+CSS3制作双螺旋DNA动画:代码详解和基础知识复习
- docker 批量删除images
热门文章
- python报错1-'int' object is not iterable('int'对象不可迭代)
- 蘑菇云【行空板Python入门教程】第三课:多功能提醒器
- 修改注册表(修改键盘按键)
- 第一次嵌入式裸机应用设计——秒表器
- 知识图谱创新FinTech,一览群智携手浪潮力推智能反洗钱
- RT-Thread_rt_kprintf()打印浮点数(解决方法1:rt_vsnprintf替换为vsnprinitf)
- 日系小清新PPT模板
- 自动判断QQ是否在线,并显示在线状态
- 北京第二次面试录音总结
- 安装matlab2020a ,解决打开错误error8