我正在尝试从此资源创建一个简单的点对点视频通话。
我只是做了它需要的所有事情,但我仍然没有从远程渲染它唯一的渲染来自本地摄像机,onRemoteVideoTrackReceive
从未调用过。我正在使用 qb 2.5 sdk我也从qb-sdk
它的作品中编译了示例sample-videochat-webrtc
很好.这是我的项目代码:
穆多尔:应用
apply plugin: 'com.android.application'
android {
compileSdkVersion 'Google Inc.:Google APIs:23'
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.hm.runanddelete"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard- android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
testCompile 'junit:junit:4.12'
compile fileTree(dir: 'libs', include: ['*.jar'])
}
项目:____
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-alpha5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hm.runanddelete">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera.front" />
<uses-feature android:name="android.hardware.microphone"/>
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
主活动
public class MainActivity extends Activity implements QBRTCClientSessionCallbacks, QBRTCClientVideoTracksCallbacks, QBRTCSignalingCallback, QBRTCSessionConnectionCallbacks {
static final String APP_ID = "...";
static final String AUTH_KEY = "...";
static final String AUTH_SECRET = "...";
static final String ACCOUNT_KEY = "...";
RTCGLVideoView LocalVideoView;
RTCGLVideoView remoteVideoView;
String login = "";
String password = "";
QBChatService chatService;
QBRTCClient rtcClient;
EditText et_user, et_paw, et_id;
Button btn_call, btn_login;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et_user = (EditText) findViewById(R.id.et_caller_user);
et_paw = (EditText) findViewById(R.id.et_caller_pw);
et_id = (EditText) findViewById(R.id.et_caller_tid);
btn_call = (Button) findViewById(R.id.btn_caller_call);
btn_login = (Button) findViewById(R.id.btn_caller_login);
LocalVideoView = (RTCGLVideoView) findViewById(R.id.localView);
remoteVideoView = (RTCGLVideoView) findViewById(R.id.opponentView);
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
login = et_user.getText().toString();
password = et_paw.getText().toString();
initializingQB();
}
});
btn_call.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
starcall(Integer.parseInt(et_id.getText().toString()));
}
});
}
private void initializingQB() {
QBSettings.getInstance().init(getApplicationContext(), APP_ID, AUTH_KEY, AUTH_SECRET);
QBSettings.getInstance().setAccountKey(ACCOUNT_KEY);
final QBUser user = new QBUser(login, password);
// CREATE SESSION WITH USER
// If you use create session with user data,
// then the user will be logged in automatically
QBAuth.createSession(login, password, new QBEntityCallback<QBSession>() {
@Override
public void onSuccess(QBSession session, Bundle bundle) {
user.setId(session.getUserId());
Toast.makeText(MainActivity.this, "Loging in!!!", Toast.LENGTH_LONG).show();
Log.w("qb", "logedin app");
// INIT CHAT SERVICE
chatService = QBChatService.getInstance();
Log.w("qb", "loging chat");
// LOG IN CHAT SERVICE
chatService.login(user, new QBEntityCallback<QBUser>() {
@Override
public void onSuccess(QBUser qbUser, Bundle bundle) {
Log.w("qb", "loged chat");
initQBRTCClient();
}
@Override
public void onError(QBResponseException errors) {
Log.w("qb", "not logedn" + errors.getMessage());
//error
}
});
}
@Override
public void onError(QBResponseException errors) {
//error
Toast.makeText(MainActivity.this, "ERROR!!!n" + errors.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
private void initQBRTCClient() {
rtcClient = QBRTCClient.getInstance(this);
// Add signalling manager
QBChatService.getInstance().getVideoChatWebRTCSignalingManager().addSignalingManagerListener(new QBVideoChatSignalingManagerListener() {
@Override
public void signalingCreated(QBSignaling qbSignaling, boolean createdLocally) {
if (!createdLocally) {
rtcClient.addSignaling((QBWebRTCSignaling) qbSignaling);
}
}
});
rtcClient.setCameraErrorHendler(new VideoCapturerAndroid.CameraErrorHandler() {
@Override
public void onCameraError(final String s) {
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
}
});
}
});
// Configure
//
QBRTCConfig.setMaxOpponentsCount(2);
QBRTCConfig.setDisconnectTime(30);
QBRTCConfig.setAnswerTimeInterval(301);
QBRTCConfig.setDebugEnabled(true);
//rtcClient.addVideoTrackCallbacksListener(this);
// rtcSession.removeVideoTrackCallbacksListener(this);
// Add activity as callback to RTCClient
rtcClient.addSessionCallbacksListener(this);
//rtcClient.addVideoTrackCallbacksListener(this);
//QBRTCClient.getInstance(this).removeSessionCallbacksListener(this);
// Start mange QBRTCSessions according to VideoCall parser's callbacks
rtcClient.prepareToProcessCalls();
}
private void starcall(int tid) {
//Set conference type
//There are two types of calls:
// - QB_CONFERENCE_TYPE_VIDEO - for video call;
// - QB_CONFERENCE_TYPE_AUDIO - for audio call;
QBRTCTypes.QBConferenceType qbConferenceType = QBRTCTypes.QBConferenceType.QB_CONFERENCE_TYPE_VIDEO;
//Initiate opponents list
List<Integer> opponents = new ArrayList<Integer>();
opponents.add(tid); //12345 - QBUser ID
//Set user information
// User can set any string key and value in user info
// Then retrieve this data from sessions which is returned in callbacks
// and parse them as he wish
Map<String, String> userInfo = new HashMap<>();
userInfo.put("key", "value");
//Init session
QBRTCSession session = rtcClient.createNewSessionWithOpponents(opponents, qbConferenceType);
session.addVideoTrackCallbacksListener(this);
session.addSessionCallbacksListener(this);
session.addSessionCallbacksListener(this);
//Start call
session.startCall(userInfo);
Log.w("qb", "startcall: " + String.valueOf(tid));
}
@Override
public void onReceiveNewSession(QBRTCSession qbrtcSession) {
// obtain received user info
Map<String, String> userInfo = qbrtcSession.getUserInfo();
// .....
// ..... your code
// .....
// Set userInfo
// User can set any string key and value in user info
userInfo = new HashMap<String, String>();
userInfo.put("Key", "Value");
// Accept incoming call
qbrtcSession.addVideoTrackCallbacksListener(this);
qbrtcSession.addSessionCallbacksListener(this);
qbrtcSession.acceptCall(userInfo);
Log.w("call", "accepted:" + String.valueOf(qbrtcSession.getSessionID()));
}
@Override
public void onUserNotAnswer(QBRTCSession qbrtcSession, Integer integer) {
}
@Override
public void onCallRejectByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
}
@Override
public void onCallAcceptByUser(QBRTCSession qbrtcSession, Integer integer, Map<String, String> map) {
}
@Override
public void onReceiveHangUpFromUser(QBRTCSession qbrtcSession, Integer integer) {
}
@Override
public void onUserNoActions(QBRTCSession qbrtcSession, Integer integer) {
}
@Override
public void onSessionClosed(QBRTCSession qbrtcSession) {
}
@Override
public void onSessionStartClose(QBRTCSession qbrtcSession) {
}
@Override
public void onLocalVideoTrackReceive(QBRTCSession qbrtcSession, QBRTCVideoTrack qbrtcVideoTrack) {
Log.w("TAG", "onLocalVideoTrackReceive()");
// RTCGLVideoView videoView, QBRTCVideoTrack videoTrack, boolean remoteRenderer
fillVideoView(LocalVideoView, qbrtcVideoTrack, false);
}
@Override
public void onRemoteVideoTrackReceive(QBRTCSession qbrtcSession, QBRTCVideoTrack qbrtcVideoTrack, Integer integer) {
Log.w("TAG", "onRemoteVideoTrackReceive(),,,");
fillVideoView(remoteVideoView, qbrtcVideoTrack, true);
}
private void fillVideoView(RTCGLVideoView videoView, QBRTCVideoTrack videoTrack, boolean remoteRenderer) {
videoTrack.addRenderer(new VideoRenderer(remoteRenderer ?
videoView.obtainVideoRenderer(RTCGLVideoView.RendererSurface.MAIN) :
videoView.obtainVideoRenderer(RTCGLVideoView.RendererSurface.SECOND)));
}
@Override
public void onSuccessSendingPacket(QBSignalingSpec.QBSignalCMD qbSignalCMD, Integer integer) {
}
@Override
public void onErrorSendingPacket(QBSignalingSpec.QBSignalCMD qbSignalCMD, Integer integer, QBRTCSignalException e) {
}
@Override
public void onStartConnectToUser(QBRTCSession qbrtcSession, Integer integer) {
Log.w("connection", "onStartConnectToUser");
}
@Override
public void onConnectedToUser(QBRTCSession qbrtcSession, Integer integer) {
Log.w("connection", "onConnectedToUser");
}
@Override
public void onConnectionClosedForUser(QBRTCSession qbrtcSession, Integer integer) {
Log.w("connection", "onConnectionClosedForUser");
}
@Override
public void onDisconnectedFromUser(QBRTCSession qbrtcSession, Integer integer) {
Log.w("connection", "onDisconnectedFromUser");
}
@Override
public void onDisconnectedTimeoutFromUser(QBRTCSession qbrtcSession, Integer integer) {
Log.w("connection", "onDisconnectedTimeoutFromUser");
}
@Override
public void onConnectionFailedWithUser(QBRTCSession qbrtcSession, Integer integer) {
Log.w("connection", "onConnectionFailedWithUser");
}
@Override
public void onError(QBRTCSession qbrtcSession, QBRTCException e) {
Log.w("connection", "onError");
}
}
布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:custom="http://schemas.android.com/apk/res-auto"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.hm.runanddelete.MainActivity">
<com.quickblox.videochat.webrtc.view.RTCGLVideoView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/localView"
android:layout_width="150dp"
android:layout_height="150dp"
/>
<com.quickblox.videochat.webrtc.view.RTCGLVideoView
android:id="@+id/opponentView"
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_alignParentBottom="true"
android:layout_alignRight="@+id/btn_caller_login"
android:layout_alignEnd="@+id/btn_caller_login" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LOGIN"
android:id="@+id/btn_caller_login"
android:layout_below="@+id/et_caller_pw"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/et_caller_user"
android:hint="QB USERNAME"
android:layout_below="@+id/localView"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginTop="25dp"
android:layout_alignRight="@+id/et_caller_pw"
android:layout_alignEnd="@+id/et_caller_pw"
android:text="" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/et_caller_pw"
android:layout_below="@+id/et_caller_user"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignRight="@+id/btn_caller_login"
android:layout_alignEnd="@+id/btn_caller_login"
android:hint="QB PASSWORD"
android:text="" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/et_caller_tid"
android:hint="QB TARGET ID"
android:layout_below="@+id/et_caller_pw"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_toLeftOf="@+id/btn_caller_login"
android:layout_toStartOf="@+id/btn_caller_login"
android:text="" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MAKE CALL"
android:id="@+id/btn_caller_call"
android:layout_below="@+id/et_caller_tid"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignRight="@+id/btn_caller_login"
android:layout_alignEnd="@+id/btn_caller_login" />
</RelativeLayout>
如果我错了,请纠正我!
更新:已添加addSessionCallbacksListener
接收电话后的日志:
02-23 22:23:09.731 18666-18666/com.hm.runanddelete W/qb: logedin app
02-23 22:23:09.787 18666-18666/com.hm.runanddelete W/qb: loging chat
02-23 22:23:13.051 18666-18958/com.hm.runanddelete W/qb: loged chat
02-23 22:24:10.454 18666-19016/com.hm.runanddelete W/call: accepted:835226fc-d9a5-4bbc-82db-3ad6e0524168
02-23 22:24:11.230 18666-19016/com.hm.runanddelete W/TAG: onLocalVideoTrackReceive()
拨打电话:
02-23 22:25:54.104 20763-20763/com.hm.runanddelete W/qb: logedin app
02-23 22:25:54.163 20763-20763/com.hm.runanddelete W/qb: loging chat
02-23 22:25:59.801 20763-21845/com.hm.runanddelete W/qb: loged chat
02-23 22:26:02.550 20763-20763/com.hm.runanddelete W/qb: startcall: 5510686
02-23 22:26:03.412 20763-21968/com.hm.runanddelete W/TAG: onLocalVideoTrackReceive()
我相信您面临的问题是,在接受呼叫后,呼叫发起方不会收到接受回调消息,该消息会触发"onCallAcceptByUser",然后开始渲染远程视频。
您的所有设置似乎都是正确的,使其工作所需的更改是,您应该在不同的活动或片段上实现"QBRTCSessionConnectionCallbacks,QBRTCClientVideoTracksCallbacks"。
因此,MainActivity 将实现 QBRTCClientSessionCallbacks, QBRTCSessionConnectionCallbacks",而另一个 Activity 或片段 Let's 让我们称之为 ConversationFragment"将实现 "QBRTCSessionConnectionCallbacks, QBRTCClientVideoTracksCallbacks",在这种情况下,您在调用发起方逻辑中创建的会话实例或者您_in呼叫接收器逻辑收到的会话将在 MainActivity 中创建,并使其可供 ConversationFragment 访问以初始化"QBRTCSessionConnectionCallbacks, QBRTCClientVideoTracksCallbacks"。
我没有时间调查此问题的原因,即"如果在同一活动中实现所有回调侦听器,则不会收到呼叫接受消息"以及如何如上所述将它们分开解决问题。但这就是我修复它的方式。
注意:我在两个版本2.5和2.5.1上都遇到了这个问题。此修复程序适用于两者。
如果您需要进一步的帮助,请告诉我。
小更新说明:我在iOS上遇到了类似的问题。在视图控制器中创建 QBSession 对象并将其传递给另一个视图控制器可防止调用"ConnectedToUser"回调方法,从而阻止完全建立调用。要修复它,只需创建QBSession,或者让我们在将处理调用的同一ViewController中调用"createNewSession"。
回调的方法 onRemoteVideoTrackReceive 在与远程跟踪建立连接后被调用。要侦听连接状态更改,您可以通过 rtcSession.addSessionCallbacksListener() 添加 QBRTCSessionConnectionCallbacks 侦听器。当对等体首先建立连接时将调用onStartConnectToUser方法,而不是onConnectedToUser,然后对等体将通过onRemoteVideoTrackReceive方法接收远程跟踪。确保调用所有方法。