Skip to content

Commit

Permalink
Add hardware api for camera, audio input/output selection. (#147)
Browse files Browse the repository at this point in the history
* chore: Add hardware api for device settings dialog, camera preview, audio input/output selection.

* update.

* update flutter-webrtc.

* chore: add popupmenu for audio/video selection.

* chore: Improve menu tooltip text.

* Removed hardware settings dialog, added it to experimental branch.

* remove unused code.

* Respond to device changes.

* fixed `flutter analyze`.

* update.

* bump verion to v1.1.1.
  • Loading branch information
cloudwebrtc authored Aug 24, 2022
1 parent c144567 commit 1d62150
Show file tree
Hide file tree
Showing 12 changed files with 300 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# CHANGELOG

## 1.1.1

* Add hardware api for camera and audio input/output selection.

## 1.1.0-hotfix

* Align the version in .podspec with the package version (fix compilation errors under ios/mac).
Expand Down
4 changes: 2 additions & 2 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ PODS:
- device_info_plus (0.0.1):
- Flutter
- Flutter (1.0.0)
- flutter_webrtc (0.9.2):
- flutter_webrtc (0.9.4):
- Flutter
- WebRTC-SDK (= 104.5112.02)
- livekit_client (1.1.0):
Expand Down Expand Up @@ -43,7 +43,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
flutter_webrtc: af1337911865d904b45c5fc95605115af4d0cdc8
flutter_webrtc: aa130dfe1eca6625c2e2e51ce830abb495bdb06e
livekit_client: f0343eef54a12a4b831d3ec1085760f13eca9ae3
path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad
Expand Down
160 changes: 153 additions & 7 deletions example/lib/widgets/controls.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';

Expand Down Expand Up @@ -29,20 +30,41 @@ class _ControlsWidgetState extends State<ControlsWidget> {
//
CameraPosition position = CameraPosition.front;

List<MediaDevice>? _audioInputs;
List<MediaDevice>? _audioOutputs;
List<MediaDevice>? _videoInputs;
MediaDevice? _selectedVideoInput;

StreamSubscription? _subscription;

@override
void initState() {
super.initState();
participant.addListener(_onChange);
_subscription = Hardware.instance.onDeviceChange.stream
.listen((List<MediaDevice> devices) {
_loadDevices(devices);
});
Hardware.instance.enumerateDevices().then(_loadDevices);
}

@override
void dispose() {
_subscription?.cancel();
participant.removeListener(_onChange);
super.dispose();
}

LocalParticipant get participant => widget.participant;

void _loadDevices(List<MediaDevice> devices) async {
_audioInputs = devices.where((d) => d.kind == 'audioinput').toList();
_audioOutputs = devices.where((d) => d.kind == 'audiooutput').toList();
_videoInputs = devices.where((d) => d.kind == 'videoinput').toList();
_selectedVideoInput = _videoInputs?.first;
setState(() {});
}

void _onChange() {
// trigger refresh
setState(() {});
Expand All @@ -69,6 +91,26 @@ class _ControlsWidgetState extends State<ControlsWidget> {
await participant.setCameraEnabled(true);
}

void _selectAudioOutput(MediaDevice device) async {
await Hardware.instance.selectAudioOutput(device);
setState(() {});
}

void _selectAudioInput(MediaDevice device) async {
await Hardware.instance.selectAudioInput(device);
setState(() {});
}

void _selectVideoInput(MediaDevice device) async {
final track = participant.videoTracks.firstOrNull?.track;
if (track == null) return;
if (_selectedVideoInput?.deviceId != device.deviceId) {
await track.switchCamera(device.deviceId);
_selectedVideoInput = device;
setState(() {});
}
}

void _toggleCamera() async {
//
final track = participant.videoTracks.firstOrNull?.track;
Expand Down Expand Up @@ -211,22 +253,126 @@ class _ControlsWidgetState extends State<ControlsWidget> {
tooltip: 'Unpublish all',
),
if (participant.isMicrophoneEnabled())
IconButton(
onPressed: _disableAudio,
icon: const Icon(EvaIcons.mic),
tooltip: 'mute audio',
PopupMenuButton<MediaDevice>(
icon: const Icon(Icons.settings_voice),
itemBuilder: (BuildContext context) {
return [
PopupMenuItem<MediaDevice>(
value: null,
child: const ListTile(
leading: Icon(
EvaIcons.micOff,
color: Colors.white,
),
title: Text('Mute Microphone'),
),
onTap: _disableAudio,
),
if (_audioInputs != null)
..._audioInputs!.map((device) {
return PopupMenuItem<MediaDevice>(
value: device,
child: ListTile(
leading: (device.deviceId ==
Hardware
.instance.selectedAudioInput?.deviceId)
? const Icon(
EvaIcons.checkmarkSquare,
color: Colors.white,
)
: const Icon(
EvaIcons.square,
color: Colors.white,
),
title: Text(device.label),
),
onTap: () => _selectAudioInput(device),
);
}).toList()
];
},
)
else
IconButton(
onPressed: _enableAudio,
icon: const Icon(EvaIcons.micOff),
tooltip: 'un-mute audio',
),
PopupMenuButton<MediaDevice>(
icon: const Icon(Icons.volume_up),
itemBuilder: (BuildContext context) {
return [
const PopupMenuItem<MediaDevice>(
value: null,
child: ListTile(
leading: Icon(
EvaIcons.speaker,
color: Colors.white,
),
title: Text('Select Audio Output'),
),
),
if (_audioOutputs != null)
..._audioOutputs!.map((device) {
return PopupMenuItem<MediaDevice>(
value: device,
child: ListTile(
leading: (device.deviceId ==
Hardware.instance.selectedAudioOutput?.deviceId)
? const Icon(
EvaIcons.checkmarkSquare,
color: Colors.white,
)
: const Icon(
EvaIcons.square,
color: Colors.white,
),
title: Text(device.label),
),
onTap: () => _selectAudioOutput(device),
);
}).toList()
];
},
),
if (participant.isCameraEnabled())
IconButton(
onPressed: _disableVideo,
PopupMenuButton<MediaDevice>(
icon: const Icon(EvaIcons.video),
tooltip: 'mute video',
itemBuilder: (BuildContext context) {
return [
PopupMenuItem<MediaDevice>(
value: null,
child: const ListTile(
leading: Icon(
EvaIcons.videoOff,
color: Colors.white,
),
title: Text('Disable Camera'),
),
onTap: _disableVideo,
),
if (_videoInputs != null)
..._videoInputs!.map((device) {
return PopupMenuItem<MediaDevice>(
value: device,
child: ListTile(
leading:
(device.deviceId == _selectedVideoInput?.deviceId)
? const Icon(
EvaIcons.checkmarkSquare,
color: Colors.white,
)
: const Icon(
EvaIcons.square,
color: Colors.white,
),
title: Text(device.label),
),
onTap: () => _selectVideoInput(device),
);
}).toList()
];
},
)
else
IconButton(
Expand Down
6 changes: 3 additions & 3 deletions example/macos/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PODS:
- device_info_plus_macos (0.0.1):
- FlutterMacOS
- flutter_webrtc (0.9.2):
- flutter_webrtc (0.9.4):
- FlutterMacOS
- WebRTC-SDK (= 104.5112.03)
- FlutterMacOS (1.0.0)
Expand Down Expand Up @@ -42,9 +42,9 @@ EXTERNAL SOURCES:

SPEC CHECKSUMS:
device_info_plus_macos: 1ad388a1ef433505c4038e7dd9605aadd1e2e9c7
flutter_webrtc: 335c834280a69d6db648228ab9bd0f855886f776
flutter_webrtc: 45cd8f5825bb32054e817708bf343ceff2c9cab8
FlutterMacOS: 57701585bf7de1b3fc2bb61f6378d73bbdea8424
livekit_client: 1076d27c06480d4abdda77641f6586309bc2dd3f
livekit_client: d229104e54e72ec7b5ffad62c14117297b5bbb23
path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19
shared_preferences_macos: a64dc611287ed6cbe28fd1297898db1336975727
WebRTC-SDK: 9f50fb5a410edc38e6fbb865fe940e3010bc8e7e
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ packages:
name: flutter_webrtc
url: "https://pub.dartlang.org"
source: hosted
version: "0.9.3"
version: "0.9.4"
google_fonts:
dependency: "direct main"
description:
Expand Down
2 changes: 1 addition & 1 deletion ios/livekit_client.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'livekit_client'
s.version = '1.1.0'
s.version = '1.1.1'
s.summary = 'Open source platform for real-time audio and video.'
s.description = 'Open source platform for real-time audio and video.'
s.homepage = 'https://livekit.io/'
Expand Down
1 change: 1 addition & 0 deletions lib/livekit_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ library livekit_client;
export 'src/core/room.dart';
export 'src/events.dart';
export 'src/exceptions.dart';
export 'src/hardware/hardware.dart';
export 'src/livekit.dart';
export 'src/managers/event.dart';
export 'src/options.dart';
Expand Down
Loading

0 comments on commit 1d62150

Please sign in to comment.