您尚未登录

登录

您尚未登录

登录

推荐您使用PC浏览器访问

确定
  • 开发者中心
  • >
  • 云游戏
  • >
  • SDK开发指南
  • >
  • 云游戏基础SDK
  • >
  • TV
  • >
  • v5.24

文档版本号:20220823-105

对应SDK版本号:master-5.24

变更历史:

SDK版本号 日期 更新内容
master-5.23 2022/8/23 1、修改发送消息接口消息回调 新增虚拟手柄类型消息(需配合“海马云虚拟手柄小程序SDK” 使用)
master-5.15 2022/5/7 1、修改发送消息接口函数为有返回boolean值函数,表示当前长链接是否连接成功
master-5.12 2022/3/23 1、新增视频帧卡顿通知接口
2、修改IDC节点测速接口获取清晰度列表接口获取游戏存档状态接口查询是否存在游戏存档接口检测未释放游戏接口根据cid释放实例接口 增加带游戏BID参数方法
master-5.5.2 2021/11/1 1、支持RTC流类型,见申请服务
2、设置可存档最小游戏时间并退出游戏,见设置可存档最小游戏时间并退出游戏接口
3、游戏启动参数携带执行脚本,见游戏启动参数携带执行脚本接口
4、将数据写入云端的文本框,见将数据写入到云端的文本框接口
5、与云游戏传输数据,见与云游戏传输数据接口

1 产品简介

海马云游戏Android TV SDK是一款助力快速部署云游戏产品的软件开发工具包。 您可以通过调用海马云游戏Android TV SDK接口,实现云游戏的播放、停止、状态回调等各类控制操作和数据交互,在海马云游戏端到端全栈云服务能力基础上,为用户带来顺畅的云游戏体验。以下简称SDK。

2 工程配置

这里向您介绍适用于Android TV开发的工程配置。

2.1 集成SDK

在Module的build.gradle文件中,添加依赖属性:

repositories {
    flatDir {
        dirs 'libs'
    }
}

dependencies {
    implementation 'com.alibaba:fastjson:1.2.0'
    implementation('io.socket:socket.io-client:1.0.0') {
        exclude group: 'org.json', module: 'json'
    }
    implementation (name: 'saas-sdk-latest.release', ext: 'aar')
}

注意

  • SDK目前只支持通过gradle集成方式。

  • saas-sdk-latest.release是海马的SDK,其他为海马SDK的依赖包,saas-sdk-latest.release根据实际提供的aar文件进行修改(.aar文件的部分)。

  • 如果无法正常集成,请在Project的build.gradle文件中配置repositories,添加 jcenter:

    allprojects {
        repositories {
            jcenter()
        }
    }

2.2 基础配置

在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.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

为避免混淆海马SDK,在Proguard混淆文件中增加以下配置:

-keep interface com.haima.hmcp.listeners.*{*;}
-keep class com.haima.hmcp.beans.*{*;}
-keep enum com.haima.hmcp.enums.*{*;}
-keep class com.haima.hmcp.**{*;}
-keep enum com.haima.hmcp.websocket.WebSocketCloseNotification{*;}
-keep interface com.haima.hmcp.websocket.WebSocket{*;}
-keep interface com.haima.hmcp.websocket.WebSocketConnectionObserver{*;}
-keep class com.haima.hmcp.websocket.WebSocketConnection{public <methods>;}
-keep class com.haima.hmcp.websocket.WebSocketOptions{public <methods>;}
-keep class com.haima.hmcp.websocket.WebSocketException{*;}
-keep class tv.haima.ijk.media.player.** { *; }
-keep interface tv.haima.ijk.media.player.listeners.*{*;}
-keep interface tv.haima.ijk.media.player.IMediaPlayer{*;}
-keep class com.netease.LDNetDiagnoService.LDNetDiagnoService{public <methods>;}
-keep interface com.netease.LDNetDiagnoService.LDNetDiagnoListener{public <methods>;}
-keep class com.netease.LDNetDiagnoService.LDNetTraceRoute { *; }
-keep class org.hmwebrtc.**{*;}
-keep class org.webrtc.haima.**{*;}
-keep class io.socket.**{*;}
-keep class com.haima.hmcp.rtc.widgets.RtcTextureViewRenderer{*;}

2.3 配置硬件加速

打开硬件加速可以提高渲染能力,提高用户体验。

<application ……
android:hardwareAccelerated="true">

2.4 添加组件

在布局文件中添加 HmcpVideoView 组件:

<com.haima.hmcp.widgets.HmcpVideoView
    android:id="@+id/gameView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"/>

HmcpVideoView 组件所在 Acitvity 需要设置以下属性:

<activity
    android:name=".xxxActivity"
    android:configChanges="orientation|screenSize"
    android:launchMode="singleTask"
    android:screenOrientation="landscape" />

2.5 外接键鼠手柄操作

如果支持外接键鼠手柄操作,需进行如下操作:

public boolean onKeyDown(int keyCode, KeyEvent event)  {
       return true;
}
public boolean onKeyUp(final int keyCode, KeyEvent event) {
       return true;
}

3 快速开始

这里向您介绍适用于Android-TV开发的快速接入文档。

表3-1 重要接口说明

重要接口 接口含义 建议调用时机
init() 初始化 SDK Application 的 onCreate()
setUserInfo() 设置用户登录信息 init() 成功回调后
generateCToken() 计算 cToken 的值 play(bundle) 调用前
play(bundle) 与海马云 Server 建立通讯、申请服务,成功后则可以开启游戏 play()方法调用前
play() 开启游戏 HmcpPlayerStatusCallback回调方法,返回JSON字符串中,status为1时

🔘说明:

  • SDK使用前请对工程进行配置,否则SDK不生效。

  • SDK的接口调用要在同一个线程下。

  • SDK回调信息请参见消息回调接口

3.1 初始化SDK

按照工程配置,已在AndroidManifest.xml文件中配置渠道信息HMCP_ACCESS_KEY_ID和HMCP_CHANNEL_ID,接入方需调用init方法初始化SDK,否则需通过Bundle对ACCESS_KEY_ID与CHANNEL_ID进行赋值。

初始化方法建议在自定义Application类中进行,如果成功回调success()方法,则初始化成功。

请求接口报错时返回的错误信息默认是普通字符串格式,若需要返回JSON格式,需要isJson参数传入true。

注意

isJson影响的接口除了init之外还有:更新uid和游戏时长接口获取游戏存档状态接口查询是否存在游戏存档接口检测未释放游戏接口根据cid释放实例接口开始直播接口停止直播接口获取授权码接口

函数原型:

public class HmcpManager {
        public void init(Context context, OnInitCallBackListener callBack)
        public void init(Bundle bundle, Context context, OnInitCallBackListener callBack)
        public void init(Bundle bundle, Context context, OnInitCallBackListener callBack,boolean isJson)
}

表3-2 bundle参数说明

参数 类型 必填项 说明
bundle Bundle 使用携带bundle的参数初始化SDK ,渠道信息将使用bundle中携带信息
context Context 应用程序上下文对象
callBack OnInitCallBackListener 初始化方法接口回调监听器

表3-3 key说明

key value 类型 必填项 说明
HmcpManager.ACCESS_KEY_ID String 接入方的唯一ID,用来区分不同的接入方,该值由海马云分配
HmcpManager.CHANNEL_ID String 渠道号,由接入方配置。如果应用本身不区分渠道,可以设置为一个随机的字符串;参数由接入方自己定义,请注意不要跟appChannel混淆

示例代码:

HmcpManager manager = HmcpManager.getInstance();
// bundle.putString(HmcpManager.ACCESS_KEY_ID, mBid); 
// 设置ACCESS_KEY_ID
// bundle.putString(HmcpManager.CHANNEL_ID, mChannelID);
// 设置CHANNEL_ID
// 带bundle参数请调用该方法
manager.init(this, new OnInitCallBackListener() {
    @Override
    public void success() {
        // 初始化SDK成功,可以云游戏
    }
    @Override
    public void fail(String s) {
        // 初始化SDK失败,不能云游戏
    }
});
//需要错误信息为JSON格式
manager.init(bundle,this, new OnInitCallBackListener() {
    @Override
    public void success() {
        // 初始化SDK成功,可以云游戏
    }
    @Override
    public void fail(String s) {
        // 初始化SDK失败,不能云游戏
        //{"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}
    }
},true);

3.2 Activity中初始化组件

以下是 Activity 中的示例代码:

public class HmcpPlayerActivity extends AppCompatActivity implements HmcpPlayerListener {
    private HmcpVideoView hmcpVideoView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 获取 HmcpVideoView 组件
        hmcpVideoView = (HmcpVideoView) this.findViewById(R.id.gameView);
    }
    // Activity需要implements HmcpPlayerListener接口
    @Override
    public void onError(ErrorType errorType, String s) {
        // 出错信息回调
    }
    @Override
    public void onSuccess() {
        // SDK启动成功并且开始播流的回调
    }
    @Override
    public void onMessage(Message message) {
        // 收到退出登录消息回调
    }
    @Override
    public void onPlayStatus(int status, long value, String data) {
        // 帧率fps,带宽Bps上报。
    }
    @Override
    public void onExitQueue() {
        // 游戏内部弹窗退出消失回调
        this.finish();
    }
    @Override
    protected void onStart() {
        hmcpVideoView.onStart();
        super.onStart();
    }
    @Override
    protected void onRestart() {
        hmcpVideoView.onRestart(int time);
        super.onRestart();
    }
    @Override
    protected void onResume() {
        hmcpVideoView.onResume();
        super.onResume();
    }
    @Override
    protected void onPause() {
       hmcpVideoView.onPause();
        super.onPause();
    }
    @Override
    protected void onStop() {
       hmcpVideoView.onStop();
        super.onStop();
    }
    @Override
    protected void onDestroy() {
        if (hmcpVideoView != null) {
            hmcpVideoView.onDestroy();
        }
        super.onDestroy();
    }
    @Override
    public void onPlayerError(String errorCode, String errorMsg) {
        //SDK上报错误信息回调接口
    }
    @Override
    public void HmcpPlayerStatusCallback(String callback) {
        //SDK使用状态回调接口
    }
    @Override
    public void onSceneChanged(String sceneMessage) {
        //SDK游戏过程中各状态发生变化时通知应用消息接口
    }
    @Override
    public void onNetworkChanged(NetWorkState netWorkState) {
        //网络变化后通知应用的接口
    }
    @Override
    public void onPermissionNotGranted(String permission) {
        //SDK没有敏感权限时回调(比如游戏途中需要语音连麦)
        //在申请到连麦权限时需要调用hmcpVideoView.startRecord重新拉起录音
    }
    @Override
    public void onCloudDeviceStatus(String status) {
        //云游戏中分享、打开摄像头、打开系统相册、游戏内截图
    }

    @Override
    public void onInterceptIntent(String intentData) {
       //intent拦截回调
    }
}

其中:

  • Activity的onResume()、onPause()、onDestroy()必须重写,并在重写的方法中调用HmcpVideoView的相应方法,可以参考上面的示例代码。

  • Activity需要实现(implement)HmcpPlayerListener接口。

  • onPlayerError(String errorCode,String errorMsg)是SDK上报播流错误信息回调接口,errorMsg是错误信息,errorCode是错误码。

  • HmcpPlayerStatusCallback(String callback)是SDK运行状态回调接口,参数callback为回调信息。详情请参见SDK状态回调

  • onSceneChanged(String sceneMessage)是SDK游戏过程中各状态发生变化时通知应用的接口,参数sceneMessage是包括sceneId和extraInfo{}两个字段的JSON串。详情请参见场景切换回调

  • onNetworkChanged(NetWorkState state)是SDK在监听到网络变化后通知应用的接口,参数NetWorkState为枚举类型,现在包括ISWIFI、NOTWIFI、NO_NETWORK三种网络状态。

  • onInputDevice(int device, int operationType)是SDK在监听到输入设备变化时通知应用的接口。

    表3-4 device类型

    类型 类型描述
    INPUT_DEVICE_NONE 未检测到输入设备
    INPUT_DEVICE_REMOTE_CONTROL 遥控器输入
    INPUT_DEVICE_KEY_MOUSE 键盘鼠标输入
    INPUT_DEVICE_GAMEPAD 实体手柄输入
    INPUT_DEVICE_VIRTUAL_GAMEPAD 虚拟手柄输入

    表3-5 operationType类型

    类型 类型描述
    INPUT_DEVICE_OPERATION_TYPE_VIRTUAL_BUTTON 虚拟按键
    INPUT_DEVICE_OPERATION_TYPE_BUTTON 实体按键
    INPUT_DEVICE_OPERATION_TYPE_VIRTUAL_TOUCH 虚拟触摸
  • onPermissionNotGranted(String permission)是SDK在没有相关敏感权限时的回调接口,需要APP申请对应权限。

  • onCloudDeviceStatus(String status)是云游戏中远端实例状态发生改变的回调接口,包括云游戏中分享、打开摄像头、打开系统相册、游戏内截图,详情请参见关键接口回调

  • onInterceptIntent(String intentData)是云游戏内实现免登等需求时进行Intent拦截的回调接口。详情请参见关键接口回调

3.3 设置用户登录信息

用户登录信息包括userId和userToken。

  • userId作为游戏客户端用户的唯一识别码,原则上为APP端的用户登录账号,在开始游戏前需设置用户登录信息,或随机生成长度在64以内的字符串,每台客户端上的账号需保证唯一性。
  • userToken用来校验userId的有效性,如果userId为随机生成,userToken也可以随机生成。
  • HmcpVideoView的setUserInfo()方法用来设置用户的登录信息。

函数原型:

public class HmcpVideoView {
        public void setUserInfo(UserInfo userInfo)
}

表3-6 用户登录信息参数说明

参数 类型 必填项 说明
userInfo UserInfo 用户登录信息(包含userID、usertoken等信息)

示例代码:

mUserInfo = new UserInfo();
mUserInfo.userId = USER_ID;
mUserInfo.userToken = USER_TOKEN;
mUserInfo.userType = 0;
hmcpVideoView.setUserInfo(mUserInfo);

注意

如果两台客户端上的userId相同,将会导致游戏异常现象。userType代表用户类型,可以不传,默认其值为0。0代表示表普通用户,5表示超级账号,超级账号需要海马云后台配合生效。

3.4 申请服务

调用HmcpVideoView的play(bundle)函数,SDK会与海马云的server通讯,申请服务成功后即可开始游戏。

函数原型:

public class HmcpVideoView {
        public void play(Bundle bundle)
}

表3-7 申请服务参数说明

参数 类型 必填项 说明
bundle Bundle 需调用对应put***()方法,将下表所有参数赋值并打包到bundle中

表3-8 bundle key说明

key value类型 必填项 说明
HmcpVideoView.ORIENTATION ScreenOrientation 标识游戏是竖屏还是横屏显示。
竖屏: ScreenOrientation.PORTRAIT
横屏: ScreenOrientation.LANDSCAPE
HmcpVideoView.PLAY_TIME int ms
HmcpVideoView.PRIORITY int 用户申请游戏服务的优先级,默认为0。数值越大优先级越高
HmcpVideoView.APP_NAME String 游戏包名,传入对应的要启动的游戏包名
HmcpVideoView.APP_CHANNEL String 如果存在多款游戏同包名的情况,可以通过appChannel区分。此参数由海马云配置。需要注意不要与channelId(接入方自己定义,与海马云无关)混淆
HmcpVideoView.C_TOKEN String 用来校验参数的有效性,cToken的计算方法请参考cToken说明文档
HmcpVideoView.EXTRA_ID String 预留参数,默认为空字符串
HmcpVideoView.PAY_STR String 支付相关参数,默认为空字符串
HmcpVideoView.ARCHIVED boolean 游戏是否存档
HmcpVideoView.PAY_PROTO_DATA String APP业务系统关心的参数,需要base64编码
HmcpVideoView.FPS_PERIOD int 采集fps周期及上报周期,单位为s
HmcpVideoView.BAND_WIDTH_PERIOD int 采集带宽的周期及上报周期,单位为s
HmcpVideoView.BAND_WIDTH_PEAK int 采集带宽周期内的最大的几个值
HmcpVideoView.DECODE_TIME_PERIOD int 采集解码时间的周期及上报周期,单位为秒s
HmcpVideoView.INTERNET_SPEED int 设置该参数可以固定的码率开始游戏,单位为KB/s
HmcpVideoView.IS_SHOW_TIME boolean 是否显示剩余游戏时间
HmcpVideoView.CLIENT_ISP String 运营商名称
HmcpVideoView.CLIENT_PROVINCE String 当前定位省份
HmcpVideoView.CLIENT_CITY String 当前定位城市
HmcpVideoView.C_ID String 第一次游玩不需要传cid,若要重连未释放游戏,则需要查询未释放游戏信息(检测未释放游戏接口中的channelInfoList)中对应cid、包名、渠道,使用该参数申请重连
HmcpVideoView.NO_INPUT_LIMIT_TIME int 无操作超时时长,单位为s
HmcpVideoView.ALLOW_COMPATIBLE_IPV6 boolean 是否支持IPV6功能,同时需海马云在后台配置
HmcpVideoView.VERTICAL_BACKGROUND int 播放器背景图,主要针对竖屏游戏黑色边框的优化
HmcpVideoView.VIEW_RESOLUTION_WIDTH int 自定义游戏推流清晰度宽度,宽度、高度可调换位置,不影响显示效果
HmcpVideoView.VIEW_RESOLUTION_HEIGHT int 自定义游戏推流清晰度高度,宽度、高度可调换位置,不影响显示效果
HmcpVideoView.AUDIO_RECORD_SOURCE Source 设置录音功能,录音数据由APP侧提供。
如果由SDK侧录音,不需要设置此参数
HmcpVideoView.STREAM_TYPE int 选择流类型。
0:表示RTMP
1:表示WEBRTC
不填写此参数时,默认为RTMP流类型
HmcpVideoView.ARCHIVE_FROM_USER_ID String 被读取的存档用户的userId
HmcpVideoView.ARCHIVE_FROM_BID String 被读取的存档用户的bid

示例代码:

boolean isPortraitOrientation = false;             
// 是否竖屏
ScreenOrientation orientation = isPortraitOrientation ? ScreenOrientation.PORTRAIT : ScreenOrientation.LANDSCAPE;

int playTime = 6000 * 1000;
int priority = 100;

String packageNameGame = "com.yodo1tier1.skizgfTV.cmcc";
String appChannel = "";
String cToken = CryptoUtils.generateCToken(packageNameGame, userId, userToken, accessKeyID, channelID, accessKey);
String extraId = "";
String payStr = "";
boolean archive = true;
String protoData = "protoData"; 
int fpsPeriod = 1;
int bandWidthPeriod = 5; 
int bandWidthPeak = 3; 
int decodeTimePeriod = 1;
int speed = 1024;
boolean isShowTime = true; 
String clientISP = "联通";
String clientProvince = "河北";
String clientCity = "廊坊";
// 根据查询未释放游戏对应信息赋值
String cid = "";
// 无操作超时时间单位为秒
int noInputLimitTime = 60;
// 是否支持IPV6功能
boolean isEnableIpv6 = false; 
// 推流画面宽度
int viewResolutionWidth = 1080;    
// 推流画面高度
int viewResolutionHeight = 1920; 

// 传入参数
Bundle bundle = new Bundle();
bundle.putSerializable(HmcpVideoView.ORIENTATION, orientaion);
bundle.putInt(HmcpVideoView.PLAY_TIME, playTime);
bundle.putInt(HmcpVideoView.PRIORITY, priority);
bundle.putString(HmcpVideoView.APP_NAME, packageName);
bundle.putString(HmcpVideoView.APP_CHANNEL, appChannel);
bundle.putString(HmcpVideoView.C_TOKEN, cToken);
bundle.putString(HmcpVideoView.EXTRA_ID, extraId);
bundle.putString(HmcpVideoView.PAY_STR, payStr);
bundle.putBoolean(HmcpVideoView.ARCHIVED, archieve);
Bundle.putString(HmcpVideoView.PAY_PROTO_DATA, protoData);
bundle.putInt(HmcpVideoView.FPS_PERIOD, fpsPeriod);
bundle.putInt(HmcpVideoView.BAND_WIDTH_PERIOD, bandWidthPeriod);
bundle.putInt(HmcpVideoView.BAND_WIDTH_PEAK, bandWidthPeak);
bundle.putInt(HmcpVideoView.DECODE_TIME_PERIOD, decodeTimePeriod);
bundle.putInt(HmcpVideoView.INTERNET_SPEED, speed);
bundle.putBoolean(HmcpVideoView.IS_SHOW_TIME,isShowTime);
bundle.putBoolean(HmcpVideoView.CLIENT_ISP, clientISP);
bundle.putBoolean(HmcpVideoView.CLIENT_PROVINCE, clientProvince);
bundle.putBoolean(HmcpVideoView. CLIENT_CITY, clientCity);
bundle.putBoolean(HmcpVideoView.C_ID,cid); 
bundle.putInt(HmcpVideoView.NO_INPUT_LIMIT_TIME, noInputLimitTime);
bundle.putInt(HmcpVideoView.ALLOW_COMPATIBLE_IPV6, isEnableIpv6);
bundle.putInt(HmcpVideoView.VIEW_RESOLUTION_WIDTH, viewResolutionWidth);
bundle.putInt(HmcpVideoView.VIEW_RESOLUTION_HEIGHT, viewResolutionHeight);
bundle.putSerializable(HmcpVideoView.AUDIO_RECORD_SOURCE, Source.APP);

hmcpVideoView.play(bundle);

3.5 开始游戏

服务请求完成后,通过HmcpVideoView的play()接口开始游戏。启动游戏时调用play()接口。

函数原型:

public class HmcpVideoView {
    public void play();
}

示例代码:

@Override
public void HmcpPlayerStatusCallback(String callback) {
      try {
      JSONObject jsonObject = new JSONObject(callback);
      String status = jsonObject.optString("status");
      if (TextUtils.equals("1", status)) {
        hmcpVideoView.play();
      }
    } catch (JSONException e) {
      e.printStackTrace();
    }
}

4 API 接口

4.1 初始化失败返回内容说明

初始化失败返回 JOSN 字符串:

{ 
        "message":"",     
        "volleyMessage": "",
        "startTime": "",
        "errorTime": "",
}

表4-1 初始化失败返回内容字段说明

参数 说明
message 错误描述
volleyMessage 网络请求失败时,错误信息
startTime 网络超时会携带该字段,表示请求开始时间
errorTime 网络超时会携带该字段,表示错误下发时间

4.2 设置配置信息接口

配置信息为免登录功能所需信息,SDK在获取云游戏服务时需要传送“配置信息”给服务器。如不使用配置信息,可传非空字符串。

函数原型:

public class HmcpVideoView {
        public void setConfigInfo (String config);
}

4.3 暂停游戏接口

游戏启动后,通过HmcpVideoView的pauseGame() 接口暂停游戏。

函数原型:

public class HmcpVideoView {
        public void pauseGame();
}

示例代码:

hmcpVideoView.pauseGame();

4.4 继续游戏接口

暂停游戏后,通过HmcpVideoView的restartGame()接口继续游戏。

函数原型:

public class HmcpVideoView {
    public void restartGame(int time);
}

表4-2 继续游戏参数说明

参数 类型 必填项 说明
time int 用户可以玩游戏的时长,单位为ms

示例代码:

hmcpVideoView.restartGame(1000 * 60 * 10 ); // 游玩10分钟

4.5 断网重新连接游戏接口

通过HmcpVideoView的reconnection()接口进行重新连接游戏,应用场景为:

  • 游戏启动后,断网重新连接游戏。
  • 游戏启动后,WIFI切换到4G。

函数原型:

public class HmcpVideoView {
        public void reconnection();
}

示例代码:

hmcpVideoView.reconnection();

4.6 重新申请游戏接口

服务请求完成后,通过HmcpVideoView的startPlay()接口重新申请游戏。应用场景为:

  • 长时间无操作后,重新申请游戏。
  • 其他情况下需重新申请游戏场景。

函数原型:

public class HmcpVideoView {
        public void startPlay();
}

示例代码:

hmcpVideoView.startPlay(); 

4.7 插队申请游戏接口

服务请求完成后,通过HmcpVideoView的startPlay(boolean isAhead)接口重新以插队方式申请游戏。可在排队失败等报错场景下,以等待申请实例队列的第一位进行插队,等待有空闲实例进行分配游玩。

函数原型:

public class HmcpVideoView {
        public void startPlay(boolean isAhead);
}

表4-3 插队申请游戏参数说明

参数 类型 必填项 说明
isAhead boolean 是否插队进行申请游戏

示例代码:

hmcpVideoView.startPlay(true); // 注意:调用 play(bundle) 成功后,才可调用该方法

4.8 退出游戏接口

结束播放,退出游戏。退出需要在Activity方法重载onPause()、onDestroy()接口。

函数原型:

public class HmcpVideoView {
        public void onPause();
        public void onDestroy();
}

示例代码:

@Override
protected void onStop() {
  super.onStop();
  hmcpVideoView.onStop();
}
@Override
protected void onDestroy() {
  if (hmcpVideoView!= null) {
    hmcpVideoView. onDestroy();
  }
  super.onDestroy();
}

4.9 切换清晰度接口

此接口用于切换清晰度,ResolutionInfo类的定义请参见清晰度信息ResolutionInfo类的定义,切换清晰度的调用时机请参见切换清晰度调用时机

函数原型:

public class HmcpVideoView {
        public void onSwitchResolution (int level, ResolutionInfo resolution, int rate)
}

表4-4 切换清晰度参数说明

参数 类型 必填项 说明
level int 预留字段,传0
resolution ResolutionInfo 要切换的清晰度信息
rate int 预留字段,传0

示例代码:

// 获取清晰度列表
List<ResolutionInfo> mResolutionList = HmcpManager.getInstance().getResolutionDatas();
// 切换清晰度
hmcpVideoView.onSwitchResolution(level, resolution, rate);

注意

切换清晰度接口仅可使用此方法。

4.10 添加控件接口

游戏启动后,通过HmcpVideoView的addView()接口添加控件,如背景图片、设置图标等。

函数原型:

public class HmcpVideoView {
        public void addView(View child);
}

表4-5 添加控件参数说明

参数 类型 必填项 说明
child View 要添加控件的View

示例代码:

// view 可以自定义
hmcpVideoView.addView(view);    

4.11 获取配置信息接口

获取图片度、清晰度、测速等相关配置信息。

函数原型:

public class HmcpVideoView {
        public IntroImageInfo mIntroImageInfo;
        public List<ResolutionInfo> mResolutionList;
}

示例代码:

// 背景图片配置信息
introImageInfos = ijkVideoView.mIntroImageInfo;          
// 清晰度配置信息
resolutionList = ijkVideoView.mResolutionList;    
// 测速配置最小值
min = Integer.parseInt(Constants.MINIMUM_BITRATE);    

4.12 进入队列接口

获取需要排队信息后调用entryQueue()接口进入队列。

函数原型:

public class HmcpVideoView {
        public void entryQueue()
}

示例代码:

hmcpVideoView.entryQueue();

4.13 退出队列接口

获取需要排队信息后调用exitQueue()接口退出队列。

函数原型:

public class HmcpVideoView {
        public void exitQueue ()
}

示例代码:

hmcpVideoView.exitQueue();

4.14 IDC节点测速接口

游戏启动前,调用HmcpManager类的testSpeed()接口进行网络带宽测试。

通过duration参数控制测试的最长时间,单位为s。测试完成后通过注册的callback接口返回测试结果,单位为 KB/s。

函数原型:

public class HmcpManager {
    public void testSpeed(boolean isIpv6, final int duration, final String clientISP,
final String clientProvince, final String clientCity, final OnSpeedTestCallBackListener listener)

    public void testSpeed(boolean isIpv6, final int duration, final String clientISP,
final String clientProvince, final String clientCity, String gameBID,final OnSpeedTestCallBackListener listener)    
}

表4-6 测速参数说明

参数 类型 说明
isIpv6 boolean 是否是Ipv6
duration Int 检测速度所用时间,单位/s
clientISP String 运营商名称
clientProvince String 当前定位省份
clientCity String 当前定位城市
gameBID String 游戏bid
listener OnSpeedTestCallBackListener 节点测速接口回调监听器

表4-7 OnSpeedTestCallBackListener说明

方法名 参数 类型 说明
onComplete success boolean 测速结果。
true:表示测速通过
false:表示测试未通过
speed int 测速值,单位为KB/s
speedThreshold int 测速最低阈值,单位为KB/s
示例代码:
HmcpManager manager = HmcpManager.getInstance();
manager.testSpeed(5, "联通", "河北", "廊坊", new OnSpeedTestCallBackListener() {
  @Override
  public void success(boolean success, int speed, int speedTheshold) {
      //to do something
  }
});

4.15 点测速接口

游戏启动后,通过HmcpVideoView的点测速接口getVideoLatency()获取实时视频网络延迟,单位为ms。

函数原型:

public class HmcpVideoView {
        public int getVideoLatency()
}

示例代码:

int latency = hmcpVideoView.getVideoLatency();

4.16 发送消息接口

游戏启动后,通过HmcpVideoView的sendMessage()接口可以向access服务器发送消息。
函数返回值表示:当前长链接是否连接成功。

函数原型:

public class HmcpVideoView {
    //返回当前长链接是否连接成功
    public boolean sendMessage(String payload, MessageType type, OnSendMessageListener listener);
}

表4-8 发送消息参数说明

参数 类型 必填项 说明
payload String 需要发送的消息。
以下为虚拟手柄特定消息:
拉起支付:Constants.MSG_VIRTUAL_GAME_PAD_PULL_UP_PAY
关闭支付弹窗:Constants.MSG_VIRTUAL_GAME_PAD_CLOSE_PAY_ALERT
type MessageType 消息类型。
支付消息:MessageType.PAY_TYPE
虚拟手柄(需配合 “海马云虚拟手柄小程序SDK”使用):MessageType.TYPE_VIRTUAL_GAME_PAD;
listener OnSendMessageListener 发送消息接口回调监听器

示例代码:

public void testSendMessage(View v) {
    if (hmcpVideoView != null) {
        //isConnect true:长链接成功  false:长链接失败
        boolean isConnect = hmcpVideoView.sendMessage("test send msg", MessageType.PAY_TYPE, new OnSendMessageListener() {
            @Override
            public void result(boolean success, String mid) {
                //success:发送结果。true:发送成功;false:发送失败;
                //mid:消息Id
            }
        });
    }
}

4.17 消息回调接口

实现HmcpPlayerListener接口后,在该接口的onMessage()函数中可以收到access服务器的消息回调。

函数原型:

public interface HmcpPlayerListener {
  void onMessage(Message message)
}

表4-9 消息回调返回值说明

返回值 类型 说明
message Message Message的定义以及参数说明请参见消息回调

示例代码:

public class HmcpPlayerActivity extends AppCompatActivity implements HmcpPlayerListener {
  @Override
  public void onMessage(Message message) {
    // 收到退出登录消息回调
  }
}

4.18 获取实时视频信息

实现HmcpPlayerListener接口后,在该接口的onPlayStatus()函数中可以收到实时数据的上报。

函数原型:

public interface HmcpPlayerListener {
  void onPlayStatus(int status, long value, String data);
}

表4-10 获取实时视频信息返回结果说明

返回结果 类型 说明
status int 状态值,可为0、1、2,value根据status值不同而含义不同
value long status = 0时,value是采样周期内接受到的视频帧的总大小,单位为Byte
status = 1时,value是采样周期内,渲染帧的总数
status = 2时,value是采样周期内,平均解码耗时,单位为ms
data String 附加信息,status = 0时,data 为采样周期内最大的N帧大小,单位为Byte

示例代码:

public class HmcpPlayerActivity extends AppCompatActivity implements HmcpPlayerListener {
    @Override
    public void onPlayStatus(int status, long value, String data) {
    }
}

4.19 更新uid和游戏时长接口

更新uid和游戏时长的接口。

函数原型:

public class HmcpVideoView {
    public void updateGameUID(Bundle bundle,final OnUpdataGameUIDListener listener)
}

表4-11 更新uid和游戏时长参数说明

参数 类型 必填项 说明
bundle Bundle 调用 put***() ,将下列所有参数赋值并打包到bundle中
listener OnUpdataGameUIDListener 结果回调监听器

表4-12 bundle key说明

key value类型 必填项 说明
HmcpVideoView.PLAY_TIME long 游戏时长,单位为ms(注意确认时间单位是否与代码一致)
HmcpVideoView.USER_ID String 新的用户ID ,uid
HmcpVideoView.TIPS_MSG String 更新成功的tip显示
HmcpVideoView.PAY_PROTO_DATA String 更新的proto data
HmcpVideoView.C_TOKEN String 更新的cToken ,用来校验参数的有效性

注意

更新uid成功后需要重新设置用户信息,详情请参见设置用户登录信息

示例代码:

Bundle bundle = new Bundle();
bundle.putLong(HmcpVideoView.PLAY_TIME, playingTime);
bundle.putString(HmcpVideoView.USER_ID, userID);
bundle.putString(HmcpVideoView.TIPS_MSG, tip);
bundle.putString(HmcpVideoView.PAY_PROTO_DATA, proto_data);
bundle.putString(HmcpVideoView.C_TOKEN, cToken);
OnUpdataGameUIDListener listener = new OnUpdataGameUIDListener () {
  @Override
  public void success(boolean result) {
      // success中返回查询结果,false(更新失败),true(更新成功)
  }
  @Override
  public void fail(String msg) {
      // fail中返回更新失败信息
      //HmcpManager.init(...,true)时
      //msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}
  }
});
hmcpVideoView. updateGameUID(bundle, listener);

4.20 获取Input地址接口

游戏收到第一帧后,通过HmcpVideoView的getInputUrl()接口获取input地址。

函数原型:

public class HmcpVideoView {
    public String getInputUrl();
}

示例代码:

String inputUrl = hmcpVideoView.getInputUrl();

4.21 获取SDK版本号接口

创建HmcpManager后,通过其getSDKVersion()获取版本号。

函数原型:

public class HmcpManager{
    public String getSDKVersion()
}

示例代码:

String sdkVersion = HmcpManager.getInstance().getSDKVersion();

4.22 获取清晰度列表接口

获取清晰度列表的接口。

函数原型:

public class HmcpManager{
    public void getResolutionInfos(String packageName, String mAppChannel, 
                                 final OnGetResolutionsCallBackListener listener)

    public void getResolutionInfos(String packageName, String mAppChannel,  String gameBID,final OnGetResolutionsCallBackListener listener)
}

表4-13 获取清晰度列表参数说明

参数 类型 必填项 说明
packageName String 游戏包名
mAppChannel String 游戏配置的AppChannel
gameBID String 游戏bid
tener String 查询结果回调监听器

示例代码:

OnGetResolutionsCallBackListener listener = new OnGetResolutionsCallBackListener () {
  @Override
  public void success(List mResolutionList) {
    // success查询成功会返回,查询结果为List。注:List可能为空
  }
  @Override
  public void fail(String msg) {
    // fail 如查询失败会返回String类型的错误信息。
  }
});
HmcpManager.getInstance().getResolutionInfos (packageName, mAppChannel, listener);

4.23 获取视频流基本参数接口

通过HmcpVideoView中的getQRCodeData()接口获取参数。

函数原型:

public class HmcpVideoView {
    public String getQRCodeData()
}

示例代码:

String qrCodeData = hmcpVideoView.getQRCodeData();
//返回数据格式:
{
  "screenShotUrl":"ws://wss.haimawan.com:9480/websocket?url=10.20.32.79:7682&st=4a61796462746b37314e424235734b45724754416a6c752b7034396445646145",
  "screenResolution":"1920x1080",
  "inputUrl":"ws://115.159.241.62:10267/4a61796462746b37314e424235734b45724754416a6c752b7034396445646145",
  "orientation":0,
  "encryption":""
}            

表4-14 视频流字段说明

字段 类型 说明
screenShotUrl String 截屏流地址
screenResolution String 视频清晰度
inputUrl String input连接地址
orientation int 横竖屏参数
encryption String 加密的cid

4.24 获取云游戏延迟信息接口

通过该接口会返回当前云游戏的延迟信息,该算法的准确性基于APP和实例的时钟校准。

函数原型:

public class HmcpVideoView {
    public VideoDelayInfo getClockDiffVideoLatencyInfo()
}

示例代码:

hmcpVideoView.getClockDiffVideoLatencyInfo();

表4-15 云游戏延迟信息方法说明

方法 方法说明
getNetDelay() 获取帧网络耗时(最近1s内随机采样1帧)
getDecodeDelay() 获取帧解码耗时(最近1s内随机采样1帧)
getRenderDelay() 获取帧渲染耗时只包含解码后送入渲染队列的时间,不包含系统渲染部分(最近1s内随机采样1帧)
getFrameSize() 获取帧大小(最近1s内随机采样1帧)
getVideoFps() 获取视频帧率
getBitRate() 获取视频码率
getReciveFrameCount() 收到的总帧数
getReceiveFrameSize() 收到帧的总大小
getPacketsLostRate() 丢包率,该接口只支持webrtc,不支持rtmp,返回为空字符串
getJitterBuffer() JitterBuffer,该接口只支持webrtc,不支持rtmp,返回为-1
getServerEncodeDelay() 服务端编码延迟,该接口只支持webrtc,不支持rtmp,返回为-1

注意

  • 如果是RTMP流类型,该接口依赖于服务器打开时钟校准配置和ROM支持,当时钟校准成功时才会有数据返回,之前会返回null。
  • 在切换清晰度,前后台切换时,需要重新进行时钟校准,校准成功前会存在异常数据,需要在重新获取第一帧之后调用。

4.25 结束播放接口

游戏启动后,通过HmcpVideoView的release()接口结束播放。可在长时间无操作后调用,也可在其他error时调用。

函数原型:

public class HmcpVideoView {
    public void release()
}

示例代码:

hmcpVideoView.release();

4.26 静音功能开关接口

设置当前的播放为静音状态或关闭静音状态。

函数原型:

public class HmcpVideoView {
    // @param isMute true:全局静音 false:取消全局静音 
      public void setAudioMute(boolean isMute)
}

表4-16 静音功能开关参数说明

参数 类型 必填项 说明
isMute boolean true:表示全局静音
false:表示取消全局静音

示例代码:

hmcpVideoView. setAudioMute(false);

4.27 设置鼠标初始坐标接口

游戏启动前,通过HmcpVideoView的setInitMousePoint接口设置鼠标初始坐标。

其中float x、float y为鼠标在屏幕x轴y轴比例,取值范围为0-1,成功返回true,失败返回false。

函数原型:

public class HmcpVideoView {
    public boolean setInitMousePoint(float x, float y)
}

表4-17 参数说明

参数 类型 说明
x float 鼠标坐标在屏幕x轴比例,取值范围为0到1之间
y float 鼠标坐标在屏幕y轴比例,取值范围为0到1之间

示例代码:

hmcpVideoView.setInitMousePoint(0.5f,0.5f);

4.28 获取键位映射数据接口

游戏启动后,通过HmcpVideoView的getButtonMappings接口获取键位映射数据。

其中List为键位映射配置列表集合,如有多套配置则list长度大于1。List为空或list.size为0则键位映射没有配置或配置格式错误。

获取键位映射列表方法为list.get(int index),表单格式为JSON格式,示例参考TV键位映射配置格式

函数原型:

public class HmcpVideoView{
        public List getButtonMappings ( )
}

示例代码:

List list = hmcpVideoView.getButtonMappings();

4.29 切换操作模式接口

在成功播流后,通过HmcpVideoView的setButtonMappingMode(int mode)接口修改操作模式,返回值为true表示切换成功,返回值为false表示切换失败。

函数原型:

public class HmcpVideoView{
        public boolean setButtonMappingMode(int mode)
}

表4-18 参数说明

参数 类型 说明
mode int 操作模式。
初始化模式:HmcpVideoView.GAMEPAD_MODE_NONE=1
鼠标操作模式:HmcpVideoView. GAMEPAD_MODE_MOUSE=2
键位映射操作模式:HmcpVideoView. GAMEPAD_MODE_MAP=4

示例代码:

hmcpVideoView.setButtonMappingMode (HmcpVideoView.GAMEPAD_MODE_MAP);//映射模式

注意

  • 未正常起播时,无法修改操作模式,会返回失败。
  • 未配置映射列表时,无法切换到映射模式,会返回失败。

4.30 获取当前操作模式接口

在成功播流后,通过HmcpVideoView的getButtonMappingMode()接口获取当前操作模式。

函数原型:

public class HmcpVideoView{
        public int getButtonMappingMode()
}

表4-19 参数说明

参数 类型 说明
mode int 操作模式。
初始化模式:HmcpVideoView.GAMEPAD_MODE_NONE=1
鼠标操作模式:HmcpVideoView. GAMEPAD_MODE_MOUSE=2
键位映射操作模式:HmcpVideoView. GAMEPAD_MODE_MAP=4

示例代码:

int mode = hmcpVideoView. getButtonMappingMode ();

4.31 设置鼠标灵敏度接口

游戏启动后,通过HmcpVideoView的setMouseMoveStep接口设置鼠标灵敏度。其中int step为鼠标灵敏度取值0-10,成功返回true,失败返回false。

函数原型:

public class HmcpVideoView{
        public boolean setMouseMoveStep(int step);
}

表4-20 参数说明

参数 类型 说明
step int 鼠标灵敏度,取值0~10

示例代码:

hmcpVideoView.setMouseMoveStep(5);

4.32 设置播放控件接口

可以使用HmcpManager中的setVideoView(int type)接口设置播放控件类型。

函数原型:

public class HmcpManager{
        public void setVideoViewType(int type)
}

表4-21 参数说明

参数 类型 说明
type int 播放器类型。
HmcpManager.RENDER_SURFACE_VIEW = 1:使用surfaceView
HmcpManager.RENDER_TEXTURE_VIEW = 2:使用textureView
注:默认使用textureView,surfaceView不支持竖屏游戏,不支持进入后台不断流。

示例代码:

// 可在初始化成功后调用
HmcpManager manager = HmcpManager.getInstance();
manager.init(this, new OnInitCallBackListener() {
   @Override
   public void success() {    
       // 初始化SDK成功,可以云游戏
       manager.setVideoViewType(HmcpManager.RENDER_TEXTURE_VIEW);
   }
   @Override
   public void fail(String s) {
       // 初始化SDK失败,不能云游戏
   }
 });

4.33 设置游戏前后台切换是否断流重连接口

可以使用HmcpVideoView中的setCloseStream(boolean close)接口设置前后台切换是否断流重连。

函数原型:

public class HmcpVideoView {
        public void setCloseStream(boolean close);
}

表4-22 参数说明

参数 类型 说明
close boolean true:断流重连
false:不断流重连
默认为true

示例代码:

hmcpVideoView.setCloseStream(true);

4.34 云游戏静音接口

可以使用HmcpVideoView中的turnOffSound()方法关闭声音,turnOnSound()打开声音。

通过isOnsound()判断是否打开声音 true为声音已打开,false为声音未打开。

函数原型:

public class HmcpVideoView {
    public void turnOffSound();
    public void turnOnSound();
    public boolean isOnSound();
}

示例代码:

hmcpVideoView.turnOffSound();

4.35 设置鼠标图标接口

可以使用HmcpVideoView中的setMouseIcon()方法设置鼠标图标。

函数原型:

public class HmcpVideoView {
    //name:;type:图片(0),gif(1) 
    public void setMouseIcon(String name,int type);
}

表4-23 参数说明

参数 类型 说明
name String 图片资源名称:”xxx.png”
type int 图片类型。
0:普通图片
1:gif图片

示例代码:

hmcpVideoView.setMouseIcon("mouse.png",0);

5 进阶API

5.1 获取视频流地址接口

游戏启动后,通过HmcpVideoView的getStreamUrl()接口接口获取视频流地址。

函数原型:

public class HmcpVideoView {
    public String getStreamUrl()
}

示例代码:

String streamUrl = hmcpVideoView.getStreamUrl();

5.2 获取cid接口

游戏启动后,通过HmcpManager的getCloudId接口获取cid。

函数原型:

public class HmcpManager{
    public String getCloudId()
}

示例代码:

String cloudId = HmcpManager.getInstance().getCloudId();

5.3 获取游戏存档状态接口

获取存档状态的接口,判断游戏所处状态(正在存档、存档完成、存档失败)。

函数原型:

public class HmcpManager{
    public void getGameArchiveStatus(String packageName, UserInfo userInfo,
                                     final OnSaveGameCallBackListener listener)

    public void getGameArchiveStatus(String packageName, UserInfo userInfo, String gameBID,final OnSaveGameCallBackListener listener)
}

表5-1 获取游戏存档状态参数说明

参数 类型 必填项 说明
packageName String 游戏包名
userInfo UserInfo 用户登录信息,请参见设置用户登录信息
gameBID String 游戏bid
listener OnSaveGameCallBackListener 查询存档结果回调监听器

示例代码:

OnSaveGameCallBackListener listener = new OnSaveGameCallBackListener() {
  @Override
  public void success(boolean result) {
      // success中返回查询结果,false(正在存档),true(存档完成)。
  }
  @Override
  public void fail(String msg) {
      // fail(存档失败),msg为失败信息。
      // HmcpManager.init(...,true)时,msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}
  }
});
HmcpManager.getInstance().getGameArchiveStatus(packageName, userInfo, listener);

5.4 查询是否存在游戏存档接口

查询当前用户是否存在存档的接口。

函数原型:

public class HmcpManager{
    public void gameArchived(String packageName, UserInfo userInfo,
                           final OnSaveGameCallBackListener listener)

    public void gameArchived(String packageName, UserInfo userInfo, String gameBID,
                             final OnSaveGameCallBackListener listener)
}

表5-2 查询是否存在游戏存档参数说明

参数 类型 必填项 说明
packageName String 游戏包名
userInfo UserInfo 用户登录信息,请参见设置用户登录信息
gameBID String 游戏bid
listener OnSaveGameCallBackListener 查询结果回调监听器

示例代码:

OnSaveGameCallBackListener listener = new OnSaveGameCallBackListener() {
  @Override
  public void success(boolean result) {
      // success中返回查询结果,false(没有游戏存档),true(有游戏存档)。
  }
  @Override
  public void fail(String msg) {
      // fail中返回查询失败信息
      // HmcpManager.init(...,true)时
      // msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}
  }
});
HmcpManager.getInstance().gameArchived(packageName, userInfo, listener);

5.5 检测未释放游戏接口

通过用户信息UserInfo查询,是否有未释放实例(仍在运行的游戏)。

函数原型:

public class HmcpManager{
    /**
        * @param userInfo 用户登录信息
        * @param listener 回调函数
        */
    public void checkPlayingGame(UserInfo userInfo, final OnGameIsAliveListener listener)

    public void checkPlayingGame(UserInfo userInfo, String gameBID, final OnGameIsAliveListener listener)
}

表5-3 检测未释放游戏参数说明

参数 类型 必填项 说明
userInfo UserInfo 用户登录信息,请参见设置用户登录信息
gameBID String 游戏bid
listener OnSaveGameCallBackListener 查询结果回调监听器

示例代码:

OnGameIsAliveListener listener = new OnGameIsAliveListener () {
  @Override
  public void success(List<CheckCloudServiceResult.ChannelInfo> channelInfoList) {
      // success 中返回查询结果,channelInfoList,返回的未释放游戏信息,含 pkgName、cid、appChannel
      // 如果有未释放游戏,则取集合第1个元素,如果没有则元素为0;
    if (channelInfoList != null && channelInfoList.size() > 0) {
      final CheckCloudServiceResult.ChannelInfo channelInfo = channelInfoList.get(0);
    }
  }
  @Override
  public void fail(String msg) {
      // fail中返回查询失败信息
      // HmcpManager.init(...,true)时,msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}
  }
});
HmcpManager.getInstance().checkPlayingGame (userInfo, listener);

5.6 根据cid释放实例接口

检测到未释放的cid后,通过调用接口,根据cid释放实例。

函数原型:

public class HmcpManager{
    public void setReleaseCid(String packageName, String cid, String cToken, String appChannel, UserInfo2 userInfo2, final OnSaveGameCallBackListener listener);

    public void setReleaseCid(String packageName, String cloudId, String cToken, String appChannel, UserInfo2 userInfo2,String gameBID, final OnSaveGameCallBackListener listener)
}

表5-4 参数说明

参数 类型 必填项 说明
packageName String 游戏包名,传入要释放的对应游戏包名
cid String 要释放的cid
cToken String 用来校验参数的有效性,cToken的计算方法请参考cToken说明文档
appChannel String 如果存在多款游戏同包名的情况,可以通过appChannel区分。如果不存在则可以忽略。
userInfo2 UserInfo2 用户登录信息,包含字段userId、token
gameBID String 游戏bid
listener OnSaveGameCallBackListener 存档结果回调监听器

表5-5 回调结果

回调结果 类型 说明
code int 请求结果标识。
0:表示请求成功
1:表示请求失败
msg String 当code = 0时返回的信息
errorCode String 当code = 1时返回的错误码
errorMsg String 当code = 1时返回的错误信息

5.7 获取网络请求数据接口

可以使用HmcpManager中的getNetText(HmcpVideoView hmcpVideoView)接口获取网络请求结果数据。

函数原型:

public class HmcpManager{
    public String getNetText (HmcpVideoView  hmcpVideoView)
}

表5-6 获取网络请求数据参数说明

参数 类型 必填项 说明
hmcpVideoView HmcpVideoView SDK播放组件,如果没有创建可以传null

示例代码:

String netText = HmcpManager.getInstance().getNetText(hmcpVideoView)

返回值为字符串格式,可能为null要做为空判断。

返回数据格式见下方:

[{
    "action": "104",
    "index": 0,
    // 结果详细描述
    "msg": "",
    "packageName": "",
    "responseTime": 1565684454987,
    // 请求结果
    "result": "success",
    "startTime": 1565684452774,
    // 请求耗时
    "time": 2213,
    "transId": "7082cbf20b8456c4a02a6e520a7f7982",
    // 网络请求的url
    "url": "https://saasauth.cmgame.com/s/rest/api" 
}, {
    "action": "108",
    "index": 1,
    "msg": "",
    "packageName": "",
    "responseTime": 1565684455511,
    "result": "success",
    "startTime": 1565684455015,
    "time": 496,
    "transId": "7082cbf20b8456c4a02a6e520a7f7982",
    "url": "https://saasauth.cmgame.com/s/rest/api"
}]

表5-7 返回值说明

返回值 类型 说明
url String 网络请求的url
time long 请求耗时
result String 请求结果
uid String 当前用户的uid
cid String 当前云游戏的cid
action String 请求的类型。
长连接:access、input
连接:input
视频流:videoUrl
音频流:audioUrl
action:actionId
transId String 当前申请的唯一id
packageName String 请求的游戏包名
startTime long 开始请求的时间
responseTime String 请求结束的时间
DNS String DNS解析后的IP地址

5.8 云游戏结束信息上报接口

在APP判定云游戏异常结束但SDK未报错误码时,可调用该接口上报云游戏信息,用于SDK排查问题做优化。正常结束也可以调用该接口,该接口对业务逻辑无影响,参数取不到或未定义时可以传空。

函数原型:

public class HmcpVideoView {
    public void reportFinishInfo(int finishCode, String cid, String pkgName, String appChannel, String appVersion, String imei, String deviceId, String gameId)
}

表5-8 云游戏结束信息上报参数说明

参数 类型 必填项 说明
finishCode String 结束状态。
0:表示正常结束
1:表示超时结束
2:表示异常结束,有SDK错误码
3:表示异常结束,无SDK错误码
cid long 当前云游戏cid
pkgName String 当前云游戏包名
appChannel String 当前云游戏渠道号
appVersion String APP版本
deviceId String 用户设备号
gameId String 当前云游戏id号

示例代码:

hmcpVideoView.reportFinishInfo(finishCode, cid, pkgName, appChannel, appVersion, imei, deviceId, gameId);

5.9 获取云游戏状态码接口

云游戏异常结束时,通过该接口返回云游戏当前的状态码,可以分析统计游戏失败原因。

函数原型:

public class HmcpVideoView {
    public String getCloudPlayStatusCode()
}

表5-9 RTMP状态码

RTMP状态码 类型 说明
100999001 String 无流地址,cid未获取成功(初始状态)
100999002 String 无流地址,cid获取成功,Socket连接失败
100999003 String 无流地址,cid获取成功,Socket连接成功,乒乓状态异常
100999004 String 无流地址,cid获取成功,Socket连接成功,乒乓状态正常
100999005 String 无流地址,video成功
100999006 String 有流地址,video失败,audio成功
100999007 String 有流地址,video失败,audio失败,input成功
100999008 String 有流地址,video失败,audio失败,input失败
100999009 String 获取流地址超时
100999010 String 刷新stoken超过次数上限
100999100 String user info为空

示例代码:

String cloudPlayStatusCode = hmcpVideoView.getCloudPlayStatusCode();

5.10 开始直播接口

函数原型:

public class HmcpVideoView {
    public void startLiving(String livingId, String livingUrl, OnLivingListener listener);
}

表5-10 开始直播参数说明

参数 类型 必填项 说明
livingId String 直播id
livingUrl String 直播地址
listener OnLivingListener 调用结果回调

示例代码:

hmcpVideoView.startLiving(livingId, livingUrl, new OnLivingListener() {
  @Override
  public void start(boolean success, String msg) {
    if (success) { 
      //开始直播成功
    }else{
     //HmcpManager.init(...,true)时,msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}}
    }
  }
  @Override
  public void stop(boolean success, String msg) {
    if (success) {
      //停止直播成功
    }else{
     //HmcpManager.init(...,true)时,msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}}
    }
  }
});

5.11 停止直播接口

函数原型:

public class HmcpVideoView {
    public void stopLiving(String livingId, OnLivingListener listener);
}

表5-11 停止直播参数说明

参数 类型 必填项 说明
listener OnLivingListener 调用结果回调
livingId String 直播id

示例代码:

hmcpVideoView.stopLiving(livingId, new OnLivingListener() {
  @Override
  public void start(boolean success, String msg) {
    if (success) { 
       //开始直播成功
    }else {
      //HmcpManager.init(...,true)时,msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}}
    }
  }
  @Override
  public void stop(boolean success, String msg) {
    if (success) {
      //停止直播成功
    }else {
      //HmcpManager.init(...,true)时,msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}}
    }
  }
});

5.12 获取授权码接口

函数原型:

public class HmcpVideoView {
    public void getPinCode(OnContronListener listener);
}

表5-12 获取授权码参数说明

参数 类型 必填项 说明
listener OnContronListener 调用结果回调

示例代码:

hmcpVideoView.getPinCode(new OnContronListener() {
  @Override
  public void pinCodeResult(boolean success, String cid, String pinCode, String msg) {
    if (success) {
      // 获取授权码成功
    } else {
      // 获取授权码失败
      //HmcpManager.init(...,true)时,msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}}
    } 
  }
  @Override
  public void contronResult(boolean success, String msg) {
    if (success) {
      // 获取控制权成功
    } else {
      // 获取控制权失败
      //HmcpManager.init(...,true)时,msg={"errorCode":"","errorCodeWithoutCid":"","errorMessage":""}}
    } 
  }
  @Override
  public void contronLost() {
    // 失去控制权
  }
});

5.13 获取控制权接口

函数原型:

public class HmcpVideoView {
    public void contronPlay(int streamType, Control controlPara, OnContronListener listener);
}

表5-13 获取控制权参数说明

参数 类型 必填项 说明
streamType int 选择流类型。
0 :表示RTMP
1 :表示WEBRTC
controlPara Control 获取控制权参数对象
listener OnContronListener 调用结果回调

表5-14 Control数据结构说明

参数 类型 必填项 说明
cid String cid
pinCode String 授权码
accessKeyID String 被转移客户端的bid(接入方的唯一ID,用来区分不同的接入方,该值由海马云分配。)
isIPV6 boolean 是否兼容IPV6环境
clientISP String 运营商名称
clientProvince String 当前定位省份
clientCity String 当前定位城市
ScreenOrientation.PORTRAIT ScreenOrientation 屏幕方向
竖屏:ScreenOrientation.PORTRAIT
横屏:ScreenOrientation.LANDSCAPE
cameraOpenPermissionCheck boolean 每次开启摄像头时,向APP申请权限的开关,不传默认为关闭。
true:表示开启
false:表示关闭
权限申请回调请参见播放器回调中onPermissionNotGranted接口,
权限结果通知请参见通知SDK权限结果

示例代码:

hmcpVideoView.contronPlay(contronCid, contronPinCode, new OnContronListener() {
  @Override
  public void pinCodeResult(boolean success, String cid, String pinCode, String msg) {
    if (success) {
      // 获取授权码成功
    } else {
      // 获取授权码失败
    } 
  }
  @Override
  public void contronResult(boolean success, String msg) {
    if (success) {
      // 获取控制权成功
    } else {
      // 获取控制权失败
    } 
  }
  @Override
  public void contronLost() {
    // 失去控制权
  }
});

5.14 是否支持直播接口

函数原型:

public class HmcpVideoView {
    public ELivingCapabilityStatus getLivingCapabilityStatus();
}

表5-15 是否支持直播返回结果说明

返回结果 类型 说明
ELivingCapabilityStatus ENUM 是否支持直播状态

示例代码:

public enum ELivingCapabilityStatus {
    // 未知
    UNKNOWN,
    // 支持
    SUPPORTED,
    // 不支持
    UNSUPPORTED
}

示例代码:

 ELivingCapabilityStatus livingCapabilityStatus = hmcpVideoView.getLivingCapabilityStatus();

5.15 发送返回键事件给实例接口

在需要发送返回键事件给实例时,可以通过调用此方法发送返回键事件。

函数原型:

public class HmcpVideoView {
    // KeyType 是枚举类,这里参数固定为 KeyType.KEY_BACK
    public void sendKeyEvent(KeyType keyType);
}

表5-16 参数说明

参数 类型 说明
KeyType ENUM 按键类型,KeyType.KEY_BACK是返回键

示例代码:

// 发送返回键事件,KeyType 是枚举类,这里参数固定为 KeyType.KEY_BACK
ijkVideoView.sendKeyEvent(KeyType.KEY_BACK);

5.16 设置录音回调接口

设置为APP侧后,需要设置录音回调,当触发录音的场景,sdk通过录音回调接口通知APP开始录音、停止录音。RecordParameter为APP侧录音,SDK回调APP的录音参数。

函数说明:

public class HmcpVideoView {
    public void setAudioRecordCallback(AudioRecordSourceCallback callback)
}

表5-17 参数说明

参数 类型 说明
callback AudioRecordSourceCallback 结果回调

表5-18 RecordParameter参数说明

方法 返回值 说明
getFormat Format 录音数据格式,目前只支持Format.PCM
getChannel int 通道数
getEncoding int 数据格式位宽
getSampleRate int 采样率

示例代码:

hmcpVideoView.setAudioRecordCallback(new AudioRecordSourceCallback() {

    @Override
    public void onAudioRecordStart(RecordParameter parameter) {
        //SDK回调APP开始录音,并将录音参数RecordParameter传递给APP
    }

    @Override
    public void onAudioRecordStop() {
        //SDK回调APP录音停止
    }

    @Override
    ublic void onAudioRecordError(String errMsg) {
        //SDK回调APP录音出现异常
    }

});

5.17 传输录音数据接口

申请服务时,设置了APP侧录音,SDK回调APP录音开始后,APP可以调用SDK的接口,传输录音数据到实例侧服务。

函数说明:

public class HmcpVideoView {
    public void sendAudioData(byte[] data)
}

表5-19 参数说明

参数 类型 说明
data byte[] 录音数据

示例代码:

hmcpVideoView.sendAudioData(data);

5.18 停止录音接口

申请服务时,设置了APP侧录音,录音过程中,APP可以停止录音。

函数说明:

public class HmcpVideoView {
    public void stopRecord()
}

示例代码:

hmcpVideoView.stopRecord();

5.19 设置可存档最小游戏时间并退出游戏接口

使用此接口可设置可存档最小游戏时间并退出游戏。

函数原型:

public class HmcpVideoView{ 
    public void stopAndDismiss(Activity activity, int archiveMinSeconds); 
}

表5-20 设置可存档最小游戏时间并退出游戏参数说明

参数 类型 必填项 说明
activity Activity APP播流页Activity对象,设置此参数,SDK会调用Activity的finish方法,关闭播流页
archiveMinSeconds int 可存档游戏的最小游戏时间,单位为s,小于0时当0处理

示例代码:

// 退出游戏,游戏时间大于 60 秒以上才可以存档,关闭activity
ijkVideoView.stopAndDismiss(activity, 60);    
// 退出游戏,游戏时间大于 60 秒以上可以存档
ijkVideoView.stopAndDismiss(null, 60);        

5.20 游戏启动参数携带执行脚本接口

在启动游戏组件时可以携带参数componentType、 action、componentName和extraData,其中:

  • componentType、action和componentName通过bundle传递,详见申请服务
  • extraData通过方法setExtraData传递。

表5-21 参数说明

参数 类型 必填 说明
componentType int 组件类型。
Activity:HmcpVideoView.COMPONENT_TYPE_ACTIVITY
Service:HmcpVideoView.COMPONENT_TYPE_SERVICE
Broadcast:HmcpVideoView.COMPONENT_TYPE_BROADCAST
action String 组件对应的action
componentName String 指定的组件名,格式(packageName/componentName),
如(快手开心消消乐):com.happyelements.AndroidAnimal.kuaishou
/com.happyelements.hellolua.MainActivity
extraData IntentExtraData 额外参数

示例代码:

Bundle bundle = new Bundle();
bundle.putInt(HmcpVideoView.COMPONENT_TYPE, HmcpVideoView.COMPONENT_TYPE_ACTIVITY);
bundle.putString(HmcpVideoView.COMPONENT_ACTION, “android.intent.action.MAIN”);
bundle.putString(HmcpVideoView.COMPONENT_NAME, “com.happyelements.AndroidAnimal.kuaishou/com.happyelements.hellolua.MainActivity”);
hmcpVideoView.play(bundle);

表5-22 IntentExtraData结构定义

参数 类型 说明
booleanExtra HashMap<String,Boolean> 向Intent中添加Boolean
integerExtra HashMap<String,Integer> 向Intent中添加Integer
integerArrayExtra HashMap<String, Integer[]> 向Intent中添加Integer数组
integerListExtra HashMap<String,List> 向Intent中添加Integer List
stringExtra HashMap<String, String> 向Intent中添加String
stringArrayExtra HashMap<String, String[]> 向Intent中添加String数组
stringListExtra HashMap<String, List> 向Intent中添加String List
floatExtra HashMap<String, Float> 向Intent中添加Float
floatArrayExtra HashMap<String, Float[]> 向Intent中添加Float数组
floatListExtra HashMap<String, List> 向Intent中添加Float List
longExtra HashMap<String, Long> 向Intent中添加Long
longArrayExtra HashMap<String, Long[]> 向Intent中添加Long数组
longListExtra HashMap<String, List> 向Intent中添加Long List
componentNameExtra HashMap<String, String> 向Intent中添加componentName
uriExtra HashMap<String, String> 向Intent中添加uri
applink String 远程组队分享链接

函数原型:

public class HmcpVideoView{
    public void setExtraData(IntentExtraData extraData);
}

示例代码:

IntentExtraData extraData = new IntentExtraData();
HashMap<String, String> map = new HashMap<>();
map.put("StringKey1", “StringValue1”);
extraData.setStringExtra(map);
hmcpVideoView.setExtraData(extraData);

5.21 帧延迟数据接口

APP开启SDK的帧延迟数据回调功能后,SDK会周期性(譬如1秒、2秒)回调APP帧延迟数据。以下帧延迟数据简称sei。

sei数据开启条件如下:

  • APP设置SDK开启sei开关。

  • saas侧配置sei数据回调间隔时间,具体配置请联系项目对接人。

  • saas侧配置sei开关,具体配置请联系项目对接人。

  • saas侧配置sei开关策略,具体配置请联系项目对接人。

函数原型:

public class HmcpVideoView{
public void setSeiListener(ISeiListener listener);

表5-23 参数说明

参数 类型 说明
listener ISeiListener APP开启sei数据,SDK通过ISeiListener回调APP sei数据集合

表5-24 ISeiListener说明

方法 返回值 参数 说明
onData List sei数据集合

表5-25 RtcSeiData说明

方法 返回值 参数 说明
getCid String cid
getUid String uid
getFrameId int 帧id
getPreEncoderTimestamp long 编码前时间戳
getEncodedTimestamp long 编码后时间戳
getPreDecoderTimestamp long 解码前时间戳
getDecodedTimestamp long 解码后时间戳
  • saas侧配置sei数据回调间隔时间,譬如1秒。

  • saas侧配置sei开关打开。

  • SDK侧sei开关配置:申请服务接口中,增加sei开关参数,示例代码如下:

    Bundle bundle = new Bundle();
    bundle.putInt(HmcpVideoView.SEI, 1);//sei数据开启
    hmcpVideoView.play(bundle);
  • APP设置sei数据回调,示例代码如下:

    HmcpVideoView.setSeiListener(new ISeiListener() {
        public void onData(List<RtcSeiData> data) {
            //to do someting...
         }
    });

5.22 将数据写入到云端的文本框接口

函数原型:

public class HmcpVideoView {
    public boolean inputText(String payload);
}

表5-26 参数说明

参数 类型 说明
payload String 发送的内容(最大长度256个字符)

示例代码:

ijkVideoView.inputText("this is test data");

5.23 与云游戏传输数据接口

播流成功之后可以与云游戏(游戏需接入MessageSDK-localPort)进行数据传输。

此功能需要配置开启,默认关闭,如需开启请联系项目对接人员。

函数原型:

public class TransferHelper{
    public void connect();
    public void disconnect();
    public boolean isConnected();
    public int send(byte[] buffer);
    public void setCallback(Callback callback);
}

表5-27 参数说明

方法名 参数 类型 描述
connect 建立连接
disconnect 断开连接
isConnected 是否连接
send buffer byte[] 发送数据
setCallback callback Callback 设置回调接口

示例代码:

public void startTransfer(View view) {
    if (ijkVideoView.getTransferDelegate() == null) {
        Toast.makeText(this, "该游戏不支持数据传输", Toast.LENGTH_LONG).show();
        return;
    }
    if (!ijkVideoView.getTransferDelegate().isConnected()) {
        ijkVideoView.getTransferDelegate().connect();
        ijkVideoView.getTransferDelegate().setCallback(mCallBack);
        startTransferBtn.setText("关闭传输");
    } else {
        ijkVideoView.getTransferDelegate().disconnect();
        startTransferBtn.setText("开启传输");
    }
}

函数原型:

public interface Callback {
    void onConnect(boolean isReconnect);
    void onClose();
    void onBinaryMessage(byte[] payload);
    void onTextMessage(String payload);
}

表5-28 参数说明

方法名 参数 类型 描述
onConnect 连接建立回调
onClose 连接断开回调
onBinaryMessage payload byte[] 收到二进制数据
onTextMessage payload String 收到文本数据

示例代码:

private TransferHelper.Callback mCallBack = new TransferHelper.Callback() {
    @Override
    public void onConnect(boolean isReconnect) {
        Toast.makeText(BasePlayerActivity.this, "长连接成功", Toast.LENGTH_LONG).show();
        startTransferBtn.setText("关闭传输");
    }

    @Override
    public void onClose() {
        Toast.makeText(BasePlayerActivity.this, "长连接断开", Toast.LENGTH_LONG).show();
        startTransferBtn.setText("开启传输");
    }

    @Override
    public void onBinaryMessage(byte[] payload) {
        LogUtils.i(TAG,"payload: " + new String(payload));
    }

    @Override
    public void onTextMessage(String payload) {
        LogUtils.i(TAG,"payload: " + payload);
    }
};

5.24 获取每帧数据

当前只提供每帧渲染完成的帧id、时间戳数据,数据通过子线程回调方式提供,非实时、间隔性回调数据。

函数原型:

public class HmcpVideoView {
    public void setHmFrameCallback(HmFrameCallback callback);
}

表5-29 参数说明

方法名 参数 类型 描述
setHmFrameCallback callback HmFrameCallback 数据回调接口

表5-30 HmFrameCallback 说明

方法名 参数 类型 描述
onFrame infoData String JSON数据结构
{
“id”: “”,
“rendered_time_stamp”: “”
}

示例代码:

hmcpVideoView.setHmFrameCallback(new HmFrameCallback() {
    @Override
    public void onFrame(String infoData) {
        Log.d(TAG, infoData);
    }
});

5.25 一键返回游戏界面接口

通过HmcpVideoView中的backToGame()接口执行返回按键操作。请根据已有逻辑, 在合适的地方增加backToGame()方法调用, 对云端设备发送指令, 相当于手机中唤起游戏到前台。

适用场景:针对有些第三方登录多级,无法返回的情况。

函数原型:

public class HmcpVideoView {
    public void backToGame()
}

示例代码:

hmcpVideoView.backToGame();

5.26 通知SDK权限结果接口

一些云游戏中功能,会触发一些权限的申请,譬如语音连麦需要录音权限、人脸识别功能需要摄像头权限。当SDK没有权限时,SDK回调通知APP申请权限(详情请参见消息回调中onPermissionNotGranted回调接口),用户允许或者拒绝权限后,APP要调用接口通知SDK权限结果。

如果APP没有摄像头权限,SDK会通知APP向用户申请摄像头权限,并一直等待授权结果,APP需要实现用户申请权限的界面和交互,并在用户同意或者不同意授权的时候将结果通知给SDK,以便摄像头的后续处理。

注意

当前只支持摄像头权限处理,SDK通过onPermissionNotGranted接口通知APP权限申请,SDK没有收到APP告知权限结果之前,不会再次通知APP相同权限申请。

函数原型:

public class HmcpVideoView {
    public void handlePermissionResult(String permission, boolean isGranted);
}

示例代码:

@Override
public void onPermissionNotGranted(String permission) {
    if (permission.equals(Manifest.permission.CAMERA)) {
        // APP帮助SDK申请摄像头权限
        ActivityCompat.requestPermissions(
            BasePlayerActivity.this, 
            new String[]{Manifest.permission.CAMERA}, 
            917
        );
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    switch (requestCode) {
        case 917:    
            // 摄像头权限结果通知SDK
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                hmcpVideoView.handlePermissionResult(Manifest.permission.CAMERA, true);
            } else {
                hmcpVideoView.handlePermissionResult(Manifest.permission.CAMERA, false);
            }

    }
}

5.27 获取用户最后一次操作时间戳接口

游戏启动后,通过该接口获取用户最后一次操作实例的时间戳。

函数原型:

public class HmcpVideoView {
    public long getLastUserOperationTimestamp()
}

示例代码:

// 默认返回0,代表用户没有操作过实例,否则返回相应时间戳
hmcpVideoView.getLastUserOperationTimestamp();    

5.28 重置无操作超时计时器接口

游戏启动后,重置无操作超时计时器时调用此函数。

函数原型:

public class HmcpVideoView {
    public int resetInputTimer()
    public int resetInputTimer(boolean needUpdateTimestamp)
}

表5-31 重置无操作超时计时器参数说明

参数 类型 必填项 说明
needUpdateTimestamp boolean true:表示重置计时器并且更新用户最后一次操作时间戳
false:表示重置计时器不更新用户最后一次操作时间戳

表5-32 返回结果说明

返回结果 类型 意义
result int 0 : 表示和实例连接异常
1 : 表示重置无操作超时计数器成功

示例代码:

hmcpVideoView.resetInputTimer();
hmcpVideoView.resetInputTimer(false);

5.29 获取当前播放器截屏接口

游戏启动后,获取当前截屏和检测功能时调用此函数。

函数原型:

public class HmcpVideoView {
    public Bitmap getShortcut()
}

表5-33 当前播放器截屏返回结果说明

返回结果 类型 说明
Bitmap Bitmap 当前播放器截屏的 bitmap 对象

示例代码:

Bitmap bitmap = hmcpVideoView.getShortcut();

5.30 检测当前截屏是否黑屏接口

检测当前截屏的bitmap对象是否黑屏功能时调用此函数。

函数原型:

public class HmcpVideoView {
    public int checkBitmap (Bitmap bitmap)
}

表5-34 检测当前截屏是否黑屏参数说明

参数 类型 必填项 说明
bitmap Bitmap 需要检测的bitmap对象

表5-35 返回结果说明

返回结果 类型 说明
1/2/3/4 int 1:表示检测结果为纯色 排除黑色和全透明色,因为播放器没开始工作,不通设备获取截屏有的是纯黑色有的是纯透明色
2:表示检测结果为纯透明色
3:表示检测结果为正常
4:表示检测结果为纯黑色

示例代码:

int result = hmcpVideoView.checkBitmap(bitmap);

5.31 视频帧卡顿通知接口

SDK监控视频帧在一定时间内处于卡顿的情况,通过回调接口通知接入方,譬如当前播流分辨率为高清,接入方收到通知后,可以提示用户降低分辨率。

注意

接口回调处于主线程上。

public class HmcpVideoView {
    public int setStreamingCallback(StreamingCallback callback)
}

表5-36 视频卡顿通知参数说明

参数 类型 必填项 说明
callback StreamingCallback 视频帧卡顿回调接口

表5-37 StreamingCallback说明

方法名 参数 类型 描述
onFreeze 视频帧出现卡顿情况

示例代码:

hmcpVideoView.setStreamingCallback(new StreamingCallback() {
    @Override
    public void onFreeze() {
        //接入方处理自己的逻辑
    }
});

6 场景说明

6.1 排队管理

排队管理的触发条件:接入方所购买云服务实例和并发数达到上限。

处理机制:

  1. onSceneChanged接收到需要排队提示。

  2. HmcpPlayerStatusCallback接收到status = STATUS_WAIT_CHOOSE状态回调:多优先级用户排队参数增加说明

    onSceneChanged ==> {"sceneId":"needWait"}
    // 收到排队消息
    "status":7
    "data":{"message":"当前排队 1 人,是否继续?--test",
     "queues":[{"index":1,"priorities":[0,1],"rank":0,"time":"300","timeStr":"5分钟"},
               {"index":0,"priorities":[2],"rank":1,"time":"0","timeStr":"00:00"}]}
  3. 调用开启排队videoView.entryQueue(),然后会接收到status = STATUS_OPERATION_INTERVAL_TIME状态回调信息。

    // 排队状态更新,返回该所有队列的排队信息
    status:13 
    {"message":"当前排队1人,当前正在排队3秒人,请稍候…",
     "queues":[{"index":1,"priorities":[0,1],"rank":0,"time":"3","timeStr":"3秒"},
               {"index":0,"priorities":[2],"rank":1,"time":"0","timeStr":"00:00"}]}
  4. 在海马云游戏管理平台进行配置禁止排队,则返回排队信息如下:

    status:10 
    Data:{"message":"当前游戏太过火爆,请您稍后再试",
          "queues":[{"index":1,"priorities":[0,1],"rank":0,"time":"300","timeStr":"5分钟"},
                    {"index":0,"prioritie":[2],"rank":1,"time":"0","timeStr":"00:00"}]}
  5. 调用取消排队ideoView.exitQueue()并直接退出游戏。

6.2 横竖屏切换

SaaS SDK提供动态切换横竖屏游戏画面功能。客户端通过SDK提供的接口,传入指定游戏横竖屏标识参数。

申请服务的时候传入orientation字段,可以控制游戏画面横竖屏显示。

设置横屏:

bundle.putSerializable(HmcpVideoView.ORIENTATION, ScreenOrientationLANDSCAPE);

设置竖屏:

bundle.putSerializable(HmcpVideoView.ORIENTATION, ScreenOrientation.PORTRAIT);

6.3 清晰度切换

  1. 在海马云游戏管理平台进行配置游戏的清晰度参数(高清、超清、流畅)。

  2. 调用开始游戏后,如果成功会有sceneId = “play”的场景回调。

    onSceneChanged ===> {"extraInfo":{"cur_rate":"200"},"sceneId":"play"}
  3. SDK调用HmcpManager.getInstance().getResolutionDatas()获取当前游戏的清晰度列表;

    "resolution":[          {"bitRate":"9600000","defaultChoice":"0","frameRate":60,"id":"4","name":"1080P","resolution":"1920x1080"},
      {"bitRate":"4000000","defaultChoice":"0","frameRate":60,"id":"2","name":"标清","resolution":"960x540"},
      {"bitRate":"3200000","defaultChoice":"1","frameRate":60,"id":"3","name":"高清","resolution":"1280x720"},
      {"bitRate":"2400000","defaultChoice":"0","frameRate":60,"id":"1","name":"流畅","resolution":"848x480"}
    ]
  4. 监听回调函数onSceneChanged并收到sceneId=”crtp”消息:

    onSceneChanged ===> {"extraInfo": {"delay_less_minimum":"0","minimum":0},"sceneId":"crtp"}

    表6-1 清晰度切换返回值说明

    返回值 类型 说明
    delay_less_minimum String 当前码率是否是最低码率。
    0:表示否
    1:表示是
    minimum int 当前码率是否低于下限。
    0:表示否
    1:表示是
  5. 开始切换码率:

    // 发起切换码率
    recordSceneEvent ===> crst{"des":"1024","method":0,"source":"50000"}
    // 切换码率时回调
    onSceneChanged ===> 
    {"extraInfo":{"des":"1024","method":0,"source":"50000"},"sceneId":"crst"}

    表6-2 参数说明

    参数 类型 必填项 说明
    method int 切换码率模式。
    0:表示手动切换码率
    1:表示自动切换码率
    des String 目标码率 ID
    • 如果手动调用onSwitchResolution()切换码率。
    • onSceneChanged接收到切换码率的消息回调scenedId = “crst”。
  6. onSceneChanged收到scenedId = “cred”切换码率后结果:

    recordSceneEvent ===> cred {"cur_rate":"500","result":1}

    表6-3 返回结果说明

    返回结果 类型 说明
    cur_rate String 当前码率是否是最低码率。
    0:表示否
    1:表示是
    result int 0:表示失败
    1:表示成功

7 数据结构定义

7.1 场景切换回调

游戏过程中的各个状态切换都会通过onSceneChanged(String sceneMessage)接口通知应用,sceneMessage字符串是有JSON串转换的,格式如下:

{ 
  // 切换到的场景ID
  "sceneId": "" ,
  // 场景切换的扩展信息,参考sceneId说明
  "extraInfo" {} , 
}

表7-1 游戏过程中各状态的sceneId说明

sceneId extraInfo{}
init 初始化中,extraInfo为空
wait 排队中,extraInfo为空
play 开始游戏,extraInfo为空
stop 游戏结束,extraInfo参考参数示例
mait 云玩维护,extraInfo参考参数示例
crtp 显示自动降低码率tips,extraInfo 参考参数示例
crst 开始切换码率(当前码率,目标码率,自动手动模式),extraInfo参考参数示例
cred 切换码率完成(成功,失败,当前码率),extraInfo参考参数示例
firstFrameArrival 拿到游戏视频第一帧

以下是游戏过程中各状态对应的扩展信息extraInfo{}描述:

  • stop : 游戏结束。

    "extraInfo" : {
        "interval" : 当次游戏时长,单位为s
        "reason"   : "time_limit"    :当次游戏事件到
                     "no_operation"  :超时无操作
                     "instance_err"  :实例出错
                     "forced"        :强制下线
                     "token_expire"  :Token失效
                     "log_off"       :游戏内注销
                     "network_off"   :网络不可用
                     "request_err"   :网络请求出错
      }
  • mait:云玩维护。

    "extraInfo" : {
        "progress" : "soon" :即将,
        "start":进入,
        "done" :恢复
      }
  • crtp:显示自动降低码率 tips。

    "extraInfo" : {
        "minimum" : 当前码率是否最低码率 "0"-否 "1"-是
    }
  • crst:开始切换码率(当前码率、目标码率、自动手动模式)。

    "extraInfo" : {
        "source" : "当前码率" ,
        "des"    : "目标码率" ,
        "method" : 自动手动模式 "0"-手动 "1"-自动
      }
  • cred : 切换码率完成 (成功,失败,当前码率)。

    "extraInfo" : {
        // "0"- 失败 "1"-成功
        "result"   : 0,
        // 当前码率 
        "cur_rate" : 1
    }

7.2 消息回调

消息方法:

public void onMessage(Message message){}

Message类的定义如下:

public class Message implements Serializable {
   // 目标接收者cid,全部推送"ALL"
    public String to; 
    // 消息ID
    public String mid; 
    // 消息内容
    public String payload; 
    // 发送者,系统消息="System"
    public String from;  
    // 消息类型,默认是传 1
    public int type;     
    // 客户端发送默认为0;服务端收到回复为1
    public int ack;     
    // 可选参数,目标uid
    public String uid;             

    @Override
    public String toString() {
        return JSON.toJSONString(this);
    }
}

表7-2 消息回调参数说明

参数 类型 必填项 说明
uid String 可选参数,目标uid
from String 消息发送方标识
to String 消息接收方标识
mid String 消息id
type Integer 消息类型。
支付消息:1
虚拟手柄(需配合 海马云虚拟手柄小程序SDK 使用):5
ack Integer 固定值为0
payload String 消息内容

payload-虚拟手柄消息格式说明

{
  "type":"HM_VirtualGamePad",//虚拟手柄消息
  "data": ""//内容。eg:关闭支付弹窗"{\"action\":\"ClosePayAlert\"}"
}

7.3 SDK状态回调

SDK的各个状态切换和sever下发通知都会通过HmcpPlayerStatusCallback(String callback)接口通知应用,callback字符串是有 JSON 串转换的,格式如下:

{
    // 切换到的场景ID
    "status": "" , 
    // 扩展信息
    "data" {} , 
}

表7-3 状态说明

状态说明 status data
开始请求游戏 STATUS_PLAY_INTERNAL = 1
开始播流 STATUS_START_PLAY = 2
停止播放 STATUS_STOP_PLAY = 3
4g切换到wifi STATUS_TIPS_CHANGE_4G_TO_WIFI = 4
Wifi切换到4g STATUS_TIPS_CHANGE_WIFI_TO_4G = 5 配置的弹框话术
网络断开 STATUS_NETWORK_UNAVAILABLE = 6 配置的弹框话术
需要排队 STATUS_WAIT_CHOOSE = 7 返回数据参照多优先级用户排队参数增加说明
开始重新连接 STATUS_START_RECONNECTION = 8
重连失败 STATUS_CONNECTION_ERROR = 9 配置的弹框话术
排队人数过多 STATUS_OPERATION_REFUSE_QUEUE = 10 返回数据参照多优先级用户排队参数增加说明
无操作时间超过配置 STATUS_TOAST_NO_INPUT = 11 {“errorCode”:””,”errorCodeWithoutCid”:””,
“errorMessage”:””,”status”:””}
进入队列消息 STATUS_OPERATION_INTERVAL_TIME = 13 返回数据参照多优先级用户排队参数增加说明
获取流地址成功 STATUS_OPERATION_STREAM_URL = 14 {“currentNetType”:””,
“currentApkType”:””}
游戏时间到 STATUS_OPERATION_GAME_OVER = 15 {“errorMessage”:””,
“finishByServer”:””,
“finishTip”:””}
排队完成消息 STATUS_OPERATION_WAITING = 16 配置的弹框话术
服务准备维护 STATUS_OPERATION_READY_PAUSE_SAAS_SERVER=17 {“errorMessage”:””}
服务器开始维护 STATUS_OPERATION_PAUSE_SAAS_SERVER = 18 {“errorMessage”:””}
服务维护中 STATUS_OPERATION_PAUSED_SAAS_SERVER = 19 配置的弹框话术
切换分辨率 STATUS_SWITCH_RESOLUTION = 20 {“defaultChoiceId”:””,
“switchResolution”:””}
播放器创建失败 STATUS_MEDIAPLAYER_ERROR = 22
获取流地址超时 STATUS_TIME_OUT = 23 {“errorCode”:””,”errorCodeWithoutCid”:””,
“errorMessage”:””,”status”:””,”rootCause”}
Tocken过期服务终止 STATUS_OPERATION_FORCED_OFFLINE = 24 {“errorCode”:””,”errorCodeWithoutCid”:””,
“errorMessage”:””,”status”:””}
自动切换分辨率 TATUS_AUTO_SWITCH_RESOLUTION = 25 {“mCurrentSpeed”:””
“mMinResolutionLevel”:””}
测速结果低于服务下限 STATUS_SPEED_LOWER_BITRATE = 26 配置的弹框话术
游戏多开 STATUS_OPERATION_OPEN_MORE_SAME_GAME = 27 {“errorCode”:””,”errorCodeWithoutCid”:””,
“errorMessage”:””,”status”:””}
服务连接错误 STATUS_OPERATION_HMCP_ERROR = 29 {“errorCode”:””,”errorCodeWithoutCid”:””,
“errorMessage”:””,”status”:””}
游戏时长提示 STATUS_OPERATION_GAME_TIME_COUNT_DOWN = 30 {“ahead”: “”,
“countDown”: “”,
“formatter”: “”}
游戏内更新时长 STATUS_OPERATION_GAME_TIME_UPDATE = 31 {“tip”: “”}
游戏可玩时长提示 STATUS_OPERATION_GAME_TIME_HIGHLIGHT = 32 {“playingTime”: “”}
获取到sever配置信息 STATUS_RECEIVE_META_INFOS = 33
暂停播放 STATUS_PAUSE_PLAY = 35
(TV)菜单呼出 STATUS_SHOW_SETTING_VIEW = 101
第一帧动画到达 STATUS_FIRST_FRAME_ARRIVAL = 102
IDC信息 STATUS_IDCINFO=44 {“idcId”: “”,”idcName”: “”,”instanceTag”: “”,”instanceTagName”: “”}

表7-4 返回结果说明

返回结果 类型 说明
errorCode String 发生出错误的错误码
errorMessage String 发生错误的错误说明
errorCodeWithoutCid String 发生出错误的错误码(不包含”-cid”)
rootCause String 对应请求描述
status String 错误信息状态
currentNetType String 网络类型
currentApkType String 游戏池化状态
finishByServer String 游戏时长到,是否结束游戏(服务端配置)
finishTip String 游戏时长到状态说明
defaultChoiceId String 切换分辨率ID
switchResolution String 是否为自动切换
mCurrentSpeed String 当前网络速度
mMinResolutionLevel String 配置的最低播流速度
ahead String 游戏时长提示的剩余时长
countDown String 是否为倒计时,countDown == 1 为倒计时
formatter String 游戏时长提示说明
tip String 更新游戏时长说明
playingTime String 可玩游戏时长
stateChangeReason String 接入方通过openApi退出游戏时自定义原因

7.4 关键接口回调

接入方必须设置此接口来监听云游戏过程中的状态变化,HmcpPlayerListener监听类定义如下:

public interface HmcpPlayerListener {
    /**
      * 启动游戏失败
      *
      * @param errorType 错误的类型名:NETWORK_ERROR,OTHER
      * @param errorInfo 错误的消息
      */
    void onError(ErrorType type, String errorInfo);
    /**
     * 启动游戏成功
     */
    void onSuccess();
    /**
     * 游戏退出
     * 需要在该回调内调用finish()时,退出Activity
     */
    void onExitQueue();
    /**
     * SDK内消息通知,包括支付消息等
     *
     * @param message 消息内容
     */
    void onMessage(Message message);
      /**
     * SDK游戏过程中各状态发生变化时的回调
     * 
     * @param sceneMessage是JSON结构体,包含 sceneId 和 extraInfo{}。具体详细请参考“参数说明”中的“场景切换”章节。
     */
    void onSceneChanged(String sceneMessage);
      /**
     * 监听到网络变化后的通知
     * 
     * @param state 是enum类型,包含 ISWIFI, NOTWIFI, NO_NETWORK
     */
    void onNetworkChanged(NetWorkState state);
      /**
     * @param status:状态值,可为 0、1、2    
     * @param value:
     *                status=0,value是采样周期内接受到的视频帧的总大小,单位:Byte; 
     *                status=1,value是采样周期内,渲染帧的总数;
     *                status=2,value是采样周期内,平均解码耗时,单位是ms;
     *
     * @param data:附加信息,status=0,data为采样周期内最大的N帧大小,单位为Byte;status=其他,data无数据;
     */
    void onPlayStatus(int status, long value, String data);
      /**
     * 使用状态回调接口
     * 
     * @param callback 状态信息
     */
    void HmcpPlayerStatusCallback(String callback);
      /**
     * 上报错误信息回调接口
     * 
     * @param errorCode 错误码 
     * @param errorMsg  错误信息
     */
    void onPlayerError(String errorCode, String errorMsg);
      /**
     * 上报错误信息回调接口
     * 
     * @param errorCode 错误码
     * @param errorMsg  错误信息
     */
    void onInputMessage(String message);
      /**
     * 监听到输入设备变化的通知
     * 
     * @param device 设备类型
     * @param operationType 键盘类型
     */
    void onInputDevice(int device, int operationType);
    /**
     * 没有相关敏感权限时回调
     * 
     * @param permission 权限名称(如:Manifest.permission.RECORD_AUDIO)
     */
    void onPermissionNotGranted(String permission);
    /**
     * 云游戏中远端实例状态发生改变
     * 云游戏中分享、打开摄像头、打开系统相册、游戏内截图
     * 
     * @param status 状态信息,详情请参见“云游戏中远端实例状态通知”
     */
    void onCloudDeviceStatus(String status);
    /**
     * intent拦截回调
     * 
     * @param intentData 拦截数据内容,详情请参见“Intent拦截”
     */
    void onInterceptIntent(String intentData);
}

7.5 多优先级用户排队参数增加说明

SDK状态回调增加多优先级用户排队状态返回。

表7-5 状态说明

状态 status data
需要排队 STATUS_WAIT_CHOOSE=7 {“message”:“配置的弹框话术” “queues”:“队列消息”}
进入队列消息 STATUS_OPERATION_INTERVAL_TIME=13 {“message”:“配置的弹框话术” “queues”:“队列消息”}
排队人数过多 STATUS_OPERATION_REFUSE_QUEUE=10 {“message”:“配置的弹框话术” “queues”:“队列消息”}

其中具体数据格式为:

{
  "message": "配置的弹框话术",
  "queues": [{
       "rank": 1,
       "timeStr": "09分15秒",
       "time": "555",
       "index": 1,
       "priorities": [
         0,
         1
       ]
    },
    {
       "rank": 2,
       "timeStr": "09分15秒",
       "time": "555",
       "index": 1,
       "priorities": [
         2,
         3
       ]
    }
  ]
}

表7-6 返回值说明

返回值 类型 说明
message String 返回的配置的弹框话术
queues List 队列信息
rank int 队列等级
index int 排队人数
time String 预估时间,单位为s
timeStr String “09分15秒”格式字符串
priorities List 用户优先级列表,即配置的该等级队列中包含那些优先级的用户

7.6 清晰度信息ResolutionInfo类的定义

public class ResolutionInfo implements Serializable {
    // 清晰度信息ID
    public String ID; 
    // 清晰度名称
    public String name; 
    // 清晰度,形如<width>x<height>
    public String resolution; 
    // 峰值码率,单位KB/s
    public String peakBitRate;     
    // 码率,单位为bit/s,类型为long
    public String bitRate;     
    // 帧率,类型为Integer
    public int frameRate;     
    // 是否是默认选择
    public String defaultChoice; 
    // 是否开启
    public String close;         
    public final String choiced = "1";

    @Override
    public String toString() {
        return "ResolutionInfo{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", resolution='" + resolution + '\'' +
                ", peakBitRate='" + peakBitRate + '\'' +
                ", frameRate='" + frameRate + '\'' +
                ", bitRate=' " + bitRate + '\'' +
                ", defaultChoice='" + defaultChoice + '\'' +
                ", close='" + close + '\'' +
                '}';
    }
}
  1. 调用play()接口成功会有sceneId = “play” 的场景回调,此时可调用HmcpManager.getInstance().getResolutionDatas()得到游戏的清晰度列表。

  2. 调用hmcpVideoView.onSwitchRsolution()接口后也会有场景回调。

    • 收到sceneId = “crst”的场景回调,表示开始切换清晰度。

    • 收到scenedId = ”cred”的场景回调,表示切换清晰度完成。

    extraInfo.cur_rate表示切换成功后的码率peakBitRate。

    • extraInfo.result = 0表示切换失败。

    • extraInfo.result = 1表示切换成功。

另外如果开启了自动切换码率,网络卡顿时会收到sceneId = ”crtp”的场景回调,该场景回调下:

  • extraInfo.minimum=1表示当前为最低码率。
  • extraInfo.minimum=0表示当前不是最低码率,这种情况下启动切换码率后会收到 scenedId = ”cred”的场景回调,需要APP更新当前清晰度。

场景回调的参数详情请参见场景切换回调

7.7 TV键位映射配置格式

键位映射配置格式:

{"version": "2.0",
 "defaultMouseMode": false,
 "buttonMappingsList": [{
   "mappingName": "侍魂",
   "mapping": [
     {"buttonName": "buttonX","x": 0.66,"y": 0.87,"keyCode": 99},
     {"buttonName": "buttonY","x": 0.75,"y": 0.66,"keyCode": 100}, 
     {"buttonName": "buttonA","x": 0.81,"y": 0.87,"keyCode": 96}, 
     {"buttonName": "buttonB","x": 0.91,"y": 0.66,"keyCode": 97}, 
     {"buttonName": "trackBallL","x": 0.17,"y": 0.76,"rx": 0.12,"ry": 0.2,"keyCode": 999}, 
     {"buttonName": "buttonUp","x": 0.17,"y": 0.60,"keyCode": 997},
     {"buttonName": "buttonDown","x": 0.17,"y": 0.92,"keyCode": 996},
     {"buttonName": "buttonLeft","x": 0.05,"y": 0.76,"keyCode": 995},
     {"buttonName": "buttonRight","x": 0.25,"y": 0.76,"keyCode": 994},
     {"buttonName": "buttonL2","x": 0.09,"y": 0.17,"keyCode": 104},
     {"buttonName": "buttonR2","x": 0.91,"y": 0.17,"keyCode": 105},
     {"buttonName ": "buttonL1B","keyCode": 97,"fnKeyCode ": 102,
      "pointList": [
        {"x": 0.17,"y": 0.92,"keyType": 2,"runTime ": 100}, 
        {"x": 0.22,"y": 0.86,"keyType ": 2,"runTime": 100},
        {"x": 0.25,"y": 0.76,"keyType": 2,"runTime ": 100}, 
        {"x ": 0.66,"y ": 0.87,"keyType ": 2,"runtime": 100},
        {"x": 0.75,"y ": 0.66,"keyType ": 2,"runtime ": 0}
      ]},
     {"buttonName": "buttonL1X","keyCode": 99,"fnKeyCode": 102,
      "pointList":[
        {"x":0.31,"y":0.99,"keyType":1,"runTime":500},
        {"x":0.43,"y":0.95,"keyType":1,"runTime":500},
        {"x":0.43,"y":0.77,"keyType":0,"runtime":0}
      ]}, 
     {"buttonName ": "buttonL1A ","x": 0.31,"y": 0.99,"keyCode": 96,"fnKeyCode ": 102}, 
     {"buttonName ": "buttonR1A ","x": 0.91,"y": 0.17,"keyCode": 96,"fnKeyCode ": 103}
   ]}]
}

defaultMouseMode:是否默认为鼠标模式。

mappingName:配置名称。

各键位详细说明见获取键位映射数据接口

  • 增加 version 参数,用来标记配置文件版本,2.0适用组合键和滑屏连续动作,不配则适用原按键配置。

  • 增加 buttonName 参数,用来配置按键的名字,可以自行定义。

  • 组合功能键配置参数将不会生效,所以可以不用配置,例如buttonL1,可以不用配置。

  • fnKeyCode是组合键功能键标记,例如组合键为L1+A键组合,则将buttonL1A的keyCode属性配置为A键的keyCode,将buttonL1A的fnKeyCode属性配置为L1键的keyCode。

  • keyCode与键位是一一对应的,可以根据手柄实际KeyCode修改,Android标准键位keyCode对应如下:

    BUTTON_A = 96

    BUTTON_B = 97

    BUTTON_X = 99

    BUTTON_Y = 100

    BUTTON_L1 = 102

    BUTTON_R1 = 103

    BUTTON_L2 = 104

    BUTTON_R2 = 105

    十字键与摇杆为约定keycode不可修改:

    十字键上 = 997

    十字键下 = 996

    十字键左 = 995

    十字键右 = 994

    左摇杆 = 999

    右摇杆 = 998

    遥控器方向键模拟手柄摇杆 = 993,不支持组合功能,也不支持配置连续操作功能

  • 增加pointList参数,在按键为连续操作模式时配置,pointList中每一个对象都是一个点,其中

    x点在x轴坐标

    y点在y轴坐标

    keyType:点的操作类型,int类型参数,各数字代表含义为1:滑动、2:点击、0:结束

    runTime:从当前点动作开始到下一个点的时间设置(点击事件的按下持续时间不可设置,主要是设置滑动的动作时间)

  • 手柄映射遥控器配置增加toKeyCode字段,表示映射遥控器键位keyCode。

7.8 TV键位映射数据返回示例

映射数据示例:

{"KeymappingItem": 
 [{"mappingName":"张飞",
   "joyKeymappingList":[
     {"name":"buttonX", "x": 0.73, "y": 0.86 },
     {"name":"buttonY", "x": 0.78, "y": 0.68 },
     {"name":"buttonB", "x": 0.89, "y": 0.58 },
     {"name":"buttonA","x": 0.89, "y": 0.85},
     {"name":"buttonUp","x": 0.09, "y": 0.42},
     {"name":"buttonDown","x": 0.09, "y": 0.53},
     {"name":"buttonLeft", "x": 0.58, "y": 0.89 },
     {"name":"buttonRight", "x": 0.66, "y": 0.89 },
     {"name":"buttonL1","x": 0.68, "y": 0.78},
     {"name":"buttonL2","x": 0.74, "y": 0.61},
     {"name":"buttonR2","x": 0.84, "y": 0.48},
     {"name":"buttonR1","x": 0.97, "y": 0.15},
     {"name":"trackBallL","x": 0.12, "y": 0.79, "rx": 0.05, "ry": 0.09},
     {"name":"trackBallR","x": 0.12, "y": 0.79, "rx": 0.05, "ry": 0.09,"sp":0.00}
   ],
   "dpadKeymappingList":[
     {"name":"buttonNum0","x": 0.73, "y": 0.86},
     {"name":"buttonNum1","x": 0.78, "y": 0.68},
     {"name":"buttonNum2","x": 0.89, "y": 0.58},
     {"name":"buttonNum3","x": 0.89, "y": 0.85},
     {"name":"buttonNum4","x": 0.09, "y": 0.42},
     {"name":"buttonNum5","x": 0.09, "y": 0.53},
     {"name":"buttonNum6","x": 0.58, "y": 0.89},
     {"name":"buttonNum7","x": 0.66, "y": 0.89},
     {"name":"buttonNum8","x": 0.68, "y": 0.78},
     {"name":"buttonNum9","x": 0.74, "y": 0.61},
     {"name":"buttonDirection", "x": 0.12, "y": 0.79, "rx": 0.04, "ry": 0.07},
     {"name":"buttonCenter","x": 0.89, "y": 0.85}
   ]},
  {"mappingName":"赵云",
   "joyKeymappingList":[
     {"name":"buttonX", "x": 0.73, "y": 0.86 },
     {"name":"buttonY", "x": 0.78, "y": 0.68 }
   ]
  }],
"keyboardKeymappingList":
 [{"buttonName": "buttonY","x": 0.66,"y": 0.87,"keyCode": 89},
  {"buttonName": "buttonU","x": 0.75,"y": 0.66,"keyCode": 85}, 
  {"buttonName": "buttonI","x": 0.81,"y": 0.87,"keyCode": 73}, 
  {"buttonName": "buttonH","x": 0.91,"y": 0.66,"keyCode": 72},
  {"buttonName": "JoyPad","x": 0.17,"y": 0.76,"rx": 0.12,"ry": 0.2,"keyCode": 888}, 
  {"buttonName": "button1","x": 0.17,"y": 0.60,"keyCode": 49},
  {"buttonName": "button2","x": 0.17,"y": 0.92,"keyCode": 50},
  {"buttonName": "button3","x": 0.05,"y": 0.76,"keyCode": 51},
  {"buttonName": "button4","x": 0.25,"y": 0.76,"keyCode": 52},
  {"buttonName": "button5","x": 0.09,"y": 0.17,"keyCode": 53}]
}

其中KeymappingItem数据格式为:

class KeymappingItem {
  String mappingName;
    List<KeymappingButton> dpadKeymappingList;
    List<KeymappingButton> joyKeymappingList;
}

mappingName:一套键位配置的名字

dpadKeymappingList:遥控器键位配置信息

joyKeymappingList:手柄键位配置信息

keyboardKeymappingList :键盘键位配置信息

KeymappingButton :数据格式如下所示。

class KeymappingButton {
  /**
   * 键位名称
   */
    String name;
  /**
   * 屏幕 x 轴位置(0.00-1.00)
   */
    float x;
  /**
   * 屏幕 y 轴位置(0.00-1.00)
   */
    float y;
  /**
   * x 轴半径长度(手柄摇杆与遥控器方向键需要配置 0.00-1.00)
   */
    float rx;
  /**
   * y 轴半径长度(手柄摇杆与遥控器方向键需要配置0.00-1.00)
   */
    float ry;
  /**
   * 移动视野灵敏度配置(0.00-1.00配置为0则视为不操作视野移动,推荐为0.03左右)
   */
    float sp;
}

表7-7 键位名称说明

键位 说明
buttonX 手柄x键
buttonB 手柄b键
buttonA 手柄b键
buttonUp 手柄十字键上
buttonDown 手柄十字键下
buttonLeft 手柄十字键左
buttonRight 手柄十字键右
buttonL1 手柄L1键
buttonL2 手柄L2键
buttonR1 手柄R1键
buttonR2 手柄R2键
trackballR 手柄右摇杆
trackBallL 手柄左摇杆
buttonNum0 遥控器数字键 0
buttonNum1 遥控器数字键 1
buttonNum2 遥控器数字键 2
buttonNum3 遥控器数字键 3
buttonNum4 遥控器数字键 4
buttonNum5 遥控器数字键 5
buttonNum6 遥控器数字键 6
buttonNum7 遥控器数字键 7
buttonNum8 遥控器数字键 8
buttonNum9 遥控器数字键 9
buttonDirection 遥控器方向键
buttonCenter 遥控器确定键

注意

新版键位配置映射数据返回没有 dpadKeymappingList 字段。

8 注意事项

8.1 安卓6.0+系统需要申请权限

申请权限代码如下:

private void requestCloudSdkPermission() {
    if (Build.VERSION.SDK_INT >= 23 && 
        ContextCompat.checkSelfPermission(this,Manifest.permission.READ_PHONE_STATE) 
        != PackageManager.PERMISSION_GRANTED) {
      String[] mPermissionList = new String[]{Manifest.permission.READ_PHONE_STATE};
      ActivityCompat.requestPermissions(CloudPlayActivity.this, mPermissionList, 100);
    } else {
        // 不需要权限
    }
}

8.2 虚拟导航栏兼容性设置问题

部分存在虚拟导航栏的手机会存在点击游戏画面错位现象,需要设置虚拟导航栏兼容性代码,添加如下代码即可:

/**
** 设置VideoView的触摸监听事件
*/
hmcpVideoView.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        int eventAction = event.getAction();
        switch (eventAction) {
                // 按下动作
            case MotionEvent.ACTION_DOWN:
                Log.e("MainActivity", "down");
                hideNavigationBar();
                break;
                // 移动
            case MotionEvent.ACTION_MOVE:
                Log.e("MainActivity", "move");
                break;
                // 抬起动作
            case MotionEvent.ACTION_UP:
                Log.e("MainActivity", "up");
                break;
        }
        return false;
    }
});

其中依赖的方法如下:

/**
* 隐藏导航栏
*/
private void hideNavigationBar(){
    boolean isHas = hasNavigationBar(getApplicationContext());
    if (isHas) {
        // 此处需要根据系统版本做兼容处理
        if ((Build.VERSION.SDK_INT > Build.VERSION_CODES.HONEYCOMB)) {
            getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                    | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                    | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE);
        }
    }
}
/**
* 是否有底部导航条
*/
public static boolean hasNavigationBar(Context context) {
    boolean hasMenuKey = true, hasBackKey = true;
    boolean ret = false;
    try {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
            hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
            hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
        }
        if ((!hasMenuKey) && (!hasBackKey)) {
            ret = true;
        }
    } catch (Exception e) {
        ret = false;
    }
    return ret;
}

8.3 全屏沉浸式效果

推荐设置游戏界面为全屏沉浸式效果,在onCreate()方法中添加如下代码:

public static boolean setTranslucentStatus(Activity activity) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && 
    Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { 
        //4.4以上,状态栏透明
        activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        return true;
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        //5.0以上状态栏透明
        Window window = activity.getWindow();
        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
        window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
        window.setStatusBarColor(Color.TRANSPARENT);
        return true;
    }
    return false;
}

8.4 一个登录账号开启多个游戏的场景

登录账号在设置用户登录信息中已经提到设置方法,其设置的登录账号可以在一个终端上同时打开多个窗口或者同时在多个终端上打开多个窗口,但是打开窗口的个数有限制。该个数限制由海马云server配置。现在的限制如下:

  • 一个账号可以打开同一款游戏的个数限制为2。
  • 一个账号可以打开多款游戏的个数限制为5。

如果超过上限,游戏就不能正常开始,SDK会有相应的提示信息。

8.5 云游戏退出二次确认提示框设置

为了避免因为用户误操作点击手机Back按键导致的云游戏退出而增加云游戏二次退出确认信息,示例代码如下:

@Override
public boolean dispatchKeyEvent(KeyEvent event) {
    if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
        if (event.getAction() == KeyEvent.ACTION_DOWN) {
            final ExitDialog networkTipsDialog = new ExitDialog(this, R.style.CustomDialog);
            networkTipsDialog.onWindowFocusChanged(true);
            networkTipsDialog.show();
            networkTipsDialog.getSureBtn().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    networkTipsDialog.dismiss();
                    finish();
                }
            });
            networkTipsDialog.getCancelBtn().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    networkTipsDialog.dismiss();
                }
            });
        }
        return true;
    }
    return super.dispatchKeyEvent(event);
}

依赖相关代码如下:

ExitDialog.java

public class ExitDialog extends Dialog {

    private Button cancelBtn, sureBtn;
    public ExitDialog(Context context, int theme) {
        super(context, theme);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.exit_dialog);
        initView();
    }

    private void initView() {
        cancelBtn = (Button) findViewById(R.id.cancelBtn);
        sureBtn = (Button) findViewById(R.id.sureBtn);
    }

    public Button getCancelBtn() {
        return cancelBtn;
    }

    public Button getSureBtn() {
        return sureBtn;
    }

}

Layout目录中增加exit_dialog.xml。

代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@android:color/transparent">

    <LinearLayout
        android:layout_width="265dp"
        android:layout_height="132dp"
        android:layout_centerInParent="true"
        android:background="#f2f2f2"
        android:gravity="center_horizontal"
        android:orientation="vertical">

        <TextView
            android:id="@+id/content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center_horizontal|center_vertical"
            android:text="是否确认退出云游戏?"
            android:textColor="#666666"
            android:textSize="13sp" />

        <View
            android:layout_width="match_parent"
            android:layout_height="0.5dp"
            android:background="#dddddd" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_vertical"
            android:orientation="horizontal">

            <Button
                android:id="@+id/sureBtn"
                android:layout_width="match_parent"
                android:layout_height="44dp"
                android:layout_weight="1"
                android:background="@null"
                android:text="确认退出"
                android:textColor="#83b233"
                android:textSize="13sp" />

            <View
                android:id="@+id/splitView"
                android:layout_width="0.5dp"
                android:layout_height="21dp"
                android:background="#dddddd" />

            <Button
                android:id="@+id/cancelBtn"
                android:layout_width="match_parent"
                android:layout_height="44dp"
                android:layout_weight="1"
                android:background="@null"
                android:text="取消"
                android:textColor="#666666"
                android:textSize="13sp" />
        </LinearLayout>
    </LinearLayout>
</LinearLayout>

style.xml中增加自定义样式

代码如下:

<!-- dialog样式 -->
<style name="CustomDialog" parent="@android:style/Theme.Dialog">
    <item name="android:windowFrame">@null</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:backgroundDimAmount">0.6</item>
</style>

8.6 云游戏片头正常播放

为了保证云游戏片头正常播放,请将SDK初始化操作在应用application中进行初始化(application中初始化成功之后,在集成云玩activity中不需要再次进行初始化),如果初始化失败请再次初始化,应用Application示例代码如下:

HmcpManager manager = HmcpManager.getInstance();
manager.init(this, new OnInitCallBackListener() {
    @Override
    public void success() {        
      // 初始化SDK成功,可以云游戏
    }
    @Override
    public void fail(String s) {        
            // 初始化SDK失败,不能云游戏,如果初始化失败请尝试重新进行初始化
    }
});

8.7 保存上次使用的清晰度

记录用户上次使用的清晰度,下次使用该清晰度播流。

用户使用的清晰度会有场景切换的回调,详情请参见场景切换回调。回调传入的字符串中”cur_rate”表示当前使用的码率,单位为kB/s。在下次启动播流时把改值设置为HmcpVideoView.INTERNET_SPEED传入SDK即可用该码率波流。详情请参见申请服务

×

本篇文章对你是否有帮助?

更多建议

请输入您的建议