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:
Hiroshi Horie
2021-10-26 02:53:34 +09:00
committed by GitHub
parent 71a21f00b6
commit 6240457333
7 changed files with 61 additions and 17 deletions
+1 -1
View File
@@ -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
View File
@@ -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})';
}
+16 -6
View File
@@ -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
View File
@@ -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,
); );
+7 -1
View File
@@ -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>(
+10 -1
View File
@@ -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
View File
@@ -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;