feat(mobile-next): 迁移 Android 一对一语音通话薄适配与入口
复用官方 OpenIMLive 信令与房间,换票改走账号服务 /api/rtc_token;入口仅音频,占线/超时/重复回调与销毁释放由公司层防护。 Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
co-authored by
Cursor
multica-agent
parent
2a817e77d8
commit
3832e080c4
@@ -59,6 +59,9 @@ class AppController extends GetxController with UpgradeManger {
|
||||
|
||||
if (isRunningBackground && !run) {}
|
||||
isRunningBackground = run;
|
||||
if (Get.isRegistered<IMController>()) {
|
||||
Get.find<IMController>().backgroundSubject.add(run);
|
||||
}
|
||||
if (!run) {
|
||||
_cancelAllNotifications();
|
||||
}
|
||||
|
||||
@@ -9,19 +9,113 @@ import 'package:openim_common/openim_common.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:openim_live/openim_live.dart';
|
||||
|
||||
import '../../company/feature_flags.dart';
|
||||
import '../../company/rtc/call_permissions.dart';
|
||||
import '../../company/rtc/call_session_guard.dart';
|
||||
import '../../company/rtc/rtc_token_api.dart';
|
||||
import '../im_callback.dart';
|
||||
|
||||
class IMController extends GetxController with IMCallback, OpenIMLive {
|
||||
late Rx<UserFullInfo> userInfo;
|
||||
late String atAllTag;
|
||||
final _rtcTokenApi = RtcTokenApi();
|
||||
final callGuard = CallSessionGuard();
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
callGuard.dispose();
|
||||
super.close();
|
||||
onCloseLive();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SignalingCertificate> getRtcCertificate(String roomID, String userID) {
|
||||
final token = DataSp.imToken;
|
||||
if (token == null || token.isEmpty) {
|
||||
return Future.error(StateError('登录状态已失效,请重新登录'));
|
||||
}
|
||||
return _rtcTokenApi.getToken(room: roomID, identity: userID, authToken: token);
|
||||
}
|
||||
|
||||
@override
|
||||
void onLiveSessionClosed() {
|
||||
callGuard.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void onLiveConnected() {
|
||||
callGuard.markConnected();
|
||||
}
|
||||
|
||||
@override
|
||||
void receiveNewInvitation(SignalingInfo info) {
|
||||
if (!FeatureFlags.livekitCall) return;
|
||||
final invitation = info.invitation;
|
||||
final roomID = invitation?.roomID ?? '';
|
||||
if (invitation?.mediaType != 'audio' || invitation?.sessionType != ConversationType.single) {
|
||||
onTapReject(info);
|
||||
return;
|
||||
}
|
||||
if (!callGuard.acceptSignaling(customType: CustomMessageType.callingInvite, roomID: roomID)) {
|
||||
return;
|
||||
}
|
||||
if (isBusy || callGuard.isBusy) {
|
||||
onTapReject(info);
|
||||
return;
|
||||
}
|
||||
if (callGuard.startIncoming(roomID) != null) {
|
||||
onTapReject(info);
|
||||
return;
|
||||
}
|
||||
super.receiveNewInvitation(info);
|
||||
}
|
||||
|
||||
@override
|
||||
void call({
|
||||
required CallObj callObj,
|
||||
required CallType callType,
|
||||
CallState callState = CallState.call,
|
||||
String? roomID,
|
||||
String? inviterUserID,
|
||||
required List<String> inviteeUserIDList,
|
||||
String? groupID,
|
||||
SignalingCertificate? credentials,
|
||||
}) async {
|
||||
if (!FeatureFlags.livekitCall) return;
|
||||
if (callType != CallType.audio || callObj != CallObj.single) {
|
||||
IMViews.showToast('暂只支持一对一语音通话');
|
||||
return;
|
||||
}
|
||||
if (isBusy || callGuard.isBusy) {
|
||||
IMViews.showToast(StrRes.callingBusy);
|
||||
return;
|
||||
}
|
||||
final granted = await CallPermissions.ensureMicrophone();
|
||||
if (!granted) return;
|
||||
callGuard.startOutgoing(roomID ?? '');
|
||||
super.call(
|
||||
callObj: callObj,
|
||||
callType: callType,
|
||||
callState: callState,
|
||||
roomID: roomID,
|
||||
inviterUserID: inviterUserID,
|
||||
inviteeUserIDList: inviteeUserIDList,
|
||||
groupID: groupID,
|
||||
credentials: credentials,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SignalingCertificate> onTapPickup(SignalingInfo signaling) async {
|
||||
final granted = await CallPermissions.ensureMicrophone();
|
||||
if (!granted) {
|
||||
await onTapReject(signaling);
|
||||
return Future.error(StateError('microphone denied'));
|
||||
}
|
||||
return super.onTapPickup(signaling);
|
||||
}
|
||||
|
||||
@override
|
||||
void onInit() async {
|
||||
super.onInit();
|
||||
@@ -84,8 +178,14 @@ class IMController extends GetxController with IMCallback, OpenIMLive {
|
||||
customType == CustomMessageType.callingReject ||
|
||||
customType == CustomMessageType.callingCancel ||
|
||||
customType == CustomMessageType.callingHungup) {
|
||||
if (!FeatureFlags.livekitCall) return;
|
||||
final signaling = SignalingInfo(invitation: InvitationInfo.fromJson(map['data']));
|
||||
signaling.userID = signaling.invitation?.inviterUserID;
|
||||
final roomID = signaling.invitation?.roomID ?? '';
|
||||
if (customType != CustomMessageType.callingInvite &&
|
||||
!callGuard.acceptSignaling(customType: customType as int, roomID: roomID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (customType) {
|
||||
case CustomMessageType.callingInvite:
|
||||
|
||||
Reference in New Issue
Block a user