human: 如何处理七牛云的直播云快速开始

gpt: [直播云](https://developer.qiniu.com/pili) > SDK 下载 > 推流端 >Android 推流端 SDK >快速开始

#  快速开始

最近更新时间: 2022-05-19 20:06:07

# 1 开发环境配置

  * 首先需要搭建好您的业务服务端。搭建好带有 [Pili Server sdk __](https://developer.qiniu.com/pili/1220/server-sdk)的业务服务端后，SDK 推流信息的输入来自服务端返回的推流地址
  * Android Studio 开发工具。官方[下载地址 __](http://developer.android.com/intl/zh-cn/sdk/index.html)
  * 下载 Android 官方开发SDK 。官方[下载地址 __](https://developer.android.com/intl/zh-cn/sdk/index.html#Other)。PLDroidMediaStreaming 要求 Android Min API 18
  * 下载 PLDroidMediaStreaming 最新的 JAR 和 SO 文件。[下载地址 __](https://github.com/pili-engineering/PLDroidMediaStreaming/tree/master/releases)
  * 请用真机调试代码，模拟器无法调试。

# 2 创建新工程

  * 通过 Android Studio 创建 Project，  
![创建新工程](https://dn-odum9helk.qbox.me/Fg8lWdPJ6vYSVPUJexZlmica2exB)

  * 设置新项目

    * 填写 Application id
    * 填写 Company Domain
    * 填写 Package id
    * 选择 Project location
    * 可以使用默认的填写项

![设置新项目 ](https://dn-odum9helk.qbox.me/Fo5ui-ItnSc3DzZWXGnWnkyCLW5E)

  * 选择 Target Android Devices

本例中选择使用 MinimumSDK API 18  
![MinimumSDK API 18](https://dn-
odum9helk.qbox.me/Fk88ADMnseEb26yOd4oVzaDc0zAK)

  * 选择 Empty Activity  
![选择 Empty Activity](https://dn-
odum9helk.qbox.me/Fn8lDqVq1AIRASTLnoxO4Usqh5Yj)

  * 填写 Main Activity 信息，作为 `android.intent.action.MAIN`  
![填写 Main Activity 信息](https://dn-
odum9helk.qbox.me/FjMOYZgnQQwtOzOd_hALFR5yXmOw)

  * 完成创建  
![完成创建](https://dn-odum9helk.qbox.me/FuSYaNpC_s_K4vh8iIhXSGN8ZW3j)

# 3 导入 SDK

  * 将右侧文件夹目录切换为 `Project` 视图

![Project](https://dn-odum9helk.qbox.me/Ft9n70Ak3L5AD4nQCCHhtFQ4x1-I)

  * 在 app/src/main 目录下创建 jniLibs 目录。按图所示，将文件导入对应的目录。

![导入路径](https://docs.qnsdk.com/PLDroidMediaStreaming_so_structure.jpg)

  * 选中 libs 目录下找到 pldroid-media-streaming-3.0.2.jar，右键添加新建库，如图所示

![添加新库](https://docs.qnsdk.com/PLDroidMediaStreaming_add_library.jpg)

  * 导入完成，双击 `build.gradle` 文件查看内容，lib 目录中的文件已经自动导入，涉及的文件名如下：

    
    
    // JAR, 以 v3.0.2 为例，实际开发需替换为相应的版本
    pldroid-media-streaming-3.0.2.jar
    
    // SO
    libpldroid_streaming_aac_encoder.so
    libpldroid_streaming_core.so
    libpldroid_streaming_h264_encoder.so
    libpldroid_mmprocessing.so
    libpldroid_streaming_amix.so
    libpldroid_streaming_puic.so
    

# 4 创建基础推流实例

您可以从[这里下载 __](https://dn-odum9helk.qbox.me/streaming_easy.zip)以下代码

## 4.1 添加相关权限并注册 Activity

  * 在 app/src/main 目录中的 AndroidManifest.xml 中增加 `uses-permission` 和 `uses-feature` 声明，并注册推流 Activity : SWCameraStreamingActivity

    
    
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.qiniu.pili.droid.streaming.demo" >
    
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    
        <uses-feature android:name="android.hardware.camera.autofocus" />
        <uses-feature
            android:glEsVersion="0x00020000"
            android:required="true" />
    
        <application
            android:allowBackup="true"
            android:name=".StreamingApplication"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_id"
            android:supportsRtl="true"
            android:theme="@style/AppTheme" >
            <activity android:name=".MainActivity" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <activity android:name=".StreamingByCameraActivity" >
            </activity>
        </application>
    
    </manifest>
    

## 4.2 添加 happy-dns 依赖

  * 检查在 app 目录下的 `build.gradle` ，并且按照如下修改： 
    * 确认在 app 目录下
    * 打开如图所示目录文件

    
    
    apply plugin: 'com.android.application'
    
    android {
        compileSdkVersion 29
        buildToolsVersion "29.0.3"
    
        defaultConfig {
            applicationId "com.qiniu.pili.droid.streaming.demo"
            minSdkVersion 18
            targetSdkVersion 29
            versionCode 1
            versionid "1.0"
        }
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            }
        }
    }
    
    dependencies {
        // 推流 SDK jar 包，为推流 SDK 必须依赖的库
        implementation files('libs/pldroid-media-streaming-3.0.2.jar')
        // dns 相关 jar 包，必须依赖
        implementation 'com.qiniu:happy-dns:0.2.17'
        // 监听应用生命周期，必须依赖
        implementation 'android.arch.lifecycle:extensions:1.1.1'
        implementation 'com.android.support:appcompat-v7:28.0.0'
    }
    
    

其中，不同版本的 SDK 需依赖的 HappyDns 版本可能不同，详情可参阅[版本升级须知
__](https://developer.qiniu.com/pili/3716/PLDroidMediaStreaming-preparation-
before-development#4)

## 4.3 实现自己的 Application

    
    
    public class StreamingApplication extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            StreamingEnv.init(getApplicationContext(), Util.getUserId(getApplicationContext()));
        }
    }
    

其中，`StreamingEnv.init` 的第二个参数代表用户唯一标识符，用于区分不同的用户

## 4.4 创建主界面

  * 查看 app/src/main/java 目录中的 MainActivity.java 文件。为了演示方便，将文件中的 `MainActivity` 父类 `AppCompatActivity` 更改为 `Activity`，即 `public class MainActivity extends AppCompatActivity`，修改为 `public class MainActivity extends Activity`，`MainActivity` 其主要工作包括：
  * 通过 start Button 去 app server 异步请求推流地址
  * 推流地址获取成功之后，启动 `SWCameraStreamingActivity`

    
    
    public class MainActivity extends Activity {
        private static final String TAG = "MainActivity";
    
        private String requestPublishURL() {
            try {
                // Replace "Your app server" by your app sever url which can get the publish URL as the SDK's input.
                HttpURLConnection httpConn = (HttpURLConnection) new URL("Your app server").openConnection();
                httpConn.setRequestMethod("POST");
                httpConn.setConnectTimeout(5000);
                httpConn.setReadTimeout(10000);
                int responseCode = httpConn.getResponseCode();
                if (responseCode != HttpURLConnection.HTTP_OK) {
                    return null;
                }
    
                int length = httpConn.getContentLength();
                if (length <= 0) {
                    return null;
                }
                InputStream is = httpConn.getInputStream();
                byte[] data = new byte[length];
                int read = is.read(data);
                is.close();
                if (read <= 0) {
                    return null;
                }
                return new String(data, 0, read);
            } catch (Exception e) {
                showToast("Network error!");
            }
            return null;
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Button btn = (Button) findViewById(R.id.start);
            btn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                // Get the publish URL from http
                                String publishURL = requestPublishURL();
    
                                Intent intent = new Intent(MainActivity.this, StreamingByCameraActivity.class);
                                intent.putExtra("stream_publish_url", publishURL);
                                startActivity(intent);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }).start();
                }
            });
        }
    }
    

## 4.5 创建主界面布局文件

  * 查看 app/src/main/res/layout 目录下的 `activity_main.xml`
  * 底部 TAB 切换至 Text 面板，粘贴如下代码

    
    
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
        android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
        android:paddingRight="@dimen/activity_horizontal_margin"
        android:paddingTop="@dimen/activity_vertical_margin"
        android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
    
        <Button
            android:id="@+id/start"
            android:text="start"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    </RelativeLayout>
    

## 4.6 创建推流界面

  * 创建名为 `SWCameraStreamingActivity` 的 Empty Activity，`SWCameraStreamingActivity` 的主要工作包括：

    * `SWCameraStreamingActivity` 获取 `MainActivity` 从 app server 获取到的推流地址
    * 在 `onCreate` 中初始化推流的配置以及推流 SDK 的核心类 `MediaStreamingManager`
    * 在 `onResume` 中调用 `mMediaStreamingManager.resume();`
    * 在接收到 `READY` 之后，开始推流 `mMediaStreamingManager.startStreaming();`，`startStreaming` 需要在非 UI 线程中进行操作。
  * 在 app/src/main/java 目录下创建 `StreamingByCameraActivity` 文件，代码如下：

    
    
    public class StreamingByCameraActivity extends Activity
            implements StreamingStateChangedListener, StreamStatusCallback, AudioSourceCallback, StreamingSessionListener {
    
        CameraPreviewFrameView mCameraPreviewSurfaceView;
        private MediaStreamingManager mMediaStreamingManager;
        private StreamingProfile mProfile;
        private String TAG = "StreamingByCameraActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_camera_streaming);
            init();
        }
    
        private void init() {
            //get form you server
            String publishURLFromServer = "rtmpp://xxxx/xx/x";
    
            mCameraPreviewSurfaceView = findViewById(R.id.cameraPreview_surfaceView);
            try {
                //encoding setting
                mProfile = new StreamingProfile();
                mProfile.setVideoQuality(StreamingProfile.VIDEO_QUALITY_HIGH1)
                        .setAudioQuality(StreamingProfile.AUDIO_QUALITY_MEDIUM2)
                        .setEncodingSizeLevel(StreamingProfile.VIDEO_ENCODING_HEIGHT_480)
                        .setEncoderRCMode(StreamingProfile.EncoderRCModes.QUALITY_PRIORITY)
                        .setPublishUrl(publishURLFromServer);
    
                //preview setting
                CameraStreamingSetting camerasetting = new CameraStreamingSetting();
                camerasetting.setCameraId(Camera.CameraInfo.CAMERA_FACING_BACK)
                        .setContinuousFocusModeEnabled(true)
                        .setCameraPrvSizeLevel(CameraStreamingSetting.PREVIEW_SIZE_LEVEL.MEDIUM)
                        .setCameraPrvSizeRatio(CameraStreamingSetting.PREVIEW_SIZE_RATIO.RATIO_16_9);
    
                //streaming engine init and setListener
                mMediaStreamingManager = new MediaStreamingManager(this, mCameraPreviewSurfaceView, AVCodecType.SW_VIDEO_WITH_SW_AUDIO_CODEC);  // soft codec
                mMediaStreamingManager.prepare(camerasetting, mProfile);
                mMediaStreamingManager.setStreamingStateListener(this);
                mMediaStreamingManager.setStreamingSessionListener(this);
                mMediaStreamingManager.setStreamStatusCallback(this);
                mMediaStreamingManager.setAudioSourceCallback(this);
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
        }
    
        @Override
        public void onStateChanged(StreamingState streamingState, Object extra) {
    
            Log.e(TAG, "streamingState = " + streamingState + "extra = " + extra);
            switch (streamingState) {
                case PREPARING:
                    Log.e(TAG, "PREPARING");
                    break;
                case READY:
                    Log.e(TAG, "READY");
                    // start streaming when READY
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            if (mMediaStreamingManager != null) {
                                mMediaStreamingManager.startStreaming();
                            }
                        }
                    }).start();
                    break;
                case CONNECTING:
                    Log.e(TAG, "连接中");
                    break;
                case STREAMING:
                    Log.e(TAG, "推流中");
                    // The av packet had been sent.
                    break;
                case SHUTDOWN:
                    Log.e(TAG, "直播中断");
                    // The streaming had been finished.
                    break;
                case IOERROR:
                    // Network connect error.
                    Log.e(TAG, "网络连接失败");
                    break;
                case OPEN_CAMERA_FAIL:
                    Log.e(TAG, "摄像头打开失败");
                    // Failed to open camera.
                    break;
                case DISCONNECTED:
                    Log.e(TAG, "已经断开连接");
                    // The socket is broken while streaming
                    break;
                case TORCH_INFO:
                    Log.e(TAG, "开启闪光灯");
                    break;
    
            }
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            mMediaStreamingManager.resume();
        }
    
        @Override
        protected void onPause() {
            super.onPause();
            // You must invoke pause here.
            mMediaStreamingManager.pause();
        }
    
        @Override
        public void notifyStreamStatusChanged(StreamingProfile.StreamStatus status) {
            Log.e(TAG, "StreamStatus = " + status);
        }
    
        @Override
        public void onAudioSourceAvailable(ByteBuffer srcBuffer, int size, long tsInNanoTime, boolean isEof) {
    
        }
    
        @Override
        public boolean onRecordAudioFailedHandled(int code) {
            Log.i(TAG, "onRecordAudioFailedHandled");
            return false;
        }
    
        @Override
        public boolean onRestartStreamingHandled(int code) {
            Log.i(TAG, "onRestartStreamingHandled");
            new Thread(new Runnable() {
                @Override
                public void run() {
                    if (mMediaStreamingManager != null) {
                        mMediaStreamingManager.startStreaming();
                    }
                }
            }).start();
            return false;
        }
    
        @Override
        public void onBackPressed() {
            super.onBackPressed();
            Intent intent = new Intent(this, MainActivity.class);
            startActivity(intent);
        }
    
        @Override
        public Camera.Size onPreviewSizeSelected(List<Camera.Size> list) {
            return null;
        }
    
        @Override
        public int onPreviewFpsSelected(List<int[]> list) {
            return -1;
        }
    

## 4.7 创建推流界面布局文件

  * 查看 app/src/main/res/layout 中的 `activity_swcamera_streaming.xml`
  * 切换至 Text 面板，粘贴如下内容

    
    
    <?xml version="1.0" encoding="utf-8"?>
    
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/background_floating_material_dark"
        tools:context=".SWCameraStreamingActivity" >
    
        <com.qiniu.pili.droid.streaming.demo.ui.CameraPreviewFrameView
            android:id="@+id/cameraPreview_surfaceView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center" />
    </RelativeLayout>
    

启动 APP 之后，当点击 start button，就可以开始推流了。

## 4.8 测试播放效果

  * 测试方法: 从 app server 获取到推流对应的播放地址，输入到播放器中进行播放。

# 5 从 SDK DEMO 开始使用

## 5.1 下载 SDK DEMO

  * 从[这里 __](https://github.com/pili-engineering/PLDroidMediaStreaming/releases)下载 SDK Demo。

## 5.2 导入 Project 到 Android Studio

  * 启动 Android Studio 并选择 `Open an existing Android Studio project`。  
![Android Studio 打开](https://dn-
odum9helk.qbox.me/Fn2A5BOF3b3Uhk_psqxzI1-kNfpJ)

  * 选择 PLDroidCameraStreamingDemo 工程。从目录 `~/workdir/workspace/sdk/PLDroidCameraStreaming-1.4.1/` 中选择 `DroidCameraStreamingDemo` 工程，选择完成后，点击 `Choose` 按钮。  
![DroidCameraStreamingDemo](https://dn-
odum9helk.qbox.me/Fnqyn0GKDbJFHJVI20E3LjFTc8Lb)

  * 恭喜你，导入完成。  
![完成](https://dn-odum9helk.qbox.me/Fsjq07Xa2u4ciLkDxMHRa9oDbk7k)

## 5.3 已有工程导入 SDK

  * SDK [下载地址 __](https://github.com/pili-engineering/PLDroidCameraStreaming)。

  * Demo Project 目录结构说明。如下图所示：

    * 红色框：是 Demo 依赖 SDK 的 JAR 文件。您也可以在 build.gradle 中自定义其路径：
    
        dependencies {
        // 推流 SDK jar 包，为推流 SDK 必须依赖的库
        implementation files('libs/pldroid-media-streaming-3.0.2.jar')
        // dns 相关 jar 包，必须依赖
        implementation 'com.qiniu:happy-dns:0.2.17'
        // 监听应用生命周期，必须依赖
        implementation 'android.arch.lifecycle:extensions:1.1.1'
        implementation 'com.android.support:appcompat-v7:28.0.0'
    }
    

    * 绿色框：是 Demo Java 代码部分。  
\- AudioStreamingActivity 是纯音频推流的样例代码  
\- AVStreamingActivity 是音视频推流的样例代码  
\- ImportStreamingActivity 是外部导入推流的样例代码  
\- ScreenStreamingActivity 是录屏推流的样例代码

    * 橙色框：是 Demo 依赖 SDK 的动态链接库文件。目前 SDK 支持主流的 ARM, ARMv7a, ARM64v8a, X86 芯片体系架构。

![demo](https://docs.qnsdk.com/PLDroidMediaStreaming_demo_structure.jpg)

以上内容是否对您有帮助？