feat: web/native device consistency management (#243)
* fix: Force audio settings to be consistent. * chore: applyAudioSettings for onUnpublish. * revert audio output select for web. * add RoomHardwareManagementMethods to Room. * update. * fix analyze. * update. * update. * chore: Reset sinkId for web when remoteTrack replays. * rename setAudioOutput to setSinkId for flutter web. * chore: Make sure AudioElement has `setSinkId` method.
This commit is contained in:
@@ -2,6 +2,7 @@ import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:livekit_client/src/hardware/hardware.dart';
|
||||
import 'package:livekit_client/src/support/app_state.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
@@ -343,6 +344,7 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
|
||||
event.stream,
|
||||
trackSid,
|
||||
receiver: event.receiver,
|
||||
audioOutputOptions: roomOptions.defaultAudioOutputOptions,
|
||||
);
|
||||
} on TrackSubscriptionExceptionEvent catch (event) {
|
||||
logger.severe('addSubscribedMediaTrack() throwed ${event}');
|
||||
@@ -640,3 +642,101 @@ extension RoomDebugMethods on Room {
|
||||
switchCandidate: switchCandidate);
|
||||
}
|
||||
}
|
||||
|
||||
/// Room extension methods for managing audio, video.
|
||||
extension RoomHardwareManagementMethods on Room {
|
||||
/// Get current audio output device.
|
||||
String? get selectedAudioOutputDeviceId =>
|
||||
roomOptions.defaultAudioOutputOptions.deviceId ??
|
||||
Hardware.instance.selectedAudioOutput?.deviceId;
|
||||
|
||||
/// Get current audio input device.
|
||||
String? get selectedAudioInputDeviceId =>
|
||||
roomOptions.defaultAudioCaptureOptions.deviceId ??
|
||||
Hardware.instance.selectedAudioInput?.deviceId;
|
||||
|
||||
/// Get current video input device.
|
||||
String? get selectedVideoInputDeviceId =>
|
||||
roomOptions.defaultCameraCaptureOptions.deviceId ??
|
||||
Hardware.instance.selectedVideoInput?.deviceId;
|
||||
|
||||
/// Get mobile device's speaker status.
|
||||
bool? get speakerOn => roomOptions.defaultAudioOutputOptions.speakerOn;
|
||||
|
||||
/// Set audio output device.
|
||||
Future<void> setAudioOutputDevice(MediaDevice device) async {
|
||||
if (lkPlatformIs(PlatformType.web)) {
|
||||
participants.forEach((_, participant) {
|
||||
for (var audioTrack in participant.audioTracks) {
|
||||
audioTrack.track?.setSinkId(device.deviceId);
|
||||
}
|
||||
});
|
||||
Hardware.instance.selectedAudioOutput = device;
|
||||
} else {
|
||||
await Hardware.instance.selectAudioOutput(device);
|
||||
}
|
||||
engine.roomOptions = engine.roomOptions.copyWith(
|
||||
defaultAudioOutputOptions: roomOptions.defaultAudioOutputOptions.copyWith(
|
||||
deviceId: device.deviceId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Set audio input device.
|
||||
Future<void> setAudioInputDevice(MediaDevice device) async {
|
||||
if (lkPlatformIs(PlatformType.web) && localParticipant != null) {
|
||||
for (var audioTrack in localParticipant!.audioTracks) {
|
||||
await audioTrack.track?.setDeviceId(device.deviceId);
|
||||
}
|
||||
Hardware.instance.selectedAudioInput = device;
|
||||
} else {
|
||||
await Hardware.instance.selectAudioInput(device);
|
||||
}
|
||||
engine.roomOptions = engine.roomOptions.copyWith(
|
||||
defaultAudioCaptureOptions:
|
||||
roomOptions.defaultAudioCaptureOptions.copyWith(
|
||||
deviceId: device.deviceId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Set video input device.
|
||||
Future<void> setVideoInputDevice(MediaDevice device) async {
|
||||
final track = localParticipant?.videoTracks.firstOrNull?.track;
|
||||
if (track == null) return;
|
||||
if (selectedVideoInputDeviceId != device.deviceId) {
|
||||
await track.switchCamera(device.deviceId);
|
||||
Hardware.instance.selectedVideoInput = device;
|
||||
}
|
||||
engine.roomOptions = engine.roomOptions.copyWith(
|
||||
defaultCameraCaptureOptions:
|
||||
roomOptions.defaultCameraCaptureOptions.copyWith(
|
||||
deviceId: device.deviceId,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> setSpeakerOn(bool speakerOn) async {
|
||||
if (lkPlatformIs(PlatformType.iOS) || lkPlatformIs(PlatformType.android)) {
|
||||
await Hardware.instance.setSpeakerphoneOn(speakerOn);
|
||||
engine.roomOptions = engine.roomOptions.copyWith(
|
||||
defaultAudioOutputOptions:
|
||||
roomOptions.defaultAudioOutputOptions.copyWith(
|
||||
speakerOn: speakerOn,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply audio output device settings.
|
||||
@internal
|
||||
Future<void> applyAudioSpeakerSettings() async {
|
||||
if (roomOptions.defaultAudioOutputOptions.speakerOn != null) {
|
||||
if (lkPlatformIs(PlatformType.iOS) ||
|
||||
lkPlatformIs(PlatformType.android)) {
|
||||
await Hardware.instance.setSpeakerphoneOn(
|
||||
roomOptions.defaultAudioOutputOptions.speakerOn!);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user