Video 场景方案

实时音视频通话

场景概览

游密Video SDK可以实现一对一、一对多、多对多的实时通话功能;在相同频道内的用户可自由发言和收看视频画面;适用于实时音视频通话、多人语音视频群聊等场景。

功能列表

主要功能 功能描述
登录房间 用户可以自由登录房间
自由语音视频互动 用户可以自由加入或退出语音视频互动

快速开始

开发环境要求

  • 两台机器,用于模拟两个用户进行语音通话。
  • 到官网注册账号、并添加应用产品以获得相关到AppKey、AppSecret参数。

SDK目录概述

语音SDK中有两个子文件夹:lib、include,下面依次介绍下这两个子文件夹。

  1. include:SDK的头文件。 详细介绍下inlude,所有接口都在这个文件夹中。
    • IYouMeVoiceEngine.h封装了语音SDK的全部功能接口,集成方可通过IYouMeVoiceEngine::getInstance ()->…来调用语音SDK接口。
    • IYouMeEventCallback.h包含语音SDK的所有回调事件接口,例如初始化结果,频道加入成功等,都将通过此接口通知集成方。
    • YouMeConstDefine.h包含语音SDK的所有枚举类型定义,如错误码等。
  2. lib:库文件,分为Android平台和iOS平台。Android平台下包括ARMv5、ARM-v7a、 ARM64-v8a和X86四种CPU架构下的libyoume_voice_engine.so文件,还包括youme_voice_engine.jar。iOS平台下包含libyoume_voice_engine.a,libffmpeg3.3.a, libYouMeCommon.a文件。
  3. LuaYTalk.h, LuaYTalk.cpp,Lua语言的封装文件。
  • lua相关SDK 此SDK是在引擎SDK基础上封装的为cocos-lua使用的SDK,包括一部分c++文件和lua文件。
    1. Classes:对应cocos-lua里的frameworks\runtime-src\Classes目录,包括一些封装过的c++文件以及c++转lua的文件。
    2. src:对应cocos-lua里的src目录,里面的YoumeSDK.lua就是提供给游戏使用的lua文件。

开发环境集成

  • 引擎SDK集成 Cocos2d-lua开发环境生成的目录结构如下图所示,将SDK目录更名为youme_voice_engine(内含“include”和“lib”两个子文件夹),并复制到游戏的根目录下,这个目录下包含了Android和iOS两个平台所需的所有C++头文件和库文件。

  • lua SDK集成 把lua相关sdk的Classes目录放入cocos-lua项目的frameworks\runtime-src\Classes目录,将src目录放入cocos-lua项目的src目录,并加入项目。

  • lua注册 修改cocos-lua原有项目中的frameworks\runtime-src\Classes\AppDelegate.cpp文件:
    1. 增加:#include "lb/lb_youmetalk.hpp"
    2. AppDelegate::applicationDidFinishLaunching()方法内加上: register_all_youmetalk(stack->getLuaState();
Android系统开发环境配置
  1. 修改proj.android/jni/Android.mk文件,对应位置增加指定内容,分别对游密实时语音SDK的动态库进行预编译处理、添加头文件路径、链接动态库。
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    $(call import-add-path,$(LOCAL_PATH)/../../cocos2d)
    $(call import-add-path,$(LOCAL_PATH)/../../cocos2d/external)
    $(call import-add-path,$(LOCAL_PATH)/../../cocos2d/cocos)

    #======Youme 添加=========
    LOCAL_MODULE := youme_voice_engine
    LOCAL_SRC_FILES := ../$(LOCAL_PATH)/../../../../youme_voice_engine/lib/android/$(TARGET_ARCH_ABI)/libyoume_voice_engine.so
    include $(PREBUILT_SHARED_LIBRARY)
    #======结束 Youme 添加=======

    LOCAL_MODULE := cocos2dcpp_shared
    LOCAL_MODULE_FILENAME := libcocos2dcpp
    LOCAL_SRC_FILES := hellocpp/main.cpp \
                       ../../Classes/Helloworld.cpp \
    #========Youme修改,不要拷贝这一行=========
                       ../../Classes/LuaYTalk.cpp
    #======结束 Youme 修改=======

    #========Youme修改=========
    LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../Classes \
                        $(LOCAL_PATH)/../../../../youme_voice_engine/include
    #======结束 Youme 修改=======

    # _COCOS_HEADER_ANDROID_BEGIN
    # _COCOS_HEADER_ANDROID_END
    LOCAL_STATIC_LIBRARIES := cocos2dx_static

    #======Youme 添加=========
    LOCAL_SHARED_LIBRARIES := youme_voice_engine
    #======结束 Youme 添加=======

    # _COCOS_LIB_ANDROID_BEGIN
    # _COCOS_LIB_ANDROID_END
    include $(BUILD_SHARED_LIBRARY)
    $(call import-module,.)
    # _COCOS_LIB_IMPORT_ANDROID_BEGIN
    # _COCOS_LIB_IMPORT_ANDROID_END
  1. 如果需要显示指定CPU架构则修改proj.android/jni/Application.mk文件,增加指定部分的内容(v5版本为APP_ABI := armeabi);如果不需要指定CPU架构Application.mk文件, 则不用修改。
  #======修改===========
  APP_ABI := armeabi-v7a
  #======结束修改=========

  APP_STL := gnustl_static
  APP_CPPFLAGS := -frtti -DCC_ENABLE_CHIPMUNK_INTEGRATION=1 -std=c++11 -fsigned-char
  APP_LDFLAGS := -latomic
  ifeq ($(NDK_DEBUG),1)
   APP_CPPFLAGS += -DCOCOS2D_DEBUG=1
   APP_OPTIM := debug
  else
   APP_CPPFLAGS += -DNDEBUG
   APP_OPTIM := release
  endif
  1. 复制youme_voice_engine/lib/android/youme_voice_engine.jar到proj.android/libs/ youme_voice_engine.jar。

  2. 修改proj.android/AndroidManifest.xml文件,确保声明了如下的权限:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
  3. 打开eclipse,导入上一步Android工程,在项目的第一个启动的AppActivity(找到AppActivity.java文件)中导入package:
import  com.youme.voiceengine.mgr.YouMeManager;
import  com.youme.voiceengine.*;

然后在onCreate方法里添加如下代码(没有此方法的话需要自己补上):

 @Override
    public void onCreate(Bundle savedInstanceState)
    {
        //以下两个函数调用顺序不能错
        YouMeManager.Init(this);
        super.onCreate(savedInstanceState);

    }
iOS系统XCode开发环境配置

添加头文件和依赖库:

  1. 添加头文件路径:在Build Settings -> Search Paths -> Header Search Paths中添加: ../../../youme_voice_engine/include (建议直接将此include文件夹拖到xcode需要填入的位置,然后路径会自动生成)。
  2. 添加库文件路径:在Build Settings -> Search Paths -> Library Search Paths中添加../../../youme_voice_engine/lib/ios/Release-universal (建议直接将此Release-universal文件夹拖到xcode需要填入的位置,然后路径会自动生成)。
  3. 添加依赖库:在Build Phases -> Link Binary With Libraries下添加:
    libsqlite3.0.tbd
    libyoume_voice_engine.a
    libz.dylib
    libz.1.2.5.tbd
    libresolv.9.tbd
    SystemConfiguration.framework
    CoreTelephony.framework
    AVFoundation.framework
    AudioToolBox.framework
    CFNetwork.framework

相关接口

init 引擎初始化。
setCaptureProperty 设置本地采集分辨率及帧率。
setVideoNetResolution 设置网络传输分辨率。
joinChannelSingleMode 加入房间。
bindTexture 创建渲染。
startCapture 开始摄像头采集。
setMicrophoneMute 设置麦克风状态。
setSpeakerMute 设置扬声器状态。

关键调用顺序

  1. 初始化(init)设置本地采集及网络传输分辨率(也可采用默认设置)。

  2. 加入房间(joinChannelSingleMode)。打开摄像头(startCapture),麦克风扬声器等设备(setMicrophoneMute,setSpeakerMute)。

  3. 接收到视频数据回调后,创建渲染(bindTexture)。

服务器录制(服务器接口RESTAPI)

场景概览

游密支持服务器录制,将语音视频通话或共享画面进行实时录制保存,提供给更多的人在方便的时间观看或回溯。

开启服务端录制

设置开启服务端录制某频道某用户的视频流或者屏幕共享流,当客户端用户加入频道开启屏幕共享成功后,调用set_media_recod_param接口,设置某频道视频录或共享流录制。

  • 请求URL
    https://api.youme.im/v2/im/set_media_recod_param?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • header

    Content-Type: application/json
  • body
    {
    "RoomID":"123456",
    "UserId":"youme_01",
    "Mode":1,
    "VoiceType":2
    }

RoomID: 游戏频道ID,字符串,必选字段。
UserId: 用户ID,字符串,可选字段(录制共享流情况下不需要传userid)。
Mode: 模式,整型,0:默认模式(相当于恢复录制),1:长时间录制模式,可选字段,UserId必须为空,长时间录制模式表示第一次开启录制。
VoiceType: 声音合流模式,整型,0:默认模式(声音与视频流合流),2:共享流模式(声音与共享流合流),可选字段。

  • 响应
    {
    "ActionStatus" : "OK",
    "ErrorCode" : 0,
    "ErrorInfo" : ""
    }

注:
appkey:在游密通信云官网注册账号时默认生成的的appkey。
curtime:当前UTC时间戳,从1970年1月1日0点0分0秒开始到现在的秒数(string类型)。
checksum:sha1(appsecret + restapikey+curtime),三个参数拼接的字符串,进行sha1计算,转化成16进制字符(string,小写), 其中restapikey和appsecret可在游密后台进行查看。

关闭服务端录制

设置关闭服务端录制某频道某用户的视频流或者屏幕共享流,当客户端用户关闭屏幕共享之前,调用del_media_recod_param接口,设置某频道视频录或共享流录制。

  • 请求URL
    https://api.youme.im/v2/im/del_media_recod_param?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • header

    Content-Type: application/json
  • body
    {
    "RoomID":"123456",
    "UserId": "youme_01",
    "Mode": 1
    }

RoomID: 游戏频道ID,字符串,必选字段。
UserId: 用户ID,字符串,可选字段(录制共享流情况下不需要传userid)。
Mode: 模式,整型,0:默认模式(相当于恢复录制),1:长时间录制模式,可选字段,UserId必须为空,长时间录制模式表示第一次开启录制。

  • 响应
    {
    "ActionStatus" : "OK",
    "ErrorCode" : 0,
    "ErrorInfo" : ""
    }

获取房间录制信息

录制结束后可以获取房间录制信息,并获取录制的id号,用于查看单个录制流的详细信息,可调用get_media_recod_infos接口。

  • 请求URL
    https://api.youme.im/v2/im/get_media_recod_infos?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • header

    Content-Type: application/json
  • body
    {
    "RoomIDs":["123456", "123457"]
    }

RoomIDs: 多个频道ID,字符串数组,必选字段。

  • 响应
    {
    "ActionStatus" : "OK",
    "ErrorCode" : 0,
    "ErrorInfo" : "",
    "MediaRecord" : [
      {
         "AppID" : 214,
         "BackgroundRecordStatus" : 2,
         "EndTime" : 1599642533,
         "RecordID" : 13,
         "RecordStatus" : 4,
         "RoomID" : "1234596",
         "StartTime" : 1599642514
      },
      {
         "AppID" : 214,
         "BackgroundRecordStatus" : 2,
         "EndTime" : 1599641917,
         "RecordID" : 9,
         "RecordStatus" : 2,
         "RoomID" : "1234596",
         "StartTime" : 1599641905
      }
    ]
    }

    响应是否获取成功:
    "RecordID": 会议录制的id号。
    "AppID": 会议录制的app id。
    "RoomID": 会议录制的房间id。
    "RecordStatus": 会议录制的状态,1:录制中 2:录制结束 3:无效录制 4:录制发布。
    "BackgroundRecordStatus": 服务器会议录制的状态,1:录制中 2:录制结束。
    "StartTime": 会议录制开始时间。
    "EndTime": 会议录制结束时间。

获取录制的详细信息(视频文件)

获取到"RecordID"即会议录制的id号后,可用于查看单个录制流的详细信息。调用get_media_recod_info接口,获取到视频文件。

  • 请求URL
    https://api.youme.im/v2/im/get_media_recod_info?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • header

    Content-Type: application/json
  • body
    {
    "RecordID": 9
    }

RoomID: 游戏频道ID,字符串,必选字段。
UserID: 游戏用户ID,字符串,必选字段。
DstUrl: 单路rtmp流目的url,字符串,必选字段。

  • 响应
    {
    "ActionStatus" : "OK",
    "AppID" : 214,
    "BackgroundRecordStatus" : 2,
    "EndTime" : 1599641917,
    "ErrorCode" : 0,
    "ErrorInfo" : "",
    "MediaFiles" : [
      {
         "EndTime" : 1599641915,
         "FileDownloadUrl" : "http://test3download.youme.im/media_file/214_1234596_an947112_1599641805_1599641915_0.mp4",
         "Format" : "mp4",
         "StartTime" : 1599641805,
         "StreamID" : 0,
         "UserID" : "an947112"
      },
      {
         "EndTime" : 1599641915,
         "FileDownloadUrl" : "http://test3download.youme.im/media_file/214_1234596_an198617_1599641805_1599641915_0.mp4",
         "Format" : "mp4",
         "StartTime" : 1599641805,
         "StreamID" : 0,
         "UserID" : "an198617"
      }
    ],
    "RecordID" : 9,
    "RecordStatus" : 2,
    "RoomID" : "1234596",
    "StartTime" : 1599641905,
    "SubtitleFiles" : [
      {
         "EndTime" : 1599641915,
         "FileDownloadUrl" : "http://test3download.youme.im/subtitle_file/1599641805.srt",
         "Format" : "srt",
         "StartTime" : 1599641805,
         "UserIdMapDownloadUrl" : "http://test3download.youme.im/subtitle_file/1599641805.json"
      }
    ]
    }

    响应是否获取成功:
    "RecordID": 会议录制的id号。
    "AppID": 会议录制的app id。
    "RoomID": 会议录制的房间id。
    "RecordStatus": 会议录制的状态,1:录制中 2:录制结束 3:无效录制 4:录制发布。
    "BackgroundRecordStatus": 服务器会议录制的状态,1:录制中 2:录制结束。
    "StartTime": 会议录制开始时间。
    "EndTime": 会议录制结束时间。
    "MediaFiles": 会议录制相关的媒体文件,如mp4。
    "MediaFiles[].UserID": 媒体文件关联的user id。
    "MediaFiles[].Format": 媒体文件关联的文件格式, mp4。
    "MediaFiles[].StreamID": 媒体文件关联的流id, 0:默认 2:共享。
    "MediaFiles[].FileDownloadUrl": 媒体文件关联的文件下载路径。
    "MediaFiles[].StartTime": 媒体文件开始时间。
    "MediaFiles[].StartTime": 媒体文件结束时间。
    "SubtitleFiles": 会议录制相关的字幕文件,如srt。
    "SubtitleFiles[].Format": 字幕文件格式,srt。
    "SubtitleFiles[].FileDownloadUrl": 字幕文件下载路径。
    "SubtitleFiles[].UserIdMapDownloadUrl": 字幕文件userid映射文件下载路径,json格式。
    "SubtitleFiles[].StartTime": 字幕文件开始时间。
    "SubtitleFiles[].EndTime": 字幕文件结束时间。

旁路直播(服务器接口RESTAPI)

场景概览

游密支持CDN旁路直播,实现将音视频流推送至第三方CDN平台,从而观众可以方便快捷地通过接入H5观看CDN直播。

开启单路rtmp服务端推流

开启音视频通讯特定频道特定人员的服务端RTMP旁路推流功能,建议主播在客户端加入直播频道成功后,调用set_single_rtmp_param接口,设置某频道的某用户单路RTMP推流。

  • 请求URL
    https://api.youme.im/v2/im/set_single_rtmp_param?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • header

    Content-Type: application/json
  • body
    {
    "RoomID":"123456",
    "UserID":"ym_jason",
    "DstUrl":"rtmp://10.10.102.205:1935/hls/111"
    }

RoomID: 游戏频道ID,字符串,必选字段。
UserID: 游戏用户ID,字符串,必选字段。
DstUrl: 单路rtmp流目的url,字符串,必选字段。

  • 响应
    {
    "ActionStatus" : "OK",
    "ErrorCode" : 0,
    "ErrorInfo" : ""
    }

注:
appkey:在游密通信云官网注册账号时默认生成的的appkey。
curtime:当前UTC时间戳,从1970年1月1日0点0分0秒开始到现在的秒数(string类型)。
checksum:sha1(appsecret + restapikey+curtime),三个参数拼接的字符串,进行sha1计算,转化成16进制字符(string,小写), 其中restapikey和appsecret可在游密后台进行查看。

停止单路rtmp服务端推流

当直播结束时,可以调用del_single_rtmp_param接口,关闭某频道的某用户单路RTMP推流。

  • header

    Content-Type: application/json
  • 请求URL

    https://api.youme.im/v2/im/del_single_rtmp_param?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • body
    {
    "RoomID":"123456",
    "UserID":"ym_jason"
    }

RoomID: 游戏频道ID,字符串,必选字段。
UserID: 游戏用户ID,字符串,必选字段。

  • 响应
    {
    "ActionStatus" : "OK",
    "ErrorCode" : 0,
    "ErrorInfo" : ""
    }

开启rtmp服务端合流推流

  • 请求URL

    https://api.youme.im/v2/im/set_room_mix_rtmp_param?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • body

    {
    "RoomID":"123456",
    "PrimaryUserID":"ym_jason",
    "DstUrl":"rtmp://10.10.102.205:1935/hls/111",
    "VideoWidth":240,
    "VideoHeight":320
    }

    body为json格式,各个字段解释如下:
    RoomID: 游戏频道ID,字符串,必选字段。
    PrimaryUserID: 合流主用户ID,字符串,必选字段。
    DstUrl: 单路rtmp流目的url,字符串,必选字段。
    VideoWidth: 视频背景宽度,整数,可选字段, 默认240。
    VideoHeight: 视频背景高度,整数,可选字段, 默认320。

  • 响应 响应指示设置是否成功。
    {
    "ActionStatus" : "OK",
    "ErrorCode" : 0,
    "ErrorInfo" : ""
    }

添加rtmp服务端合流单个用户参数

添加某游戏某频道某用户rtmp合流推流参数。

  • 请求URL

    https://api.youme.im/v2/im/add_room_mix_user?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • body

    {
    "RoomID":"123456",
    "UserID":"ym_jason",
    "VideoWidth":240,
    "VideoHeight":320,
    "X":0,
    "Y":0,
    "Z": 0
    }

    body为json格式,各个字段解释如下:
    RoomID: 游戏频道ID,字符串,必选字段。
    UserID: 用户ID,字符串,必选字段。
    X: 视频显示X坐标,整数,必选字段。
    Y: 视频显示Y坐标,整数,必选字段。
    Z: 视频显示层次,整数,必选字段。
    VideoWidth: 视频显示宽度,整数,必选字段。
    VideoHeight: 视频显示高度,整数,必选字段。

  • 响应 响应指示设置是否成功。
    {
    "ActionStatus" : "OK",
    "ErrorCode" : 0,
    "ErrorInfo" : ""
    }

删除rtmp服务端合流单个用户参数

删除某游戏某频道某用户rtmp合流推流参数,若请求删除主用户合流参数,则整个频道合流参数被删除。

  • 请求URL

    https://api.youme.im/v2/im/del_room_mix_user?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • body

    {
    "RoomID":"123456",
    "UserID":"ym_jason",
    }

    RoomID: 游戏频道ID,字符串,必选字段。
    UserID: 用户ID,字符串,必选字段。

  • 响应 响应指示设置是否成功。
    {
    "ActionStatus" : "OK",
    "ErrorCode" : 0,
    "ErrorInfo" : ""
    }

停止rtmp服务端合流推流

  • 请求URL

    https://api.youme.im/v2/im/del_room_mix_rtmp_param?appkey=123456789&identifier=admin&curtime=123456789&checksum=123456789abcdefg
  • body

    {
    "RoomID":"123456",
    }

    RoomID: 游戏频道ID,字符串,必选字段。

  • 响应 响应指示设置是否成功。
    {
    "ActionStatus" : "OK",
    "ErrorCode" : 0,
    "ErrorInfo" : ""
    }