安卓用七牛云做直播

安卓用七牛云做直播_第1张图片

上图为拉流页面(即看直播页面)

最近刚刚做完直播项目,来总结一下,直播使用七牛云直播实现的,直播和看直播写了两个Activiy,公用同一个Fragment,大致结构是这样的。下面先来说主播页面(前期引入sak省略):

  CameraPreviewFrameView cameraPreviewFrameView =
                (CameraPreviewFrameView) findViewById(R.id.cameraPreview_surfaceView);
        cameraPreviewFrameView.setListener(this);

        streamingProfile = new StreamingProfile();

        try {

//            // audio sample rate is 44100, audio bitrate is 96 * 1024 bps
//            StreamingProfile.AudioProfile aProfile = new StreamingProfile.AudioProfile(44100, 96 * 1024);
//// fps is 30, video bitrate is 1000 * 1024 bps, maxKeyFrameInterval is 48
//            StreamingProfile.VideoProfile vProfile = new StreamingProfile.VideoProfile(30, 1000 * 1024, 48);
//            StreamingProfile.AVProfile avProfile = new StreamingProfile.AVProfile(vProfile, aProfile);
            streamingProfile
//                    .setAVProfile(avProfile)
                    .setVideoQuality(StreamingProfile.VIDEO_QUALITY_MEDIUM2)//视频的 fps 为 30,码率为 1000 kbps
                    .setAudioQuality(StreamingProfile.AUDIO_QUALITY_MEDIUM2)//音频的采样率为 44100 HZ,码率为 48 kbps。

                    .setEncodingSizeLevel(StreamingProfile.VIDEO_ENCODING_HEIGHT_480)//使用内置的 encoding size level
                    .setBitrateAdjustMode(StreamingProfile.BitrateAdjustMode.Auto)
//                    .setAudioQuality(StreamingProfile.AUDIO_QUALITY_LOW1)
//                .setPreferredVideoEncodingSize(960, 544)
                    //.setEncodingSizeLevel(StreamingProfile.VIDEO_ENCODING_HEIGHT_480)
                    .setEncoderRCMode(StreamingProfile.EncoderRCModes.QUALITY_PRIORITY)//质量优先,实际的码率可能高于设置的码率
//                .setAVProfile(avProfile)
//                    .setDnsManager(getMyDnsManager())
//                    .setAdaptiveBitrateEnable(true)
                    .setFpsControllerEnable(true)
                    .setStreamStatusConfig(new StreamingProfile.StreamStatusConfig(3))
                    .setPublishUrl(urlPush)//推流url
//                .setEncodingOrientation(StreamingProfile.ENCODING_ORIENTATION.PORT)
                    .setSendingBufferProfile(new StreamingProfile.SendingBufferProfile(0.2f, 0.8f, 3.0f, 20 * 1000));
            CameraStreamingSetting setting = new CameraStreamingSetting();

            setting.setCameraId(Camera.CameraInfo.CAMERA_FACING_BACK)
                    .setContinuousFocusModeEnabled(true)

                    // FaceBeautySetting 中的参数依次为:beautyLevel,whiten,redden,即磨皮程度、美白程度以及红润程度,取值范围为[0.0f, 1.0f]
                    .setFaceBeautySetting(new CameraStreamingSetting.FaceBeautySetting(1.0f, 1.0f, 0.8f))
                    .setVideoFilter(CameraStreamingSetting.VIDEO_FILTER_TYPE.VIDEO_FILTER_BEAUTY)
                    .setCameraPrvSizeLevel(CameraStreamingSetting.PREVIEW_SIZE_LEVEL.LARGE)
                    .setCameraPrvSizeRatio(CameraStreamingSetting.PREVIEW_SIZE_RATIO.RATIO_16_9);


//            streamingManager = new MediaStreamingManager(this, cameraPreview_afl, cameraPreviewFrameView,
//                    AVCodecType.HW_VIDEO_WITH_HW_AUDIO_CODEC);// 视频硬编,音频硬编
            streamingManager = new MediaStreamingManager(this, cameraPreviewFrameView,
                    AVCodecType.HW_VIDEO_WITH_HW_AUDIO_CODEC);// 视频硬编,音频硬编

            // hw codec  // soft codec
            mMicrophoneStreamingSetting = new MicrophoneStreamingSetting();
            streamingManager.setStreamingSessionListener(this);
            mMicrophoneStreamingSetting.setBluetoothSCOEnabled(false);//蓝牙麦克风支持关闭
            streamingManager.prepare(setting, null, null, streamingProfile);
            streamingManager.setStreamingStateListener(this);
            streamingManager.setStreamStatusCallback(this);

        } catch (URISyntaxException e) {
            e.printStackTrace();
        }

备注也是很清晰明了。

下面是直播的一些状态:

    @Override
    public void onStateChanged(StreamingState streamingState, Object o) {
        switch (streamingState) {
            case PREPARING:

                break;
            case READY:
                Log.e("TAGresponse", "READY" + " ");
                // start streaming when READY
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        if (streamingManager != null) {
                            streamingManager.startStreaming();
                        }
                    }
                }).start();


                break;
            case CONNECTING:

                Log.e("TAGresponse", "CONNECTING" + " ");
                currntzoom = streamingManager.getZoom();

                maxZoom = streamingManager.getMaxZoom();


                seekBar.setMax(maxZoom);

                seekBar.setProgress(currntzoom);

                seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
                    @Override
                    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

                        currntzoom = progress;

                        if (streamingManager.isZoomSupported()) {

                            streamingManager.setZoomValue(currntzoom);
                        }

                    }

                    @Override
                    public void onStartTrackingTouch(SeekBar seekBar) {

                    }

                    @Override
                    public void onStopTrackingTouch(SeekBar seekBar) {

                    }
                });


                ArticleLvbState_v2();


                break;
            case STREAMING:
                Log.e("TAGresponse", "STREAMING" + " ");
                // The av packet had been sent.
                break;
            case SHUTDOWN:
                Log.e("TAGresponse", "SHUTDOWN" + " ");
                // The streaming had been finished.
                break;
            case IOERROR:

                Log.e("TAGresponse", "IOERROR" + " ");
//                streamingManager.stopStreaming();

//                finish();
                if (NetWorkCheckTool.isNetworkAvailable(this)) {
                    showNetWorkDialog("当前流中断,是否退出", "确定", true);
                } else {
                    showNetWorkDialog("当前网络中断,请重新连接", "重连", false);

                }


                // Network connect error.
                break;
            case SENDING_BUFFER_EMPTY:
                Log.e("TAGresponse", "SENDING_BUFFER_EMPTY" + " ");
                break;
            case SENDING_BUFFER_FULL:
                Log.e("TAGresponse", "SENDING_BUFFER_FULL" + " ");
                break;
            case AUDIO_RECORDING_FAIL:
                Log.e("TAGresponse", "AUDIO_RECORDING_FAIL" + " ");
                // Failed to record audio.
                break;
            case OPEN_CAMERA_FAIL:
                Log.e("TAGresponse", "OPEN_CAMERA_FAIL" + " ");
                // Failed to open camera.
                break;
            case DISCONNECTED:
                Log.e("TAGresponse", "DISCONNECTED" + " ");
//                streamingManager.stopStreaming();
//                finish();
                if (NetWorkCheckTool.isNetworkAvailable(this)) {
//                    RetrieveLvb();
                } else {
                }

                // The socket is broken while streaming
                break;
            case TORCH_INFO://

                break;
        }

    }

 

当断网或是其他错误会走IOERROR,这是会判断是否联网,未联网的话会提示网络连接中断,是否重新连接,这里会请求服务器进行重连,若网络连接成功并且服务器返回重连url的话会进行重新推流,若服务器返回当前推流中断,则提示主播是否要退出直播;若网络连接没问题,则直接提示主播当前流中断,是否退出直播。

剩下的就是fragment页面逻辑(关注,聊天、禁言、切换摄像头、静音等等)

下面就是观看直播页面

  View loadingView = findViewById(R.id.LoadingView);
        mVideoView.setOnErrorListener(this);
        mVideoView.setOnCompletionListener(this);
        mVideoView.setBufferingIndicator(loadingView);
        mVideoView.setVideoPath(pull);

        mVideoView.setDisplayAspectRatio(PLVideoView.ASPECT_RATIO_PAVED_PARENT);

        mVideoView.setOnCompletionListener(this);
        mVideoView.setCoverView(loadingView);
        mVideoView.start();

代码很简单,这样就实现了观看直播。

    @Override
    public boolean onError(int i) {
//        if(i == -875574520){
//        Toast.makeText(this, "直播异常请稍后", Toast.LENGTH_SHORT).show();
//            finish();
//            return true;
//        }
        Log.i(TAG, "onError: " + i);
//        mVideoView.setVideoPath(pull);
//        mVideoView.start();

        switch (i) {
            case ERROR_CODE_IO_ERROR://网络异常
                if (NetWorkCheckTool.isNetworkAvailable(this)) {
                    if (!TextUtils.isEmpty(errorCode) && errorCode.equals("406")) {

                    } else {

                        new Handler().postDelayed(new Runnable() {
                            @Override
                            public void run() {

                                GetStreamState();
                            }
                        }, 2000);

                    }

                } else {//
                    showNetWorkDialog("网络已断开,请重新连接", "重连", false);
                }
                break;
            case MEDIA_ERROR_UNKNOWN://未知错误
                break;
            case ERROR_CODE_OPEN_FAILED://播放器打开失败
                break;
            case ERROR_CODE_SEEK_FAILED://拖动失败
                break;
            case ERROR_CODE_HW_DECODE_FAILURE://硬解失败
                break;
            case ERROR_CODE_PLAYER_DESTROYED://播放器已被销毁,需要再次 setVideoURL 或 prepareAsync
                break;
            case ERROR_CODE_PLAYER_VERSION_NOT_MATCH://so 库版本不匹配,需要升级
                break;
            case ERROR_CODE_PLAYER_CREATE_AUDIO_FAILED://AudioTrack 初始化失败,可能无法播放音频
                break;
        }


        return true;
    }

这是观看直播的一个状态,上面备注 很清晰了,这样拉流页面也实现了,

剩下的fragment页面逻辑,改天有时间再更新,由于时间问题,暂时先写到这,有问题欢迎留言。

你可能感兴趣的:(android)