diff --git a/QNDroidRTCDemo/app/build.gradle b/QNDroidRTCDemo/app/build.gradle index d61687a..9c2b93c 100644 --- a/QNDroidRTCDemo/app/build.gradle +++ b/QNDroidRTCDemo/app/build.gradle @@ -1,16 +1,16 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion '26.0.2' + compileSdkVersion 28 defaultConfig { applicationId "com.qiniu.droid.rtc.demo" minSdkVersion 18 - targetSdkVersion 25 - versionCode 9 - versionName "1.2.0" + targetSdkVersion 28 + versionCode 12 + versionName "2.0.0" buildConfigField "long", "BUILD_TIMESTAMP", System.currentTimeMillis() + "L" } + buildTypes { release { minifyEnabled false @@ -18,18 +18,25 @@ android { } } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + lintOptions { + disable 'GoogleAppIndexingWarning' + abortOnError false } } dependencies { - compile files('libs/qndroid-rtc-1.2.0.jar') - compile 'com.android.support:appcompat-v7:25+' - compile 'com.squareup.okhttp3:okhttp:3.9.1' - compile 'com.bugsnag:bugsnag-android-ndk:1.+' - compile 'de.greenrobot:eventbus:2.4.0' - compile 'com.android.support:recyclerview-v7:25.4.0' - implementation files('libs/pldroid-player-2.1.4.jar') + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.squareup.okhttp3:okhttp:3.9.1' + implementation 'com.bugsnag:bugsnag-android-ndk:1.+' + implementation 'de.greenrobot:eventbus:2.4.0' + implementation 'com.android.support:recyclerview-v7:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + + // QNDroidRTCLibrary + if (buildWithQNDroidRTCLibrary) { + implementation project(':library') + implementation files('libs/pldroid-player-2.1.4.jar') + } else { + implementation fileTree(include: ['*.jar'], dir: 'libs') + } } diff --git a/QNDroidRTCDemo/app/libs/qndroid-rtc-1.2.0.jar b/QNDroidRTCDemo/app/libs/qndroid-rtc-1.2.0.jar deleted file mode 100644 index 005b579..0000000 Binary files a/QNDroidRTCDemo/app/libs/qndroid-rtc-1.2.0.jar and /dev/null differ diff --git a/QNDroidRTCDemo/app/libs/qndroid-rtc-2.0.0.jar b/QNDroidRTCDemo/app/libs/qndroid-rtc-2.0.0.jar new file mode 100644 index 0000000..7bddf83 Binary files /dev/null and b/QNDroidRTCDemo/app/libs/qndroid-rtc-2.0.0.jar differ diff --git a/QNDroidRTCDemo/app/src/main/AndroidManifest.xml b/QNDroidRTCDemo/app/src/main/AndroidManifest.xml index 6c98aa0..ecc6ebc 100644 --- a/QNDroidRTCDemo/app/src/main/AndroidManifest.xml +++ b/QNDroidRTCDemo/app/src/main/AndroidManifest.xml @@ -34,18 +34,15 @@ + - + + @@ -64,14 +61,17 @@ android:resource="@xml/update_apk_paths" /> - + android:screenOrientation="portrait" /> - + android:launchMode="singleTop" + android:screenOrientation="portrait" + android:theme="@style/AppTheme" /> - \ No newline at end of file + diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/RTCApplication.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/RTCApplication.java index b254279..2d8d3dc 100644 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/RTCApplication.java +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/RTCApplication.java @@ -16,5 +16,11 @@ public void onCreate() { */ QNRTCEnv.init(getApplicationContext()); QNRTCEnv.setLogFileEnabled(true); + /** + * 正式版本需要去掉!!!! + * 正式版本需要去掉!!!! + * 正式版本需要去掉!!!! + */ + QNRTCEnv.setLogFileMaxCount(10); } } diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/LiveRoomActivity.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/LiveRoomActivity.java index 0acbd86..c35cb8a 100644 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/LiveRoomActivity.java +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/LiveRoomActivity.java @@ -337,6 +337,10 @@ public void run() { } + @Override + public void onCameraCaptureReady() { + } + @Override public void onJoinedRoom() { mIsJoinedRoom = true; diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/MainActivity.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/MainActivity.java index aa0001a..49ba0af 100644 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/MainActivity.java +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/MainActivity.java @@ -25,6 +25,7 @@ import com.qiniu.droid.rtc.demo.model.UpdateInfo; import com.qiniu.droid.rtc.demo.model.UserList; import com.qiniu.droid.rtc.demo.service.DownloadService; +import com.qiniu.droid.rtc.demo.ui.RadioGroupFlow; import com.qiniu.droid.rtc.demo.utils.Config; import com.qiniu.droid.rtc.demo.utils.QNAppServer; import com.qiniu.droid.rtc.demo.utils.ToastUtils; @@ -39,10 +40,11 @@ public class MainActivity extends AppCompatActivity { private EditText mRoomEditText; private ProgressDialog mProgressDialog; - private RadioGroup mCaptureModeRadioGroup; + private RadioGroupFlow mCaptureModeRadioGroup; private RadioButton mScreenCapture; private RadioButton mCameraCapture; private RadioButton mOnlyAudioCapture; + private RadioButton mMutiTrackCapture; private String mUserName; private String mRoomName; @@ -116,7 +118,7 @@ public void onClickConference(final View v) { handleRoomInfo(); SharedPreferences preferences = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); mUserName = preferences.getString(Config.USER_NAME, ""); - mIsScreenCaptureEnabled = (mCaptureMode == Config.SCREEN_CAPTURE); + mIsScreenCaptureEnabled = (mCaptureMode == Config.SCREEN_CAPTURE || mCaptureMode == Config.MUTI_TRACK_CAPTURE); if (mIsScreenCaptureEnabled) { QNScreenCaptureUtil.requestScreenCapture(this); } else { @@ -145,7 +147,7 @@ public void run() { ToastUtils.s(MainActivity.this, getString(R.string.null_room_token_toast)); return; } - Intent intent = new Intent(MainActivity.this, mIsScreenCaptureEnabled ? ScreenCaptureActivity.class : RoomActivity.class); + Intent intent = new Intent(MainActivity.this, RoomActivity.class); intent.putExtra(RoomActivity.EXTRA_ROOM_ID, roomName.trim()); intent.putExtra(RoomActivity.EXTRA_ROOM_TOKEN, token); intent.putExtra(RoomActivity.EXTRA_USER_ID, mUserName); @@ -221,11 +223,12 @@ private boolean handleRoomInfo() { private void initView() { setContentView(R.layout.activity_main); mRoomEditText = (EditText) findViewById(R.id.room_edit_text); - mCaptureModeRadioGroup = (RadioGroup) findViewById(R.id.capture_mode_button); + mCaptureModeRadioGroup = findViewById(R.id.capture_mode_button); mCaptureModeRadioGroup.setOnCheckedChangeListener(mOnCheckedChangeListener); mScreenCapture = (RadioButton) findViewById(R.id.screen_capture_button); mCameraCapture = (RadioButton) findViewById(R.id.camera_capture_button); mOnlyAudioCapture = (RadioButton) findViewById(R.id.audio_capture_button); + mMutiTrackCapture = findViewById(R.id.muti_track_button); SharedPreferences preferences = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); String roomName = preferences.getString(Config.ROOM_NAME, Config.PILI_ROOM); @@ -235,8 +238,10 @@ private void initView() { mScreenCapture.setChecked(true); } else if (captureMode == Config.CAMERA_CAPTURE) { mCameraCapture.setChecked(true); - } else { + } else if (captureMode == Config.ONLY_AUDIO_CAPTURE){ mOnlyAudioCapture.setChecked(true); + } else { + mMutiTrackCapture.setChecked(true); } } else { mScreenCapture.setEnabled(false); @@ -313,6 +318,9 @@ public void onCheckedChanged(RadioGroup group, int checkedId) { case R.id.audio_capture_button: mCaptureMode = Config.ONLY_AUDIO_CAPTURE; break; + case R.id.muti_track_button: + mCaptureMode = Config.MUTI_TRACK_CAPTURE; + break; } } }; diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/RoomActivity.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/RoomActivity.java index 1e9b8ea..4ada495 100644 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/RoomActivity.java +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/RoomActivity.java @@ -11,59 +11,51 @@ import android.content.pm.PackageManager; import android.os.Build; import android.os.Bundle; -import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Log; -import android.view.Gravity; import android.view.View; import android.view.Window; import android.view.WindowManager; -import android.view.WindowManager.LayoutParams; -import android.widget.FrameLayout; import android.widget.Toast; import com.qiniu.droid.rtc.QNBeautySetting; import com.qiniu.droid.rtc.QNCameraSwitchResultCallback; -import com.qiniu.droid.rtc.QNRTCManager; +import com.qiniu.droid.rtc.QNErrorCode; +import com.qiniu.droid.rtc.QNRTCEngine; +import com.qiniu.droid.rtc.QNRTCEngineEventListener; import com.qiniu.droid.rtc.QNRTCSetting; -import com.qiniu.droid.rtc.QNRemoteAudioCallback; -import com.qiniu.droid.rtc.QNRemoteSurfaceView; -import com.qiniu.droid.rtc.QNRoomEventListener; import com.qiniu.droid.rtc.QNRoomState; +import com.qiniu.droid.rtc.QNSourceType; import com.qiniu.droid.rtc.QNStatisticsReport; +import com.qiniu.droid.rtc.QNTrackInfo; +import com.qiniu.droid.rtc.QNTrackKind; import com.qiniu.droid.rtc.QNVideoFormat; import com.qiniu.droid.rtc.demo.R; import com.qiniu.droid.rtc.demo.fragment.ControlFragment; -import com.qiniu.droid.rtc.demo.ui.LocalVideoView; -import com.qiniu.droid.rtc.demo.ui.RTCVideoView; +import com.qiniu.droid.rtc.demo.ui.UserTrackView; import com.qiniu.droid.rtc.demo.utils.Config; import com.qiniu.droid.rtc.demo.utils.QNAppServer; import com.qiniu.droid.rtc.demo.utils.ToastUtils; +import com.qiniu.droid.rtc.demo.utils.TrackWindowMgr; import com.qiniu.droid.rtc.model.QNAudioDevice; -import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import static com.qiniu.droid.rtc.QNErrorCode.ERROR_KICKED_OUT_OF_ROOM; import static com.qiniu.droid.rtc.demo.utils.Config.DEFAULT_BITRATE; import static com.qiniu.droid.rtc.demo.utils.Config.DEFAULT_FPS; import static com.qiniu.droid.rtc.demo.utils.Config.DEFAULT_RESOLUTION; -public class RoomActivity extends Activity implements QNRoomEventListener, ControlFragment.OnCallEvents { - +public class RoomActivity extends Activity implements QNRTCEngineEventListener, ControlFragment.OnCallEvents { private static final String TAG = "RoomActivity"; + private static final int BITRATE_FOR_SCREEN_VIDEO = (int) (1.5 * 1000 * 1000); - public static final String EXTRA_ROOM_ID = "ROOM_ID"; - public static final String EXTRA_ROOM_TOKEN = "ROOM_TOKEN"; public static final String EXTRA_USER_ID = "USER_ID"; - public static final String EXTRA_VIDEO_WIDTH = "VIDEO_WIDTH"; - public static final String EXTRA_VIDEO_HEIGHT = "VIDEO_HEIGHT"; - public static final String EXTRA_HW_CODEC = "HW_CODEC"; + public static final String EXTRA_ROOM_TOKEN = "ROOM_TOKEN"; + public static final String EXTRA_ROOM_ID = "ROOM_ID"; private static final String[] MANDATORY_PERMISSIONS = { "android.permission.MODIFY_AUDIO_SETTINGS", @@ -71,112 +63,93 @@ public class RoomActivity extends Activity implements QNRoomEventListener, Contr "android.permission.INTERNET" }; + private Toast mLogToast; private List mHWBlackList = new ArrayList<>(); - private List mUsedWindowList; - private List mUnusedWindowList; - private ConcurrentHashMap mUserWindowMap; - private String[] mMergeStreamPosition; - - private RTCVideoView mRemoteWindowA; - private RTCVideoView mRemoteWindowB; - private RTCVideoView mRemoteWindowC; - private RTCVideoView mRemoteWindowD; - private RTCVideoView mRemoteWindowE; - private RTCVideoView mRemoteWindowF; - private RTCVideoView mRemoteWindowG; - private RTCVideoView mRemoteWindowH; - private RTCVideoView mLocalWindow; - private Toast mLogToast; - private QNRTCManager mRTCManager; + private UserTrackView mTrackWindowFullScreen; + private List mTrackWindowsList; + private AlertDialog mKickOutDialog; - private boolean mIsError; - private boolean mCallControlFragmentVisible = true; - private long mCallStartedTimeMs = 0; + private QNRTCEngine mEngine; + private String mRoomToken; + private String mUserId; + private String mRoomId; private boolean mMicEnabled = true; private boolean mBeautyEnabled = false; private boolean mVideoEnabled = true; private boolean mSpeakerEnabled = true; + private boolean mIsError = false; + private boolean mIsAdmin = false; private boolean mIsJoinedRoom = false; - private String mRoomId; - private String mRoomToken; - private String mUserId; - private String mLocalLogText; private ControlFragment mControlFragment; + private List mLocalTrackList; + + private QNTrackInfo mLocalVideoTrack; + private QNTrackInfo mLocalAudioTrack; + private QNTrackInfo mLocalScreenTrack; private int mScreenWidth = 0; private int mScreenHeight = 0; - private int mVideoWidth = 0; - private int mVideoHeight = 0; - private float mDensity = 0; - private boolean mIsAdmin = false; + private int mCaptureMode = Config.CAMERA_CAPTURE; - private AlertDialog mKickoutDialog; + private TrackWindowMgr mTrackWindowMgr; @Override - public void onCreate(Bundle savedInstanceState) { + protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().addFlags(LayoutParams.FLAG_FULLSCREEN | LayoutParams.FLAG_KEEP_SCREEN_ON - | LayoutParams.FLAG_DISMISS_KEYGUARD | LayoutParams.FLAG_SHOW_WHEN_LOCKED - | LayoutParams.FLAG_TURN_SCREEN_ON); + getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON + | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED + | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); getWindow().getDecorView().setSystemUiVisibility(getSystemUiVisibility()); - WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); + final WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); DisplayMetrics outMetrics = new DisplayMetrics(); windowManager.getDefaultDisplay().getRealMetrics(outMetrics); - mScreenWidth = outMetrics.widthPixels; mScreenHeight = outMetrics.heightPixels; - mDensity = outMetrics.density; - setContentView(R.layout.activity_room); + setContentView(R.layout.activity_muti_track_room); Intent intent = getIntent(); - mRoomId = intent.getStringExtra(EXTRA_ROOM_ID); mRoomToken = intent.getStringExtra(EXTRA_ROOM_TOKEN); mUserId = intent.getStringExtra(EXTRA_USER_ID); - - mLocalWindow = (LocalVideoView) findViewById(R.id.local_video_view); - mLocalWindow.setUserId(mUserId); - - mRemoteWindowA = (RTCVideoView) findViewById(R.id.remote_video_view_a); - mRemoteWindowB = (RTCVideoView) findViewById(R.id.remote_video_view_b); - mRemoteWindowC = (RTCVideoView) findViewById(R.id.remote_video_view_c); - mRemoteWindowD = (RTCVideoView) findViewById(R.id.remote_video_view_d); - mRemoteWindowE = (RTCVideoView) findViewById(R.id.remote_video_view_e); - mRemoteWindowF = (RTCVideoView) findViewById(R.id.remote_video_view_f); - mRemoteWindowG = (RTCVideoView) findViewById(R.id.remote_video_view_g); - mRemoteWindowH = (RTCVideoView) findViewById(R.id.remote_video_view_h); - - mUsedWindowList = Collections.synchronizedList(new LinkedList()); - mUsedWindowList.add(mLocalWindow); - mUnusedWindowList = Collections.synchronizedList(new LinkedList()); - mUnusedWindowList.add(mRemoteWindowA); - mUnusedWindowList.add(mRemoteWindowB); - mUnusedWindowList.add(mRemoteWindowC); - mUnusedWindowList.add(mRemoteWindowD); - mUnusedWindowList.add(mRemoteWindowE); - mUnusedWindowList.add(mRemoteWindowF); - mUnusedWindowList.add(mRemoteWindowG); - mUnusedWindowList.add(mRemoteWindowH); - - // every remote window can switch with local window - for (final RTCVideoView rtcVideoView : mUnusedWindowList) { - rtcVideoView.setOnLongClickListener(mOnLongClickListener); - rtcVideoView.setOnClickListener(new View.OnClickListener() { + mRoomId = intent.getStringExtra(EXTRA_ROOM_ID); + mIsAdmin = mUserId.equals(QNAppServer.ADMIN_USER); + + mTrackWindowFullScreen = (UserTrackView) findViewById(R.id.track_window_full_screen); + mTrackWindowsList = new LinkedList(Arrays.asList( + (UserTrackView) findViewById(R.id.track_window_a), + (UserTrackView) findViewById(R.id.track_window_b), + (UserTrackView) findViewById(R.id.track_window_c), + (UserTrackView) findViewById(R.id.track_window_d), + (UserTrackView) findViewById(R.id.track_window_e), + (UserTrackView) findViewById(R.id.track_window_f), + (UserTrackView) findViewById(R.id.track_window_g), + (UserTrackView) findViewById(R.id.track_window_h), + (UserTrackView) findViewById(R.id.track_window_i) + )); + + for (final UserTrackView view : mTrackWindowsList) { + view.setOnLongClickListener(new View.OnLongClickListener() { @Override - public void onClick(View v) { - mRTCManager.switchWindow(rtcVideoView.getRemoteSurfaceView()); + public boolean onLongClick(View v) { + if (mIsAdmin) { + showKickoutDialog(view.getUserId()); + } + return false; } }); } - mUserWindowMap = new ConcurrentHashMap<>(); - + // init Control fragment mControlFragment = new ControlFragment(); + mControlFragment.setArguments(intent.getExtras()); + FragmentTransaction ft = getFragmentManager().beginTransaction(); + ft.add(R.id.control_fragment_container, mControlFragment); + ft.commitAllowingStateLoss(); + // permission check for (String permission : MANDATORY_PERMISSIONS) { if (checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { logAndToast("Permission " + permission + " is not granted"); @@ -186,18 +159,28 @@ public void onClick(View v) { } } + // init rtcEngine and local track info list. + initQNRTCEngine(); + initLocalTrackInfoList(); + + // init decorate and set default to p2p mode + mTrackWindowMgr = new TrackWindowMgr(mUserId, mScreenWidth, mScreenHeight, outMetrics.density + , mEngine, mTrackWindowFullScreen, mTrackWindowsList); + + List localTrackListExcludeScreenTrack = new ArrayList<>(mLocalTrackList); + localTrackListExcludeScreenTrack.remove(mLocalScreenTrack); + mTrackWindowMgr.addTrackInfo(mUserId, localTrackListExcludeScreenTrack); + } + + private void initQNRTCEngine() { SharedPreferences preferences = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); - mVideoWidth = preferences.getInt(Config.WIDTH, DEFAULT_RESOLUTION[1][0]); - mVideoHeight = preferences.getInt(Config.HEIGHT, DEFAULT_RESOLUTION[1][1]); + int videoWidth = preferences.getInt(Config.WIDTH, DEFAULT_RESOLUTION[1][0]); + int videoHeight = preferences.getInt(Config.HEIGHT, DEFAULT_RESOLUTION[1][1]); int fps = preferences.getInt(Config.FPS, DEFAULT_FPS[1]); - boolean isHwCodec = preferences.getInt(Config.CODEC_MODE, Config.SW) == Config.HW; - boolean isScreenCaptureEnabled = preferences.getInt(Config.CAPTURE_MODE, Config.CAMERA_CAPTURE) == Config.SCREEN_CAPTURE; - boolean isAudioOnly = preferences.getInt(Config.CAPTURE_MODE, Config.CAMERA_CAPTURE) == Config.ONLY_AUDIO_CAPTURE; - boolean isVideoEnable = !isAudioOnly; - - if (isScreenCaptureEnabled || isAudioOnly) { - mLocalWindow.setAudioViewVisible(0); - } + boolean isHwCodec = preferences.getInt(Config.CODEC_MODE, Config.HW) == Config.HW; + int videoBitrate = preferences.getInt(Config.BITRATE, DEFAULT_BITRATE[1]); + boolean isMaintainRes = preferences.getBoolean(Config.MAINTAIN_RES, false); + mCaptureMode = preferences.getInt(Config.CAPTURE_MODE, Config.CAMERA_CAPTURE); // get the items in hw black list, and set isHwCodec false forcibly String[] hwBlackList = getResources().getStringArray(R.array.hw_black_list); @@ -206,149 +189,100 @@ public void onClick(View v) { isHwCodec = false; } + QNVideoFormat format = new QNVideoFormat(videoWidth, videoHeight, fps); QNRTCSetting setting = new QNRTCSetting(); - setting.setVideoEnabled(isVideoEnable) - .setCameraID(QNRTCSetting.CAMERA_FACING_ID.FRONT) + setting.setCameraID(QNRTCSetting.CAMERA_FACING_ID.FRONT) .setHWCodecEnabled(isHwCodec) - .setScreenCaptureEnabled(isScreenCaptureEnabled) - .setVideoPreviewFormat(new QNVideoFormat(mVideoWidth, mVideoHeight, fps)) - .setVideoEncodeFormat(new QNVideoFormat(mVideoWidth, mVideoHeight, fps)); - - int audioBitrate = 64 * 1000; - int videoBitrate = preferences.getInt(Config.BITRATE, DEFAULT_BITRATE[1]); - //设置音频初始码率 - setting.setAudioBitrate(audioBitrate); - //设置视频初始码率 - setting.setVideoBitrate(videoBitrate); - //当设置的最低码率,远高于弱网下的常规传输码率值时,会严重影响连麦的画面流畅度 - //音频码率上限内部已有默认值,此处只传递视频码率上限即可 - setting.setBitrateRange(0, videoBitrate); - - mControlFragment.setArguments(intent.getExtras()); - mControlFragment.setScreenCaptureEnabled(isScreenCaptureEnabled); - mControlFragment.setAudioOnly(isAudioOnly); - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.add(R.id.control_fragment_container, mControlFragment); - ft.commitAllowingStateLoss(); - - mRTCManager = new QNRTCManager(); - mRTCManager.setRoomEventListener(this); - mRTCManager.addRemoteWindow(mRemoteWindowA.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowB.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowC.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowD.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowE.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowF.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowG.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowH.getRemoteSurfaceView()); - mRTCManager.initialize(this, setting); - mRTCManager.setLocalWindow(mLocalWindow.getLocalSurfaceView()); - } - - public void onClickScreen(View v) { - if (mUsedWindowList.size() < 3) { - toggleControlFragmentVisibility(); - } - } - - private void toggleControlFragmentVisibility() { - if (!mControlFragment.isAdded()) { - return; - } - - mCallControlFragmentVisible = !mCallControlFragmentVisible; - FragmentTransaction ft = getFragmentManager().beginTransaction(); - if (mCallControlFragmentVisible) { - ft.show(mControlFragment); - } else { - ft.hide(mControlFragment); + .setMaintainResolution(isMaintainRes) + .setVideoBitrate(videoBitrate) + .setVideoEncodeFormat(format) + .setVideoPreviewFormat(format); + mEngine = QNRTCEngine.createEngine(getApplicationContext(), setting, this); + } + + private void initLocalTrackInfoList() { + mLocalTrackList = new ArrayList<>(); + mLocalAudioTrack = mEngine.createTrackInfoBuilder() + .setSourceType(QNSourceType.AUDIO) + .setMaster(true) + .create(); + mLocalTrackList.add(mLocalAudioTrack); + + QNVideoFormat screenEncodeFormat = new QNVideoFormat(mScreenWidth/2, mScreenHeight/2, 15); + switch (mCaptureMode) { + case Config.CAMERA_CAPTURE: + mLocalVideoTrack = mEngine.createTrackInfoBuilder() + .setSourceType(QNSourceType.VIDEO_CAMERA) + .setMaster(true) + .setTag(UserTrackView.TAG_CAMERA).create(); + mLocalTrackList.add(mLocalVideoTrack); + break; + case Config.ONLY_AUDIO_CAPTURE: + mControlFragment.setAudioOnly(true); + break; + case Config.SCREEN_CAPTURE: + mLocalScreenTrack = mEngine.createTrackInfoBuilder() + .setVideoPreviewFormat(screenEncodeFormat) + .setBitrate(BITRATE_FOR_SCREEN_VIDEO) + .setSourceType(QNSourceType.VIDEO_SCREEN) + .setMaster(true) + .setTag(UserTrackView.TAG_SCREEN).create(); + mLocalTrackList.add(mLocalScreenTrack); + mControlFragment.setAudioOnly(true); + break; + case Config.MUTI_TRACK_CAPTURE: + mLocalScreenTrack = mEngine.createTrackInfoBuilder() + .setSourceType(QNSourceType.VIDEO_SCREEN) + .setVideoPreviewFormat(screenEncodeFormat) + .setBitrate(BITRATE_FOR_SCREEN_VIDEO) + .setMaster(true) + .setTag(UserTrackView.TAG_SCREEN).create(); + mLocalVideoTrack = mEngine.createTrackInfoBuilder() + .setSourceType(QNSourceType.VIDEO_CAMERA) + .setTag(UserTrackView.TAG_CAMERA).create(); + mLocalTrackList.add(mLocalScreenTrack); + mLocalTrackList.add(mLocalVideoTrack); + break; } - ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); - ft.commitAllowingStateLoss(); } - private void startCall() { - if (mRTCManager == null || mIsJoinedRoom) { - return; + @Override + protected void onResume() { + super.onResume(); + if (!mIsJoinedRoom) { + mEngine.joinRoom(mRoomToken); } - mCallStartedTimeMs = System.currentTimeMillis(); - - logAndToast(getString(R.string.connecting_to, mRoomId)); - mRTCManager.joinRoom(mRoomToken); - mIsJoinedRoom = true; } - private void onConnectedInternal() { - final long delay = System.currentTimeMillis() - mCallStartedTimeMs; - Log.i(TAG, "Call connected: delay=" + delay + "ms"); - logAndToast(getString(R.string.connected_to_room)); + @Override + public void onBackPressed() { + super.onBackPressed(); + finish(); } - private void subscribeAllRemoteStreams() { - ArrayList publishingUsers = mRTCManager.getPublishingUserList(); - if (publishingUsers != null && !publishingUsers.isEmpty()) { - for (String userId : publishingUsers) { - mRTCManager.subscribe(userId); - mRTCManager.addRemoteAudioCallback(userId, new QNRemoteAudioCallback() { - @Override - public void onRemoteAudioAvailable(String userId, ByteBuffer audioData, int size, int bitsPerSample, int sampleRate, int numberOfChannels) { - } - }); - } + @Override + protected void onDestroy() { + super.onDestroy(); + if (mEngine != null) { + mEngine.destroy(); + mEngine = null; } - } - - private void clearAllRemoteStreams() { - if (mUsedWindowList.size() > 2) { - setTargetWindowParams(1, 0, mLocalWindow); + if (mTrackWindowFullScreen != null) { + mTrackWindowFullScreen.dispose(); } - mUsedWindowList.clear(); - mUsedWindowList.add(mLocalWindow); - - for (RTCVideoView rtcVideoView : mUserWindowMap.values()) { - rtcVideoView.setVisible(false); + for (UserTrackView item : mTrackWindowsList) { + item.dispose(); } - mUserWindowMap.clear(); - - mUnusedWindowList.clear(); - mUnusedWindowList.add(mRemoteWindowA); - mUnusedWindowList.add(mRemoteWindowB); - mUnusedWindowList.add(mRemoteWindowC); - mUnusedWindowList.add(mRemoteWindowD); - mUnusedWindowList.add(mRemoteWindowE); - mUnusedWindowList.add(mRemoteWindowF); - mUnusedWindowList.add(mRemoteWindowG); - mUnusedWindowList.add(mRemoteWindowH); + mTrackWindowsList.clear(); } - private void disconnect() { - runOnUiThread(new Runnable() { - @Override - public void run() { - mControlFragment.stopTimer(); - } - }); + private void logAndToast(final String msg) { + Log.d(TAG, msg); if (mLogToast != null) { mLogToast.cancel(); } - if (mRTCManager != null) { - if (mIsAdmin) { - mRTCManager.stopMergeStream(); - } - mRTCManager.destroy(); - mRTCManager = null; - } - mLocalWindow = null; - mRemoteWindowA = null; - mRemoteWindowB = null; - mRemoteWindowC = null; - mRemoteWindowD = null; - mRemoteWindowE = null; - mRemoteWindowF = null; - mRemoteWindowG = null; - mRemoteWindowH = null; - - mIsJoinedRoom = false; + mLogToast = Toast.makeText(this, msg, Toast.LENGTH_SHORT); + mLogToast.show(); } private void disconnectWithErrorMessage(final String errorMessage) { @@ -367,189 +301,34 @@ public void onClick(DialogInterface dialog, int id) { .show(); } - private void logAndToast(final String msg) { - runOnUiThread(new Runnable() { - @Override - public void run() { - Log.d(TAG, msg); - if (mLogToast != null) { - mLogToast.cancel(); - } - mLogToast = Toast.makeText(RoomActivity.this, msg, Toast.LENGTH_SHORT); - mLogToast.show(); - } - }); - } - private void reportError(final String description) { - runOnUiThread(new Runnable() { - @Override - public void run() { - if (!mIsError) { - mIsError = true; - disconnectWithErrorMessage(description); - } - } - }); - } - - private RTCVideoView getWindowByUserId(String userId) { - return mUserWindowMap.containsKey(userId) ? mUserWindowMap.get(userId) : null; - } - - private void toggleToMultiUsersUI(final int userCount, List windowList) { - for (int i = 0; i < userCount; i++) { - setTargetWindowParams(userCount, i, windowList.get(i)); - } - } - - public synchronized void setTargetWindowParams(final int userCount, final int targetPos, final RTCVideoView targetWindow) { - runOnUiThread(new Runnable() { - @Override - public void run() { - switch (userCount) { - case 1: - updateLayoutParams(targetWindow, 0, mScreenWidth, mScreenHeight, 0, 0, -1); - case 2: - if (targetPos == 0) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth, mScreenHeight, 0, 0, -1); - } else if (targetPos == 1) { - updateLayoutParams(targetWindow, targetPos, (int) (120 * mDensity + 0.5f), (int) (160 * mDensity + 0.5f), 0, 0, Gravity.TOP | Gravity.END); - } - break; - case 3: - if (targetPos == 0) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 2, mScreenWidth / 2, 0, 0, -1); - } else if (targetPos == 1) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 2, mScreenWidth / 2, mScreenWidth / 2, 0, -1); - } else { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 2, mScreenWidth / 2, 0, mScreenWidth / 2, Gravity.CENTER_HORIZONTAL); - } - break; - case 4: - if (targetPos == 0) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 2, mScreenWidth / 2, 0, 0, -1); - } else if (targetPos == 1) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 2, mScreenWidth / 2, mScreenWidth / 2, 0, -1); - } else if (targetPos == 2) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 2, mScreenWidth / 2, 0, mScreenWidth / 2, Gravity.START); - } else { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 2, mScreenWidth / 2, mScreenWidth / 2, mScreenWidth / 2, -1); - } - break; - case 5: - case 6: - case 7: - case 8: - case 9: - if (targetPos == 0) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 3, mScreenWidth / 3, 0, 0, -1); - } else if (targetPos == 1) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth / 3, 0, -1); - } else if (targetPos == 2) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth * 2 / 3, 0, Gravity.END); - } else if (targetPos == 3) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 3, mScreenWidth / 3, 0, mScreenWidth / 3, -1); - } else if (targetPos == 4) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth / 3, -1); - } else if (targetPos == 5) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth * 2 / 3, mScreenWidth / 3, -1); - } else if (targetPos == 6) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 3, mScreenWidth / 3, 0, mScreenWidth * 2 / 3, -1); - } else if (targetPos == 7) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth * 2 / 3, -1); - } else if (targetPos == 8) { - updateLayoutParams(targetWindow, targetPos, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth * 2 / 3, mScreenWidth * 2 / 3, -1); - } - break; - } - } - }); - } - - private void updateLayoutParams(RTCVideoView targetView, int targetPos, int width, int height, int marginStart, int marginTop, int gravity) { - FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) targetView.getLayoutParams(); - lp.width = width; - lp.height = height; - lp.topMargin = marginTop; - lp.gravity = gravity; - lp.setMarginStart(marginStart); - targetView.setLayoutParams(lp); - targetView.setMicrophoneStateVisibility( - (width == mScreenWidth && height == mScreenHeight) ? View.INVISIBLE : View.VISIBLE); - if (targetView.getAudioViewVisibility() == View.VISIBLE) { - targetView.updateAudioView(targetPos); - } - } - - private void updateRemoteLogText(final String logText) { - runOnUiThread(new Runnable() { - @Override - public void run() { - mControlFragment.updateRemoteLogText(logText); - } - }); - } - - private boolean isAdmin() { - return mUserId.equals(QNAppServer.ADMIN_USER); - } - - private synchronized void clearMergeStreamPos(String userId) { - int pos = -1; - if (mMergeStreamPosition != null && !TextUtils.isEmpty(userId)) { - for (int i = 0; i < mMergeStreamPosition.length; i++) { - if (userId.equals(mMergeStreamPosition[i])) { - pos = i; - break; - } - } - } - if (pos >= 0 && pos < mMergeStreamPosition.length) { - mMergeStreamPosition[pos] = null; - } - } - - private int getMergeStreamIdlePos() { - int pos = -1; - for (int i = 0; i < mMergeStreamPosition.length; i++) { - if (TextUtils.isEmpty(mMergeStreamPosition[i])) { - pos = i; - break; - } - } - return pos; - } - - private synchronized void setMergeRemoteStreamLayout(String userId) { - if (mIsAdmin) { - int pos = getMergeStreamIdlePos(); - if (pos == -1) { - Log.e(TAG, "No idle position for merge streaming, so discard."); - return; - } - int x = QNAppServer.MERGE_STREAM_POS[pos][0]; - int y = QNAppServer.MERGE_STREAM_POS[pos][1]; - mRTCManager.setMergeStreamLayout(userId, x, y, 1, QNAppServer.MERGE_STREAM_WIDTH, QNAppServer.MERGE_STREAM_HEIGHT); - mMergeStreamPosition[pos] = userId; + // TODO: handle error. + if (!mIsError) { + mIsError = true; + disconnectWithErrorMessage(description); } } private void showKickoutDialog(final String userId) { - if (mKickoutDialog == null) { - mKickoutDialog = new AlertDialog.Builder(this) + if (mKickOutDialog == null) { + mKickOutDialog = new AlertDialog.Builder(this) .setNegativeButton(R.string.negative_dialog_tips, null) .create(); } - mKickoutDialog.setMessage(getString(R.string.kickout_tips, userId)); - mKickoutDialog.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(R.string.positive_dialog_tips), + mKickOutDialog.setMessage(getString(R.string.kickout_tips, userId)); + mKickOutDialog.setButton(DialogInterface.BUTTON_POSITIVE, getResources().getString(R.string.positive_dialog_tips), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - mRTCManager.kickOutUser(userId); + mEngine.kickOutUser(userId); } }); - mKickoutDialog.show(); + mKickOutDialog.show(); + } + + private void updateRemoteLogText(final String logText) { + Log.i(TAG, logText); + mControlFragment.updateRemoteLogText(logText); } @TargetApi(19) @@ -562,303 +341,197 @@ private static int getSystemUiVisibility() { } @Override - protected void onResume() { - super.onResume(); - startCall(); - } - - @Override - public void onBackPressed() { - disconnect(); - super.onBackPressed(); - } - - @Override - public void onCallHangUp() { - disconnect(); - finish(); + public void onRoomStateChanged(QNRoomState state) { + Log.i(TAG, "onRoomStateChanged:" + state.name()); + switch (state) { + case RECONNECTING: + logAndToast(getString(R.string.reconnecting_to_room)); + mControlFragment.stopTimer(); + break; + case CONNECTED: + mEngine.publishTracks(mLocalTrackList); + logAndToast(getString(R.string.connected_to_room)); + mIsJoinedRoom = true; + mControlFragment.startTimer(); + break; + case RECONNECTED: + logAndToast(getString(R.string.connected_to_room)); + mControlFragment.startTimer(); + break; + case CONNECTING: + logAndToast(getString(R.string.connecting_to, mRoomId)); + break; + } } @Override - public void onCameraSwitch() { - if (mRTCManager != null) { - mRTCManager.switchCamera(new QNCameraSwitchResultCallback() { - @Override - public void onCameraSwitchDone(boolean isFrontCamera) { - } - - @Override - public void onCameraSwitchError(String errorMessage) { - } - }); - } + public void onRemoteUserJoined(String remoteUserId, String userData) { + updateRemoteLogText("onRemoteUserJoined:remoteUserId = " + remoteUserId + " ,userData = " + userData); } @Override - public boolean onToggleMic() { - if (mRTCManager != null) { - mMicEnabled = !mMicEnabled; - mRTCManager.muteLocalAudio(!mMicEnabled); - mLocalWindow.updateMicrophoneStateView(!mMicEnabled); - } - return mMicEnabled; + public void onRemoteUserLeft(final String remoteUserId) { + updateRemoteLogText("onRemoteUserLeft:remoteUserId = " + remoteUserId); } @Override - public boolean onToggleVideo() { - if (mRTCManager != null) { - mVideoEnabled = !mVideoEnabled; - mRTCManager.muteLocalVideo(!mVideoEnabled); - if (!mVideoEnabled) { - mUsedWindowList.get(0).setAudioViewVisible(0); - } else { - mUsedWindowList.get(0).setAudioViewInvisible(); - } - mRTCManager.setPreviewEnabled(mVideoEnabled); - } - return mVideoEnabled; + public void onLocalPublished(List trackInfoList) { + updateRemoteLogText("onLocalPublished"); + mEngine.enableStatistics(); } @Override - public boolean onToggleSpeaker() { - if (mRTCManager != null) { - mSpeakerEnabled = !mSpeakerEnabled; - mRTCManager.muteRemoteAudio(!mSpeakerEnabled); - } - return mSpeakerEnabled; + public void onRemotePublished(String remoteUserId, List trackInfoList) { + updateRemoteLogText("onRemotePublished:remoteUserId = " + remoteUserId); } @Override - public boolean onToggleBeauty() { - if (mRTCManager != null) { - mBeautyEnabled = !mBeautyEnabled; - QNBeautySetting beautySetting = new QNBeautySetting(0.5f, 0.5f, 0.5f); - beautySetting.setEnable(mBeautyEnabled); - mRTCManager.setBeauty(beautySetting); + public void onRemoteUnpublished(final String remoteUserId, List trackInfoList) { + updateRemoteLogText("onRemoteUnpublished:remoteUserId = " + remoteUserId); + if (mTrackWindowMgr != null) { + mTrackWindowMgr.removeTrackInfo(remoteUserId, trackInfoList); } - return mBeautyEnabled; } @Override - public void onJoinedRoom() { - mIsAdmin = isAdmin(); - if (mIsAdmin) { - mMergeStreamPosition = new String[9]; + public void onRemoteUserMuted(String remoteUserId, List trackInfoList) { + updateRemoteLogText("onRemoteUserMuted:remoteUserId = " + remoteUserId); + if (mTrackWindowMgr != null) { + mTrackWindowMgr.onTrackInfoMuted(remoteUserId); } - onConnectedInternal(); - mRTCManager.publish(); - subscribeAllRemoteStreams(); - runOnUiThread(new Runnable() { - @Override - public void run() { - mControlFragment.startTimer(); - } - }); } @Override - public void onLocalPublished() { - if (mIsAdmin) { - mRTCManager.setMergeStreamLayout(mUserId, 0, 0, 0, QNAppServer.STREAMING_WIDTH, QNAppServer.STREAMING_HEIGHT); + public void onSubscribed(String remoteUserId, List trackInfoList) { + updateRemoteLogText("onSubscribed:remoteUserId = " + remoteUserId); + if (mTrackWindowMgr != null) { + mTrackWindowMgr.addTrackInfo(remoteUserId, trackInfoList); } - mRTCManager.setStatisticsInfoEnabled(mUserId, true, 3000); } @Override - public void onSubscribed(String userId) { - Log.i(TAG, "onSubscribed: userId: " + userId); - updateRemoteLogText("onSubscribed : " + userId); - setMergeRemoteStreamLayout(userId); - mRTCManager.setStatisticsInfoEnabled(userId, true, 3000); + public void onKickedOut(String userId) { + ToastUtils.s(RoomActivity.this, getString(R.string.kicked_by_admin)); + finish(); } @Override - public void onRemotePublished(String userId, boolean hasAudio, boolean hasVideo) { - Log.i(TAG, "onRemotePublished: userId: " + userId); - updateRemoteLogText("onRemotePublished : " + userId + " hasAudio : " + hasAudio + " hasVideo : " + hasVideo); - mRTCManager.subscribe(userId); - mRTCManager.addRemoteAudioCallback(userId, new QNRemoteAudioCallback() { - @Override - public void onRemoteAudioAvailable(String userId, ByteBuffer audioData, int size, int bitsPerSample, int sampleRate, int numberOfChannels) { + public void onStatisticsUpdated(final QNStatisticsReport report) { + if (report.userId == null || report.userId.equals(mUserId)) { + if (QNTrackKind.AUDIO.equals(report.trackKind)) { + final String log = "音频码率:" + report.audioBitrate / 1000 + "kbps \n" + + "音频丢包率:" + report.audioPacketLostRate; + mControlFragment.updateLocalAudioLogText(log); + } else if (QNTrackKind.VIDEO.equals(report.trackKind)) { + final String log = "视频码率:" + report.videoBitrate / 1000 + "kbps \n" + + "视频丢包率:" + report.videoPacketLostRate + " \n" + + "视频的宽:" + report.width + " \n" + + "视频的高:" + report.height + " \n" + + "视频的帧率:" + report.frameRate; + mControlFragment.updateLocalVideoLogText(log); } - }); - } - - @Override - public QNRemoteSurfaceView onRemoteStreamAdded(final String userId, final boolean isAudioEnabled, final boolean isVideoEnabled, - final boolean isAudioMuted, final boolean isVideoMuted) { - Log.i(TAG, "onRemoteStreamAdded: user = " + userId + ", hasAudio = " + isAudioEnabled + ", hasVideo = " + isVideoEnabled - + ", isAudioMuted = " + isAudioMuted + ", isVideoMuted = " + isVideoMuted); - updateRemoteLogText("onRemoteStreamAdded : " + userId); - - // 判断是否还有空闲的窗口用来绘制画面 - if (mUnusedWindowList.size() == 0) { - Log.e(TAG, "There were more than 9 published users in the room, with no unUsedWindow to draw."); - return null; } - final RTCVideoView remoteWindow = mUnusedWindowList.remove(0); - remoteWindow.getRemoteSurfaceView().setZOrderMediaOverlay(true); - remoteWindow.setUserId(userId); - mUserWindowMap.put(userId, remoteWindow); - mUsedWindowList.add(remoteWindow); - final int userCount = mUsedWindowList.size(); - - runOnUiThread(new Runnable() { - @Override - public void run() { - remoteWindow.setVisible(true); - remoteWindow.updateMicrophoneStateView(isAudioMuted); - if (isVideoMuted || !isVideoEnabled) { - remoteWindow.setAudioViewVisible(mUsedWindowList.indexOf(remoteWindow)); - remoteWindow.setAudioOnly(!isVideoEnabled); - } - - if (userCount <= 5) { - toggleToMultiUsersUI(userCount, mUsedWindowList); - } else { - setTargetWindowParams(userCount, userCount - 1, remoteWindow); - } - if (userCount >= 3) { - mCallControlFragmentVisible = true; - FragmentTransaction ft = getFragmentManager().beginTransaction(); - ft.show(mControlFragment); - ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); - ft.commitAllowingStateLoss(); - } - } - }); - return remoteWindow.getRemoteSurfaceView(); } @Override - public void onRemoteStreamRemoved(final String userId) { - Log.i(TAG, "onRemoteStreamRemoved: " + userId); - updateRemoteLogText("onRemoteStreamRemoved : " + userId); - clearMergeStreamPos(userId); - runOnUiThread(new Runnable() { - @Override - public void run() { - if (mUserWindowMap.containsKey(userId)) { - RTCVideoView remoteVideoView = mUserWindowMap.remove(userId); - remoteVideoView.setVisible(false); - mUsedWindowList.remove(remoteVideoView); - mUnusedWindowList.add(remoteVideoView); - } - toggleToMultiUsersUI(mUsedWindowList.size(), mUsedWindowList); - } - }); + public void onAudioRouteChanged(QNAudioDevice routing) { + updateRemoteLogText("onAudioRouteChanged: " + routing.name()); } @Override - public void onRemoteUserLeaved(String userId) { - Log.i(TAG, "onUserOut: " + userId); - updateRemoteLogText("onRemoteUserLeaved : " + userId); + public void onCreateMergeJobSuccess(String mergeJobId) { } @Override - public void onRemoteUserJoined(String userId) { - Log.i(TAG, "onUserIn: " + userId); - updateRemoteLogText("onRemoteUserJoined : " + userId); + public void onError(int errorCode, String description) { + if (errorCode == QNErrorCode.ERROR_TOKEN_ERROR + || errorCode == QNErrorCode.ERROR_TOKEN_EXPIRED + || errorCode == QNErrorCode.ERROR_AUTH_FAIL + || errorCode == QNErrorCode.ERROR_RECONNECT_TOKEN_ERROR + || errorCode == QNErrorCode.ERROR_SIGNAL_IO_EXCEPTION + || errorCode == QNErrorCode.ERROR_TOKEN_INVALID) { + reportError("roomToken 错误,请重新加入房间"); + } else if (errorCode == QNErrorCode.ERROR_PUBLISH_FAIL) { + reportError("发布失败,请重新加入房间发布"); + } else if (errorCode == QNErrorCode.ERROR_ACCESSTOKEN_INVALID) { + reportError("服务端发生了一些问题,加入房间失败,请重试"); + } else { + logAndToast("errorCode:" + errorCode + " description:" + description); + } } + // Demo control @Override - public void onRemoteUnpublished(String userId) { - Log.i(TAG, "onRemoteUnpublish: " + userId); - updateRemoteLogText("onRemoteUnpublished : " + userId); + public void onCallHangUp() { + if (mEngine != null) { + mEngine.leaveRoom(); + } + finish(); } @Override - public void onRemoteMute(final String userId, final boolean isAudioMuted, final boolean isVideoMuted) { - Log.i(TAG, "onRemoteMute: user = " + userId + ", isAudioMuted = " + isAudioMuted + ", isVideoMuted = " + isVideoMuted); - runOnUiThread(new Runnable() { - @Override - public void run() { - RTCVideoView remoteWindow = getWindowByUserId(userId); - if (remoteWindow != null) { - if (isVideoMuted && remoteWindow.getAudioViewVisibility() != View.VISIBLE) { - remoteWindow.setAudioViewVisible(mUsedWindowList.indexOf(remoteWindow)); - } else if (!isVideoMuted && remoteWindow.getAudioViewVisibility() != View.INVISIBLE && !remoteWindow.isAudioOnly()) { - remoteWindow.setAudioViewInvisible(); - } - remoteWindow.updateMicrophoneStateView(isAudioMuted); + public void onCameraSwitch() { + if (mEngine != null) { + mEngine.switchCamera(new QNCameraSwitchResultCallback() { + @Override + public void onCameraSwitchDone(boolean isFrontCamera) { } - } - }); - } - @Override - public void onStateChanged(QNRoomState state) { - Log.i(TAG, "onStateChanged: " + state); - updateRemoteLogText("onStateChanged : " + state.name()); - switch (state) { - case RECONNECTING: - mCallStartedTimeMs = System.currentTimeMillis(); - logAndToast(getString(R.string.reconnecting_to_room)); - break; - case CONNECTED: - break; + @Override + public void onCameraSwitchError(String errorMessage) { + } + }); } } @Override - public void onError(final int errorCode, String description) { - Log.i(TAG, "onError: " + errorCode + " " + description); - updateRemoteLogText("onError : " + errorCode + " " + description); - switch (errorCode) { - case ERROR_KICKED_OUT_OF_ROOM: - runOnUiThread(new Runnable() { - @Override - public void run() { - ToastUtils.s(RoomActivity.this, getString(R.string.kicked_by_admin)); - } - }); - onCallHangUp(); - break; - default: - reportError("errorCode: " + errorCode + "\ndescription: \n" + description); - break; + public boolean onToggleMic() { + if (mEngine != null && mLocalAudioTrack != null) { + mMicEnabled = !mMicEnabled; + mLocalAudioTrack.setMuted(!mMicEnabled); + mEngine.muteTracks(Collections.singletonList(mLocalAudioTrack)); + if (mTrackWindowMgr != null) { + mTrackWindowMgr.onTrackInfoMuted(mUserId); + } } + return mMicEnabled; } @Override - public void onStatisticsUpdated(QNStatisticsReport report) { - Log.d(TAG, "onStatisticsUpdated: " + report.toString()); - if (!mUserId.equals(report.userId)) { - return; - } - mLocalLogText = String.format(getString(R.string.log_text), report.userId, report.frameRate, report.videoBitrate / 1000, report.audioBitrate / 1000, report.videoPacketLostRate, report.audioPacketLostRate, report.width, report.height); - runOnUiThread(new Runnable() { - @Override - public void run() { - mControlFragment.updateLocalLogText(mLocalLogText); + public boolean onToggleVideo() { + if (mEngine != null && mLocalVideoTrack != null) { + mVideoEnabled = !mVideoEnabled; + mLocalVideoTrack.setMuted(!mVideoEnabled); + if (mLocalScreenTrack != null) { + mLocalScreenTrack.setMuted(!mVideoEnabled); + mEngine.muteTracks(Arrays.asList(mLocalScreenTrack, mLocalVideoTrack)); + } else { + mEngine.muteTracks(Collections.singletonList(mLocalVideoTrack)); } - }); - } - - @Override - public void onUserKickedOut(String userId) { - Log.i(TAG, "kicked out user: " + userId); - updateRemoteLogText("onUserKickedOut : " + userId); + if (mTrackWindowMgr != null) { + mTrackWindowMgr.onTrackInfoMuted(mUserId); + } + } + return mVideoEnabled; } @Override - public void onAudioRouteChanged(QNAudioDevice routing) { - Log.i(TAG, "onAudioRouteChanged: " + routing.value()); + public boolean onToggleSpeaker() { + if (mEngine != null) { + mSpeakerEnabled = !mSpeakerEnabled; + mEngine.muteRemoteAudio(!mSpeakerEnabled); + } + return mSpeakerEnabled; } @Override - public void onCreateMergeJobSuccess(String mergeJobId) { - Log.i(TAG, "onCreateMergeJobSuccess: " + mergeJobId); - } - - private RTCVideoView.OnLongClickListener mOnLongClickListener = new RTCVideoView.OnLongClickListener() { - @Override - public void onLongClick(String userId) { - if (!mIsAdmin) { - Log.i(TAG, "Only admin user can kick a player!"); - return; - } - showKickoutDialog(userId); + public boolean onToggleBeauty() { + if (mEngine != null) { + mBeautyEnabled = !mBeautyEnabled; + QNBeautySetting beautySetting = new QNBeautySetting(0.5f, 0.5f, 0.5f); + beautySetting.setEnable(mBeautyEnabled); + mEngine.setBeauty(beautySetting); } - }; -} \ No newline at end of file + return mBeautyEnabled; + } +} diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/ScreenCaptureActivity.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/ScreenCaptureActivity.java deleted file mode 100644 index 981707b..0000000 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/ScreenCaptureActivity.java +++ /dev/null @@ -1,431 +0,0 @@ -package com.qiniu.droid.rtc.demo.activity; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.graphics.SurfaceTexture; -import android.hardware.Camera; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; -import android.view.TextureView; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ImageButton; - -import com.qiniu.droid.rtc.QNLocalSurfaceView; -import com.qiniu.droid.rtc.QNRTCManager; -import com.qiniu.droid.rtc.QNRTCSetting; -import com.qiniu.droid.rtc.QNRemoteAudioCallback; -import com.qiniu.droid.rtc.QNRemoteSurfaceView; -import com.qiniu.droid.rtc.QNRoomEventListener; -import com.qiniu.droid.rtc.QNRoomState; -import com.qiniu.droid.rtc.QNStatisticsReport; -import com.qiniu.droid.rtc.QNVideoFormat; -import com.qiniu.droid.rtc.demo.R; -import com.qiniu.droid.rtc.demo.ui.RTCVideoView; -import com.qiniu.droid.rtc.demo.ui.RemoteVideoView; -import com.qiniu.droid.rtc.demo.utils.Config; -import com.qiniu.droid.rtc.demo.utils.ToastUtils; -import com.qiniu.droid.rtc.model.QNAudioDevice; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; - -import static com.qiniu.droid.rtc.QNErrorCode.ERROR_KICKED_OUT_OF_ROOM; - -public class ScreenCaptureActivity extends Activity implements QNRoomEventListener { - private static final String TAG = "ScreenCaptureActivity"; - public static final String EXTRA_ROOM_TOKEN = "ROOM_TOKEN"; - - private static final String[] MANDATORY_PERMISSIONS = { - "android.permission.MODIFY_AUDIO_SETTINGS", - "android.permission.RECORD_AUDIO", - "android.permission.INTERNET", - "android.permission.CAMERA" - }; - - private List mUsedWindowList; - private List mUnusedWindowList; - private ConcurrentHashMap mUserWindowMap; - - private ImageButton mBtnVideo; - private RemoteVideoView mRemoteWindowA; - private RemoteVideoView mRemoteWindowB; - private RemoteVideoView mRemoteWindowC; - private RemoteVideoView mRemoteWindowD; - private RemoteVideoView mRemoteWindowE; - private RemoteVideoView mRemoteWindowF; - private RemoteVideoView mRemoteWindowG; - private RemoteVideoView mRemoteWindowH; - - private QNRTCManager mRTCManager; - private String mRoomToken; - private Camera mCamera; - private FrameLayout mPreviewLayout; - private boolean mIsPreviewEnable = true; - private boolean mIsPreviewFirstFrame = true; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - requestWindowFeature(Window.FEATURE_NO_TITLE); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON - | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED - | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); - getWindow().getDecorView().setSystemUiVisibility(getSystemUiVisibility()); - - setContentView(R.layout.activity_screen_capture); - - for (String permission : MANDATORY_PERMISSIONS) { - if (checkCallingOrSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { - ToastUtils.s(getApplicationContext(), "Permission " + permission + " is not granted"); - setResult(RESULT_CANCELED); - finish(); - return; - } - } - - Intent intent = getIntent(); - mRoomToken = intent.getStringExtra(EXTRA_ROOM_TOKEN); - - SharedPreferences preferences = getSharedPreferences(getString(R.string.app_name), Context.MODE_PRIVATE); - int videoWidth = preferences.getInt(Config.WIDTH, QNRTCSetting.DEFAULT_WIDTH); - int videoHeight = preferences.getInt(Config.HEIGHT, QNRTCSetting.DEFAULT_HEIGHT); - boolean isHwCodec = preferences.getInt(Config.CODEC_MODE, Config.SW) == Config.HW; - - mPreviewLayout = (FrameLayout) findViewById(R.id.camera_preview); - mBtnVideo = (ImageButton) findViewById(R.id.video_button); - mRemoteWindowA = (RemoteVideoView) findViewById(R.id.remote_video_view_a); - mRemoteWindowB = (RemoteVideoView) findViewById(R.id.remote_video_view_b); - mRemoteWindowC = (RemoteVideoView) findViewById(R.id.remote_video_view_c); - mRemoteWindowD = (RemoteVideoView) findViewById(R.id.remote_video_view_d); - mRemoteWindowE = (RemoteVideoView) findViewById(R.id.remote_video_view_e); - mRemoteWindowF = (RemoteVideoView) findViewById(R.id.remote_video_view_f); - mRemoteWindowG = (RemoteVideoView) findViewById(R.id.remote_video_view_g); - mRemoteWindowH = (RemoteVideoView) findViewById(R.id.remote_video_view_h); - - mUserWindowMap = new ConcurrentHashMap<>(); - mUsedWindowList = Collections.synchronizedList(new LinkedList()); - mUnusedWindowList = Collections.synchronizedList(new LinkedList()); - mUnusedWindowList.add(mRemoteWindowA); - mUnusedWindowList.add(mRemoteWindowB); - mUnusedWindowList.add(mRemoteWindowC); - mUnusedWindowList.add(mRemoteWindowD); - mUnusedWindowList.add(mRemoteWindowE); - mUnusedWindowList.add(mRemoteWindowF); - mUnusedWindowList.add(mRemoteWindowG); - mUnusedWindowList.add(mRemoteWindowH); - - TextureView previewTextureView = (TextureView) findViewById(R.id.camera_preview_texture_view); - previewTextureView.setSurfaceTextureListener(mPreviewSurfaceTextureListener); - - QNLocalSurfaceView localSurfaceView = (QNLocalSurfaceView) findViewById(R.id.local_surface_view); - QNRTCSetting setting = new QNRTCSetting(); - setting.setHWCodecEnabled(isHwCodec) - .setScreenCaptureEnabled(true) - .setVideoPreviewFormat(new QNVideoFormat(videoWidth, videoHeight, QNRTCSetting.DEFAULT_FPS)) - .setVideoEncodeFormat(new QNVideoFormat(videoWidth, videoHeight, QNRTCSetting.DEFAULT_FPS)); - mRTCManager = new QNRTCManager(); - mRTCManager.setRoomEventListener(this); - mRTCManager.addRemoteWindow(mRemoteWindowA.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowB.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowC.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowD.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowE.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowF.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowG.getRemoteSurfaceView()); - mRTCManager.addRemoteWindow(mRemoteWindowH.getRemoteSurfaceView()); - mRTCManager.initialize(getApplicationContext(), setting, localSurfaceView); - } - - @Override - protected void onResume() { - super.onResume(); - startCameraPreview(); - mIsPreviewFirstFrame = true; - mRTCManager.joinRoom(mRoomToken); - } - - @Override - protected void onPause() { - super.onPause(); - if (mCamera != null) { - mCamera.stopPreview(); - mCamera.release(); - mCamera = null; - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - if (mRTCManager != null) { - mRTCManager.destroy(); - } - - mRemoteWindowA = null; - mRemoteWindowB = null; - mRemoteWindowC = null; - mRemoteWindowD = null; - mRemoteWindowE = null; - mRemoteWindowF = null; - mRemoteWindowG = null; - mRemoteWindowH = null; - } - - @TargetApi(19) - private static int getSystemUiVisibility() { - int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { - flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; - } - return flags; - } - - private static Camera getCameraInstance() { - Camera c = null; - try { - c = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT); // 打开前置摄像头 - } catch (Exception e) { - // 相机不可用 - } - return c; - } - - private void startCameraPreview() { - mCamera = getCameraInstance(); - if (mCamera != null) { - Camera.Parameters parameters = mCamera.getParameters(); - float ratio = 9f / 16f; - float temp = 0f; - float minDiff = 100f; - int previewWidth = 0; - int previewHeight = 0; - List supportedPreviewSizes = parameters.getSupportedPreviewSizes(); - for (Camera.Size s : supportedPreviewSizes) { - temp = Math.abs(((float) s.height / (float) s.width) - ratio); - if (temp < minDiff) { - minDiff = temp; - previewWidth = s.width; - previewHeight = s.height; - } - } - parameters.setPreviewSize(previewWidth, previewHeight); - mCamera.setParameters(parameters); - Log.i(TAG, "previewWidth = " + previewWidth + " previewHeight = " + previewHeight); - mCamera.startPreview(); - } - } - - private void subscribeAllRemoteStreams() { - ArrayList publishingUsers = mRTCManager.getPublishingUserList(); - if (publishingUsers != null && !publishingUsers.isEmpty()) { - for (String userId : publishingUsers) { - mRTCManager.subscribe(userId); - mRTCManager.addRemoteAudioCallback(userId, new QNRemoteAudioCallback() { - @Override - public void onRemoteAudioAvailable(String userId, ByteBuffer audioData, int size, int bitsPerSample, int sampleRate, int numberOfChannels) { - } - }); - } - } - } - - public void onClickHangUp(View view) { - finish(); - } - - public void onClickPreviewEnable(View view) { - mPreviewLayout.setVisibility(mIsPreviewEnable ? View.GONE : View.VISIBLE); - mIsPreviewEnable = !mIsPreviewEnable; - mBtnVideo.setImageResource(mIsPreviewEnable ? R.mipmap.video_open : R.mipmap.video_close); - } - - public void onClickToHome(View view) { - ToastUtils.l(this, "正在全局录制,可以返回应用"); - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.addCategory(Intent.CATEGORY_HOME); - startActivity(intent); - } - - @Override - public void onJoinedRoom() { - mRTCManager.publish(); - } - - @Override - public void onLocalPublished() { - subscribeAllRemoteStreams(); - } - - @Override - public void onSubscribed(String userId) { - Log.i(TAG, "onSubscribed = " + userId); - } - - @Override - public void onRemotePublished(String userId, boolean hasAudio, boolean hasVideo) { - mRTCManager.subscribe(userId); - } - - @Override - public QNRemoteSurfaceView onRemoteStreamAdded(final String userId, final boolean isAudioEnabled, final boolean isVideoEnabled, - final boolean isAudioMuted, final boolean isVideoMuted) { - Log.i(TAG, "onRemoteStreamAdded: user = " + userId + ", hasAudio = " + isAudioEnabled + ", hasVideo = " + isVideoEnabled - + ", isAudioMuted = " + isAudioMuted + ", isVideoMuted = " + isVideoMuted); - final RTCVideoView remoteWindow = mUnusedWindowList.remove(0); - remoteWindow.setUserId(userId); - mUserWindowMap.put(userId, remoteWindow); - mUsedWindowList.add(remoteWindow); - - runOnUiThread(new Runnable() { - @Override - public void run() { - remoteWindow.setVisible(true); - remoteWindow.setMicrophoneStateVisibility(View.GONE); - remoteWindow.updateMicrophoneStateView(isAudioMuted); - if (isVideoMuted || !isVideoEnabled) { - remoteWindow.setAudioViewVisible(mUsedWindowList.indexOf(remoteWindow)); - remoteWindow.setAudioOnly(!isVideoEnabled); - } - } - }); - return remoteWindow.getRemoteSurfaceView(); - } - - @Override - public void onRemoteStreamRemoved(final String userId) { - Log.i(TAG, "onRemoteStreamRemoved: " + userId); - runOnUiThread(new Runnable() { - @Override - public void run() { - if (mUserWindowMap.containsKey(userId)) { - RTCVideoView remoteVideoView = mUserWindowMap.remove(userId); - remoteVideoView.setVisibility(View.GONE); - mUsedWindowList.remove(remoteVideoView); - mUnusedWindowList.add(remoteVideoView); - } - } - }); - } - - @Override - public void onRemoteUserJoined(String userId) { - Log.i(TAG, "onUserIn: " + userId); - } - - @Override - public void onRemoteUserLeaved(String userId) { - Log.i(TAG, "onUserOut: " + userId); - } - - @Override - public void onRemoteUnpublished(String userId) { - Log.i(TAG, "onRemoteUnpublish: " + userId); - } - - @Override - public void onRemoteMute(final String userId, final boolean isAudioMuted, final boolean isVideoMuted) { - Log.i(TAG, "onRemoteMute: user = " + userId + ", audio = " + isAudioMuted + ", video = " + isVideoMuted); - runOnUiThread(new Runnable() { - @Override - public void run() { - RTCVideoView remoteWindow = mUserWindowMap.containsKey(userId) ? mUserWindowMap.get(userId) : null; - if (remoteWindow != null) { - if (isVideoMuted && remoteWindow.getAudioViewVisibility() != View.VISIBLE) { - remoteWindow.setAudioViewVisible(mUsedWindowList.indexOf(remoteWindow)); - } else if (!isVideoMuted && remoteWindow.getAudioViewVisibility() != View.INVISIBLE && !remoteWindow.isAudioOnly()) { - remoteWindow.setAudioViewInvisible(); - } - } - } - }); - } - - @Override - public void onStateChanged(QNRoomState state) { - Log.i(TAG, "onStateChanged: " + state); - } - - @Override - public void onError(int errorCode, String description) { - Log.i(TAG, "onError: " + errorCode + " " + description); - if (errorCode == ERROR_KICKED_OUT_OF_ROOM) { - runOnUiThread(new Runnable() { - @Override - public void run() { - ToastUtils.s(ScreenCaptureActivity.this, getString(R.string.kicked_by_admin)); - } - }); - finish(); - } - } - - @Override - public void onStatisticsUpdated(QNStatisticsReport report) { - Log.d(TAG, "onStatisticsUpdated: " + report.toString()); - } - - @Override - public void onUserKickedOut(String userId) { - Log.i(TAG, "kicked out user: " + userId); - } - - @Override - public void onAudioRouteChanged(QNAudioDevice routing) { - Log.i(TAG, "onAudioRouteChanged: " + routing.value()); - } - - @Override - public void onCreateMergeJobSuccess(String mergeJobId) { - Log.i(TAG, "onCreateMergeJobSuccess: " + mergeJobId); - } - - private TextureView.SurfaceTextureListener mPreviewSurfaceTextureListener = new TextureView.SurfaceTextureListener() { - @Override - public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { - try { - mCamera.setPreviewTexture(surface); - mCamera.setDisplayOrientation(90); - } catch (IOException e) { - e.printStackTrace(); - } - } - - @Override - public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { - Log.i(TAG, "onSurfaceTextureSizeChanged"); - } - - @Override - public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { - Log.i(TAG, "onSurfaceTextureDestroyed"); - return false; - } - - @Override - public void onSurfaceTextureUpdated(SurfaceTexture surface) { - if (mCamera != null && mIsPreviewFirstFrame) { - try { - mCamera.setPreviewTexture(surface); - mCamera.setDisplayOrientation(90); - mIsPreviewFirstFrame = false; - } catch (IOException e) { - e.printStackTrace(); - } - } - } - }; -} diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/SettingActivity.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/SettingActivity.java index c1530a2..3e7286c 100644 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/SettingActivity.java +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/activity/SettingActivity.java @@ -39,11 +39,15 @@ public class SettingActivity extends AppCompatActivity { private RadioGroup mCodecModeRadioGroup; private RadioButton mHwCodecMode; private RadioButton mSwCodecMode; + private RadioGroup mMaintainResRadioGroup; + private RadioButton mMaintainResolutionYes; + private RadioButton mMaintainResolutionNo; private EditText mAppIdEditText; private int mSelectPos = 0; private String mUserName; private int mEncodeMode = 0; + private boolean mMaintainResolution = false; private List mDefaultConfiguration = new ArrayList<>(); private ArrayAdapter mAdapter; private SpinnerPopupWindow mSpinnerPopupWindow; @@ -64,6 +68,11 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { mHwCodecMode = (RadioButton) findViewById(R.id.hw_radio_button); mSwCodecMode = (RadioButton) findViewById(R.id.sw_radio_button); + mMaintainResRadioGroup = (RadioGroup) findViewById(R.id.maintain_resolution_button); + mMaintainResRadioGroup.setOnCheckedChangeListener(mOnMaintainResCheckedChangeListener); + mMaintainResolutionYes = (RadioButton) findViewById(R.id.maintain_res_button_yes); + mMaintainResolutionNo = (RadioButton) findViewById(R.id.maintain_res_button_no); + mAppIdEditText = (EditText) findViewById(R.id.app_id_edit_text); mVersionCodeTextView.setText(String.format(getString(R.string.version_code), getVersionDescription(), getBuildTimeDescription())); @@ -87,13 +96,20 @@ protected void onCreate(@Nullable Bundle savedInstanceState) { mSelectPos = preferences.getInt(Config.CONFIG_POS, 1); mConfigTextView.setText(mDefaultConfiguration.get(mSelectPos)); - int codecMode = preferences.getInt(Config.CODEC_MODE, Config.SW); + int codecMode = preferences.getInt(Config.CODEC_MODE, Config.HW); if (codecMode == Config.HW) { mHwCodecMode.setChecked(true); } else { mSwCodecMode.setChecked(true); } + mMaintainResolution = preferences.getBoolean(Config.MAINTAIN_RES, false); + if (mMaintainResolution) { + mMaintainResolutionYes.setChecked(true); + } else { + mMaintainResolutionNo.setChecked(true); + } + mSpinnerPopupWindow = new SpinnerPopupWindow(this); mSpinnerPopupWindow.setOnSpinnerItemClickListener(mOnSpinnerItemClickListener); @@ -128,6 +144,7 @@ public void onClickSaveConfiguration(View v) { editor.putInt(Config.CONFIG_POS, mSelectPos); editor.putInt(Config.CODEC_MODE, mEncodeMode); + editor.putBoolean(Config.MAINTAIN_RES, mMaintainResolution); editor.putInt(Config.WIDTH, Config.DEFAULT_RESOLUTION[mSelectPos][0]); editor.putInt(Config.HEIGHT, Config.DEFAULT_RESOLUTION[mSelectPos][1]); @@ -190,9 +207,9 @@ protected String getBuildTimeDescription() { } private boolean isTestMode() { - if (mAppIdEditText.getText().toString().compareTo(QNAppServer.TEST_MODE_APP_ID) == 0) { - return true; - } +// if (mAppIdEditText.getText().toString().compareTo(QNAppServer.TEST_MODE_APP_ID) == 0) { +// return true; +// } return false; } @@ -211,9 +228,25 @@ public void onCheckedChanged(RadioGroup group, int checkedId) { switch (group.getCheckedRadioButtonId()) { case R.id.hw_radio_button: mEncodeMode = Config.HW; + mMaintainResRadioGroup.setVisibility(View.GONE); break; case R.id.sw_radio_button: mEncodeMode = Config.SW; + mMaintainResRadioGroup.setVisibility(View.VISIBLE); + break; + } + } + }; + + private RadioGroup.OnCheckedChangeListener mOnMaintainResCheckedChangeListener = new RadioGroup.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(RadioGroup group, int checkedId) { + switch (group.getCheckedRadioButtonId()) { + case R.id.maintain_res_button_yes: + mMaintainResolution = true; + break; + case R.id.maintain_res_button_no: + mMaintainResolution = false; break; } } diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/fragment/ControlFragment.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/fragment/ControlFragment.java index be3b980..b2944cf 100644 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/fragment/ControlFragment.java +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/fragment/ControlFragment.java @@ -28,7 +28,8 @@ public class ControlFragment extends Fragment { private ImageButton mToggleVideoButton; private ImageButton mLogShownButton; private LinearLayout mLogView; - private TextView mLocalTextView; + private TextView mLocalTextViewForVideo; + private TextView mLocalTextViewForAudio; private TextView mRemoteTextView; private StringBuffer mRemoteLogText; private Chronometer mTimer; @@ -77,8 +78,10 @@ public View onCreateView( mToggleVideoButton = (ImageButton) mControlView.findViewById(R.id.camera_button); mLogShownButton = (ImageButton) mControlView.findViewById(R.id.log_shown_button); mLogView = (LinearLayout) mControlView.findViewById(R.id.log_text); - mLocalTextView = (TextView) mControlView.findViewById(R.id.local_log_text); - mLocalTextView.setMovementMethod(ScrollingMovementMethod.getInstance()); + mLocalTextViewForVideo = (TextView) mControlView.findViewById(R.id.local_log_text_video); + mLocalTextViewForVideo.setMovementMethod(ScrollingMovementMethod.getInstance()); + mLocalTextViewForAudio = (TextView) mControlView.findViewById(R.id.local_log_text_audio); + mLocalTextViewForAudio.setMovementMethod(ScrollingMovementMethod.getInstance()); mRemoteTextView = (TextView) mControlView.findViewById(R.id.remote_log_text); mRemoteTextView.setMovementMethod(ScrollingMovementMethod.getInstance()); mTimer = (Chronometer) mControlView.findViewById(R.id.timer); @@ -156,9 +159,15 @@ public void stopTimer() { mTimer.stop(); } - public void updateLocalLogText(String logText) { + public void updateLocalVideoLogText(String logText) { if (mLogView.getVisibility() == View.VISIBLE) { - mLocalTextView.setText(logText); + mLocalTextViewForVideo.setText(logText); + } + } + + public void updateLocalAudioLogText(String logText) { + if (mLogView.getVisibility() == View.VISIBLE) { + mLocalTextViewForAudio.setText(logText); } } diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/LocalVideoView.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/LocalVideoView.java deleted file mode 100644 index c2a3937..0000000 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/LocalVideoView.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.qiniu.droid.rtc.demo.ui; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; - -import com.qiniu.droid.rtc.QNLocalSurfaceView; -import com.qiniu.droid.rtc.QNLocalVideoCallback; -import com.qiniu.droid.rtc.demo.R; - -import org.webrtc.VideoFrame; - -public class LocalVideoView extends RTCVideoView implements QNLocalVideoCallback { - - public LocalVideoView(Context context, AttributeSet attrs) { - super(context, attrs); - LayoutInflater.from(mContext).inflate(R.layout.local_video_view, this, true); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mLocalSurfaceView = (QNLocalSurfaceView) findViewById(R.id.local_surface_view); - mLocalSurfaceView.setLocalVideoCallback(this); - } - - @Override - public int onRenderingFrame(int textureId, int width, int height, VideoFrame.TextureBuffer.Type type, long timestampNs) { - return textureId; - } - - @Override - public void onPreviewFrame(byte[] data, int width, int height, int rotation, int fmt, long timestampNs) { - } - - @Override - public void onSurfaceCreated() { - - } - - @Override - public void onSurfaceChanged(int i, int i1) { - - } - - @Override - public void onSurfaceDestroyed() { - - } -} diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/RTCVideoView.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/RTCVideoView.java deleted file mode 100644 index 1933d7e..0000000 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/RTCVideoView.java +++ /dev/null @@ -1,137 +0,0 @@ -package com.qiniu.droid.rtc.demo.ui; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; - -import com.qiniu.droid.rtc.QNLocalSurfaceView; -import com.qiniu.droid.rtc.QNRemoteSurfaceView; -import com.qiniu.droid.rtc.demo.R; - -public class RTCVideoView extends FrameLayout implements View.OnLongClickListener { - - protected Context mContext; - protected QNLocalSurfaceView mLocalSurfaceView; - protected QNRemoteSurfaceView mRemoteSurfaceView; - private ImageView mMicrophoneStateView; - private TextView mAudioView; - private OnLongClickListener mOnLongClickListener; - private String mUserId; - private boolean mIsAudioOnly = false; - - public interface OnLongClickListener { - void onLongClick(String userId); - } - - public RTCVideoView(Context context) { - super(context); - mContext = context; - } - - public RTCVideoView(Context context, AttributeSet attrs) { - super(context, attrs); - mContext = context; - } - - public void setUserId(String userId) { - mUserId = userId; - } - - public void updateMicrophoneStateView(boolean isMute) { - mMicrophoneStateView.setImageResource(isMute ? R.mipmap.microphone_disable : R.drawable.microphone_state_enable); - } - - public QNLocalSurfaceView getLocalSurfaceView() { - return mLocalSurfaceView; - } - - public QNRemoteSurfaceView getRemoteSurfaceView() { - return mRemoteSurfaceView; - } - - public ImageView getMicrophoneStateView() { - return mMicrophoneStateView; - } - - public void setVisible(boolean isVisible) { - if (!isVisible) { - mUserId = null; - mAudioView.setVisibility(INVISIBLE); - } - setVisibility(isVisible ? VISIBLE : INVISIBLE); - mMicrophoneStateView.setVisibility(isVisible ? VISIBLE : INVISIBLE); - setVideoViewVisible(isVisible); - } - - public void setMicrophoneStateVisibility(int visibility) { - mMicrophoneStateView.setVisibility(visibility); - } - - public void setAudioViewVisible(int pos) { - if (getVisibility() != VISIBLE) { - setVisibility(VISIBLE); - } - mAudioView.setText(mUserId); - mAudioView.setBackgroundColor(getTargetColor(pos)); - mAudioView.setVisibility(VISIBLE); - setVideoViewVisible(false); - } - - public void setAudioViewInvisible() { - mAudioView.setVisibility(INVISIBLE); - setVideoViewVisible(true); - } - - public void updateAudioView(int pos) { - mAudioView.setBackgroundColor(getTargetColor(pos)); - } - - public int getAudioViewVisibility() { - return mAudioView.getVisibility(); - } - - public void setOnLongClickListener(OnLongClickListener listener) { - mOnLongClickListener = listener; - } - - public void setAudioOnly(boolean isAudioOnly) { - mIsAudioOnly = isAudioOnly; - } - - public boolean isAudioOnly() { - return mIsAudioOnly; - } - - private void setVideoViewVisible(boolean isVisible) { - if (mLocalSurfaceView != null) { - mLocalSurfaceView.setVisibility(isVisible ? VISIBLE : INVISIBLE); - } - if (mRemoteSurfaceView != null) { - mRemoteSurfaceView.setVisibility(isVisible ? VISIBLE : INVISIBLE); - } - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - setOnLongClickListener(this); - mMicrophoneStateView = (ImageView) findViewById(R.id.microphone_state_view); - mAudioView = (TextView) findViewById(R.id.qn_audio_view); - } - - private int getTargetColor(int pos) { - int[] customizedColors = mContext.getResources().getIntArray(R.array.audioBackgroundColors); - return customizedColors[pos % 6]; - } - - @Override - public boolean onLongClick(View v) { - if (mOnLongClickListener != null) { - mOnLongClickListener.onLongClick(mUserId); - } - return false; - } -} diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/RadioGroupFlow.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/RadioGroupFlow.java new file mode 100644 index 0000000..1d919ab --- /dev/null +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/RadioGroupFlow.java @@ -0,0 +1,67 @@ +package com.qiniu.droid.rtc.demo.ui; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.View; +import android.widget.RadioGroup; + +public class RadioGroupFlow extends RadioGroup { + public RadioGroupFlow(Context context) { + super(context); + } + + public RadioGroupFlow(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int maxWidth = MeasureSpec.getSize(widthMeasureSpec); + int childCount = getChildCount(); + int x = 0; + int y = 0; + int row = 0; + + for (int index = 0; index < childCount; index++) { + final View child = getChildAt(index); + if (child.getVisibility() != View.GONE) { + child.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); + + int width = child.getMeasuredWidth(); + int height = child.getMeasuredHeight(); + x += width; + y = row * height + height; + if (x > maxWidth) { + x = width; + row++; + y = row * height + height; + } + } + } + setMeasuredDimension(maxWidth, y); + } + + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + final int childCount = getChildCount(); + int maxWidth = r - l; + int x = 0; + int y = 0; + int row = 0; + for (int i = 0; i < childCount; i++) { + final View child = this.getChildAt(i); + if (child.getVisibility() != View.GONE) { + int width = child.getMeasuredWidth(); + int height = child.getMeasuredHeight(); + x += width; + y = row * height + height; + if (x > maxWidth) { + x = width; + row++; + y = row * height + height; + } + child.layout(x - width, y - height, x, y); + } + } + } +} diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/RemoteVideoView.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/RemoteVideoView.java deleted file mode 100644 index 718fae5..0000000 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/RemoteVideoView.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.qiniu.droid.rtc.demo.ui; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.LayoutInflater; - -import com.qiniu.droid.rtc.QNRemoteSurfaceView; -import com.qiniu.droid.rtc.QNRemoteVideoCallback; -import com.qiniu.droid.rtc.demo.R; - -import org.webrtc.VideoFrame; - -public class RemoteVideoView extends RTCVideoView implements QNRemoteVideoCallback { - - public RemoteVideoView(Context context) { - super(context); - mContext = context; - } - - public RemoteVideoView(Context context, AttributeSet attrs) { - super(context, attrs); - LayoutInflater.from(mContext).inflate(R.layout.remote_video_view, this, true); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - mRemoteSurfaceView = (QNRemoteSurfaceView) findViewById(R.id.remote_surface_view); - mRemoteSurfaceView.setRemoteVideoCallback(this); - } - - @Override - public void onRenderingFrame(VideoFrame frame) { - - } - - @Override - public void onSurfaceCreated() { - - } - - @Override - public void onSurfaceChanged(int i, int i1) { - - } - - @Override - public void onSurfaceDestroyed() { - - } -} diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/UserTrackView.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/UserTrackView.java new file mode 100644 index 0000000..fa0af6f --- /dev/null +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/UserTrackView.java @@ -0,0 +1,432 @@ +package com.qiniu.droid.rtc.demo.ui; + +import android.content.Context; +import android.content.res.Resources; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.TextView; + +import com.qiniu.droid.rtc.QNRTCEngine; +import com.qiniu.droid.rtc.QNSurfaceView; +import com.qiniu.droid.rtc.QNTrackInfo; +import com.qiniu.droid.rtc.QNTrackKind; +import com.qiniu.droid.rtc.demo.R; + +import org.webrtc.RendererCommon; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class UserTrackView extends FrameLayout { + + private static final String TAG = "UserTrackView"; + private static final boolean PRINT_DEBUG_LOG = false; + + private static final boolean DISPLAY_LARGE_VIDEO_TRACK = true; + private static final boolean DISPLAY_SMALL_VIDEO_TRACK = true; + + public static final String TAG_CAMERA = "camera"; + public static final String TAG_SCREEN = "screen"; + + private boolean inited = false; + private ViewGroup mVideoViewLargeParent; + private QNSurfaceView mSurfaceViewLarge; + + private ViewGroup mVideoViewSmallParent; + private QNSurfaceView mSurfaceViewSmall; + + private ImageView mMicrophoneStateView; + private TextView mAudioView; + + private QNRTCEngine mQNRTCEngine; + private String mUserId; + private QNTrackInfo mQNAudioTrackInfo; + private List mQNVideoTrackInfos = new ArrayList<>(); + + private QNTrackInfo mTrackInfoDisplayInLargeView = null; + private QNTrackInfo mTrackInfoDisplayInSmallView = null; + private int mMicrophoneViewVisibility = -1; + private int mPos = -1; + + public UserTrackView(@NonNull Context context) { + super(context); + init(); + } + + public UserTrackView(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + init(); + } + + private void init() { + if (inited) { + return; + } + inited = true; + LayoutInflater.from(getContext()).inflate(getLayout(), this, true); + } + + protected int getLayout() { + return R.layout.user_tracks_view; + } + + public String getUserId() { + return mUserId; + } + + public boolean isTaken() { + return !TextUtils.isEmpty(getUserId()); + } + + public List getTrackInfos() { + List trackInfos = new ArrayList<>(); + if (mQNAudioTrackInfo != null) { + trackInfos.add(mQNAudioTrackInfo); + } + trackInfos.addAll(mQNVideoTrackInfos); + return trackInfos; + } + + + public void setUserTrackInfo(QNRTCEngine engine, String userId, List trackInfos) { + setUserTrackInfo(engine, userId, trackInfos, View.VISIBLE); + } + + public void setUserTrackInfo(QNRTCEngine engine, String userId, List trackInfos, int microphoneViewVisibility) { + LogD(TAG, "setUserTrackInfo() userId: " + userId); + mQNRTCEngine = engine; + mUserId = userId; + mQNAudioTrackInfo = null; + mQNVideoTrackInfos.clear(); + + if (TextUtils.isEmpty(mUserId)) { + return; + } + setMicrophoneStateVisibility(microphoneViewVisibility); + mAudioView.setText(mUserId); + onAddTrackInfo(trackInfos); + } + + public void unSetUserTrackInfo() { + if (mQNRTCEngine != null) { + if (mTrackInfoDisplayInLargeView != null) { + mQNRTCEngine.setRenderWindow(mTrackInfoDisplayInLargeView, null); + } + if (mTrackInfoDisplayInSmallView != null) { + mQNRTCEngine.setRenderWindow(mTrackInfoDisplayInSmallView, null); + } + } + reset(); + } + + public void reset() { + LogD(TAG, "reset()"); + mQNRTCEngine = null; + mUserId = null; + mQNAudioTrackInfo = null; + mQNVideoTrackInfos.clear(); + mPos = -1; + + mSurfaceViewLarge.setVisibility(View.GONE); + mVideoViewLargeParent.setVisibility(View.GONE); + mSurfaceViewSmall.setVisibility(View.GONE); + mVideoViewSmallParent.setVisibility(View.GONE); + mAudioView.setText(""); + mAudioView.setVisibility(View.GONE); + mTrackInfoDisplayInLargeView = null; + mTrackInfoDisplayInSmallView = null; + } + + public void dispose() { + LogD(TAG, "dispose()"); + mSurfaceViewLarge.release(); + mSurfaceViewSmall.release(); + } + + public void onAddTrackInfo(List trackInfos) { + LogD(TAG, "onAddTrackInfo()"); + for (QNTrackInfo item : trackInfos) { + onAddTrackInfo(item, false); + } + onTrackInfoChanged(); + } + + @SuppressWarnings("unused") + public void onAddTrackInfo(QNTrackInfo trackInfo) { + onAddTrackInfo(trackInfo, true); + } + + private void onAddTrackInfo(QNTrackInfo trackInfo, boolean notify) { + if (QNTrackKind.AUDIO.equals(trackInfo.getTrackKind())) { + mQNAudioTrackInfo = trackInfo; + } else { + mQNVideoTrackInfos.add(trackInfo); + } + if (notify) { + onTrackInfoChanged(); + } + } + + public boolean onRemoveTrackInfo(List trackInfos) { + LogD(TAG, "onRemoveTrackInfo()"); + for (QNTrackInfo item : trackInfos) { + onRemoveTrackInfo(item, false); + } + onTrackInfoChanged(); + return mQNAudioTrackInfo != null || !mQNVideoTrackInfos.isEmpty(); + } + + @SuppressWarnings("unused") + public void onRemoveTrackInfo(QNTrackInfo trackInfo) { + onRemoveTrackInfo(trackInfo, true); + } + + public void onRemoveTrackInfo(QNTrackInfo trackInfo, boolean notify) { + if (QNTrackKind.AUDIO.equals(trackInfo.getTrackKind())) { + mQNAudioTrackInfo = null; + } else { + mQNVideoTrackInfos.remove(trackInfo); + } + if (notify) { + onTrackInfoChanged(); + } + } + + public void onTracksMuteChanged() { + LogD(TAG, "onTracksMuteChanged()"); + // audio track + if (mQNAudioTrackInfo != null) { + setMicrophoneStateVisibilityInner(View.VISIBLE); + updateMicrophoneStateView(mQNAudioTrackInfo.isMuted()); + } else { + setMicrophoneStateVisibilityInner(View.INVISIBLE); + } + + // video tracks + boolean hideAudioView = containsUnMutedVideoTracks(2); + setAudioViewStateVisibility(hideAudioView ? View.GONE : View.VISIBLE); + // note : mSurfaceViewSmall is on top, so set visibility + if (mTrackInfoDisplayInSmallView != null) { + mSurfaceViewSmall.setVisibility(hideAudioView ? View.VISIBLE : View.GONE); + } + } + + private void onTrackInfoChanged() { + onTracksMuteChanged(); + + QNTrackInfo cameraTrackInfo = findVideoTrack(TAG_CAMERA); + QNTrackInfo screenTrackInfo = findVideoTrack(TAG_SCREEN); + + // in case, camera has no tag. + if (cameraTrackInfo == null && !mQNVideoTrackInfos.isEmpty()) { + List trackInfosExcludeScreenTrack = new ArrayList<>(mQNVideoTrackInfos); + trackInfosExcludeScreenTrack.remove(screenTrackInfo); + if (!trackInfosExcludeScreenTrack.isEmpty()) { + cameraTrackInfo = trackInfosExcludeScreenTrack.get(0); + } + } + + QNTrackInfo trackInfoDisplayInLargeView = null; + QNTrackInfo trackInfoDisplayInSmallView = null; + if (cameraTrackInfo != null && screenTrackInfo != null) { + LogD(TAG, "contains camera and screen track info"); + trackInfoDisplayInLargeView = screenTrackInfo; + trackInfoDisplayInSmallView = cameraTrackInfo; + } else { + if (cameraTrackInfo != null) { + LogD(TAG, "just contains camera track info"); + trackInfoDisplayInLargeView = cameraTrackInfo; + } + if (screenTrackInfo != null) { + LogD(TAG, "just contains screen track info"); + trackInfoDisplayInLargeView = screenTrackInfo; + } + } + updateTrackInfoInLargeView(trackInfoDisplayInLargeView); + updateTrackInfoInSmallView(trackInfoDisplayInSmallView); + } + + private QNTrackInfo findVideoTrack(String tag) { + QNTrackInfo found = null; + for (QNTrackInfo item : mQNVideoTrackInfos) { + if (tag.equals(item.getTag())) { + found = item; + break; + } + } + return found; + } + + private void updateTrackInfoInLargeView(QNTrackInfo trackInfoDisplayInLargeView) { + if (mTrackInfoDisplayInLargeView != null && mTrackInfoDisplayInLargeView == trackInfoDisplayInLargeView) { + LogD(TAG, "skip updateTrackInfoInLargeView, same track"); + return; + } + mTrackInfoDisplayInLargeView = trackInfoDisplayInLargeView; + if (mTrackInfoDisplayInLargeView != null) { + if (DISPLAY_LARGE_VIDEO_TRACK) { + mSurfaceViewLarge.setVisibility(View.VISIBLE); + mQNRTCEngine.setRenderWindow(mTrackInfoDisplayInLargeView, mSurfaceViewLarge); + if (TAG_SCREEN.equals(mTrackInfoDisplayInLargeView.getTag())) { + mSurfaceViewLarge.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT); + } else { + mSurfaceViewLarge.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FILL); + } + } else { + mSurfaceViewLarge.setVisibility(View.GONE); + mVideoViewLargeParent.setBackgroundColor(getTargetColor(new Random().nextInt(6))); + } + mVideoViewLargeParent.setVisibility(View.VISIBLE); + } else { + mSurfaceViewLarge.setVisibility(View.GONE); + mVideoViewLargeParent.setVisibility(View.GONE); + } + } + + private void updateTrackInfoInSmallView(QNTrackInfo trackInfoDisplayInSmallView) { + if (mTrackInfoDisplayInSmallView != null && mTrackInfoDisplayInSmallView == trackInfoDisplayInSmallView) { + LogD(TAG, "skip updateTrackInfoInSmallView, same track"); + return; + } + mTrackInfoDisplayInSmallView = trackInfoDisplayInSmallView; + if (mTrackInfoDisplayInSmallView != null) { + if (DISPLAY_SMALL_VIDEO_TRACK) { + mSurfaceViewSmall.setVisibility(View.VISIBLE); + mQNRTCEngine.setRenderWindow(mTrackInfoDisplayInSmallView, mSurfaceViewSmall); + } else { + mSurfaceViewSmall.setVisibility(View.GONE); + mVideoViewSmallParent.setBackgroundColor(getTargetColor(new Random().nextInt(6))); + } + mVideoViewSmallParent.setVisibility(View.VISIBLE); + } else { + mSurfaceViewSmall.setVisibility(View.GONE); + mVideoViewSmallParent.setVisibility(View.GONE); + } + } + + @SuppressWarnings("all") + private boolean containsUnMutedVideoTracks(int count) { + boolean unMuted = false; + for (int i = 0; i < mQNVideoTrackInfos.size() && i < count; i++) { + QNTrackInfo item = mQNVideoTrackInfos.get(i); + if (!item.isMuted()) { + unMuted = true; + break; + } + } + return unMuted; + } + + + public void changeViewBackgroundByPos(int pos) { + LogD(TAG, "changeViewBackgroundByPos() " + pos); + mPos = pos; + if (mPos != -1) { + mAudioView.setBackgroundColor(getTargetColor(pos)); + } + } + + private void setAudioViewStateVisibility(int visibility) { + mAudioView.setVisibility(visibility); + } + + public void setMicrophoneStateVisibility(int visibility) { + mMicrophoneViewVisibility = visibility; + mMicrophoneStateView.setVisibility(visibility); + } + + private void setMicrophoneStateVisibilityInner(int visibility) { + if (mMicrophoneViewVisibility == -1 || mMicrophoneViewVisibility == View.VISIBLE) { + mMicrophoneStateView.setVisibility(visibility); + } + } + + private void updateMicrophoneStateView(boolean isMute) { + mMicrophoneStateView.setImageResource(isMute ? R.mipmap.microphone_disable : R.drawable.microphone_state_enable); + } + + @SuppressWarnings("all") + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + mVideoViewLargeParent = findViewById(R.id.qn_surface_view_large_parent); + mSurfaceViewLarge = (QNSurfaceView) findViewById(R.id.qn_surface_view_large); + + mVideoViewSmallParent = findViewById(R.id.qn_surface_view_small_parent); + mSurfaceViewSmall = (QNSurfaceView) findViewById(R.id.qn_surface_view_small); + + mMicrophoneStateView = (ImageView) findViewById(R.id.microphone_state_view); + mAudioView = (TextView) findViewById(R.id.qn_audio_view); + } + + @Override + public void setVisibility(int visibility) { + if (visibility == View.GONE) { + mSurfaceViewLarge.setVisibility(visibility); + mSurfaceViewSmall.setVisibility(visibility); + } else { + if (mTrackInfoDisplayInLargeView != null) { + mSurfaceViewLarge.setVisibility(visibility); + } + if (mTrackInfoDisplayInSmallView != null) { + mSurfaceViewSmall.setVisibility(visibility); + } + } + super.setVisibility(visibility); + } + + private int getTargetColor(int pos) { + int[] customizedColors = getContext().getResources().getIntArray(R.array.audioBackgroundColors); + return customizedColors[pos % 6]; + } + + public void setZOrderMediaOverlay(boolean isMediaOverlay, boolean onTop) { + if (DISPLAY_LARGE_VIDEO_TRACK) { + mSurfaceViewLarge.setZOrderMediaOverlay(isMediaOverlay); + } + if (DISPLAY_SMALL_VIDEO_TRACK) { + mSurfaceViewSmall.setZOrderMediaOverlay(isMediaOverlay); + mSurfaceViewSmall.setZOrderOnTop(onTop); + } + } + + public static void swap(QNRTCEngine engine, UserTrackView trackViewFirst, UserTrackView trackViewSecond) { + String userIdFirst = trackViewFirst.getUserId(); + List trackInfosFirst = trackViewFirst.getTrackInfos(); + int postFirst = trackViewFirst.mPos; + + String userIdSecond = trackViewSecond.getUserId(); + List trackInfosSecond = trackViewSecond.getTrackInfos(); + int postSecond = trackViewSecond.mPos; + + trackViewFirst.setUserTrackInfo(engine, userIdSecond, trackInfosSecond, trackViewFirst.mMicrophoneViewVisibility); + trackViewFirst.changeViewBackgroundByPos(postSecond); + + trackViewSecond.setUserTrackInfo(engine, userIdFirst, trackInfosFirst, trackViewSecond.mMicrophoneViewVisibility); + trackViewSecond.changeViewBackgroundByPos(postFirst); + } + + public String getResourceName() { + try { + return this.getResources().getResourceEntryName(this.getId()); + } catch (Resources.NotFoundException var2) { + return ""; + } + } + + + private void LogD(String tag, String message) { + if (PRINT_DEBUG_LOG) { + Log.d(tag + " " + getResourceName(), message); + } + } +} diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/UserTrackViewFullScreen.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/UserTrackViewFullScreen.java new file mode 100644 index 0000000..c3097f2 --- /dev/null +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/ui/UserTrackViewFullScreen.java @@ -0,0 +1,24 @@ +package com.qiniu.droid.rtc.demo.ui; + +import android.content.Context; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.util.AttributeSet; + +import com.qiniu.droid.rtc.demo.R; + +public class UserTrackViewFullScreen extends UserTrackView { + + public UserTrackViewFullScreen(@NonNull Context context) { + super(context); + } + + public UserTrackViewFullScreen(@NonNull Context context, @Nullable AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected int getLayout() { + return R.layout.user_tracks_view_full_screen; + } +} diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/Config.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/Config.java index ed887fb..0af67e6 100644 --- a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/Config.java +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/Config.java @@ -19,12 +19,14 @@ public class Config { public static final String CODEC_MODE = "encodeMode"; public static final String CAPTURE_MODE = "captureMode"; public static final String BITRATE = "bitrate"; + public static final String MAINTAIN_RES = "maintainRes"; public static final int HW = 0; public static final int SW = 1; public static final int CAMERA_CAPTURE = 0; public static final int SCREEN_CAPTURE = 1; public static final int ONLY_AUDIO_CAPTURE = 2; + public static final int MUTI_TRACK_CAPTURE = 3; public static final int[][] DEFAULT_RESOLUTION = { {352, 288}, diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/MyHashMap.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/MyHashMap.java new file mode 100644 index 0000000..1a2c4a2 --- /dev/null +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/MyHashMap.java @@ -0,0 +1,53 @@ +package com.qiniu.droid.rtc.demo.utils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +public class MyHashMap extends HashMap { + + private List mOrderedValues = new LinkedList<>(); + + public List getOrderedValues() { + return new ArrayList<>(mOrderedValues); + } + + public List getOrderedValues(V exclude) { + LinkedList result = new LinkedList<>(mOrderedValues); + result.remove(exclude); + return result; + } + + public V put(K key, V value, boolean insertToFirst) { + // in case replace key + mOrderedValues.remove(get(key)); + // in case replace value + mOrderedValues.remove(value); + + if (insertToFirst) { + mOrderedValues.add(0, value); + } else { + mOrderedValues.add(value); + } + return super.put(key, value); + } + + @Override + public V put(K key, V value) { + return put(key, value, false); + } + + @Override + public V remove(Object key) { + V result = super.remove(key); + mOrderedValues.remove(result); + return result; + } + + @Override + public void clear() { + mOrderedValues.clear(); + super.clear(); + } +} diff --git a/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/TrackWindowMgr.java b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/TrackWindowMgr.java new file mode 100644 index 0000000..615ff55 --- /dev/null +++ b/QNDroidRTCDemo/app/src/main/java/com/qiniu/droid/rtc/demo/utils/TrackWindowMgr.java @@ -0,0 +1,308 @@ +package com.qiniu.droid.rtc.demo.utils; + +import android.view.Gravity; +import android.view.View; +import android.widget.FrameLayout; + +import com.qiniu.droid.rtc.QNRTCEngine; +import com.qiniu.droid.rtc.QNTrackInfo; +import com.qiniu.droid.rtc.demo.ui.UserTrackView; + +import org.webrtc.Logging; + +import java.util.ArrayList; +import java.util.List; + +public class TrackWindowMgr { + + private static final String TAG = "TrackWindowMgr"; + + // Current userId. + private String mCurrentUserId; + // Screen resolution. + private int mScreenWidth; + @SuppressWarnings("all") + private int mScreenHeight; + // Screen density. + private float mDensity; + // QNRTCEngine instance. + private QNRTCEngine mEngine; + // TrackView full screen. + private UserTrackView mTrackFullScreenWin; + // TrackView item in grid. + private List mTrackCandidateWins; + // Map userId to TrackView. + private MyHashMap mUserWindowMap = new MyHashMap<>(); + // Flag, Windows mode p2p, otherwise multi user. + private Boolean mTrackWindowP2PMode = null; + + public TrackWindowMgr(String currentUserId, int screenWidth, int screenHeight, float density + , QNRTCEngine engine, UserTrackView trackFullScreenWin, List trackCandidateWins) { + mCurrentUserId = currentUserId; + mScreenWidth = screenWidth; + mScreenHeight = screenHeight; + mDensity = density; + mEngine = engine; + mTrackFullScreenWin = trackFullScreenWin; + mTrackCandidateWins = new ArrayList<>(trackCandidateWins); + + mTrackFullScreenWin.setZOrderMediaOverlay(false, true); + mTrackFullScreenWin.changeViewBackgroundByPos(0); + mTrackFullScreenWin.setMicrophoneStateVisibility(View.GONE); + mTrackFullScreenWin.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mUserWindowMap.size() <= 1) { + Logging.d(TAG, "skip for single user."); + } else if (mUserWindowMap.size() == 2) { + // swap + switchToFullScreenWindow(mUserWindowMap.getOrderedValues(mTrackFullScreenWin).get(0)); + } else { + // exit from full screen and display all + if (mTrackCandidateWins.isEmpty()) { + mTrackFullScreenWin.unSetUserTrackInfo(); + mTrackFullScreenWin.setVisibility(View.GONE); + } else { + UserTrackView userTrackView = mTrackCandidateWins.remove(0); + switchToFullScreenWindow(userTrackView); + userTrackView.changeViewBackgroundByPos(mUserWindowMap.size()); + + setTrackUserWindowsVisibility(View.VISIBLE); + updateTrackWindowsLayout(); + } + } + } + }); + + for (final UserTrackView view : mTrackCandidateWins) { + view.setZOrderMediaOverlay(true, true); + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (mUserWindowMap.size() <= 1) { + Logging.d(TAG, "skip for single user."); + } else if (mUserWindowMap.size() == 2) { + // swap + switchToFullScreenWindow(view); + } else { + // full screen and hide others + switchToFullScreenWindow(view); + setTrackUserWindowsVisibility(View.GONE); + } + } + }); + } + } + + public void addTrackInfo(String userId, List trackInfoList) { + if (mTrackCandidateWins.size() == 0) { + Logging.e(TAG, "There were more than 9 published users in the room, with no unUsedWindow to draw."); + return; + } + UserTrackView userTrackView = mUserWindowMap.get(userId); + if (userTrackView != null) { + // user has already displayed in screen + userTrackView.onAddTrackInfo(trackInfoList); + } else { + // allocate new track windows + userTrackView = mTrackCandidateWins.remove(0); + mUserWindowMap.put(userId, userTrackView, userId.equals(mCurrentUserId)); + userTrackView.setUserTrackInfo(mEngine, userId, trackInfoList); + userTrackView.changeViewBackgroundByPos(mUserWindowMap.size()); + + userTrackView.setVisibility(View.VISIBLE); + + // update whole layout + updateTrackWindowsLayout(); + } + } + + public void onTrackInfoMuted(String remoteUserId) { + UserTrackView window = mUserWindowMap.get(remoteUserId); + if (window != null) { + window.onTracksMuteChanged(); + } + } + + public void removeTrackInfo(String userId, List trackInfoList) { + UserTrackView remoteVideoView = mUserWindowMap.get(userId); + if (remoteVideoView == null) { + return; + } + boolean trackInfoRemains = remoteVideoView.onRemoveTrackInfo(trackInfoList); + if (userId.equals(mCurrentUserId)) { + // always show myself in screen + return; + } + if (!trackInfoRemains) { + // check, if no more tracks for this user. remove it + removeTrackWindow(userId); + } + } + + private void removeTrackWindow(String remoteUserId) { + UserTrackView remoteVideoView = mUserWindowMap.remove(remoteUserId); + if (remoteVideoView == null) { + return; + } + remoteVideoView.reset(); + if (mTrackFullScreenWin == remoteVideoView) { + if (mUserWindowMap.size() == 1) { + switchToFullScreenWindow(mUserWindowMap.getOrderedValues().get(0)); + } else { + mTrackFullScreenWin.setVisibility(View.GONE); + updateTrackWindowsLayout(); + } + } else { + remoteVideoView.setVisibility(View.GONE); + mTrackCandidateWins.add(remoteVideoView); + updateTrackWindowsLayout(); + } + } + + private void updateTrackWindowsLayout() { + if (mUserWindowMap.isEmpty()) { + return; + } + updateTrackWindowMode(mUserWindowMap.size() <= 2); + + List userWindows = mUserWindowMap.getOrderedValues(mTrackFullScreenWin); + int userCountInGridWindow = userWindows.size(); + for (int i = 0; i < userCountInGridWindow; i++) { + UserTrackView trackView = userWindows.get(i); + setTargetWindowParams(userCountInGridWindow, i, trackView); + } + } + + private void switchToFullScreenWindow(UserTrackView userTrackView) { + if (userTrackView == mTrackFullScreenWin) { + return; + } + + UserTrackView.swap(mEngine, mTrackFullScreenWin, userTrackView); + if (mTrackFullScreenWin.isTaken()) { + Logging.d(TAG, "put " + mTrackFullScreenWin.getUserId() + " to " + mTrackFullScreenWin.getResourceName()); + mTrackFullScreenWin.setVisibility(View.VISIBLE); + mUserWindowMap.put(mTrackFullScreenWin.getUserId(), mTrackFullScreenWin, mTrackFullScreenWin.getUserId().equals(mCurrentUserId)); + } else { + Logging.d(TAG, "recycle " + mTrackFullScreenWin.getResourceName()); + mTrackFullScreenWin.reset(); + mTrackFullScreenWin.setVisibility(View.GONE); + } + + if (userTrackView.isTaken()) { + Logging.d(TAG, "put " + userTrackView.getUserId() + " to " + userTrackView.getResourceName()); + userTrackView.setVisibility(View.VISIBLE); + mUserWindowMap.put(userTrackView.getUserId(), userTrackView, userTrackView.getUserId().equals(mCurrentUserId)); + } else { + Logging.d(TAG, "recycle " + userTrackView.getResourceName()); + userTrackView.reset(); + userTrackView.setVisibility(View.GONE); + // recycle + mTrackCandidateWins.add(userTrackView); + } + } + + private void setTrackUserWindowsVisibility(int visibility) { + List userWindows = mUserWindowMap.getOrderedValues(mTrackFullScreenWin); + for (int i = 0; i < userWindows.size(); i++) { + UserTrackView trackView = userWindows.get(i); + trackView.setVisibility(visibility); + } + } + + private void updateTrackWindowMode(boolean trackWindowP2PMode) { + if (mUserWindowMap.isEmpty()) { + return; + } + if (mTrackWindowP2PMode != null && mTrackWindowP2PMode == trackWindowP2PMode) { + return; + } + if (trackWindowP2PMode) { + Logging.d(TAG, "switch to p2p mode"); + // relayout. switch to p2p mode. put first user to full screen. + // ( 0 user -> 1 user || 3 users -> 2 users) + switchToFullScreenWindow(mUserWindowMap.getOrderedValues().get(0)); + } else { + Logging.d(TAG, "switch to multi user mode"); + // relayout. switch to multi user mode. + // (2 users -> 3 users) + if (mTrackFullScreenWin.isTaken()) { + if (!mTrackCandidateWins.isEmpty()) { + UserTrackView userTrackView = mTrackCandidateWins.remove(0); + switchToFullScreenWindow(userTrackView); + userTrackView.changeViewBackgroundByPos(mUserWindowMap.size()); + } + } + } + mTrackWindowP2PMode = trackWindowP2PMode; + } + + private void setTargetWindowParams(final int userCount, final int targetPos, final UserTrackView targetWindow) { + switch (userCount) { + case 1: + if (targetPos == 0) { + updateLayoutParams(targetWindow, (int) (120 * mDensity + 0.5f), (int) (160 * mDensity + 0.5f), 0, 0, Gravity.TOP | Gravity.END); + } + break; + case 2: + // never in this case. + break; + case 3: + if (targetPos == 0) { + updateLayoutParams(targetWindow, mScreenWidth / 2, mScreenWidth / 2, 0, 0, -1); + } else if (targetPos == 1) { + updateLayoutParams(targetWindow, mScreenWidth / 2, mScreenWidth / 2, mScreenWidth / 2, 0, -1); + } else { + updateLayoutParams(targetWindow, mScreenWidth / 2, mScreenWidth / 2, 0, mScreenWidth / 2, Gravity.CENTER_HORIZONTAL); + } + break; + case 4: + if (targetPos == 0) { + updateLayoutParams(targetWindow, mScreenWidth / 2, mScreenWidth / 2, 0, 0, -1); + } else if (targetPos == 1) { + updateLayoutParams(targetWindow, mScreenWidth / 2, mScreenWidth / 2, mScreenWidth / 2, 0, -1); + } else if (targetPos == 2) { + updateLayoutParams(targetWindow, mScreenWidth / 2, mScreenWidth / 2, 0, mScreenWidth / 2, Gravity.START); + } else { + updateLayoutParams(targetWindow, mScreenWidth / 2, mScreenWidth / 2, mScreenWidth / 2, mScreenWidth / 2, -1); + } + break; + case 5: + case 6: + case 7: + case 8: + case 9: + if (targetPos == 0) { + updateLayoutParams(targetWindow, mScreenWidth / 3, mScreenWidth / 3, 0, 0, -1); + } else if (targetPos == 1) { + updateLayoutParams(targetWindow, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth / 3, 0, -1); + } else if (targetPos == 2) { + updateLayoutParams(targetWindow, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth * 2 / 3, 0, Gravity.END); + } else if (targetPos == 3) { + updateLayoutParams(targetWindow, mScreenWidth / 3, mScreenWidth / 3, 0, mScreenWidth / 3, -1); + } else if (targetPos == 4) { + updateLayoutParams(targetWindow, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth / 3, -1); + } else if (targetPos == 5) { + updateLayoutParams(targetWindow, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth * 2 / 3, mScreenWidth / 3, -1); + } else if (targetPos == 6) { + updateLayoutParams(targetWindow, mScreenWidth / 3, mScreenWidth / 3, 0, mScreenWidth * 2 / 3, -1); + } else if (targetPos == 7) { + updateLayoutParams(targetWindow, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth * 2 / 3, -1); + } else if (targetPos == 8) { + updateLayoutParams(targetWindow, mScreenWidth / 3, mScreenWidth / 3, mScreenWidth * 2 / 3, mScreenWidth * 2 / 3, -1); + } + break; + } + } + + private void updateLayoutParams(UserTrackView targetView, int width, int height, int marginStart, int marginTop, int gravity) { + FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) targetView.getLayoutParams(); + lp.width = width; + lp.height = height; + lp.topMargin = marginTop; + lp.gravity = gravity; + lp.setMarginStart(marginStart); + targetView.setLayoutParams(lp); + } +} diff --git a/QNDroidRTCDemo/app/src/main/jniLibs/arm64-v8a/libqndroid_beauty.so b/QNDroidRTCDemo/app/src/main/jniLibs/arm64-v8a/libqndroid_beauty.so index e96c20a..d96ac6a 100755 Binary files a/QNDroidRTCDemo/app/src/main/jniLibs/arm64-v8a/libqndroid_beauty.so and b/QNDroidRTCDemo/app/src/main/jniLibs/arm64-v8a/libqndroid_beauty.so differ diff --git a/QNDroidRTCDemo/app/src/main/jniLibs/arm64-v8a/libqndroid_rtc.so b/QNDroidRTCDemo/app/src/main/jniLibs/arm64-v8a/libqndroid_rtc.so index 0c1ed9a..11fe11e 100755 Binary files a/QNDroidRTCDemo/app/src/main/jniLibs/arm64-v8a/libqndroid_rtc.so and b/QNDroidRTCDemo/app/src/main/jniLibs/arm64-v8a/libqndroid_rtc.so differ diff --git a/QNDroidRTCDemo/app/src/main/jniLibs/armeabi-v7a/libqndroid_beauty.so b/QNDroidRTCDemo/app/src/main/jniLibs/armeabi-v7a/libqndroid_beauty.so index b195e19..3751d45 100755 Binary files a/QNDroidRTCDemo/app/src/main/jniLibs/armeabi-v7a/libqndroid_beauty.so and b/QNDroidRTCDemo/app/src/main/jniLibs/armeabi-v7a/libqndroid_beauty.so differ diff --git a/QNDroidRTCDemo/app/src/main/jniLibs/armeabi-v7a/libqndroid_rtc.so b/QNDroidRTCDemo/app/src/main/jniLibs/armeabi-v7a/libqndroid_rtc.so index bd14e0f..abf1bce 100755 Binary files a/QNDroidRTCDemo/app/src/main/jniLibs/armeabi-v7a/libqndroid_rtc.so and b/QNDroidRTCDemo/app/src/main/jniLibs/armeabi-v7a/libqndroid_rtc.so differ diff --git a/QNDroidRTCDemo/app/src/main/jniLibs/armeabi/libqndroid_beauty.so b/QNDroidRTCDemo/app/src/main/jniLibs/armeabi/libqndroid_beauty.so index 3001ae6..dedba51 100755 Binary files a/QNDroidRTCDemo/app/src/main/jniLibs/armeabi/libqndroid_beauty.so and b/QNDroidRTCDemo/app/src/main/jniLibs/armeabi/libqndroid_beauty.so differ diff --git a/QNDroidRTCDemo/app/src/main/jniLibs/armeabi/libqndroid_rtc.so b/QNDroidRTCDemo/app/src/main/jniLibs/armeabi/libqndroid_rtc.so index 263ced1..eb58c78 100755 Binary files a/QNDroidRTCDemo/app/src/main/jniLibs/armeabi/libqndroid_rtc.so and b/QNDroidRTCDemo/app/src/main/jniLibs/armeabi/libqndroid_rtc.so differ diff --git a/QNDroidRTCDemo/app/src/main/jniLibs/x86/libqndroid_beauty.so b/QNDroidRTCDemo/app/src/main/jniLibs/x86/libqndroid_beauty.so index fc5c8a2..5ac2bbf 100755 Binary files a/QNDroidRTCDemo/app/src/main/jniLibs/x86/libqndroid_beauty.so and b/QNDroidRTCDemo/app/src/main/jniLibs/x86/libqndroid_beauty.so differ diff --git a/QNDroidRTCDemo/app/src/main/jniLibs/x86/libqndroid_rtc.so b/QNDroidRTCDemo/app/src/main/jniLibs/x86/libqndroid_rtc.so index 23765ed..9785e4f 100755 Binary files a/QNDroidRTCDemo/app/src/main/jniLibs/x86/libqndroid_rtc.so and b/QNDroidRTCDemo/app/src/main/jniLibs/x86/libqndroid_rtc.so differ diff --git a/QNDroidRTCDemo/app/src/main/res/layout/activity_main.xml b/QNDroidRTCDemo/app/src/main/res/layout/activity_main.xml index 040a3ee..3bbc426 100644 --- a/QNDroidRTCDemo/app/src/main/res/layout/activity_main.xml +++ b/QNDroidRTCDemo/app/src/main/res/layout/activity_main.xml @@ -1,14 +1,14 @@ + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/backgroundColor"> @@ -16,30 +16,30 @@ android:id="@+id/setting_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:src="@mipmap/setting" + android:layout_alignParentTop="true" + android:layout_alignParentEnd="true" + android:layout_margin="16dp" android:background="@color/backgroundColor" android:onClick="onClickToSetting" - android:layout_margin="16dp" - android:layout_alignParentTop="true" - android:layout_alignParentEnd="true" /> + android:src="@mipmap/setting" /> + android:textColor="@color/textColor" + android:textColorHint="@color/textColor" + android:textSize="15sp" /> + android:paddingEnd="15dp" + android:text="@string/room_tips" + android:textColor="@color/textColor" /> - + android:paddingTop="2dp" + android:paddingEnd="0dp" + android:paddingBottom="2dp"> @@ -96,7 +95,16 @@ android:text="@string/screen_capture" android:textColor="@color/textColor" /> - + + +