基于智慧教室|无纸化会议的新选择:RTMP解决方案

简介: 基于智慧教室或是会议的技术方案,一般主要是涉及到屏幕采集和推送,整体技术方案这块,一般建议走RTMP,说到这里,好人开发者提到,市面上也有RTSP的技术方案,甚至RTSP组播方案,这块,大牛直播SDK Github 也做过相关对比,总的来说60人智慧教室或类似同屏场景下,最可靠的还是RTMP的解决方案(不赘述,具体可自行测试对比)。

基于智慧教室或是会议的技术方案,一般主要是涉及到屏幕采集和推送,整体技术方案这块,一般建议走RTMP,说到这里,好人开发者提到,市面上也有RTSP的技术方案,甚至RTSP组播方案,这块,大牛直播SDK Github 也做过相关对比,总的来说60人智慧教室或类似同屏场景下,最可靠的还是RTMP的解决方案(不赘述,具体可自行测试对比)。


有人说,RTMP延迟大,这种说法,相对片面,好多是由于推拉流模块本身问题导致(如果服务器系NIGNX或SRS,基本可排除服务器转发导致的大时延,不要再赖服务器了),从我们官方和实际场景来看,RTMP整体技术方案,延迟可做到1秒内,毫秒级。

整体设计方案如下

20200201113924231.png

注意事项

1. 组网:无线组网,需要好的AP模块才能撑得住大的并发流量,推送端到AP,最好是有线网链接;


2. 服务器部署:如果Windows平台,可以考虑NGINX,如果是Linux,可以考虑SRS或NGINX,服务器可以和Windows平台的教师机部署在一台机器;


3. 教师端:如教师有移动的PAD,可以直接推到RTMP服务器,然后共享出去;


4. 学生端:直接拉取RTMP流播放即可;


5. 教师和学生互动:学生端如需作为示范案例,屏幕数据共享给其他同学,只需请求同屏,数据反推到RTMP服务器,其他学生查看即可。


6. 扩展监控:如果需要更进一步的技术方案,如教师端想监控学生端的屏幕情况,可以有两种方案,如学生端直接推RTMP过来,或者,学生端启动内置RTSP服务,教师端想看的时候,随时看即可(亦可轮询播放)。

以下分平台介绍相关配置选项

Windows平台RTMP推送端

对应DEMO:SmartPublisherDemo.exe


1. 如果采集屏幕,只要采集部分区域的话,可以点击“选取屏幕区域”按钮,选择需要采集的区域,采集推送过程中,可以移动采集区域;


2. 如果是高分屏(如有些采集设备,是4K屏,原始分辨率过高),用户又不想推这么高的分辨率的话,可以选中“缩放屏幕大小”,并指定缩放比例,可以先缩放,后编码推送数据;


3. 设置采集帧率:如果是PPT/Word文档类,一般8-12帧足矣,如果是电影之类,可以设置到20-30帧不等,关键帧间隔一般设置到帧率的2-4倍,屏幕推送的话,建议平均码率模式;


4. 如果需要采集电脑端输出的声音,可以选中“采集扬声器”,如果需要采集外部麦克风的音频,选择“采集麦克风”即可,并选择对应的采集设备;


5. 设置下推送的RTMP URL,然后,点击“推送”,就可以了;


6. 如果想预览推送出去的数据,点击“预览”即可,想停止预览的话,点击“停止预览”即可。

20200106163725507.png

Android平台RTMP屏幕推送端

对应工程:SmartServicePublisherV2


需要注意的事项:


1. Android 8.0及以上版本设备,需要加入省电优化白名单,6.0以上版本,需要动态获取audio权限,具体代码如下:

        //加入省电优化白名单,以免8.0及以上版本设备后台运行超过一分钟被自动停掉
        //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
        if (Build.VERSION.SDK_INT >=26)
        {
            if(!isIgnoringBatteryOptimizations())
            {
                gotoSettingIgnoringBatteryOptimizations();
            }
        }
        //6.0及以上版本,动态获取Audio权限
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
        {
            RequestAudioPermission();
        }
    //拉起请求加入省电白名单弹窗
    private void gotoSettingIgnoringBatteryOptimizations() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            try {
                Intent intent = new Intent();
                String packageName = getPackageName();
                intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                intent.setData(Uri.parse("package:" + packageName));
                startActivityForResult(intent, REQUEST_IGNORE_BATTERY_CODE);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    //动态获取Audio权限
    private void RequestAudioPermission()
    {
        if (PackageManager.PERMISSION_GRANTED ==  ContextCompat.checkSelfPermission(this.getApplicationContext(), android.Manifest.permission.RECORD_AUDIO))
        {
        }
        else {
            //提示用户开户权限音频
            String[] perms = {"android.permission.RECORD_AUDIO"};
            ActivityCompat.requestPermissions(this, perms, RESULT_CODE_STARTAUDIO);
        }
    }

2. 持续的补帧策略,防止屏幕不动,没数据下去;


3.  如果需要传部分区域下去,可以用 SmartPublisherOnCaptureVideoClipedRGBAData() 接口;


4. 横竖屏切换,上层无需过问,底层会自动切。

iOS平台RTMP屏幕推送端

对应工程: SmartServiceCameraPublisherV2


注意事项:ReplayKit2 的直播扩展目前是有50M的内存使用限制,超过此限制系统会直接杀死扩展进程,因此 ReplayKit2 上建议推流分辨率和帧率、码率不要太高。


以下是核心processSampleBuffer() 处理,iOS 11.0以上 加入了横竖屏自动切换适配:

- (void)processSampleBuffer:(CMSampleBufferRef)sampleBuffer
                   withType:(RPSampleBufferType)sampleBufferType {
    CGFloat cur_memory = [self GetCurUsedMemoryInMB];
    if( cur_memory > 20.0f)
    {
        //NSLog(@"processSampleBuffer cur: %.2fM", cur_memory);
        return;
    }
    switch (sampleBufferType) {
        case RPSampleBufferTypeVideo:
            {
                if (!CMSampleBufferIsValid(sampleBuffer))
                    return;
                NSInteger rotation_degress = 0;
                //11.1以上支持自动旋转
    #ifdef __IPHONE_11_1
                if (UIDevice.currentDevice.systemVersion.floatValue > 11.1) {
                    CGImagePropertyOrientation orientation = ((__bridge NSNumber*)CMGetAttachment(sampleBuffer, (__bridge CFStringRef)RPVideoSampleOrientationKey , NULL)).unsignedIntValue;
                    //NSLog(@"cur org: %d", orientation);
                    switch (orientation)
                    {
                        //竖屏
                        case kCGImagePropertyOrientationUp:{
                            rotation_degress = 0;
                        }
                            break;
                        case kCGImagePropertyOrientationDown:{
                            rotation_degress = 180;
                            break;
                        }
                        case kCGImagePropertyOrientationLeft: {
                            //静音键那边向上 所需转90度
                            rotation_degress = 90;
                        }
                            break;
                        case kCGImagePropertyOrientationRight:{
                            //关机键那边向上 所需转270
                            rotation_degress = 270;
                        }
                            break;
                        default:
                            break;
                    }
                }
    #endif
                //NSLog(@"RPSampleBufferTypeVideo");
                if(_smart_publisher_sdk)
                {
                    //[_smart_publisher_sdk SmartPublisherPostVideoSampleBuffer:sampleBuffer];
                    [_smart_publisher_sdk SmartPublisherPostVideoSampleBufferV2:sampleBuffer rotateDegress:rotation_degress];
                }
                //NSLog(@"video ts:%.2f", CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)));
            }
            break;
        case RPSampleBufferTypeAudioApp:
            //NSLog(@"RPSampleBufferTypeAudioApp");
            if (CMSampleBufferDataIsReady(sampleBuffer) != NO)
            {
                if(_smart_publisher_sdk)
                {
                    NSInteger type = 2;
                    [_smart_publisher_sdk SmartPublisherPostAudioSampleBuffer:sampleBuffer inputType:type];
                }
            }
            //NSLog(@"App ts:%.2f", CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)));
            break;
        case RPSampleBufferTypeAudioMic:
            //NSLog(@"RPSampleBufferTypeAudioMic");
            if(_smart_publisher_sdk)
            {
                NSInteger type = 1;
                [_smart_publisher_sdk SmartPublisherPostAudioSampleBuffer:sampleBuffer inputType:type];
            }
            //NSLog(@"Mic ts:%.2f", CMTimeGetSeconds(CMSampleBufferGetPresentationTimeStamp(sampleBuffer)));
            break;
        default:
            break;
    }
}


相关文章
|
数据采集 编解码 监控
Android对接实现内网无纸化会议|智慧教室|实时同屏功能
本文主要讲的是基于Android平台实现RTMP的技术方案设计,基础架构图如下:
127 0
Android对接实现内网无纸化会议|智慧教室|实时同屏功能
深入解读:多人语音聊天室源码开发搭建社交分享功能
我们就实现了多人语音聊天室源码开发搭建的社交分享功能,社交分享功能对于多人语音聊天室源码平台是非常重要的,它可以方便地扩大交流范围、提升互动性、促进合作和协作,同时增强用户体验。
深入解读:多人语音聊天室源码开发搭建社交分享功能
|
编解码 开发工具 数据安全/隐私保护
内网无纸化会议/智慧教室实时同屏RTSP组播技术方案思考
内网环境下,为了满足内网无纸化/电子教室等内网超低延迟需求,避免让用户配置单独的服务器,好多开发者希望有RTSP的技术方案,用于小并发场景,特别是在组网环境好的有线环境下,使用RTSP服务配合组播,是也是好多开发者考量的因素之一。
192 2
|
Web App开发 网络协议 API
干货满满:多人语音聊天室源码开发解析
目前,一对一直播源码平台已经不能满足广大社交场景和人群了,而多人语音聊天室源码的开发属性,正好满足此需求,也让社交更加多样化、娱乐化,那么在技术上如何开发多人语音聊天室源码呢?
干货满满:多人语音聊天室源码开发解析
|
编解码 开发工具 Android开发
【技术分享】无纸化会议|智慧教室同屏走RTSP组播还是RTMP?
我们在做内网多人同屏(比如无纸化会议、智慧教室同屏)技术方案的时候,遇到个问题:到底使用轻量级RTSP服务实现组播,还是基于RTMP的解决方案?
249 0
《从此爱上开会 云投屏和视频会议系统提升会议体验和效率》电子版地址
从此爱上开会 云投屏和视频会议系统提升会议体验和效率
103 0
《从此爱上开会 云投屏和视频会议系统提升会议体验和效率》电子版地址
|
人工智能 大数据 5G
直播回顾 | 第三期直播课堂:5G消息如何助力智能售后(帜讯信息副总裁直播分享)
由中国移动5G消息开发者社区举办的第三期5G消息学院直播课堂圆满结束,本期课堂以“5G消息助力智能售后,打开企业服务新方式”为主题,特别邀请上海帜讯信息技术股份有限公司副总裁陈忻展开内容分享。
直播回顾 | 第三期直播课堂:5G消息如何助力智能售后(帜讯信息副总裁直播分享)
|
5G 数据安全/隐私保护 开发者
直播回顾|第12期5G消息云课堂,汽车服务的“升级密码” | 文末有回放
5G消息作为当今品牌服务提质增效的工具,在碰上汽车行业后,两者又将如何进行融合?实现汽车客户全生命周期价值管理?
直播回顾|第12期5G消息云课堂,汽车服务的“升级密码” | 文末有回放
网络直播授课简报
网络直播授课简报,遇到问题,及解决方案
161 0
今晚直播:全新审批流设计器使用详解
《你好,低代码》第十四期今天(7月29日)晚上7点准时直播。本期将为大家介绍钉钉宜搭全新的审批流设计器,记得准时收看哦~
662 0
今晚直播:全新审批流设计器使用详解

热门文章

最新文章