完成android端基本功能升级
This commit is contained in:
parent
062ceea091
commit
d9554f7571
@ -1,55 +0,0 @@
|
||||
package com.chuwa.cordova.trtc;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
|
||||
import com.tencent.trtc.videocall.VideoCallingEnterActivity;
|
||||
import com.tencent.trtc.videocall.VideoCallingActivity;
|
||||
|
||||
import org.apache.cordova.CordovaInterface;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.apache.cordova.CallbackContext;
|
||||
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
public class Trtc extends CordovaPlugin {
|
||||
|
||||
static final String ACTION_SHOW_CREATE_PAGE = "showCreatePage"; // for test
|
||||
static final String ACTION_JOIN_CHANNEL = "joinChannel";
|
||||
|
||||
@Override
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
Activity activity = this.cordova.getActivity();
|
||||
|
||||
// if (ACTION_SHOW_CREATE_PAGE.equals(action)) {
|
||||
// Intent intent = new Intent(activity, VideoCallingEnterActivity.class);
|
||||
// cordova.startActivityForResult(this, intent, 666);
|
||||
// } else
|
||||
if (ACTION_JOIN_CHANNEL.equals(action)) {
|
||||
Intent intent = new Intent(activity, VideoCallingActivity.class);
|
||||
JSONObject arg = args.getJSONObject(0);
|
||||
String ROOM_ID = arg.getString("ROOM_ID");
|
||||
String USER_ID = arg.getString("USER_ID");
|
||||
int SDK_APP_ID = arg.getInt("SDK_APP_ID");
|
||||
String USER_SIG = arg.getString("USER_SIG");
|
||||
intent.putExtra("room_id", ROOM_ID);
|
||||
intent.putExtra("user_id", USER_ID);
|
||||
intent.putExtra("sdk_app_id", SDK_APP_ID);
|
||||
intent.putExtra("user_sig", USER_SIG);
|
||||
cordova.startActivityForResult(this, intent, 666);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
||||
super.initialize(cordova, webView);
|
||||
}
|
||||
|
||||
|
||||
}
|
45
src/android/java/com/tencent/trtc/CordovaEventKit.java
Normal file
45
src/android/java/com/tencent/trtc/CordovaEventKit.java
Normal file
@ -0,0 +1,45 @@
|
||||
package com.tencent.trtc;
|
||||
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class CordovaEventKit {
|
||||
public static CordovaEventKit kit = null;
|
||||
private CordovaPlugin plugin;
|
||||
|
||||
|
||||
private CordovaEventKit(CordovaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public static void init(CordovaPlugin plugin){
|
||||
if(CordovaEventKit.kit == null){
|
||||
CordovaEventKit.kit = new CordovaEventKit(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void fireEvent(String event, JSONArray obj){
|
||||
this.fireEvent(event,obj == null ? null obj.toString());
|
||||
}
|
||||
|
||||
public void fireEvent(String event, JSONObject obj){
|
||||
this.fireEvent(event,obj == null ? null :obj.toString());
|
||||
}
|
||||
|
||||
public void fireEvent(String event, String obj){
|
||||
if (plugin == null || event == null || obj == null) {
|
||||
return;
|
||||
}
|
||||
event = event.replace('\'','_');
|
||||
String format = "window.cordova.plugin.trtc.fireEvent('%s',%s);";
|
||||
final String js = String.format(format,event, obj);
|
||||
plugin.cordova.getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
plugin.webView.loadUrl("javascript:" + js);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
132
src/android/java/com/tencent/trtc/CustomVideoView.java
Normal file
132
src/android/java/com/tencent/trtc/CustomVideoView.java
Normal file
@ -0,0 +1,132 @@
|
||||
package com.tencent.trtc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.tencent.rtmp.ui.TXCloudVideoView;
|
||||
import com.tencent.trtc.event.Events;
|
||||
import com.tencent.trtc.videocall.UserInfo;
|
||||
|
||||
public class CustomVideoView extends RelativeLayout {
|
||||
|
||||
private Context mContext;
|
||||
private View mView;
|
||||
|
||||
private TXCloudVideoView videoView;
|
||||
private TextView titleView;
|
||||
|
||||
private UserInfo userInfo;
|
||||
|
||||
private boolean alwaysHide = false;
|
||||
private boolean mainView;
|
||||
|
||||
|
||||
public CustomVideoView(Context context) {
|
||||
this(context,null);
|
||||
}
|
||||
|
||||
public CustomVideoView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs,0);
|
||||
}
|
||||
|
||||
public CustomVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
this(context, attrs, defStyleAttr,0);
|
||||
}
|
||||
|
||||
public CustomVideoView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
super(context, attrs, defStyleAttr, defStyleRes);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
mContext = context;
|
||||
LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
mView = inflater.inflate(getId("custom_video_view_layout", "layout"), this, true);
|
||||
videoView = (TXCloudVideoView) findViewById(getId("video", "id"));
|
||||
titleView = (TextView) findViewById(getId("title","id"));
|
||||
}
|
||||
|
||||
|
||||
private int getId(String idName, String type) {
|
||||
return getResources().getIdentifier(idName, type, mContext.getPackageName());
|
||||
}
|
||||
|
||||
public void changeUser(TRTCCloud mTRTCCloud, UserInfo userInfo) {
|
||||
if(userInfo == null){
|
||||
setVisibility(View.GONE);
|
||||
}else {
|
||||
setVisibility(alwaysHide?INVISIBLE:VISIBLE);
|
||||
}
|
||||
// if(this.userInfo != null){
|
||||
// if(this.userInfo.isLocal()){
|
||||
// mTRTCCloud.stopLocalPreview();
|
||||
// mTRTCCloud.stopLocalAudio();
|
||||
//// }else{
|
||||
//// mTRTCCloud.stopRemoteView(this.userInfo.getPersonid());
|
||||
// }
|
||||
// }
|
||||
if(isChanged(userInfo)){
|
||||
this.userInfo = userInfo;
|
||||
if(this.userInfo != null){
|
||||
if(this.userInfo.isLocal()){
|
||||
mTRTCCloud.startLocalPreview(userInfo.isFrontCamera(), videoView);
|
||||
mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_SPEECH);
|
||||
} else {
|
||||
mTRTCCloud.startRemoteView(this.userInfo.getPersonid(), TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_SMALL, videoView);
|
||||
}
|
||||
if(this.userInfo.getDisplayName() == null || this.userInfo.getDisplayName().length() == 0){
|
||||
this.titleView.setText(this.userInfo.getPersonid());
|
||||
}else {
|
||||
this.titleView.setText(this.userInfo.getDisplayName());
|
||||
}
|
||||
this.titleView.setVisibility(VISIBLE);
|
||||
}else {
|
||||
this.titleView.setVisibility(INVISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isChanged(UserInfo userInfo){
|
||||
return (this.userInfo == null && userInfo !=null) ||
|
||||
(this.userInfo != null && !this.userInfo.equals(userInfo));
|
||||
}
|
||||
|
||||
public boolean isAlwaysHide() {
|
||||
return alwaysHide;
|
||||
}
|
||||
|
||||
public CustomVideoView setAlwaysHide(boolean alwaysHide) {
|
||||
this.alwaysHide = alwaysHide;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isMainView() {
|
||||
return mainView;
|
||||
}
|
||||
|
||||
public CustomVideoView setMainView(boolean mainView) {
|
||||
this.mainView = mainView;
|
||||
if(!mainView){
|
||||
Events.addListener("subview.always.hide",(extra)->{
|
||||
this.alwaysHide = extra.getBoolean("alwaysHide",false);
|
||||
this.setVisibility(alwaysHide?INVISIBLE:VISIBLE);
|
||||
});
|
||||
}
|
||||
Events.addListener("userinfo.update",(extra -> {
|
||||
if(this.userInfo !=null && this.userInfo.getDisplayName() == null
|
||||
&& this.userInfo.getDisplayName().length() == 0
|
||||
&& extra.getString("personid").equals(this.userInfo.getPersonid())){
|
||||
this.titleView.setText(extra.getString("displayName",this.userInfo.getDisplayName()));
|
||||
}
|
||||
}));
|
||||
return this;
|
||||
}
|
||||
|
||||
public UserInfo getUserInfo() {
|
||||
return userInfo;
|
||||
}
|
||||
}
|
10
src/android/java/com/tencent/trtc/MessageObject.java
Normal file
10
src/android/java/com/tencent/trtc/MessageObject.java
Normal file
@ -0,0 +1,10 @@
|
||||
package com.tencent.trtc;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
public interface MessageObject {
|
||||
|
||||
String getEvent();
|
||||
|
||||
JSONObject toJson();
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package android.java.com.example.basic;
|
||||
package com.tencent.trtc;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
86
src/android/java/com/tencent/trtc/TrtcPlugin.java
Normal file
86
src/android/java/com/tencent/trtc/TrtcPlugin.java
Normal file
@ -0,0 +1,86 @@
|
||||
package com.tencent.trtc;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tencent.trtc.CordovaEventKit;
|
||||
import com.tencent.trtc.event.Events;
|
||||
import com.tencent.trtc.videocall.VideoCallingEnterActivity;
|
||||
import com.tencent.trtc.videocall.VideoCallingActivity;
|
||||
|
||||
import org.apache.cordova.CordovaInterface;
|
||||
import org.apache.cordova.CordovaPlugin;
|
||||
import org.apache.cordova.CallbackContext;
|
||||
|
||||
import org.apache.cordova.CordovaWebView;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
|
||||
public class TrtcPlugin extends CordovaPlugin {
|
||||
private static final String TAG = TrtcPlugin.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* 加入会议
|
||||
* @param args
|
||||
* @param callbackContext
|
||||
* @throws JSONException
|
||||
*/
|
||||
public void joinChannel(JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
Intent intent = new Intent(this.cordova.getActivity(), VideoCallingActivity.class);
|
||||
JSONObject arg = args.getJSONObject(0);
|
||||
String ROOM_ID = arg.getString("ROOM_ID");
|
||||
String USER_ID = arg.getString("USER_ID");
|
||||
int SDK_APP_ID = arg.getInt("SDK_APP_ID");
|
||||
String USER_SIG = arg.getString("USER_SIG");
|
||||
intent.putExtra("room_id", ROOM_ID);
|
||||
intent.putExtra("user_id", USER_ID);
|
||||
intent.putExtra("sdk_app_id", SDK_APP_ID);
|
||||
intent.putExtra("user_sig", USER_SIG);
|
||||
cordova.startActivityForResult(this, intent, 666);
|
||||
}
|
||||
|
||||
|
||||
public void userInfoChange(JSONArray args,CallbackContext callbackContext) throws JSONException{
|
||||
JSONObject object = args.getJSONObject(0);
|
||||
if(object != null){
|
||||
Events.fireEvent("userinfo.update",extra -> {
|
||||
try {
|
||||
extra.putString("personid",object.getString("personid"));
|
||||
extra.putString("displayName",object.getString("displayName"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
|
||||
cordova.getThreadPool().execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
Method method = TrtcPlugin.class.getDeclaredMethod(action, JSONArray.class, CallbackContext.class);
|
||||
method.invoke(TrtcPlugin.this, args, callbackContext);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, e.toString());
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
|
||||
super.initialize(cordova, webView);
|
||||
CordovaEventKit.init(this);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -1,280 +0,0 @@
|
||||
package com.tencent.trtc.debug;
|
||||
|
||||
|
||||
import android.util.Base64;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
import java.util.zip.Deflater;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
/**
|
||||
* Module: GenerateTestUserSig
|
||||
*
|
||||
* Function: 用于生成测试用的 UserSig,UserSig 是腾讯云为其云服务设计的一种安全保护签名。
|
||||
* 其计算方法是对 SDKAppID、UserID 和 EXPIRETIME 进行加密,加密算法为 HMAC-SHA256。
|
||||
*
|
||||
* Attention: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下:
|
||||
*
|
||||
* 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品,
|
||||
* 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。
|
||||
* 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。
|
||||
*
|
||||
* 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。
|
||||
* 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。
|
||||
*
|
||||
* Reference:https://cloud.tencent.com/document/product/647/17275#Server
|
||||
*/
|
||||
|
||||
/**
|
||||
* Module: GenerateTestUserSig
|
||||
*
|
||||
* Description: generates UserSig for testing. UserSig is a security signature designed by Tencent Cloud for its cloud services.
|
||||
* It is calculated based on `SDKAppID`, `UserID`, and `EXPIRETIME` using the HMAC-SHA256 encryption algorithm.
|
||||
*
|
||||
* Attention: do not use the code below in your commercial app. This is because:
|
||||
*
|
||||
* The code may be able to calculate UserSig correctly, but it is only for quick testing of the SDK’s basic features, not for commercial apps.
|
||||
* `SECRETKEY` in client code can be easily decompiled and reversed, especially on web.
|
||||
* Once your key is disclosed, attackers will be able to steal your Tencent Cloud traffic.
|
||||
*
|
||||
* The correct method is to deploy the `UserSig` calculation code and encryption key on your project server so that your app can request from your server a `UserSig` that is calculated whenever one is needed.
|
||||
* Given that it is more difficult to hack a server than a client app, server-end calculation can better protect your key.
|
||||
*
|
||||
* Reference: https://cloud.tencent.com/document/product/647/17275#Server
|
||||
*/
|
||||
public class GenerateTestUserSig {
|
||||
|
||||
/**
|
||||
* 配置为CDN发布、混流的域名
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Domain name for CDN publishing and stream mixing
|
||||
*/
|
||||
public static final String CDN_DOMAIN_NAME = "testuser";
|
||||
|
||||
/**
|
||||
* CDN发布功能 混流bizId
|
||||
*/
|
||||
|
||||
/**
|
||||
* `bizId` for CDN publishing and stream mixing
|
||||
*/
|
||||
public static final int BIZID = 111;
|
||||
|
||||
/**
|
||||
* CDN发布功能 混流appId
|
||||
*/
|
||||
|
||||
/**
|
||||
* `appId` for CDN publishing and stream mixing
|
||||
*/
|
||||
public static final int APPID = 111;
|
||||
|
||||
/**
|
||||
* 腾讯云 SDKAppId,需要替换为您自己账号下的 SDKAppId。
|
||||
*
|
||||
* 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ) 创建应用,即可看到 SDKAppId,
|
||||
* 它是腾讯云用于区分客户的唯一标识。
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tencent Cloud `SDKAppID`. Set it to the `SDKAppID` of your account.
|
||||
*
|
||||
* You can view your `SDKAppID` after creating an application in the [TRTC console](https://console.cloud.tencent.com/rav).
|
||||
* `SDKAppID` uniquely identifies a Tencent Cloud account.
|
||||
*/
|
||||
public static final int SDKAPPID = 1400593044;
|
||||
|
||||
/**
|
||||
* 签名过期时间,建议不要设置的过短
|
||||
* <p>
|
||||
* 时间单位:秒
|
||||
* 默认时间:7 x 24 x 60 x 60 = 604800 = 7 天
|
||||
*/
|
||||
|
||||
/**
|
||||
* Signature validity period, which should not be set too short
|
||||
* <p>
|
||||
* Unit: second
|
||||
* Default value: 604800 (7 days)
|
||||
*/
|
||||
private static final int EXPIRETIME = 604800;
|
||||
|
||||
|
||||
/**
|
||||
* 计算签名用的加密密钥,获取步骤如下:
|
||||
*
|
||||
* step1. 进入腾讯云实时音视频[控制台](https://console.cloud.tencent.com/rav ),如果还没有应用就创建一个,
|
||||
* step2. 单击应用信息,并进一步找到“快速上手”部分。
|
||||
* step3. 点击“复制密钥”按钮,复制密钥,请将其拷贝并复制到如下的变量中
|
||||
*
|
||||
* 注意:该方案仅适用于调试Demo,正式上线前请将 UserSig 计算代码和密钥迁移到您的后台服务器上,以避免加密密钥泄露导致的流量盗用。
|
||||
* 文档:https://cloud.tencent.com/document/product/647/17275#Server
|
||||
*/
|
||||
|
||||
/**
|
||||
* Follow the steps below to obtain the key required for UserSig calculation.
|
||||
*
|
||||
* Step 1. Log in to the [TRTC console](https://console.cloud.tencent.com/rav), and create an application if you don’t have one.
|
||||
* Step 2. Find your application, click “Application Info”, and click the “Quick Start” tab.
|
||||
* Step 3. Copy and paste the key to the code, as shown below.
|
||||
*
|
||||
* Note: this method is for testing only. Before commercial launch, please migrate the UserSig calculation code and key to your backend server to prevent key disclosure and traffic stealing.
|
||||
* Reference: https://cloud.tencent.com/document/product/647/17275#Server
|
||||
*/
|
||||
public static final String SECRETKEY = "f814a0480cfa95a3ffffd8891844f3cd36888166dbef5347303043744f247c06";
|
||||
|
||||
/**
|
||||
* 计算 UserSig 签名
|
||||
*
|
||||
* 函数内部使用 HMAC-SHA256 非对称加密算法,对 SDKAPPID、userId 和 EXPIRETIME 进行加密。
|
||||
*
|
||||
* @note: 请不要将如下代码发布到您的线上正式版本的 App 中,原因如下:
|
||||
*
|
||||
* 本文件中的代码虽然能够正确计算出 UserSig,但仅适合快速调通 SDK 的基本功能,不适合线上产品,
|
||||
* 这是因为客户端代码中的 SECRETKEY 很容易被反编译逆向破解,尤其是 Web 端的代码被破解的难度几乎为零。
|
||||
* 一旦您的密钥泄露,攻击者就可以计算出正确的 UserSig 来盗用您的腾讯云流量。
|
||||
*
|
||||
* 正确的做法是将 UserSig 的计算代码和加密密钥放在您的业务服务器上,然后由 App 按需向您的服务器获取实时算出的 UserSig。
|
||||
* 由于破解服务器的成本要高于破解客户端 App,所以服务器计算的方案能够更好地保护您的加密密钥。
|
||||
*
|
||||
* 文档:https://cloud.tencent.com/document/product/647/17275#Server
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculating UserSig
|
||||
*
|
||||
* The asymmetric encryption algorithm HMAC-SHA256 is used in the function to calculate UserSig based on `SDKAppID`, `UserID`, and `EXPIRETIME`.
|
||||
*
|
||||
* @note: do not use the code below in your commercial app. This is because:
|
||||
*
|
||||
* The code may be able to calculate UserSig correctly, but it is only for quick testing of the SDK’s basic features, not for commercial apps.
|
||||
* `SECRETKEY` in client code can be easily decompiled and reversed, especially on web.
|
||||
* Once your key is disclosed, attackers will be able to steal your Tencent Cloud traffic.
|
||||
*
|
||||
* The correct method is to deploy the `UserSig` calculation code on your project server so that your app can request from your server a `UserSig` that is calculated whenever one is needed.
|
||||
* Given that it is more difficult to hack a server than a client app, server-end calculation can better protect your key.
|
||||
*
|
||||
* Reference: https://cloud.tencent.com/document/product/647/17275#Server
|
||||
*/
|
||||
public static String genTestUserSig(String userId) {
|
||||
return GenTLSSignature(SDKAPPID, userId, EXPIRETIME, null, SECRETKEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 tls 票据
|
||||
*
|
||||
* @param sdkappid 应用的 appid
|
||||
* @param userId 用户 id
|
||||
* @param expire 有效期,单位是秒
|
||||
* @param userbuf 默认填写null
|
||||
* @param priKeyContent 生成 tls 票据使用的私钥内容
|
||||
* @return 如果出错,会返回为空,或者有异常打印,成功返回有效的票据
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generating a TLS Ticket
|
||||
*
|
||||
* @param sdkappid `appid` of your application
|
||||
* @param userId User ID
|
||||
* @param expire Validity period, in seconds
|
||||
* @param userbuf `null` by default
|
||||
* @param priKeyContent Private key required for generating a TLS ticket
|
||||
* @return If an error occurs, an empty string will be returned or exceptions printed. If the operation succeeds, a valid ticket will be returned.
|
||||
*/
|
||||
private static String GenTLSSignature(long sdkappid, String userId, long expire, byte[] userbuf, String priKeyContent) {
|
||||
long currTime = System.currentTimeMillis() / 1000;
|
||||
JSONObject sigDoc = new JSONObject();
|
||||
try {
|
||||
sigDoc.put("TLS.ver", "2.0");
|
||||
sigDoc.put("TLS.identifier", userId);
|
||||
sigDoc.put("TLS.sdkappid", sdkappid);
|
||||
sigDoc.put("TLS.expire", expire);
|
||||
sigDoc.put("TLS.time", currTime);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
String base64UserBuf = null;
|
||||
if (null != userbuf) {
|
||||
base64UserBuf = Base64.encodeToString(userbuf, Base64.NO_WRAP);
|
||||
try {
|
||||
sigDoc.put("TLS.userbuf", base64UserBuf);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
String sig = hmacsha256(sdkappid, userId, currTime, expire, priKeyContent, base64UserBuf);
|
||||
if (sig.length() == 0) {
|
||||
return "";
|
||||
}
|
||||
try {
|
||||
sigDoc.put("TLS.sig", sig);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Deflater compressor = new Deflater();
|
||||
compressor.setInput(sigDoc.toString().getBytes(Charset.forName("UTF-8")));
|
||||
compressor.finish();
|
||||
byte[] compressedBytes = new byte[2048];
|
||||
int compressedBytesLength = compressor.deflate(compressedBytes);
|
||||
compressor.end();
|
||||
return new String(base64EncodeUrl(Arrays.copyOfRange(compressedBytes, 0, compressedBytesLength)));
|
||||
}
|
||||
|
||||
|
||||
private static String hmacsha256(long sdkappid, String userId, long currTime, long expire, String priKeyContent, String base64Userbuf) {
|
||||
String contentToBeSigned = "TLS.identifier:" + userId + "\n"
|
||||
+ "TLS.sdkappid:" + sdkappid + "\n"
|
||||
+ "TLS.time:" + currTime + "\n"
|
||||
+ "TLS.expire:" + expire + "\n";
|
||||
if (null != base64Userbuf) {
|
||||
contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
|
||||
}
|
||||
try {
|
||||
byte[] byteKey = priKeyContent.getBytes("UTF-8");
|
||||
Mac hmac = Mac.getInstance("HmacSHA256");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
|
||||
hmac.init(keySpec);
|
||||
byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes("UTF-8"));
|
||||
return new String(Base64.encode(byteSig, Base64.NO_WRAP));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
return "";
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
return "";
|
||||
} catch (InvalidKeyException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] base64EncodeUrl(byte[] input) {
|
||||
byte[] base64 = new String(Base64.encode(input, Base64.NO_WRAP)).getBytes();
|
||||
for (int i = 0; i < base64.length; ++i)
|
||||
switch (base64[i]) {
|
||||
case '+':
|
||||
base64[i] = '*';
|
||||
break;
|
||||
case '/':
|
||||
base64[i] = '-';
|
||||
break;
|
||||
case '=':
|
||||
base64[i] = '_';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return base64;
|
||||
}
|
||||
|
||||
}
|
54
src/android/java/com/tencent/trtc/event/Events.java
Normal file
54
src/android/java/com/tencent/trtc/event/Events.java
Normal file
@ -0,0 +1,54 @@
|
||||
package com.tencent.trtc.event;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.json.JSONException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class Events {
|
||||
private static final String PREFIX = "com.tencent.trtc.event";
|
||||
private static Map<String, List<Listener>> events = new HashMap();
|
||||
public static void fireEvent(String event){
|
||||
fireEvent(event,null);
|
||||
}
|
||||
public static void fireEvent(String event, Extra extra){
|
||||
if(events.containsKey(PREFIX+event)){
|
||||
for(Listener listener : events.get(PREFIX+event)){
|
||||
Bundle bundle = extra == null ? Bundle.EMPTY: new Bundle();
|
||||
if(extra != null){
|
||||
extra.extra(bundle);
|
||||
}
|
||||
listener.on(extra == null ? Bundle.EMPTY : bundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void addListener(String eventName,Listener listener){
|
||||
if(!events.containsKey(PREFIX+eventName)){
|
||||
events.put(PREFIX+eventName,new ArrayList<>());
|
||||
}
|
||||
List<Listener> list = events.get(PREFIX+eventName);
|
||||
if(!list.contains(listener)){
|
||||
list.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeListener(String eventName,Listener listener){
|
||||
if(!events.containsKey(PREFIX+eventName)){
|
||||
events.put(PREFIX+eventName,new ArrayList<>());
|
||||
}
|
||||
List<Listener> list = events.get(PREFIX+eventName);
|
||||
if(list.contains(listener)){
|
||||
list.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface Extra{
|
||||
public void extra(Bundle extra);
|
||||
}
|
||||
}
|
7
src/android/java/com/tencent/trtc/event/Listener.java
Normal file
7
src/android/java/com/tencent/trtc/event/Listener.java
Normal file
@ -0,0 +1,7 @@
|
||||
package com.tencent.trtc.event;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
public interface Listener {
|
||||
void on(Bundle extra);
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.tencent.trtc.message;
|
||||
|
||||
import com.tencent.trtc.MessageObject;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class LayoutChangeMessage implements MessageObject {
|
||||
|
||||
private String room;
|
||||
private String personid;
|
||||
|
||||
|
||||
public LayoutChangeMessage(String room, String personid) {
|
||||
this.room = room;
|
||||
this.personid = personid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEvent() {
|
||||
return "LayoutChangeMessage";
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getJson() {
|
||||
JSONObject obj = new JSONObject();
|
||||
return obj;
|
||||
}
|
||||
}
|
@ -1,193 +0,0 @@
|
||||
package com.tencent.trtc.videocall;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
/**
|
||||
* 悬浮球,点击可以弹出菜单
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public class FloatingView extends FrameLayout implements GestureDetector.OnGestureListener {
|
||||
|
||||
private Context mContext;
|
||||
private WindowManager mWindowManager;
|
||||
private GestureDetector mGestureDetector;
|
||||
private WindowManager.LayoutParams mLayoutParams;
|
||||
private float mLastX;
|
||||
private float mLastY;
|
||||
private PopupWindow mPopupWindow;
|
||||
private long mTapOutsideTime;
|
||||
private boolean mIsShowing = false;
|
||||
|
||||
public FloatingView(Context context) {
|
||||
super(context);
|
||||
this.mContext = context;
|
||||
this.mGestureDetector = new GestureDetector(context, this);
|
||||
}
|
||||
|
||||
public FloatingView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
this.mContext = context;
|
||||
this.mGestureDetector = new GestureDetector(context, this);
|
||||
}
|
||||
|
||||
public FloatingView(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
this.mContext = context;
|
||||
this.mGestureDetector = new GestureDetector(context, this);
|
||||
}
|
||||
|
||||
public FloatingView(Context context, int viewResId) {
|
||||
super(context);
|
||||
this.mContext = context;
|
||||
View.inflate(context, viewResId, this);
|
||||
this.mGestureDetector = new GestureDetector(context, this);
|
||||
}
|
||||
|
||||
public void showView(View view) {
|
||||
showView(view, WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
public void showView(View view, int width, int height) {
|
||||
mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
|
||||
int type = WindowManager.LayoutParams.TYPE_TOAST;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
|
||||
} else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
|
||||
type = WindowManager.LayoutParams.TYPE_PHONE;
|
||||
}
|
||||
mLayoutParams = new WindowManager.LayoutParams(type);
|
||||
mLayoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
mLayoutParams.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
|
||||
mLayoutParams.width = width;
|
||||
mLayoutParams.height = height;
|
||||
mLayoutParams.format = PixelFormat.TRANSLUCENT;
|
||||
mWindowManager.addView(view, mLayoutParams);
|
||||
}
|
||||
|
||||
public void hideView() {
|
||||
if (null != mWindowManager) {
|
||||
mWindowManager.removeViewImmediate(this);
|
||||
}
|
||||
mWindowManager = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
return mGestureDetector.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent e) {
|
||||
mLastX = e.getRawX();
|
||||
mLastY = e.getRawY();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShowPress(MotionEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
float nowX, nowY, tranX, tranY;
|
||||
nowX = e2.getRawX();
|
||||
nowY = e2.getRawY();
|
||||
tranX = nowX - mLastX;
|
||||
tranY = nowY - mLastY;
|
||||
mLayoutParams.x += tranX;
|
||||
mLayoutParams.y += tranY;
|
||||
mWindowManager.updateViewLayout(this, mLayoutParams);
|
||||
mLastX = nowX;
|
||||
mLastY = nowY;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLongPress(MotionEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setPopupWindow(int id) {
|
||||
mPopupWindow = new PopupWindow(this);
|
||||
mPopupWindow.setWidth(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mPopupWindow.setHeight(ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
mPopupWindow.setTouchable(true);
|
||||
mPopupWindow.setOutsideTouchable(true);
|
||||
mPopupWindow.setFocusable(false);
|
||||
mPopupWindow.setBackgroundDrawable(new BitmapDrawable());
|
||||
mPopupWindow.setContentView(LayoutInflater.from(getContext()).inflate(id, null));
|
||||
mPopupWindow.setTouchInterceptor(new OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
|
||||
mPopupWindow.dismiss();
|
||||
mTapOutsideTime = System.currentTimeMillis();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public View getPopupView() {
|
||||
return mPopupWindow.getContentView();
|
||||
}
|
||||
|
||||
public void setOnPopupItemClickListener(OnClickListener listener) {
|
||||
if (mPopupWindow == null)
|
||||
return;
|
||||
|
||||
ViewGroup layout = (ViewGroup) mPopupWindow.getContentView();
|
||||
for (int i = 0; i < layout.getChildCount(); i++) {
|
||||
layout.getChildAt(i).setOnClickListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (!mIsShowing) {
|
||||
showView(this);
|
||||
}
|
||||
mIsShowing = true;
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
if (mIsShowing) {
|
||||
hideView();
|
||||
}
|
||||
mIsShowing = false;
|
||||
ViewGroup layout = (ViewGroup) mPopupWindow.getContentView();
|
||||
for (int i = 0; i < layout.getChildCount(); i++) {
|
||||
layout.getChildAt(i).setOnClickListener(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSingleTapUp(MotionEvent e) {
|
||||
if (null != mPopupWindow)
|
||||
mPopupWindow.dismiss();
|
||||
if (!(System.currentTimeMillis() - mTapOutsideTime < 80)) {
|
||||
mPopupWindow.showAtLocation(this, Gravity.NO_GRAVITY, 100, 0);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
67
src/android/java/com/tencent/trtc/videocall/UserInfo.java
Normal file
67
src/android/java/com/tencent/trtc/videocall/UserInfo.java
Normal file
@ -0,0 +1,67 @@
|
||||
package com.tencent.trtc.videocall;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class UserInfo {
|
||||
String personid;
|
||||
String displayName;
|
||||
boolean isLocal;
|
||||
|
||||
boolean frontCamera = true;
|
||||
|
||||
public String getPersonid() {
|
||||
return personid;
|
||||
}
|
||||
|
||||
public UserInfo setPersonid(String personid) {
|
||||
this.personid = personid;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public UserInfo setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isLocal() {
|
||||
return isLocal;
|
||||
}
|
||||
|
||||
public UserInfo setLocal(boolean local) {
|
||||
isLocal = local;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isFrontCamera() {
|
||||
return frontCamera;
|
||||
}
|
||||
|
||||
public UserInfo setFrontCamera(boolean frontCamera) {
|
||||
this.frontCamera = frontCamera;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getPersonid().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if(obj == null){
|
||||
return false;
|
||||
}
|
||||
if(obj instanceof UserInfo){
|
||||
return getPersonid() == null ? ((UserInfo) obj).getPersonid() == null
|
||||
: getPersonid().equals(((UserInfo) obj).getPersonid());
|
||||
}else if(obj instanceof String){
|
||||
return getPersonid() == null ? obj == null : getPersonid().equals(obj);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,31 +1,31 @@
|
||||
package com.tencent.trtc.videocall;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import android.java.com.example.basic.TRTCBaseActivity;
|
||||
import com.tencent.trtc.CordovaEventKit;
|
||||
import com.tencent.trtc.CustomVideoView;
|
||||
import com.tencent.trtc.TRTCBaseActivity;
|
||||
|
||||
import com.tencent.liteav.TXLiteAVCode;
|
||||
import com.tencent.liteav.device.TXDeviceManager;
|
||||
import com.tencent.rtmp.ui.TXCloudVideoView;
|
||||
import com.tencent.trtc.TRTCCloud;
|
||||
import com.tencent.trtc.TRTCCloudDef;
|
||||
import com.tencent.trtc.TRTCCloudListener;
|
||||
import com.tencent.trtc.debug.Constant;
|
||||
import com.tencent.trtc.event.Events;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@ -61,7 +61,7 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
private static final int OVERLAY_PERMISSION_REQ_CODE = 1234;
|
||||
|
||||
private TextView mTextTitle;
|
||||
private TXCloudVideoView mTXCVVLocalPreviewView;
|
||||
// private CustomVideoView mTXCVVLocalPreviewView;
|
||||
private ImageView mImageBack;
|
||||
private ImageView mButtonMuteVideo;
|
||||
private ImageView mButtonMuteAudio;
|
||||
@ -71,15 +71,17 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
private TRTCCloud mTRTCCloud;
|
||||
private TXDeviceManager mTXDeviceManager;
|
||||
private boolean mIsFrontCamera = true;
|
||||
private List<String> mRemoteUidList;
|
||||
private List<TXCloudVideoView> mRemoteViewList;
|
||||
private List<UserInfo> mUserList;
|
||||
private List<CustomVideoView> mRemoteViewList;
|
||||
private int mUserCount = 0;
|
||||
private String mRoomId;
|
||||
private String mUserId;
|
||||
private int sdkAppId;
|
||||
private String userSig;
|
||||
private boolean hideSub;
|
||||
private boolean mAudioRouteFlag = true;
|
||||
private FloatingView mFloatingView;
|
||||
|
||||
private UserInfo localUserInfo;
|
||||
|
||||
private int getId(String idName, String type) {
|
||||
return getResources().getIdentifier(idName, type, getPackageName());
|
||||
@ -127,7 +129,6 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
// R.id.iv_back
|
||||
mImageBack = findViewById(getId("iv_back", "id"));
|
||||
// R.id.txcvv_main
|
||||
mTXCVVLocalPreviewView = findViewById(getId("txcvv_main", "id"));
|
||||
// R.id.btn_mute_video
|
||||
mButtonMuteVideo = findViewById(getId("btn_mute_video", "id"));
|
||||
// R.id.btn_mute_audio
|
||||
@ -146,21 +147,45 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
mButtonSwitchCamera.setOnClickListener(this);
|
||||
mButtonAudioRoute.setOnClickListener(this);
|
||||
|
||||
mRemoteUidList = new ArrayList<>();
|
||||
mUserList = new ArrayList<>();
|
||||
localUserInfo = new UserInfo().setPersonid(mUserId).setLocal(true)
|
||||
.setDisplayName("我").setFrontCamera(mIsFrontCamera);
|
||||
mUserList.add(localUserInfo);
|
||||
mRemoteViewList = new ArrayList<>();
|
||||
// R.id.trtc_view_1
|
||||
mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_1", "id")));
|
||||
mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_2", "id")));
|
||||
mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_3", "id")));
|
||||
mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_4", "id")));
|
||||
mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_5", "id")));
|
||||
mRemoteViewList.add((TXCloudVideoView) findViewById(getId("trtc_view_6", "id")));
|
||||
for(int i=0;i<7;i++){
|
||||
CustomVideoView videoView = ((CustomVideoView) findViewById(getId("trtc_view_"+i, "id"))).setMainView(i == 0);
|
||||
if(i > 0){
|
||||
videoView.setOnClickListener((view)->{
|
||||
if(view instanceof CustomVideoView && !((CustomVideoView) view).isMainView()){
|
||||
UserInfo mainUser = this.mUserList.get(0);
|
||||
UserInfo viewUser = ((CustomVideoView) view).getUserInfo();
|
||||
Collections.swap(this.mUserList,0,this.mUserList.indexOf(viewUser));
|
||||
mTRTCCloud.stopLocalPreview();
|
||||
mTRTCCloud.stopLocalAudio();
|
||||
mRemoteViewList.get(0).changeUser(mTRTCCloud,viewUser);
|
||||
((CustomVideoView) view).changeUser(mTRTCCloud,mainUser);
|
||||
try {
|
||||
JSONObject object = new JSONObject();
|
||||
object.put("room",mRoomId);
|
||||
object.put("personid",viewUser.getPersonid());
|
||||
CordovaEventKit.kit.fireEvent("LayoutChangeMessage",object);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
mRemoteViewList.add(videoView);
|
||||
}
|
||||
Events.fireEvent("subview.always.hide",(extra)->extra.putBoolean("alwaysHide",false));
|
||||
|
||||
// R.layout.videocall_view_floating_default
|
||||
mFloatingView = new FloatingView(getApplicationContext(), getId("videocall_view_floating_default", "layout"));
|
||||
// R.layout.videocall_popup_layout
|
||||
mFloatingView.setPopupWindow(getId("videocall_popup_layout", "layout"));
|
||||
mFloatingView.setOnPopupItemClickListener(this);
|
||||
Events.addListener("userinfo.update",(extra -> {
|
||||
String user = extra.getString("personid");
|
||||
int index = this.mUserList.indexOf(user);
|
||||
if(index > -1){
|
||||
this.mUserList.get(index).setDisplayName(extra.getString("displayName"));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private void enterRoom() {
|
||||
@ -174,23 +199,26 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
trtcParams.roomId = Integer.parseInt(mRoomId);
|
||||
trtcParams.userSig = this.userSig;
|
||||
|
||||
mTRTCCloud.startLocalPreview(mIsFrontCamera, mTXCVVLocalPreviewView);
|
||||
mTRTCCloud.startLocalAudio(TRTCCloudDef.TRTC_AUDIO_QUALITY_SPEECH);
|
||||
mRemoteViewList.get(0).changeUser(mTRTCCloud, mUserList.get(0));
|
||||
mTRTCCloud.enterRoom(trtcParams, TRTCCloudDef.TRTC_APP_SCENE_VIDEOCALL);
|
||||
JSONObject object = new JSONObject();
|
||||
try {
|
||||
object.put("room",mRoomId);
|
||||
object.put("personid",mUserList.get(0).getPersonid());
|
||||
CordovaEventKit.kit.fireEvent("LayoutChangeMessage",object);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
requestDrawOverLays();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
if (mFloatingView != null && mFloatingView.isShown()) {
|
||||
mFloatingView.dismiss();
|
||||
}
|
||||
exitRoom();
|
||||
}
|
||||
|
||||
@ -208,9 +236,6 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
if (mFloatingView != null && mFloatingView.isShown()) {
|
||||
mFloatingView.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -232,58 +257,21 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
switchCamera();
|
||||
} else if (id == getId("btn_audio_route", "id")) {
|
||||
audioRoute();
|
||||
} else if (id == getId("iv_return", "id")) {
|
||||
floatViewClick();
|
||||
}
|
||||
}
|
||||
|
||||
private void floatViewClick() {
|
||||
Intent intent = new Intent(this, VideoCallingActivity.class);
|
||||
if (intent != null) {
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
}
|
||||
try {
|
||||
startActivity(intent);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void muteVideo() {
|
||||
boolean isSelected = mButtonMuteVideo.isSelected();
|
||||
if (!isSelected) {
|
||||
mButtonMuteVideo.setImageDrawable(getDrawable(getId("view_open", "mipmap")));
|
||||
closeRemoteVideoViews();
|
||||
} else {
|
||||
mButtonMuteVideo.setImageDrawable(getDrawable(getId("view_close", "mipmap")));
|
||||
refreshRemoteVideoViews();
|
||||
}
|
||||
Events.fireEvent("subview.always.hide",(extra)->extra.putBoolean("alwaysHide",!isSelected));
|
||||
mButtonMuteVideo.setSelected(!isSelected);
|
||||
}
|
||||
|
||||
|
||||
private void closeRemoteVideoViews() {
|
||||
for (int i = 0; i < mRemoteViewList.size(); i++) {
|
||||
if (i < mRemoteUidList.size()) {
|
||||
mRemoteViewList.get(i).setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
mRemoteViewList.get(i).setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshRemoteVideoViews() {
|
||||
for (int i = 0; i < mRemoteViewList.size(); i++) {
|
||||
if (i < mRemoteUidList.size()) {
|
||||
String remoteUid = mRemoteUidList.get(i);
|
||||
mRemoteViewList.get(i).setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
mRemoteViewList.get(i).setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void muteAudio() {
|
||||
boolean isSelected = mButtonMuteAudio.isSelected();
|
||||
if (!isSelected) {
|
||||
@ -298,6 +286,7 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
|
||||
private void switchCamera() {
|
||||
mIsFrontCamera = !mIsFrontCamera;
|
||||
localUserInfo.setFrontCamera(mIsFrontCamera);
|
||||
mTXDeviceManager.switchCamera(mIsFrontCamera);
|
||||
}
|
||||
|
||||
@ -313,6 +302,17 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshRemoteVideoViews() {
|
||||
for (int i = 0; i < mRemoteViewList.size(); i++) {
|
||||
if (i < mUserList.size()) {
|
||||
UserInfo user = mUserList.get(i);
|
||||
mRemoteViewList.get(i).changeUser(mTRTCCloud,user);
|
||||
} else {
|
||||
mRemoteViewList.get(i).changeUser(mTRTCCloud,null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TRTCCloudImplListener extends TRTCCloudListener {
|
||||
|
||||
private WeakReference<VideoCallingActivity> mContext;
|
||||
@ -325,19 +325,20 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
@Override
|
||||
public void onUserVideoAvailable(String userId, boolean available) {
|
||||
Log.d(TAG, "onUserVideoAvailable userId " + userId + ", mUserCount " + mUserCount + ",available " + available);
|
||||
int index = mRemoteUidList.indexOf(userId);
|
||||
UserInfo info = new UserInfo().setPersonid(userId);
|
||||
int index = mUserList.indexOf(info);
|
||||
if (available) {
|
||||
if (index != -1) {
|
||||
return;
|
||||
}
|
||||
mRemoteUidList.add(userId);
|
||||
mUserList.add(info);
|
||||
refreshRemoteVideoViews();
|
||||
} else {
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
mTRTCCloud.stopRemoteView(userId);
|
||||
mRemoteUidList.remove(index);
|
||||
mUserList.remove(index);
|
||||
refreshRemoteVideoViews();
|
||||
}
|
||||
|
||||
@ -345,12 +346,11 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
|
||||
private void refreshRemoteVideoViews() {
|
||||
for (int i = 0; i < mRemoteViewList.size(); i++) {
|
||||
if (i < mRemoteUidList.size()) {
|
||||
String remoteUid = mRemoteUidList.get(i);
|
||||
mRemoteViewList.get(i).setVisibility(View.VISIBLE);
|
||||
mTRTCCloud.startRemoteView(remoteUid, TRTCCloudDef.TRTC_VIDEO_STREAM_TYPE_SMALL, mRemoteViewList.get(i));
|
||||
if (i < mUserList.size()) {
|
||||
UserInfo user = mUserList.get(i);
|
||||
mRemoteViewList.get(i).changeUser(mTRTCCloud,user);
|
||||
} else {
|
||||
mRemoteViewList.get(i).setVisibility(View.GONE);
|
||||
mRemoteViewList.get(i).changeUser(mTRTCCloud,null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -377,21 +377,4 @@ public class VideoCallingActivity extends TRTCBaseActivity implements View.OnCli
|
||||
|
||||
}
|
||||
|
||||
public void requestDrawOverLays() {
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N && !Settings.canDrawOverlays(VideoCallingActivity.this)) {
|
||||
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + VideoCallingActivity.this.getPackageName()));
|
||||
startActivityForResult(intent, OVERLAY_PERMISSION_REQ_CODE);
|
||||
} else {
|
||||
showFloatingView();
|
||||
}
|
||||
}
|
||||
|
||||
private void showFloatingView() {
|
||||
if (mFloatingView != null && !mFloatingView.isShown()) {
|
||||
if ((null != mTRTCCloud)) {
|
||||
mFloatingView.show();
|
||||
mFloatingView.setOnPopupItemClickListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
24
src/android/res/layout/custom_video_view_layout.xml
Normal file
24
src/android/res/layout/custom_video_view_layout.xml
Normal file
@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.tencent.rtmp.ui.TXCloudVideoView
|
||||
android:id="@+id/video"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/video"
|
||||
android:textColor="#ffffff"
|
||||
android:background="@color/colorPrimaryDark"
|
||||
android:paddingTop="1dp"
|
||||
android:paddingBottom="1dp"
|
||||
android:paddingLeft="5dp"
|
||||
android:paddingRight="5dp"
|
||||
android:textAlignment="center"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
</RelativeLayout>
|
@ -5,11 +5,11 @@
|
||||
android:background="@color/rl_main_bg">
|
||||
|
||||
|
||||
<com.tencent.rtmp.ui.TXCloudVideoView
|
||||
android:id="@+id/txcvv_main"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="72dp" />
|
||||
<com.tencent.trtc.CustomVideoView
|
||||
android:id="@+id/trtc_view_0"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginBottom="72dp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
@ -38,58 +38,58 @@
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<com.tencent.rtmp.ui.TXCloudVideoView
|
||||
android:id="@+id/trtc_view_1"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="70dp"
|
||||
android:layout_marginRight="15dp"/>
|
||||
<com.tencent.trtc.CustomVideoView
|
||||
android:id="@+id/trtc_view_1"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="70dp"
|
||||
android:layout_marginRight="15dp" />
|
||||
|
||||
<com.tencent.rtmp.ui.TXCloudVideoView
|
||||
android:id="@+id/trtc_view_2"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_below="@id/trtc_view_1"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginTop="10dp"/>
|
||||
<com.tencent.trtc.CustomVideoView
|
||||
android:id="@+id/trtc_view_2"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_below="@id/trtc_view_1"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginTop="10dp"/>
|
||||
|
||||
<com.tencent.rtmp.ui.TXCloudVideoView
|
||||
android:id="@+id/trtc_view_3"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_below="@id/trtc_view_2"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="15dp"
|
||||
android:layout_marginTop="10dp"/>
|
||||
<com.tencent.trtc.CustomVideoView
|
||||
android:id="@+id/trtc_view_3"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_below="@id/trtc_view_2"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginRight="15dp" />
|
||||
|
||||
|
||||
<com.tencent.rtmp.ui.TXCloudVideoView
|
||||
android:id="@+id/trtc_view_4"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignTop="@+id/trtc_view_3"
|
||||
android:layout_marginLeft="15dp"/>
|
||||
<com.tencent.trtc.CustomVideoView
|
||||
android:id="@+id/trtc_view_4"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignTop="@+id/trtc_view_3"
|
||||
android:layout_marginLeft="15dp"/>
|
||||
|
||||
|
||||
<com.tencent.rtmp.ui.TXCloudVideoView
|
||||
android:id="@+id/trtc_view_5"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignTop="@+id/trtc_view_2"
|
||||
android:layout_marginLeft="15dp"/>
|
||||
<com.tencent.trtc.CustomVideoView
|
||||
android:id="@+id/trtc_view_5"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignTop="@+id/trtc_view_2"
|
||||
android:layout_marginLeft="15dp"/>
|
||||
|
||||
|
||||
<com.tencent.rtmp.ui.TXCloudVideoView
|
||||
android:id="@+id/trtc_view_6"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignTop="@+id/trtc_view_1"
|
||||
android:layout_marginLeft="15dp"/>
|
||||
<com.tencent.trtc.CustomVideoView
|
||||
android:id="@+id/trtc_view_6"
|
||||
android:layout_width="90dp"
|
||||
android:layout_height="160dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignTop="@+id/trtc_view_1"
|
||||
android:layout_marginLeft="15dp"/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/videocall_background"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iv_return"
|
||||
android:layout_marginTop="2dp"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:layout_marginLeft="10dp"
|
||||
android:layout_marginRight="10dp"
|
||||
android:padding="2dp"
|
||||
android:src="@mipmap/videocall_home"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp" />
|
||||
</LinearLayout>
|
@ -1,12 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<ImageView
|
||||
android:src="@mipmap/videocall_float_logo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
Loading…
x
Reference in New Issue
Block a user