diff --git a/CHANGELOG.md b/CHANGELOG.md index e9b8e1e..6b02214 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog -------------------------------------------- +[1.0.14] - 2023-01-30 + +* Add support for getCapabilities/setCodecPreferences. + [1.0.13] - 2022-12-12 * export jsRtpReciver. diff --git a/lib/src/factory_impl.dart b/lib/src/factory_impl.dart index 8a4292c..78e9e7c 100644 --- a/lib/src/factory_impl.dart +++ b/lib/src/factory_impl.dart @@ -1,12 +1,26 @@ import 'dart:async'; import 'dart:convert'; import 'dart:html' as html; +import 'package:js/js.dart'; import 'package:webrtc_interface/webrtc_interface.dart'; import 'media_recorder_impl.dart'; import 'media_stream_impl.dart'; import 'navigator_impl.dart'; import 'rtc_peerconnection_impl.dart'; +import 'rtc_rtp_capailities_imp.dart'; + +@JS('RTCRtpSender') +@anonymous +class RTCRtpSenderJs { + external static Object getCapabilities(String kind); +} + +@JS('RTCRtpReceiver') +@anonymous +class RTCRtpReceiverJs { + external static Object getCapabilities(String kind); +} class RTCFactoryWeb extends RTCFactory { RTCFactoryWeb._internal(); @@ -47,6 +61,18 @@ class RTCFactoryWeb extends RTCFactory { @override Navigator get navigator => NavigatorWeb(); + + @override + Future getRtpReceiverCapabilities(String kind) async { + var caps = RTCRtpReceiverJs.getCapabilities(kind); + return RTCRtpCapabilitiesWeb.fromJsObject(caps); + } + + @override + Future getRtpSenderCapabilities(String kind) async { + var caps = RTCRtpSenderJs.getCapabilities(kind); + return RTCRtpCapabilitiesWeb.fromJsObject(caps); + } } Future createPeerConnection( @@ -60,6 +86,14 @@ Future createLocalMediaStream(String label) { return RTCFactoryWeb.instance.createLocalMediaStream(label); } +Future getRtpReceiverCapabilities(String kind) async { + return RTCFactoryWeb.instance.getRtpReceiverCapabilities(kind); +} + +Future getRtpSenderCapabilities(String kind) async { + return RTCFactoryWeb.instance.getRtpSenderCapabilities(kind); +} + MediaRecorder mediaRecorder() { return RTCFactoryWeb.instance.mediaRecorder(); } diff --git a/lib/src/rtc_rtp_capailities_imp.dart b/lib/src/rtc_rtp_capailities_imp.dart new file mode 100644 index 0000000..4174d70 --- /dev/null +++ b/lib/src/rtc_rtp_capailities_imp.dart @@ -0,0 +1,14 @@ +import 'dart:js_util' as jsutil; +import 'package:webrtc_interface/webrtc_interface.dart'; + +class RTCRtpCapabilitiesWeb { + static RTCRtpCapabilities fromJsObject(Object object) { + return RTCRtpCapabilities.fromMap({ + 'codecs': jsutil.dartify(jsutil.getProperty(object, 'codecs')), + 'headerExtensions': + jsutil.dartify(jsutil.getProperty(object, 'headerExtensions')), + 'fecMechanisms': + jsutil.dartify(jsutil.getProperty(object, 'fecMechanisms')) ?? [] + }); + } +} diff --git a/lib/src/rtc_rtp_transceiver_impl.dart b/lib/src/rtc_rtp_transceiver_impl.dart index d22e11a..6369e1f 100644 --- a/lib/src/rtc_rtp_transceiver_impl.dart +++ b/lib/src/rtc_rtp_transceiver_impl.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:js_util' as jsutil; +import 'package:webrtc_interface/src/rtc_rtp_capabilities.dart'; import 'package:webrtc_interface/webrtc_interface.dart'; import 'media_stream_impl.dart'; @@ -53,6 +54,8 @@ extension RTCRtpTransceiverInitWebExt on RTCRtpTransceiverInit { }); } + + class RTCRtpTransceiverWeb extends RTCRtpTransceiver { RTCRtpTransceiverWeb(this._jsTransceiver, _peerConnectionId); @@ -109,4 +112,14 @@ class RTCRtpTransceiverWeb extends RTCRtpTransceiver { throw 'Unable to RTCRtpTransceiver::stop: ${e..toString()}'; } } + + @override + Future setCodecPreferences(List codecs) async { + try { + jsutil.callMethod(_jsTransceiver, 'setCodecPreferences', + [jsutil.jsify(codecs.map((e) => e.toMap()).toList())]); + } on Exception catch (e) { + throw 'Unable to RTCRtpTransceiver::setCodecPreferences: ${e..toString()}'; + } + } } diff --git a/pubspec.yaml b/pubspec.yaml index e0412f9..94e8bff 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,15 +1,16 @@ name: dart_webrtc description: Use the dart/js library to re-wrap the webrtc js interface of the browser, to adapted common browsers. -version: 1.0.13 +version: 1.0.14 homepage: https://github.com/flutter-webrtc/dart-webrtc environment: sdk: '>=2.13.0 <3.0.0' dependencies: + js: ^0.6.4 platform_detect: ^2.0.7 - webrtc_interface: ^1.0.10 - + webrtc_interface: ^1.0.11 + dev_dependencies: build_runner: ^1.10.0 build_web_compilers: ^2.11.0 diff --git a/web/main.dart b/web/main.dart index da166b6..264ba9d 100644 --- a/web/main.dart +++ b/web/main.dart @@ -29,8 +29,20 @@ void loopBackTest() async { var remotelVideo = RTCVideoElement(); remote!.append(remotelVideo.htmlElement); + var acaps = await getRtpSenderCapabilities('audio'); + print('sender audio capabilities: ${acaps.toMap()}'); + + var vcaps = await getRtpSenderCapabilities('video'); + print('sender video capabilities: ${vcaps.toMap()}'); + /* + capabilities = await getRtpReceiverCapabilities('audio'); + print('receiver audio capabilities: ${capabilities.toMap()}'); + + capabilities = await getRtpReceiverCapabilities('video'); + print('receiver video capabilities: ${capabilities.toMap()}'); + */ var pc2 = await createPeerConnection({}); - pc2.onTrack = (event) { + pc2.onTrack = (event) async { if (event.track.kind == 'video') { remotelVideo.srcObject = event.streams[0]; } @@ -81,6 +93,27 @@ void loopBackTest() async { await pc1.addTrack(track, stream); }); + var transceivers = await pc1.getTransceivers(); + transceivers.forEach((transceiver) { + print('transceiver: ${transceiver.sender.track!.kind!}'); + if (transceiver.sender.track!.kind! == 'video') { + transceiver.setCodecPreferences([ + RTCRtpCodecCapability( + mimeType: 'video/AV1', + clockRate: 90000, + ) + ]); + } else if (transceiver.sender.track!.kind! == 'audio') { + transceiver.setCodecPreferences([ + RTCRtpCodecCapability( + mimeType: 'audio/PCMA', + clockRate: 8000, + channels: 1, + ) + ]); + } + }); + var offer = await pc1.createOffer(); await pc2.addTransceiver(