start method
Implementation
Future<CallHandleImpl> start({String? toUser, String? toGroup, List<String>? usernames, required CallMedia media, Map<String, String>? ext}) async {
core.requireSignedIn();
if (config()?['rtc_enabled'] == false) {
throw DRException(code: 'permission_denied', details: {'reason': 'rtc_disabled'}, source: ErrorSource.local, message: 'rtc_disabled');
}
final data = <String, Object?>{'client_call_id': core.platform.random.uuid(), 'media': media.name, 'media_providers': providerKinds};
if (toUser != null) {
if (toGroup != null) throw validationError('invalid_value', 'to_group');
if (toUser.isEmpty) throw validationError('required', 'to_user');
data['to_user'] = toUser.toLowerCase();
} else {
if (toGroup == null || toGroup.isEmpty) throw validationError('required', 'to_group');
data['to_group'] = toGroup;
if (usernames != null) {
final max = asInt(config()?['max_group_call_participants']);
if (max != null && max > 0 && usernames.length > max - 1) throw validationError('too_many_invitees', 'usernames', {'max': max - 1});
data['usernames'] = [for (final u in usernames) u.toLowerCase()];
}
}
if (ext != null) data['ext'] = Map<String, String>.of(ext);
// 发起不自动重试限流;长连接上的网络错误、超时用同一个 client_call_id 改用客户端 API 重试一次
final result = await signal('rtc.start', '/client/v1/calls', data);
final call = asMap(result['call']);
if (call == null) throw localError('internal', message: 'rtc.start 的响应中没有 call');
final handle = _upsert(call, self: asMap(call['self']) ?? selfOf(call, me, true));
// 对方忙:返回的通话已经结束,不连接媒体
final mediaJson = asMap(result['media']);
if (call['status'] != 'ended' && mediaJson != null) fireAndForget(handle.attachMedia(mediaJson, asInt(result['heartbeat_interval_seconds'])));
return handle;
}