Option to control DTX (#25)
* protocol 4 * default to v4 * mediaStreamTrack.enabled * track start * private constructor * remote audio/video tracks * log sdp * organize imports * dtx option (default true)
This commit is contained in:
@@ -79,7 +79,7 @@ class _ConnectPageState extends State<ConnectPage> {
|
|||||||
_uriCtrl.text,
|
_uriCtrl.text,
|
||||||
_tokenCtrl.text,
|
_tokenCtrl.text,
|
||||||
options: ConnectOptions(
|
options: ConnectOptions(
|
||||||
defaultPublishOptions: TrackPublishOptions(
|
defaultVideoPublishOptions: VideoPublishOptions(
|
||||||
simulcast: _simulcast,
|
simulcast: _simulcast,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
+23
-5
@@ -6,23 +6,27 @@ class ConnectOptions {
|
|||||||
/// Auto-subscribe to room tracks upon connect, defaults to true.
|
/// Auto-subscribe to room tracks upon connect, defaults to true.
|
||||||
final bool autoSubscribe;
|
final bool autoSubscribe;
|
||||||
|
|
||||||
/// Default options used when publishing a track
|
/// Default options used when publishing a video track
|
||||||
final TrackPublishOptions defaultPublishOptions;
|
final VideoPublishOptions defaultVideoPublishOptions;
|
||||||
|
|
||||||
|
/// Default options used when publishing a audio track
|
||||||
|
final AudioPublishOptions defaultAudioPublishOptions;
|
||||||
|
|
||||||
const ConnectOptions({
|
const ConnectOptions({
|
||||||
this.autoSubscribe = true,
|
this.autoSubscribe = true,
|
||||||
this.defaultPublishOptions = const TrackPublishOptions(),
|
this.defaultVideoPublishOptions = const VideoPublishOptions(),
|
||||||
|
this.defaultAudioPublishOptions = const AudioPublishOptions(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class TrackPublishOptions {
|
class VideoPublishOptions {
|
||||||
///
|
///
|
||||||
final VideoEncoding? videoEncoding;
|
final VideoEncoding? videoEncoding;
|
||||||
|
|
||||||
///
|
///
|
||||||
final bool simulcast;
|
final bool simulcast;
|
||||||
|
|
||||||
const TrackPublishOptions({
|
const VideoPublishOptions({
|
||||||
this.videoEncoding,
|
this.videoEncoding,
|
||||||
this.simulcast = false,
|
this.simulcast = false,
|
||||||
});
|
});
|
||||||
@@ -31,3 +35,17 @@ class TrackPublishOptions {
|
|||||||
String toString() =>
|
String toString() =>
|
||||||
'${runtimeType}(videoEncoding: ${videoEncoding}, simulcast: ${simulcast})';
|
'${runtimeType}(videoEncoding: ${videoEncoding}, simulcast: ${simulcast})';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AudioPublishOptions {
|
||||||
|
/// DTX (Discontinuous Transmission)
|
||||||
|
/// https://en.wikipedia.org/wiki/Discontinuous_transmission
|
||||||
|
/// defaults to true
|
||||||
|
final bool dtx;
|
||||||
|
|
||||||
|
const AudioPublishOptions({
|
||||||
|
this.dtx = true,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => '${runtimeType}(dtx: ${dtx})';
|
||||||
|
}
|
||||||
|
|||||||
@@ -23,12 +23,15 @@ class LocalParticipant extends Participant {
|
|||||||
@internal
|
@internal
|
||||||
final RTCEngine engine;
|
final RTCEngine engine;
|
||||||
@internal
|
@internal
|
||||||
final TrackPublishOptions? defaultPublishOptions;
|
final VideoPublishOptions? defaultVideoPublishOptions;
|
||||||
|
@internal
|
||||||
|
final AudioPublishOptions? defaultAudioPublishOptions;
|
||||||
|
|
||||||
LocalParticipant({
|
LocalParticipant({
|
||||||
required this.engine,
|
required this.engine,
|
||||||
required lk_models.ParticipantInfo info,
|
required lk_models.ParticipantInfo info,
|
||||||
this.defaultPublishOptions,
|
this.defaultVideoPublishOptions,
|
||||||
|
this.defaultAudioPublishOptions,
|
||||||
required EventsEmitter<RoomEvent> roomEvents,
|
required EventsEmitter<RoomEvent> roomEvents,
|
||||||
}) : super(
|
}) : super(
|
||||||
info.sid,
|
info.sid,
|
||||||
@@ -39,16 +42,23 @@ class LocalParticipant extends Participant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// publish an audio track to the room
|
/// publish an audio track to the room
|
||||||
Future<TrackPublication> publishAudioTrack(LocalAudioTrack track) async {
|
Future<TrackPublication> publishAudioTrack(
|
||||||
|
LocalAudioTrack track, {
|
||||||
|
AudioPublishOptions? options,
|
||||||
|
}) async {
|
||||||
if (audioTracks.any(
|
if (audioTracks.any(
|
||||||
(e) => e.track?.mediaStreamTrack.id == track.mediaStreamTrack.id)) {
|
(e) => e.track?.mediaStreamTrack.id == track.mediaStreamTrack.id)) {
|
||||||
throw TrackPublishException('track already exists');
|
throw TrackPublishException('track already exists');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use defaultPublishOptions if options is null
|
||||||
|
options = options ?? defaultAudioPublishOptions;
|
||||||
|
|
||||||
final trackInfo = await engine.addTrack(
|
final trackInfo = await engine.addTrack(
|
||||||
cid: track.getCid(),
|
cid: track.getCid(),
|
||||||
name: track.name,
|
name: track.name,
|
||||||
kind: track.kind,
|
kind: track.kind,
|
||||||
|
dtx: options?.dtx,
|
||||||
);
|
);
|
||||||
|
|
||||||
await track.start();
|
await track.start();
|
||||||
@@ -73,15 +83,15 @@ class LocalParticipant extends Participant {
|
|||||||
/// Publish a video track to the room
|
/// Publish a video track to the room
|
||||||
Future<TrackPublication> publishVideoTrack(
|
Future<TrackPublication> publishVideoTrack(
|
||||||
LocalVideoTrack track, {
|
LocalVideoTrack track, {
|
||||||
TrackPublishOptions? options,
|
VideoPublishOptions? options,
|
||||||
}) async {
|
}) async {
|
||||||
if (videoTracks.any(
|
if (videoTracks.any(
|
||||||
(e) => e.track?.mediaStreamTrack.id == track.mediaStreamTrack.id)) {
|
(e) => e.track?.mediaStreamTrack.id == track.mediaStreamTrack.id)) {
|
||||||
throw TrackPublishException('track already exists');
|
throw TrackPublishException('track already exists');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use default options from `ConnectOptions` if options is null
|
// Use defaultPublishOptions if options is null
|
||||||
options = options ?? defaultPublishOptions;
|
options = options ?? defaultVideoPublishOptions;
|
||||||
|
|
||||||
final trackInfo = await engine.addTrack(
|
final trackInfo = await engine.addTrack(
|
||||||
cid: track.getCid(),
|
cid: track.getCid(),
|
||||||
|
|||||||
+2
-1
@@ -75,7 +75,8 @@ class Room extends DisposableChangeNotifier with EventsEmittable<RoomEvent> {
|
|||||||
localParticipant = LocalParticipant(
|
localParticipant = LocalParticipant(
|
||||||
engine: engine,
|
engine: engine,
|
||||||
info: joinResponse.participant,
|
info: joinResponse.participant,
|
||||||
defaultPublishOptions: connectOptions?.defaultPublishOptions,
|
defaultVideoPublishOptions: connectOptions?.defaultVideoPublishOptions,
|
||||||
|
defaultAudioPublishOptions: connectOptions?.defaultAudioPublishOptions,
|
||||||
roomEvents: events,
|
roomEvents: events,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -136,12 +136,18 @@ class RTCEngine extends Disposable with EventsEmittable<EngineEvent> {
|
|||||||
required String name,
|
required String name,
|
||||||
required lk_models.TrackType kind,
|
required lk_models.TrackType kind,
|
||||||
TrackDimension? dimension,
|
TrackDimension? dimension,
|
||||||
|
bool? dtx,
|
||||||
}) async {
|
}) async {
|
||||||
// TODO: Check if cid already published
|
// TODO: Check if cid already published
|
||||||
|
|
||||||
// send request to add track
|
// send request to add track
|
||||||
signalClient.sendAddTrack(
|
signalClient.sendAddTrack(
|
||||||
cid: cid, name: name, type: kind, dimension: dimension);
|
cid: cid,
|
||||||
|
name: name,
|
||||||
|
type: kind,
|
||||||
|
dimension: dimension,
|
||||||
|
dtx: dtx,
|
||||||
|
);
|
||||||
|
|
||||||
// wait for response, or timeout
|
// wait for response, or timeout
|
||||||
final event = await _signalListener.waitFor<SignalLocalTrackPublishedEvent>(
|
final event = await _signalListener.waitFor<SignalLocalTrackPublishedEvent>(
|
||||||
|
|||||||
@@ -155,16 +155,25 @@ class SignalClient extends Disposable with EventsEmittable<SignalEvent> {
|
|||||||
required String name,
|
required String name,
|
||||||
required lk_models.TrackType type,
|
required lk_models.TrackType type,
|
||||||
TrackDimension? dimension,
|
TrackDimension? dimension,
|
||||||
|
bool? dtx,
|
||||||
}) {
|
}) {
|
||||||
final req = lk_rtc.AddTrackRequest(
|
final req = lk_rtc.AddTrackRequest(
|
||||||
cid: cid,
|
cid: cid,
|
||||||
name: name,
|
name: name,
|
||||||
type: type,
|
type: type,
|
||||||
);
|
);
|
||||||
if (dimension != null) {
|
|
||||||
|
if (type == lk_models.TrackType.VIDEO && dimension != null) {
|
||||||
|
// video specific
|
||||||
req.width = dimension.width;
|
req.width = dimension.width;
|
||||||
req.height = dimension.height;
|
req.height = dimension.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type == lk_models.TrackType.AUDIO && dtx != null) {
|
||||||
|
// audio specific
|
||||||
|
req.disableDtx = !dtx;
|
||||||
|
}
|
||||||
|
|
||||||
_sendRequest(lk_rtc.SignalRequest(
|
_sendRequest(lk_rtc.SignalRequest(
|
||||||
addTrack: req,
|
addTrack: req,
|
||||||
));
|
));
|
||||||
|
|||||||
+2
-2
@@ -83,9 +83,9 @@ class Utils {
|
|||||||
static List<rtc.RTCRtpEncoding>? computeVideoEncodings({
|
static List<rtc.RTCRtpEncoding>? computeVideoEncodings({
|
||||||
int? width,
|
int? width,
|
||||||
int? height,
|
int? height,
|
||||||
TrackPublishOptions? options,
|
VideoPublishOptions? options,
|
||||||
}) {
|
}) {
|
||||||
options ??= const TrackPublishOptions();
|
options ??= const VideoPublishOptions();
|
||||||
|
|
||||||
VideoEncoding? videoEncoding = options.videoEncoding;
|
VideoEncoding? videoEncoding = options.videoEncoding;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user