Android Development - access Tencent cloud streaming SDK in Android to realize live streaming function

preface

Nowadays, with the development of mobile Internet in China for several years, mobile development technology is relatively mature, and live broadcasting is indispensable in the mobile App we use everyday. Whether it's entertainment, game, sports or education apps, live broadcasting is indispensable in some commercial or non-commercial applications Function. At present, there are many popular live apps in China, such as: fighting fish (Game Live), YY live (national entertainment live), Huya (game + video competition live) and Yingke (entertainment live).

In order to realize the function of live streaming in our Android application, it is necessary to make a technical selection of the live streaming SDK on the market (if a company with conditions can develop a live streaming platform by itself, it can not use the third-party streaming SDK). Because the previous projects of our company need to use the live streaming SDK, so the author has a direct view of the current market We have a good understanding of the streaming SDK. So I will briefly introduce how to access Tencent cloud streaming SDK in Android to realize live streaming. (P.S. if you want to know about the Alibaba cloud streaming SDK's live streaming function, you can see this blog I wrote earlier: https://blog.csdn.net/fukaimei/article/details/103237654
)

Preparations before accessing streaming SDK

  • Functions of Tencent cloud live service
    The essence of cloud live service is a broadcast process, similar to the live TV programs sent to thousands of households through cable TV network. In order to complete this process, cloud live broadcasting needs to have collection and streaming devices (similar to cameras), cloud live broadcasting services (similar to cable TV networks of TV stations) and broadcasting devices (similar to TV). The collection and streaming devices and playback devices can be mobile phones, PC s, pads and other intelligent terminals as well as Web browsers.
    Tencent cloud live service address is as follows: https://console.cloud.tencent.com/live/livestat?from=product-banner-use-lvb

  • Binding domain names of push and pull streams
    The precondition for binding the domain names of push stream and pull stream is that your domain name must be a filed domain name before binding, and then select Domain name management , click Add domain name to add the streaming domain name you have filed. For details, see Add own domain name.

  • Apply for the Key value and LicenseUrl value of the mobile live SDK License
    The Key value and LicenseUrl value of SDK License are used during SDK initialization. Please refer to License usage guide.

Start to access streaming SDK

First, copy the aar files related to the downloaded Android streaming SDK of Tencent cloud to the libs directory of AS project, AS shown below:


And then inside the AS build.gradle Add stream related dependencies to


android {
    ........
    defaultConfig {
         ........
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a'
        }
    }
    sourceSets {
        main {
            jniLibs.srcDir 'libs'
        }
    }
    repositories {
        flatDir {
            dirs 'libs'
        }
    }
}
dependencies {
    ........
    implementation(name: 'LiteAVSDK_Smart', ext: 'aar')
}

Finally, in the list file AndroidManifest.xml Add the corresponding permissions required for live streaming in

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_LOGS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
    <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

Note: for live streaming over Android 6.0, camera permission must be granted dynamically in Java code or Kotlin code before preview of camera interface and launching live streaming( Manifest.permission.CAMERA )And microphone permissions( Manifest.permission.RECORD_AUDIO), otherwise the application will flash back.

Coding implementation

In this phase of coding implementation, you can directly view Tencent cloud streaming development document To access, you can also download the Demo source code provided by them to access.

  • Add Layout layout
    In order to display the video image of the player, the first step is to add the following code to the layout xml file:
<com.tencent.rtmp.ui.TXCloudVideoView
        android:id="@+id/pusher_tx_cloud_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
  • Initialize SDK and create Player
        // Set SDK License
        String licenceURL = ShareUtils.getString(this, "LicenceURL", "");
        String licenceKey = ShareUtils.getString(this, "LicenceKey", "");
        TXLiveBase.getInstance().setLicence(this, licenceURL, licenceKey);

        mLivePushConfig = new TXLivePushConfig();
        // Allow two finger gestures to enlarge Preview
        mLivePushConfig.setEnableZoom(true);
        // Set noise suppression
        mLivePushConfig.enableAEC(true);
        // Turn on hardware acceleration
        mLivePushConfig.setHardwareAcceleration(TXLiveConstants.ENCODE_VIDEO_HARDWARE);
        // Turn on MainProfile hardcode mode
        mLivePushConfig.enableVideoHardEncoderMainProfile(true);
        mLivePusher = new TXLivePusher(this);
        mLivePusher.setConfig(mLivePushConfig);
        mLivePusher.startCameraPreview(mPusherView);

The TXLivePlayer module in the video cloud SDK is responsible for the live broadcast function, and uses the setPlayerView interface to connect it with the pusher we just added to the interface_ Tx_ cloud_ View control.

  • Get push-pull stream splicing address
    Obtain the authentication string information of the push-pull stream splicing address = push-pull stream domain name + room number + encryption information and effective time stamp. The generated push-pull tool code is as follows:
/**
 * Push and pull address splicing address
 */
public class PushUrlToken {

    public static String getUrlToken() {

        String pushKey = ShareUtils.getString(PushApplication.getInstance(), "PushKey", "");
        String urlNO = ShareUtils.getString(PushApplication.getInstance(), "UrlNO", "");

        String urlToken = getSafeUrl(pushKey, urlNO, dateToStamp());
        return urlToken;
    }

    private static final char[] DIGITS_LOWER =
            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /*
     * KEY+ streamName + txTime
     */
    private static String getSafeUrl(String key, String streamName, long txTime) {
        String input = new StringBuilder().
                append(key).
                append(streamName).
                append(Long.toHexString(txTime).toUpperCase()).toString();

        String txSecret = null;
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            txSecret = byteArrayToHexString(
                    messageDigest.digest(input.getBytes("UTF-8")));
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return txSecret == null ? "" :
                new StringBuilder().
                        append("txSecret=").
                        append(txSecret).
                        append("&").
                        append("txTime=").
                        append(Long.toHexString(txTime).toUpperCase()).
                        toString();
    }

    private static String byteArrayToHexString(byte[] data) {
        char[] out = new char[data.length << 1];
        for (int i = 0, j = 0; i < data.length; i++) {
            out[j++] = DIGITS_LOWER[(0xF0 & data[i]) >>> 4];
            out[j++] = DIGITS_LOWER[0x0F & data[i]];
        }
        return new String(out);
    }

    /**
     * Ten digit time stamp
     *
     * @return
     * @throws ParseException
     */
    private static long dateToStamp() {
        Long time = System.currentTimeMillis();
        time += 30 * 1000 * 60;
        String res = "";
        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date date = simpleDateFormat.parse(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(time));
            long ts = date.getTime();
            ts = ts / 1000;
            res = String.valueOf(ts);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Long.valueOf(res).longValue();
    }

}
  • Start live streaming
    /**
     * Start streaming
     */
    private void startPush() {
        if (isPush) {
            mLivePusher = new TXLivePusher(this);
            mLivePusher.setConfig(mLivePushConfig);
            mLivePusher.startCameraPreview(mPusherView);
        }
        int ret = mLivePusher.startPusher(pushUrl.trim());
        L.i("ret: " + ret);
        if (ret == -5) {
            L.i("startRTMPPush: license Verification failed");
            ToastUtil.showToastLong("startRTMPPush: license Verification failed");
        }
    }

Before starting live streaming, first verify whether the SDK has been initialized and whether the SDK License is valid mLivePusher.startPusher ( pushUrl.trim () if the return value is equal to - 5, it means that the License verification fails. At this time, go to Tencent cloud live platform to check whether the License has expired or configure whether Android package name is in AS with itself Whether the package name of the created project is consistent. The pushurl is the push address of the live broadcast. The push address format of the live broadcast can be RTMP, FLV or m3u8. If there is a high demand for the push delay of the live broadcast, the first two formats are recommended.

  • Stop live streaming
   /**
     * Stop streaming
     */
    private void stopPush() {
        mLivePusher.stopPusher();
        // If camera preview has already been activated, turn it off when you end streaming
        mLivePusher.stopCameraPreview(true);
        isPush = true;
    }

Stop live streaming calls the stopPusher() method of TXLivePusher. If there is currently a camera picture previewing, call the stopCameraPreview(true) method of TXLivePusher to close it.

  • Switch live streaming front and rear camera
    /**
     * Switch cameras
     */
    private void switchCamera() {
        mLivePusher.switchCamera();
    }

Before and after switching, the camera is relatively simple, which can be realized by calling the switchCamera() method of TXLivePusher in one line of code.

  • Live horizontal screen or vertical screen streaming
    /**
     * Horizontal and vertical screen push flow switching
     *
     * @param isPortrait
     */
    private void onOrientationChange(boolean isPortrait) {
        if (isPortrait) {
            mLivePushConfig.setHomeOrientation(TXLiveConstants.VIDEO_ANGLE_HOME_DOWN);
            mLivePusher.setConfig(mLivePushConfig);
            mLivePusher.setRenderRotation(0);
        } else {
            mLivePushConfig.setHomeOrientation(TXLiveConstants.VIDEO_ANGLE_HOME_RIGHT);
            mLivePusher.setConfig(mLivePushConfig);
            // Because the acquisition is rotated, to ensure that the local rendering is positive, set the rendering angle to 90 degrees.
            mLivePusher.setRenderRotation(90);
        }
    }

The screen preview collected by live horizontal screen or vertical screen streaming may not have an effect on the host, but it can be seen on the audience. For example, when the host is set to horizontal screen streaming, the screen seen by the audience is the screen seen by the host rotating 90 degrees.

  • The complete code of streaming logic is as follows:
public class CameraPusherActivity extends BaseActivity {

    @BindView(R.id.pusher_tx_cloud_view)
    TXCloudVideoView mPusherView;
    @BindView(R.id.tv_play_url)
    TextView tvPlayUrl;
    private TXLivePusher mLivePusher;
    private TXLivePushConfig mLivePushConfig;
    // Streaming url
    private String bsePushUrl;
    private String pushUrl;
    // Pull url
    private String basePlayUrl;
    private String playUrl;
    private String urlNO;
    // Authentication string information
    private String urlToken;
    // Whether the flow has been pushed
    private boolean isPush;

    @Override
    protected int getLayoutId() {
        return R.layout.activity_camera_pusher;
    }

    @Override
    protected void initView() {
        ButterKnife.bind(this);
        // How to obtain the License? Please refer to the official website Guide https://cloud.tencent.com/document/product/454/34750
        String licenceURL = ShareUtils.getString(this, "LicenceURL", "");
        String licenceKey = ShareUtils.getString(this, "LicenceKey", "");
        TXLiveBase.getInstance().setLicence(this, licenceURL, licenceKey);
        mLivePushConfig = new TXLivePushConfig();
        // Allow two finger gestures to enlarge Preview
        mLivePushConfig.setEnableZoom(true);
        // Set noise suppression
        mLivePushConfig.enableAEC(true);
        // Turn on hardware acceleration
        mLivePushConfig.setHardwareAcceleration(TXLiveConstants.ENCODE_VIDEO_HARDWARE);
        // Turn on MainProfile hardcode mode
        mLivePushConfig.enableVideoHardEncoderMainProfile(true);
        mLivePusher = new TXLivePusher(this);
        mLivePusher.setConfig(mLivePushConfig);
        mLivePusher.startCameraPreview(mPusherView);
        isPush = false;
    }

    @Override
    protected void initData() {
        bsePushUrl = ShareUtils.getString(this, "PushDomain", "");
        basePlayUrl = ShareUtils.getString(this, "LiveDomain", "");
        urlNO = ShareUtils.getString(this, "UrlNO", "");
        urlToken = PushUrlToken.getUrlToken();
        pushUrl = bsePushUrl + urlNO + "?" + urlToken;
        playUrl = basePlayUrl + urlNO + "?" + urlToken;
        L.i("Pull address:" + playUrl);
//        ToastUtil.showToastLong("streaming address:" + playUrl);
    }

    /**
     * Start streaming
     */
    private void startPush() {
        if (isPush) {
            mLivePusher = new TXLivePusher(this);
            mLivePusher.setConfig(mLivePushConfig);
            mLivePusher.startCameraPreview(mPusherView);
        }
        int ret = mLivePusher.startPusher(pushUrl.trim());
        L.i("ret: " + ret);
        if (ret == -5) {
            L.i("startRTMPPush: license Verification failed");
            ToastUtil.showToastLong("startRTMPPush: license Verification failed");
        }
        tvPlayUrl.setText(String.format("Pull address:%s%s", basePlayUrl, urlNO));
        L.i(String.format("Pull address:%s%s", basePlayUrl, urlNO));
    }

    /**
     * Stop streaming
     */
    private void stopPush() {
        mLivePusher.stopPusher();
        // If camera preview has already been activated, turn it off when you end streaming
        mLivePusher.stopCameraPreview(true);
        tvPlayUrl.setText("");
        isPush = true;
        ToastUtil.showToast("Streaming stopped");
    }

    /**
     * Switch cameras
     */
    private void switchCamera() {
        mLivePusher.switchCamera();
        ToastUtil.showToast("Camera switched");
    }

    /**
     * Horizontal and vertical screen push flow switching
     *
     * @param isPortrait
     */
    private void onOrientationChange(boolean isPortrait) {
        if (isPortrait) {
            mLivePushConfig.setHomeOrientation(TXLiveConstants.VIDEO_ANGLE_HOME_DOWN);
            mLivePusher.setConfig(mLivePushConfig);
            mLivePusher.setRenderRotation(0);
        } else {
            mLivePushConfig.setHomeOrientation(TXLiveConstants.VIDEO_ANGLE_HOME_RIGHT);
            mLivePusher.setConfig(mLivePushConfig);
            // Because the acquisition is rotated, to ensure that the local rendering is positive, set the rendering angle to 90 degrees.
            mLivePusher.setRenderRotation(90);
        }
    }

    @OnClick({R.id.btn_start_push, R.id.btn_stop_push, R.id.btn_switch_camera
            , R.id.btn_horizontal, R.id.btn_portrait})
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_start_push:
                ToastUtil.showToast("Start streaming");
                startPush();
                break;
            case R.id.btn_stop_push:
                stopPush();
                break;
            case R.id.btn_switch_camera:
                switchCamera();
                break;
            case R.id.btn_horizontal:
                // Horizontal screen push flow
                onOrientationChange(false);
                ToastUtil.showToast("Stream pushed across screen");
                break;
            case R.id.btn_portrait:
                // Vertical screen push flow
                onOrientationChange(true);
                ToastUtil.showToast("Stream is pushed vertically");
                break;
            default:
                break;
        }
    }

    @Override
    protected void onDestroy() {
        stopPush();
        ToastUtil.showToast("Streaming stopped");
        super.onDestroy();
    }
}

The operation effect diagram of the interface is as follows:

Open web address( http://www.cutv.com/demo/live_test.swf )Input the pull stream address to see whether the push stream is successful. If you can see the screen, the push stream is successful. The picture is as follows:

apk installation package download experience address:

You can scan the following QR code for download and installation, or click the following link http://app.fukaimei.top/tcpush Download and install.

---- The end ----

It's not easy to code. If you think this blog is good, you can appreciate a cup of coffee~~

Download address 1 of Demo source code (GitHub)
Download address 2 of Demo source code (code cloud)

Tags: Android SDK Mobile xml

Posted on Wed, 20 May 2020 08:01:27 -0400 by CaptainStarbuck