zoukankan      html  css  js  c++  java
  • 使用EasyPusher进行手机低延时直播推流便捷开发

    基于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的封装做了两件事情:

    • 在底层可以捕获到上层ActivityFragment的生命周期,从而自己管理自己的状态,包括初始化启动停止反初始化等工作.这样,上层就轻松多了.
    • 使用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(":	" + 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

    EasyDarwin

  • 相关阅读:
    JSON.parse()和JSON.stringify()(转载)
    Bootstrap 栅格系统(转载)
    基于Java的WebSocket推送【转载】
    VirtualBox中的虚拟机要如何设置,才能够上网
    String类和StringBuffer类的区别
    split命令参数及用法详解
    linux du小练习
    内部类(innerclasses)、匿名对象
    构造器、方法的重载、方法的重写
    继承、封装、多态、抽象、接口
  • 原文地址:https://www.cnblogs.com/babosa/p/8206955.html
Copyright © 2011-2022 走看看