You need to enable JavaScript to run this app.
导航

使用Android SDK实现简单推流功能

最近更新时间2022.05.25 13:09:24

首次发布时间2022.05.25 13:09:24

前言

集成Android SDK,实现简单的推流功能。

关于实验

预计部署时间:20分钟
级别:初级
相关产品:视频直播
受众: 通用

实验说明
  1. 已经开通视频直播功能:
    点击打开控制台
  2. 添加推拉流域名,并进行关联,操作请参考官网文档:
    点击打开文档
  3. 参考文档,创建 "SDK应用":
    点击打开文档
实验步骤

第一步-环境准备

本次测试使用环境:
1. Android Studio Bumblebee | 2021.1.1 Patch 2
2. macOS 12.3
3. Gradle Plugin Version 7.1.2
4. Gradle Version 7.4.1
5. Gradle JDK 17

第二步-新建项目

  1. 新建空项目,包名要和控制台申请License时的包名一致。
    alt
  2. 参考文档,获取License。
    点击打开文档
  3. 创建assets文件夹,将License导入assets文件夹。
    alt

第三步-导入SDK

  1. setting.gradle 的 dependencyResolutionManagement 添加以下内容。
jcenter()
  maven { url "https://artifact.bytedance.com/repository/Volcengine/" }
  1. APP的build.gradle添加以下内容。
android {
   defaultConfig {
       ndk {
           //设置 SO 库架构,支持 armv7a 和 arm64 架构。
           abiFilters 'armeabi-v7a', 'arm64-v8a'
        }
         // APPLOG_SCHEME 为必填参数,空缺会造成编译失败。
         // online 表示直播场景。
         manifestPlaceholders.put("APPLOG_SCHEME", "online")
   }
}

    //添加 AppLog 在线集成地址。用于 SDK 日志上报。
    implementation 'com.bytedance.applog:RangersAppLog-Lite-cn:6.8.0'
    implementation 'com.bytedanceapi:ttsdk-ttlivepush_rtc:1.26.2.7'
  1. gradle.properties 中添加
android.enableJetifier=true
  1. 在AndroidManifest.xml添加权限声明。
<!-- 使用权限 -->
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />


  1. 导入并编译。
    alt

第四步-代码设置

  1. 创建class,用于初始化证书和Applog。
package com.quit.xxxx;

import static com.pandora.common.Constants.APPLog.APP_REGION_CHINA;

import android.app.Application;
import android.content.Context;
import android.util.Log;

import com.pandora.common.env.Env;
import com.pandora.common.env.config.Config;
import com.pandora.common.utils.TimeUtil;
import com.pandora.common.utils.Times;
import com.pandora.ttlicense2.License;
import com.pandora.ttlicense2.LicenseManager;

public class APP extends Application {

    public static final String TAG = "pushDemo";
    private static Context context;

    /* 获取全局上下文 */
    public static Context getContext() {
        return context;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        context = getApplicationContext();
        Env.openAppLog(true);

                Env.init(new Config.Builder()
                .setAppName("com.quit.test")
                .setAppID("330309")
                .setAppRegion(APP_REGION_CHINA)
                .setApplicationContext(context)
                .setAppVersion("1.0")
                .setAppChannel("push-demo")
                .setLicenseUri("assets:///License/l-100871-ch-live-a-330309.lic")
                .build());

        //添加 License 鉴权。
        LicenseManager.init(getApplicationContext());
        //开启 License 模块 logcat 输出。建议排查问题时开启,发包时关闭。
        LicenseManager.turnOnLogcat(true);
        //配置授权文件 URI,推流 SDK 支持从 assets 文件夹中读取授权。
        String assetsLicenseUri = "assets:///xxxxxx.lic";
        //添加授权文件。将 license URI 添加到 LicenseManager。
        LicenseManager.getInstance().addLicense(assetsLicenseUri, null);
        //License 信息获取。
        License license = LicenseManager.getInstance().getLicense("100871");
        if (license != null) {
            StringBuilder builder = new StringBuilder();
            builder.append("License id:" + license.getId()).append("\n")
                    .append("License package:" + license.getPackageName()).append("\n")
                    .append("License test:" + license.getType()).append("\n")
                    .append("License version:" + license.getVersion()).append("\n");

            if (license.getModules() != null) {
                String names = "";
                for (License.Module module : license.getModules()) {
                    names = "module name:" + module.getName() + ", start time:" +
                            TimeUtil.format(module.getStartTime(), Times.YYYY_MM_DD_KK_MM_SS)
                            + ", expire time:" + TimeUtil.format(module.getExpireTime(), Times.YYYY_MM_DD_KK_MM_SS) + "\n";
                    builder.append("License modules:" + names);
                }
            }
        }
    }
}
  1. 在AndroidManifest.xml中添加第1步中创建的class。
<application
        android:name=".APP"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        ......
  1. 在 activity_main.xml 中添加 TextureView 和 Button。
<Button
        android:id="@+id/start_button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        tools:ignore="MissingConstraints" />

    <TextureView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

  1. MainActivity 推流代码。
package com.quit.xxxx;

import static com.ss.avframework.livestreamv2.LiveStreamBuilder.VIDEO_CAPTURE_DEVICE_CAM_FRONT;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.TextureView;
import android.view.View;
import android.widget.Button;

import com.pandora.ttsdk.newapi.LiveCoreBuilder;
import com.pandora.ttsdk.newapi.LiveCoreEngine;
import com.ss.avframework.livestreamv2.ILiveStream;
import com.ss.avframework.livestreamv2.LiveStreamBuilder;
import com.ss.avframework.livestreamv2.core.LiveCore;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    public LiveCoreBuilder builder;
    public TextureView surfaceView;
    public LiveCore mliveCore;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        checkPermission(1001);
        initTTSDK();

        Button start_button = findViewById(R.id.start_button);
        start_button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            mliveCore.start("rtmp://lsspush.yzyzyang.xyz/live/spting-test");
            }
        });
    }

    public void initTTSDK() {
        builder = new LiveCoreBuilder();

    //视频参数配置。
    //采集帧率,默认值为 30。
        builder.setVideoCaptureFps(30);
    //视频采集宽度,默认值为 720。
        builder.setVideoCaptureWidth(1080);
    //视频采集高度,默认值为 1280。
        builder. setVideoCaptureHeight(1920);
    //启动前置/后置摄像头,默认值为 VIDEO_CAPTURE_DEVICE_CAM_FRONE。
    //VIDEO_CAPTURE_DEVICE_CAM_FRONE 表示前置摄像头;VIDEO_CAPTURE_DEVICE_CAM_BACK 表示后置摄像头。
        builder.setVideoCaptureDevice(VIDEO_CAPTURE_DEVICE_CAM_FRONT);
    //开启硬件加速,默认值为 true。
        builder.setEnableVideoEncodeAccelera(true);
    //推流宽度,默认值为 540。
        builder.setVideoWidth(720);
    //推流高度,默认值为 960。
        builder.setVideoHeight(1280);
    //推流帧率,默认值为 25。
        builder.setVideoFps(30);
    //编码等级,默认值为 VIDEO_ENCODER_PROFILE_HIGH
        builder.setVideoProfile(LiveStreamBuilder.VIDEO_ENCODER_PROFILE_HIGH);
    //码率,默认值为 800*1000。
        builder.setVideoBitrate( 800*1000);
    //配置码率控制策略、最大码率和最小码率。
    //码率控制策略默认值为 BITRATE_ADAPT_STRATEGY_NORMAL
        builder.setBitrateAdaptStrategy(LiveStreamBuilder.BITRATE_ADAPT_STRATEGY_NORMAL);
    //最大码率默认为设置码率的 5/3。
        builder.setVideoMaxBitrate( 800*1000 * 5 / 3);
    //最小码率默认为设置码率的 2/5。
        builder.setVideoMinBitrate( 800*1000 * 2 / 5);

    //音频参数配置,采集设备。                      
        builder.setAudioCaptureDevice(LiveStreamBuilder.AUDIO_CAPTURE_DEVICE_ADM);
     //采集采样率,默认值为 44100。
        builder.setAudioCaptureSampleHZ(44100);
     //采集声道数,默认值为 1,1 表示单声道,2 表示双声道。
        builder.setAudioCaptureChannel(1);

     //创建推流引擎。
        LiveCoreEngine liveCoreEngine = builder.getLiveCoreEngine();

        mliveCore = liveCoreEngine.getLiveCore();
        mliveCore.enableMirror(true,true);

        surfaceView =  (TextureView) findViewById(R.id.surfaceView);
        surfaceView.setVisibility(View.VISIBLE);
        mliveCore.setDisplay(surfaceView);
     //开始视频采集。
        mliveCore.startVideoCapture();
        mliveCore.startAudioCapture();

        mliveCore.setErrorListener(new ILiveStream.ILiveStreamErrorListener() {
            @Override
            public void onError(int i, int i1, Exception e) {
                Log.e("onERROR","ERROR",e);
            }
        });
        mliveCore.setDataListener(new ILiveStream.ILiveStreamDataListener() {
            @Override
            public void onData(int i, int i1, int i2) {
                Log.i("onData","surfaceCreated"+i+"i1"+i1);
            }
        });
      //必填配置,设置推流消息监听。
        mliveCore.setInfoListener(new ILiveStream.ILiveStreamInfoListener() {
            @Override
            public void onInfo(int i, int i1, int i2) {
                Log.i("onInfo","onInfo"+i+"i1"+i1);
            }
        });
    }

    //获取权限
    private boolean checkPermission(int request) {
        String permissions[] = new String[]{
                Manifest.permission.CAMERA,
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.READ_PHONE_STATE,
                Manifest.permission.MODIFY_AUDIO_SETTINGS,
                Manifest.permission.ACCESS_NETWORK_STATE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE
        };
        List<String> permissionList = new ArrayList<>();
        for (String permission : permissions) {
            boolean granted = ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED;
            if (granted) continue;
            permissionList.add(permission);
        }
        if (permissionList.isEmpty()) return true;

        String permissionsToGrant[] = new String[permissionList.size()];
        permissionList.toArray(permissionsToGrant);
        ActivityCompat.requestPermissions(this, permissionsToGrant, request);
        return false;
    }
}