attachMedia method
连接媒体:按 media.provider 选择适配;连上后第一次心跳带 media_connected。
Implementation
Future<void> attachMedia(JsonMap mediaJson, [int? heartbeatSeconds]) async {
final media = MediaCredential(freezeMap(mediaJson));
_media = media;
_heartbeatMs = (heartbeatSeconds ?? defaultHeartbeatS) * 1000;
_mediaConnectedSent = false;
_holding = true;
_module.reportHolder(callId, true);
_startHeartbeat();
_scheduleRenew();
final adapter = _module.provider(media.provider);
if (adapter == null) {
_holding = false;
_set(media: 'disconnected');
throw DRException(
code: 'permission_denied',
details: {'reason': 'media_provider_unsupported', 'provider': media.provider},
source: ErrorSource.local,
message: 'media_provider_unsupported',
);
}
_set(media: 'connecting');
final kind = snapshot.call.media;
try {
await adapter.load();
final session = await adapter.connect(media, media: kind, identityToUid: (identity) => snapshot.call.member(identity)?.mediaUid);
if (_ended) {
await session.disconnect().catchError((Object _) {});
return;
}
_bindSession(session);
_set(media: 'connected');
unawaited(_beat());
Object? failure;
try {
await session.setMicrophoneEnabled(true);
_set(local: CallLocalMedia(microphone: true, camera: snapshot.local.camera));
} catch (e) {
failure = e;
}
if (kind == 'video') {
try {
await session.setCameraEnabled(true);
_set(local: CallLocalMedia(microphone: snapshot.local.microphone, camera: true));
} catch (e) {
failure ??= e;
}
}
// 已经接听,只是没有打开设备:App 引导授权后再打开
if (failure != null) throw failure;
} catch (err) {
if (_session == null) {
_module.log.warn('连接媒体服务失败', code: err is DRException ? err.code : err.runtimeType.toString());
// 与 Web SDK 不同:连接失败后可以 resume() 重试(Web SDK 中这个标签页仍算持有媒体连接,不能恢复)
_holding = false;
_set(media: 'disconnected');
}
rethrow;
}
}