基于EasyPusher sdk库工程(即library module)实现一个推送客户端非常简单便捷,因为sdk端已经将各种烦人的状态维护\错误检查\权限判定\UI同步等功能都实现了,开发者仅仅只需要实现若干接口即可.

让我们看看如何实现一个Pusher吧!

首先我们介绍一下Pusher sdk的封装用到了哪些技术.

  1. Android Architecture Components

Android architecture components是Google 官方出的一个Android APP的开发标准与指南.其官方介绍文档如下:

A collection of libraries that help you design robust, testable, and maintainable apps. Start with classes for managing your UI component lifecycle and handling data persistence.

基于这个AAC库,Pusher 的sdk的封装做了两件事情:

  • 在底层可以捕获到上层Activity\Fragment的生命周期,从而自己管理自己的状态,包括初始化\启动\停止\反初始化等工作.这样,上层就轻松多了.
  • 使用LiveData保存维护自己的一些状态,上层可以方便通过注册LiveData,来获取到当前的状态,以及获取到状态变更的回调.

    1. Reactivestreams

reactive streams 即响应式编程,是一种基于”数据流和变化传播的编程范式”,更多的介绍见ReactiveX.pusher的library层一些接口基于Reactivestreams实现,这样很方便上层使用rxjava等库进行开发.

好了,我们看看如何基于library库实现一个pusher吧.sdk主要功能在MediaStream里实现,这个类是一个服务类.

  1. 启动服务:
// 启动服务...
Intent intent = new Intent(this, MediaStream.class);
startService(intent);
  1. 获取MediaStream对象.由于MediaStream是个服务,所以我们无法直接创建其对象,只能通过binder来绑定.这个过程是异步的.sdk内部对这个过程进行了封装,返回一个publisher,我们可以观察这个publisher来获取到MediaStream的对象.上层代码如下:

    // (异步)获取MediaStream对象
    private Single<MediaStream> getMediaStream() {
    Single<MediaStream> single = RxHelper.single(MediaStream.getBindedMediaStream(this, this), mediaStream);
    if (mediaStream == null) {
    return single.doOnSuccess(new Consumer<MediaStream>() {
    @Override
    public void accept(MediaStream ms) throws Exception {
    mediaStream = ms;
    }
    });
    } else {
    return single;
    }
    }
  2. 观察MediaStream内部状态更改并更新UI:

    final TextView pushingStateText = findViewById(R.id.pushing_state);
    final TextView pushingBtn = findViewById(R.id.pushing);
    ms.observePushingState(MainActivity.this, new Observer<MediaStream.PushingState>() { @Override
    public void onChanged(@Nullable MediaStream.PushingState pushingState) {
    if (pushingState.screenPushing) {
    pushingStateText.setText("屏幕推送"); // 更改屏幕推送按钮状态. TextView tview = findViewById(R.id.pushing_desktop);
    if (pushingState.state > 0) {
    tview.setText("取消推送");
    } else {
    tview.setText("推送屏幕");
    }
    findViewById(R.id.pushing_desktop).setEnabled(true);
    } else {
    pushingStateText.setText("推送"); if (pushingState.state > 0) {
    pushingBtn.setText("停止");
    } else {
    pushingBtn.setText("推送");
    } }
    pushingStateText.append(":\t" + pushingState.msg);
    if (pushingState.state > 0) {
    pushingStateText.append(pushingState.url);
    } }
    });

  3. 设置或者关闭摄像头View.

    TextureView textureView = findViewById(R.id.texture_view);
    textureView.setSurfaceTextureListener(new SurfaceTextureListenerWrapper() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {
    ms.setSurfaceTexture(surfaceTexture);
    }
    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
    ms.setSurfaceTexture(null);
    return true;
    }
    });
  4. 尝试申请权限,并在权限获取到后,告知SDK.


    if (ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED ||
    ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
    ActivityCompat.requestPermissions(MainActivity.this, new String[]{android.Manifest.permission.CAMERA, android.Manifest.permission.RECORD_AUDIO}, REQUEST_CAMERA_PERMISSION);
    }
    mediaStream.notifyPermissionGranted();
  5. 打开摄像头并预览.

    mediaStream.openCameraPreview();
  6. 启动推送

    mediaStream.startStream("cloud.easydarwin.org", "554", id);
  7. 停止推送

    mediaStream.stopStream();
  8. 停止预览

    mediaStream.closeCameraPreview();
  9. 退出

    // 终止服务...
    Intent intent = new Intent(this, MediaStream.class);
    stopService(intent);

以上代码就是一个启动推送\退出的过程,注意,其中包括了摄像头权限申请,推送状态回调,摄像头预览界面设置,界面关闭时自动释放,Activity recreate处理等等许多隐性工作..这些工作看似不是SDK主要的工作,但是作为一个稳定的APP却必须十分小心地处理,我们必须慎之又慎才能处理好这些隐性工作.而通常处理的过程中会使得我们的逻辑变得异常复杂,导致bug频繁.

以上相关代码都可以在EasyPusher的library分支的demo里面看到.地址:

https://github.com/EasyDSS/EasyPusher-Android/tree/library

除此之外,sdk还支持摄像头切换\录像\UVC摄像头推送等功能.将会在别的文章进行介绍.

获取更多信息

邮件:support@easydarwin.org

EasyDarwin开源流媒体服务器:www.EasyDarwin.org

EasyDSS商用流媒体解决方案:www.EasyDSS.com

EasyNVR无插件直播方案:www.EasyNVR.com

Copyright © EasyDarwin Team 2012-2017

使用EasyPusher进行手机低延时直播推流便捷开发的更多相关文章

  1. 阿里云低延时直播 RTS 能力升级 让直播推流效果更佳

    行业背景 直播技术飞速发展让各个行业的用户体验呈现多样化和个性化,不同业务场景下创新实践满足大众对于音视频互动体验和参与的高标准要求.历经2020年初的巨变之后,以视频.游戏.电商.教育为主的互联网经 ...

  2. EasyDarwin开源流媒体服务器低延时直播之转发缓存跟进算法

    前言 前一段时间,我们为EasyDarwin实现了客户端快速显示画面/听到同步声音的缓存关键帧检索方案,具体的实现方法分别在<EasyDarwin手机直播是如何实现的快速显示视频的方法>和 ...

  3. 阿里云李刚:下一代低延时的直播CDN

    在上周落幕帷幕的多媒体领域技术盛会——LiveVideoStackCon音视频技术大会上,阿里云的高级技术专家李刚进行了<下一代低延时的直播CDN>技术分享.主讲人李刚,多年关注在CDN这 ...

  4. EasyNVR无插件摄像机直播之:摄像机网页低延时无插件直播实现

    背景需求 对于摄像机直播,客户反馈的最多就是实现web直播.摆脱插件,可以自定义集成等问题, 对于熟悉EasyNVR已经完美的解决了这些问题.然而对于web播放也存在一些问题,通常我们web播放RTM ...

  5. 低延时的P2P HLS直播技术实践

    本文根据4月21日OSC源创会·武汉站的现场分享为蓝本,重新整理.以下是演讲内容: 近几年,随着直播.短视频等视频领域对带宽要求的提升以及CDN行业竞争的加剧,很多CDN公司开始往P2P-CDN方向发 ...

  6. EasyPusher/EasyDarwin支持H.265 RTSP/RTP直播推流与分发播放

    前言描述 随着大屏时代和高清时代的到来,人们已经不再满足于VGA.CIF这种小分辨率了,取而代之的是720P.1080P.4K级的视频传输,虽然我们国家的基础带宽一直在上升,但普遍情况下,传输高清视频 ...

  7. EasyNVR无插件直播服务器软件览器低延时播放监控摄像头视频(EasyNVR播放FLV视频流)

    背景描述 EasyNVR的使用者应该都是清楚的了解到,EasyNVR一个强大的功能就是可以进行全平台的无插件直播.主要原因在于rtsp协议的视频流(默认是需要插件才可以播放的)经由EasyNVR处理可 ...

  8. 直播推流端弱网优化策略 | 直播 SDK 性能优化实践

    弱网优化的场景 网络直播行业经过一年多的快速发展,衍生出了各种各样的玩法.最早的网络直播是主播坐在 PC 前,安装好专业的直播设备(如摄像头和麦克风),然后才能开始直播.后来随着手机性能的提升和直播技 ...

  9. [转帖]技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解

    技术扫盲:新一代基于UDP的低延时网络传输层协议——QUIC详解    http://www.52im.net/thread-1309-1-1.html   本文来自腾讯资深研发工程师罗成的技术分享, ...

随机推荐

  1. AC日记——[ZJOI2009]狼和羊的故事 bzoj 1412

    1412 思路: 最小割: 狼作为一个点集a,空领地作为点集b,羊作为点集c: s向a连边,c向t连边,a向b连边,b向b连边,b向c连边: 如何理解最小割? a,c之间割掉最少的路径(栅栏)使其没有 ...

  2. WKWebView遇到的问题汇总

    一.手势放大缩小页面解决方法 1.通过操作webview中scrollview的代理方法来关闭 -(UIView *)viewForZoomingInScrollView:(UIScrollView ...

  3. 洛谷——P1462 通往奥格瑞玛的道路

    P1462 通往奥格瑞玛的道路 题目背景 在艾泽拉斯大陆上有一位名叫歪嘴哦的神奇术士,他是部落的中坚力量 有一天他醒来后发现自己居然到了联盟的主城暴风城 在被众多联盟的士兵攻击后,他决定逃回自己的家乡 ...

  4. IntelliJ IDEA关闭代码自动补全

    关闭代码自动补全之后,可以使用[Ctrl]+[P]进行强制调出提示. [Editor]-[Code Completion]页里有个[Case sensitive completion],可以设置只第一 ...

  5. Git历险记(五)——Git里的分支&合并

    分支与合并 在Git里面我们可以创建不同的分支,来进行调试.发布.维护等不同工作,而互不干扰.下面我们还是来创建一个试验仓库,看一下Git分支运作的台前幕后: $rm -rf test_branch_ ...

  6. *** Python版一键安装脚本

    本脚本适用环境:系统支持:CentOS 6,7,Debian,Ubuntu内存要求:≥128M日期:2018 年 02 月 07 日 关于本脚本:一键安装 Python 版 *** 的最新版.友情提示 ...

  7. 2016.6.21 -Dmaven.multiModuleProjectDirectory system propery is not set,Check $M2_HOME environment variable and mvn script match.

    eclipse中使用maven插件的时候,运行run as maven build的时候报错: -Dmaven.multiModuleProjectDirectory system propery i ...

  8. .NET创建宿主设计器--DesignHost、DesignSurface.

    一个窗口在运行时,是这样的: 但是,在设计时,却远比这复杂的多,它需要一个设计器对象:它仅存在于设计时,并连接到运行时存在的对象.   宿主容器 我们可以看到每个窗体和按钮均有与之相关的设计器.这两个 ...

  9. ANT安装及配置

    首先,到http://ant.apache.org/找到合适的版本下载. 其次,讲下载的zip包解压,得到的目录拷贝到硬盘,如C:\apache-ant-1.9.4 其三,设置环境变量 ANT_HOM ...

  10. JAVA Eclipse ActivityManager Warning Activity not started, its current task has been brought to the front怎么办

    Eclipse运行提示Activity not started,因为当前程序已经在运行,需要退出当前程序再测试