8000 [WIP] - Selecting an audio output (#422) · DEVILcong/flutter-webrtc@c2ce476 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit c2ce476

Browse files
authored
[WIP] - Selecting an audio output (flutter-webrtc#422)
* Initial code * FIX - enumerateDevices cast Example - Add list audiooutputs for native.
1 parent 456acf3 commit c2ce476

9 files changed

+81
-10
lines changed

example/lib/src/get_user_media_sample.dart

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ class _GetUserMediaSampleState extends State<GetUserMediaSample> {
2323
MediaRecorder _mediaRecorder;
2424
bool get _isRec => _mediaRecorder != null;
2525

26+
List<MediaDeviceInfo> _mediaDevicesList;
27+
2628
@override
2729
void initState() {
2830
super.initState();
@@ -60,6 +62,7 @@ class _GetUserMediaSampleState extends State<GetUserMediaSample> {
6062

6163
try {
6264
var stream = await navigator.getUserMedia(mediaConstraints);
65+
_mediaDevicesList = await navigator.mediaDevices.enumerateDevices();
6366
_localStream = stream;
6467
_localRenderer.srcObject = _localStream;
6568
} catch (e) {
@@ -172,6 +175,21 @@ class _GetUserMediaSampleState extends State<GetUserMediaSample> {
172175
icon: Icon(_isRec ? Icons.stop : Icons.fiber_manual_record),
173176
onPressed: _isRec ? _stopRecording : _startRecording,
174177
),
178+
PopupMenuButton<String>(
179+
onSelected: _selectAudioOutput,
180+
itemBuilder: (BuildContext context) {
181+
return _mediaDevicesList
182+
.where((device) => device.kind == 'audiooutput')
183+
.map((device) {
184+
if (device.kind == 'audiooutput') {
185+
return PopupMenuItem<String>(
186+
value: device.deviceId,
187+
child: Text(device.label),
188+
);
189+
}
190+
}).toList();
191+
},
192+
),
175193
]
176194
: null,
177195
),
@@ -195,4 +213,8 @@ class _GetUserMediaSampleState extends State<GetUserMediaSample> {
195213
),
196214
);
197215
}
216+
217+
void _selectAudioOutput(String deviceId) {
218+
_localRenderer.audioOutput = deviceId;
219+
}
198220
}

example/lib/src/get_user_media_sample_web.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import 'dart:html' as html;
44

55
import 'package:flutter/material.dart';
66
import 'package:flutter_webrtc/flutter_webrtc.dart';
7-
import 'package:flutter_webrtc/src/interface/mediadevices.dart';
87

98
/*
109
* getUserMedia sample

lib/flutter_webrtc.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export 'src/helper.dart';
44
export 'src/interface/enums.dart';
55
export 'src/interface/media_stream.dart';
66
export 'src/interface/media_stream_track.dart';
7+
export 'src/interface/mediadevices.dart' hide MediaDevices;
78
export 'src/interface/rtc_data_channel.dart';
89
export 'src/interface/rtc_dtmf_sender.dart';
910
export 'src/interface/rtc_ice_candidate.dart';

lib/src/helper.dart

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@ class Helper {
1919
static Future<List<MediaDeviceInfo>> get cameras =>
2020
enumerateDevices('videoinput');
2121

22+
/// Return the available audiooutputs
23+
///
24+
/// Note: Make sure to call this gettet after
25+
/// navigator.mediaDevices.getUserMedia(), otherwise the devices will not be
26+
/// listed.
27+
static Future<List<MediaDeviceInfo>> get audiooutputs =>
28+
enumerateDevices('audiooutput');
29+
2230
/// To select a a specific camera, you need to set constraints
2331
/// eg.
2432
/// constraints = {

lib/src/interface/rtc_video_renderer.dart

Lines changed: 3 additions & 0 deletions
B421
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ abstract class VideoRenderer extends ValueNotifier<RTCVideoValue> {
5555
bool get muted;
5656
set muted(bool mute);
5757

58+
///Return true if the audioOutput have been succesfully changed
59+
Future<bool> audioOutput(String deviceId);
60+
5861
bool get renderVideo;
5962
int get textureId;
6063

lib/src/native/mediadevices_impl.dart

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,14 @@ class MediaDeviceNative extends MediaDevices {
6363
@override
6464
Future<List<MediaDeviceInfo>> enumerateDevices() async {
6565
var _source = await getSources();
66-
return _source.map(
67-
(e) => MediaDeviceInfo(
68-
deviceId: e['deviceId'],
69-
groupId: e['groupId'],
70-
kind: e['kind'],
71-
label: e['label']),
72-
);
66+
return _source
67+
.map(
68+
(e) => MediaDeviceInfo(
69+
deviceId: e['deviceId'],
70+
groupId: e['groupId'],
71+
kind: e['kind'],
72+
label: e['label']),
73+
)
74+
.toList();
7375
}
7476
}

lib/src/native/rtc_video_renderer_impl.dart

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:async';
22

33
import 'package:flutter/services.dart';
4+
import 'package:flutter_webrtc/flutter_webrtc.dart';
45

56
import '../interface/media_stream.dart';
67
import '../interface/rtc_video_renderer.dart';
@@ -91,10 +92,27 @@ class RTCVideoRendererNative extends VideoRenderer {
9192
bool get renderVideo => srcObject != null;
9293

9394
@override
94-
bool get muted => throw UnimplementedError();
95+
bool get muted => _srcObject?.getAudioTracks()[0]?.muted ?? true;
9596

9697
@override
9798
set muted(bool mute) {
98-
throw UnimplementedError();
99+
if (_srcObject == null) {
100+
throw Exception('Can\'t be muted: The MediaStream is null');
101+
}
102+
if (_srcObject.ownerTag != 'local') {
103+
throw Exception(
104+
'You\'re trying to mute a remote track, this is not supported');
105+
}
106+
if (_srcObject.getAudioTracks()[0] == null) {
107+
throw Exception('Can\'t be muted: The MediaStreamTrack is null');
108+
}
109+
110+
Helper.setMicrophoneMute(mute, _srcObject.getAudioTracks()[0]);
111+
}
112+
113+
@override
114+
Future<bool> audioOutput(String deviceId) {
115+
// TODO(cloudwebrtc): related to https://github.com/flutter-webrtc/flutter-webrtc/issues/395
116+
throw UnimplementedError('This is not implement yet');
99117
}
100118
}

lib/src/rtc_video_renderer.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ class RTCVideoRenderer {
2424

2525
set muted(bool mute) => _delegate.muted = mute;
2626

27+
set audioOutput(String deviceId) => _delegate.audioOutput(deviceId);
28+
2729
set srcObject(MediaStream stream) => _delegate.srcObject = stream;
2830

2931
int get textureId => _delegate.textureId;

lib/src/web/rtc_video_renderer_impl.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'dart:async';
22
import 'dart:html' as html;
3+
import 'dart:js_util' as jsutil;
34

45
import 'package:flutter/services.dart';
56

@@ -163,4 +164,19 @@ class RTCVideoRendererWeb extends VideoRenderer {
163164
_videoElement.load();
164165
return super.dispose();
165166
}
167+
168+
@override
169+
Future<bool> audioOutput(String deviceId) async {
170+
try {
171+
if (jsutil.hasProperty(_videoElement, 'setSinkId')) {
172+
await jsutil.promiseToFuture<void>(
173+
jsutil.callMethod(_videoElement, 'setSinkId', [deviceId]));
174+
175+
return true;
176+
}
177+
} catch (e) {
178+
print('Unable to setSinkId: ${e.toString()}');
179+
}
180+
return false;
181+
}
166182
}

0 commit comments

Comments
 (0)
0