Skip to content

Commit

Permalink
support Manual subscription.
Browse files Browse the repository at this point in the history
  • Loading branch information
cloudwebrtc committed Nov 27, 2023
1 parent 005950e commit 35faaa1
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 35 deletions.
63 changes: 45 additions & 18 deletions example/lib/pages/connect.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class _ConnectPageState extends State<ConnectPage> {
static const _storeKeyE2EE = 'e2ee';
static const _storeKeySharedKey = 'shared-key';
static const _storeKeyMultiCodec = 'multi-codec';
static const _storeKeyAutoSubscribe = 'auto-subscribe';

final _uriCtrl = TextEditingController();
final _tokenCtrl = TextEditingController();
Expand All @@ -40,6 +41,7 @@ class _ConnectPageState extends State<ConnectPage> {
bool _fastConnect = false;
bool _e2ee = false;
bool _multiCodec = false;
bool _autoSubscribe = true;
String _preferredCodec = 'Preferred Codec';
String _backupCodec = 'VP8';

Expand Down Expand Up @@ -100,6 +102,7 @@ class _ConnectPageState extends State<ConnectPage> {
_fastConnect = prefs.getBool(_storeKeyFastConnect) ?? false;
_e2ee = prefs.getBool(_storeKeyE2EE) ?? false;
_multiCodec = prefs.getBool(_storeKeyMultiCodec) ?? false;
_autoSubscribe = prefs.getBool(_storeKeyAutoSubscribe) ?? true;
});
}

Expand All @@ -115,6 +118,7 @@ class _ConnectPageState extends State<ConnectPage> {
await prefs.setBool(_storeKeyFastConnect, _fastConnect);
await prefs.setBool(_storeKeyE2EE, _e2ee);
await prefs.setBool(_storeKeyMultiCodec, _multiCodec);
await prefs.setBool(_storeKeyAutoSubscribe, _autoSubscribe);
}

Future<void> _connect(BuildContext ctx) async {
Expand Down Expand Up @@ -145,25 +149,28 @@ class _ConnectPageState extends State<ConnectPage> {

// create new room
final room = Room(
connectOptions: ConnectOptions(
autoSubscribe: _autoSubscribe,
),
roomOptions: RoomOptions(
adaptiveStream: _adaptiveStream,
dynacast: _dynacast,
defaultAudioPublishOptions: const AudioPublishOptions(
dtx: true,
),
defaultVideoPublishOptions: VideoPublishOptions(
simulcast: _simulcast,
videoCodec: preferredCodec,
),
defaultScreenShareCaptureOptions: const ScreenShareCaptureOptions(
useiOSBroadcastExtension: true,
params: VideoParametersPresets.screenShareH1080FPS30),
e2eeOptions: e2eeOptions,
defaultCameraCaptureOptions: const CameraCaptureOptions(
maxFrameRate: 30,
params: VideoParametersPresets.h720_169,
),
));
adaptiveStream: _adaptiveStream,
dynacast: _dynacast,
defaultAudioPublishOptions: const AudioPublishOptions(
dtx: true,
),
defaultVideoPublishOptions: VideoPublishOptions(
simulcast: _simulcast,
videoCodec: preferredCodec,
),
defaultScreenShareCaptureOptions: const ScreenShareCaptureOptions(
useiOSBroadcastExtension: true,
params: VideoParametersPresets.screenShareH1080FPS30),
e2eeOptions: e2eeOptions,
defaultCameraCaptureOptions: const CameraCaptureOptions(
maxFrameRate: 30,
params: VideoParametersPresets.h720_169,
),
));

// Create a Listener before connecting
final listener = room.createListener();
Expand Down Expand Up @@ -202,6 +209,13 @@ class _ConnectPageState extends State<ConnectPage> {
});
}

void _setAutoSubscribe(bool? value) async {
if (value == null || _autoSubscribe == value) return;
setState(() {
_autoSubscribe = value;
});
}

void _setE2EE(bool? value) async {
if (value == null || _e2ee == value) return;
setState(() {
Expand Down Expand Up @@ -305,6 +319,19 @@ class _ConnectPageState extends State<ConnectPage> {
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text('Auto Subscribe'),
Switch(
value: _autoSubscribe,
onChanged: (value) => _setAutoSubscribe(value),
),
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Row(
Expand Down
13 changes: 12 additions & 1 deletion example/lib/pages/room.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ class _RoomPageState extends State<RoomPage> {
})
..on<LocalTrackPublishedEvent>((_) => _sortParticipants())
..on<LocalTrackUnpublishedEvent>((_) => _sortParticipants())
..on<TrackSubscribedEvent>((_) => _sortParticipants())
..on<TrackUnsubscribedEvent>((_) => _sortParticipants())
..on<TrackE2EEStateEvent>(_onE2EEStateEvent)
..on<ParticipantNameUpdatedEvent>((event) {
print(
Expand Down Expand Up @@ -140,6 +142,9 @@ class _RoomPageState extends State<RoomPage> {
List<ParticipantTrack> userMediaTracks = [];
List<ParticipantTrack> screenTracks = [];
for (var participant in widget.room.participants.values) {
if (participant.videoTracks.isEmpty || participant.audioTracks.isEmpty) {
continue;
}
for (var t in participant.videoTracks) {
if (t.isScreenShare) {
screenTracks.add(ParticipantTrack(
Expand All @@ -158,6 +163,12 @@ class _RoomPageState extends State<RoomPage> {
}
// sort speakers for the grid
userMediaTracks.sort((a, b) {
return a.participant.audioTracks.isNotEmpty &&
a.participant.audioTracks.first.muted == false
? -1
: 1;
});
/*userMediaTracks.sort((a, b) {
// loudest speaker first
if (a.participant.isSpeaking && b.participant.isSpeaking) {
if (a.participant.audioLevel > b.participant.audioLevel) {
Expand All @@ -183,7 +194,7 @@ class _RoomPageState extends State<RoomPage> {
// joinedAt
return a.participant.joinedAt.millisecondsSinceEpoch -
b.participant.joinedAt.millisecondsSinceEpoch;
});
});*/

final localParticipantTracks = widget.room.localParticipant?.videoTracks;
if (localParticipantTracks != null) {
Expand Down
43 changes: 27 additions & 16 deletions example/lib/widgets/participant.dart
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ abstract class _ParticipantWidgetState<T extends ParticipantWidget>
...extraWidgets(widget.isScreenShare),
ParticipantInfoWidget(
title: widget.participant.name.isNotEmpty
? '${widget.participant.name} (${widget.participant.identity})'
: widget.participant.identity,
? '${widget.participant.isCameraEnabled()} ${widget.participant.name} (${widget.participant.identity})'
: '${widget.participant.isCameraEnabled()} ${widget.participant.identity}',
audioAvailable: firstAudioPublication?.muted == false &&
firstAudioPublication?.subscribed == true,
connectionQuality: widget.participant.connectionQuality,
Expand Down Expand Up @@ -217,15 +217,17 @@ class _RemoteParticipantWidgetState
mainAxisAlignment: MainAxisAlignment.end,
children: [
// Menu for RemoteTrackPublication<RemoteAudioTrack>
if (firstAudioPublication != null && !isScreenShare)
if (widget.participant.audioTracks.isNotEmpty)
RemoteTrackPublicationMenuWidget(
pub: firstAudioPublication!,
remote: widget.participant,
source: TrackSource.microphone,
icon: Icons.volume_up,
),
// Menu for RemoteTrackPublication<RemoteVideoTrack>
if (videoPublication != null)
if (widget.participant.videoTracks.isNotEmpty)
RemoteTrackPublicationMenuWidget(
pub: videoPublication!,
remote: widget.participant,
source: TrackSource.camera,
icon: isScreenShare ? Icons.monitor : Icons.videocam,
),
if (videoPublication != null)
Expand All @@ -245,36 +247,45 @@ class _RemoteParticipantWidgetState

class RemoteTrackPublicationMenuWidget extends StatelessWidget {
final IconData icon;
final RemoteTrackPublication pub;
final RemoteParticipant remote;
final TrackSource source;
const RemoteTrackPublicationMenuWidget({
required this.pub,
required this.remote,
required this.source,
required this.icon,
Key? key,
}) : super(key: key);

List<RemoteTrackPublication> get publications =>
source == TrackSource.microphone
? remote.audioTracks
: remote.videoTracks;

@override
Widget build(BuildContext context) => Material(
color: Colors.black.withOpacity(0.3),
child: PopupMenuButton<Function>(
tooltip: 'Subscribe menu',
icon: Icon(icon,
color: {
TrackSubscriptionState.notAllowed: Colors.red,
TrackSubscriptionState.unsubscribed: Colors.grey,
TrackSubscriptionState.subscribed: Colors.green,
}[pub.subscriptionState]),
TrackSubscriptionState.notAllowed: Colors.red,
TrackSubscriptionState.unsubscribed: Colors.grey,
TrackSubscriptionState.subscribed: Colors.green,
}[publications.firstOrNull?.subscriptionState] ??
Colors.white),
onSelected: (value) => value(),
itemBuilder: (BuildContext context) => <PopupMenuEntry<Function>>[
// Subscribe/Unsubscribe
if (pub.subscribed == false)
if (publications.isNotEmpty &&
publications.firstOrNull?.subscribed == false)
PopupMenuItem(
child: const Text('Subscribe'),
value: () => pub.subscribe(),
value: () => publications.firstOrNull?.subscribe(),
)
else if (pub.subscribed == true)
else if (publications.firstOrNull?.subscribed ?? false)
PopupMenuItem(
child: const Text('Un-subscribe'),
value: () => pub.unsubscribe(),
value: () => publications.firstOrNull?.unsubscribe(),
),
],
),
Expand Down

0 comments on commit 35faaa1

Please sign in to comment.