Skip to content

Commit 427630a

Browse files
Brazold3xvn
andauthored
fix: fixing iOS speakerphone initialization (#664)
* fixing iOS speakerphone initialization * extracted String extensions --------- Co-authored-by: Deven Joshi <[email protected]>
1 parent 7cfea49 commit 427630a

File tree

9 files changed

+71
-27
lines changed

9 files changed

+71
-27
lines changed

packages/stream_video/lib/src/call/call.dart

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import '../shared_emitter.dart';
2020
import '../state_emitter.dart';
2121
import '../utils/cancelable_operation.dart';
2222
import '../utils/cancelables.dart';
23+
import '../utils/extensions.dart';
2324
import '../utils/future.dart';
2425
import '../utils/standard.dart';
2526
import '../webrtc/model/stats/rtc_ice_candidate_pair.dart';
@@ -1052,6 +1053,7 @@ class Call {
10521053
VideoSettingsRequestCameraFacingEnum.front
10531054
? FacingMode.user
10541055
: FacingMode.environment,
1056+
speakerDefaultOn: settings.audio.speakerDefaultOn,
10551057
);
10561058
}
10571059

@@ -1070,6 +1072,12 @@ class Call {
10701072

10711073
if (_connectOptions.audioOutputDevice != null) {
10721074
await setAudioOutputDevice(_connectOptions.audioOutputDevice!);
1075+
} else {
1076+
if (CurrentPlatform.isIos) {
1077+
await _session?.rtcManager?.setAppleAudioConfiguration(
1078+
speakerOn: _connectOptions.speakerDefaultOn,
1079+
);
1080+
}
10731081
}
10741082

10751083
_logger.v(() => '[applyConnectOptions] finished');
@@ -1963,7 +1971,3 @@ enum TrackType {
19631971
}
19641972
}
19651973
}
1966-
1967-
extension on String {
1968-
bool equalsIgnoreCase(String other) => toUpperCase() == other.toUpperCase();
1969-
}

packages/stream_video/lib/src/call/call_connect_options.dart

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class CallConnectOptions with EquatableMixin {
99
this.screenShare = TrackDisabled._instance,
1010
this.audioOutputDevice,
1111
this.audioInputDevice,
12+
this.speakerDefaultOn = false,
1213
this.cameraFacingMode = FacingMode.user,
1314
});
1415

@@ -18,6 +19,7 @@ class CallConnectOptions with EquatableMixin {
1819

1920
final RtcMediaDevice? audioOutputDevice;
2021
final RtcMediaDevice? audioInputDevice;
22+
final bool speakerDefaultOn;
2123

2224
final FacingMode cameraFacingMode;
2325

@@ -28,6 +30,7 @@ class CallConnectOptions with EquatableMixin {
2830
RtcMediaDevice? audioOutputDevice,
2931
RtcMediaDevice? audioInputDevice,
3032
FacingMode? cameraFacingMode,
33+
bool? speakerDefaultOn,
3134
}) {
3235
return CallConnectOptions(
3336
camera: camera ?? this.camera,
@@ -36,6 +39,7 @@ class CallConnectOptions with EquatableMixin {
3639
audioOutputDevice: audioOutputDevice ?? this.audioOutputDevice,
3740
audioInputDevice: audioInputDevice ?? this.audioInputDevice,
3841
cameraFacingMode: cameraFacingMode ?? this.cameraFacingMode,
42+
speakerDefaultOn: speakerDefaultOn ?? this.speakerDefaultOn,
3943
);
4044
}
4145

@@ -47,6 +51,7 @@ class CallConnectOptions with EquatableMixin {
4751
audioOutputDevice: other.audioOutputDevice,
4852
audioInputDevice: other.audioInputDevice,
4953
cameraFacingMode: other.cameraFacingMode,
54+
speakerDefaultOn: other.speakerDefaultOn,
5055
);
5156
}
5257

@@ -58,6 +63,7 @@ class CallConnectOptions with EquatableMixin {
5863
audioOutputDevice,
5964
audioInputDevice,
6065
cameraFacingMode,
66+
speakerDefaultOn,
6167
];
6268

6369
@override
@@ -68,7 +74,8 @@ class CallConnectOptions with EquatableMixin {
6874
' screenShare: $screenShare, '
6975
' audioOutput: $audioOutputDevice,'
7076
' audioInput: $audioInputDevice, '
71-
' cameraFacingMode: $cameraFacingMode'
77+
' cameraFacingMode: $cameraFacingMode, '
78+
' speakerDefaultOn: $speakerDefaultOn'
7279
'}';
7380
}
7481
}

packages/stream_video/lib/src/call/session/call_session.dart

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,6 @@ class CallSession extends Disposable {
186186
);
187187
});
188188

189-
if (CurrentPlatform.isIos) {
190-
await rtcManager?.setAppleAudioConfiguration();
191-
}
192-
193189
_logger.v(() => '[start] completed');
194190
return const Result.success(none);
195191
} catch (e, stk) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// Extensions on [String].
2+
extension StringExtension on String {
3+
bool equalsIgnoreCase(String other) => toUpperCase() == other.toUpperCase();
4+
String capitalizeFirstLetter() => '${this[0].toUpperCase()}${substring(1)}';
5+
}

packages/stream_video/lib/src/webrtc/rtc_manager.dart

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'package:collection/collection.dart';
22
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
33
import 'package:rxdart/rxdart.dart';
44

5+
import '../../stream_video.dart';
56
import '../disposable.dart';
67
import '../errors/video_error_composer.dart';
78
import '../logger/impl/tagged_logger.dart';
@@ -10,6 +11,7 @@ import '../models/call_cid.dart';
1011
import '../platform_detector/platform_detector.dart';
1112
import '../sfu/data/models/sfu_model_parser.dart';
1213
import '../sfu/data/models/sfu_track_type.dart';
14+
import '../utils/extensions.dart';
1315
import '../utils/none.dart';
1416
import '../utils/result.dart';
1517
import 'codecs_helper.dart' as codecs;
@@ -661,6 +663,17 @@ extension RtcManagerTrackHelper on RtcManager {
661663
}
662664

663665
try {
666+
if (CurrentPlatform.isIos &&
667+
device.id.equalsIgnoreCase(
668+
AudioSettingsRequestDefaultDeviceEnum.speaker.value,
669+
)) {
670+
await setAppleAudioConfiguration(
671+
speakerOn: true,
672+
);
673+
} else {
674+
await setAppleAudioConfiguration();
675+
}
676+
664677
// Change the audio output device for all remote audio tracks.
665678
await rtc.Helper.selectAudioOutput(device.id);
666679
for (final audioTrack in audioTracks) {
@@ -847,13 +860,18 @@ extension RtcManagerTrackHelper on RtcManager {
847860
return Result.error('Unsupported trackType $trackType');
848861
}
849862

850-
Future<Result<None>> setAppleAudioConfiguration() async {
863+
Future<Result<None>> setAppleAudioConfiguration({
864+
bool speakerOn = false,
865+
}) async {
851866
try {
852867
await rtc.Helper.setAppleAudioConfiguration(
853868
rtc.AppleAudioConfiguration(
854-
appleAudioMode: rtc.AppleAudioMode.videoChat,
869+
appleAudioMode: speakerOn
870+
? rtc.AppleAudioMode.videoChat
871+
: rtc.AppleAudioMode.voiceChat,
855872
appleAudioCategory: rtc.AppleAudioCategory.playAndRecord,
856873
appleAudioCategoryOptions: {
874+
if (speakerOn) rtc.AppleAudioCategoryOption.defaultToSpeaker,
857875
rtc.AppleAudioCategoryOption.mixWithOthers,
858876
rtc.AppleAudioCategoryOption.allowBluetooth,
859877
rtc.AppleAudioCategoryOption.allowBluetoothA2DP,

packages/stream_video/lib/src/webrtc/rtc_media_device/rtc_media_device_notifier.dart

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
import 'package:collection/collection.dart';
12
import 'package:flutter_webrtc/flutter_webrtc.dart' as rtc;
23
import 'package:rxdart/rxdart.dart';
34

5+
import '../../../stream_video.dart';
46
import '../../errors/video_error_composer.dart';
7+
import '../../utils/extensions.dart';
58
import '../../utils/result.dart';
69
import 'rtc_media_device.dart';
710

@@ -33,14 +36,29 @@ class RtcMediaDeviceNotifier {
3336
try {
3437
final devices = await rtc.navigator.mediaDevices.enumerateDevices();
3538

36-
final mediaDevices = devices.map((it) {
37-
return RtcMediaDevice(
38-
id: it.deviceId,
39-
label: it.label,
40-
groupId: it.groupId,
41-
kind: RtcMediaDeviceKind.fromAlias(it.kind),
42-
);
43-
});
39+
final mediaDevices = [
40+
...devices.map((it) {
41+
return RtcMediaDevice(
42+
id: it.deviceId,
43+
label: it.label,
44+
groupId: it.groupId,
45+
kind: RtcMediaDeviceKind.fromAlias(it.kind),
46+
);
47+
}),
48+
if (CurrentPlatform.isIos &&
49+
(kind == null || kind == RtcMediaDeviceKind.audioOutput) &&
50+
devices.none(
51+
(d) => d.deviceId.equalsIgnoreCase(
52+
AudioSettingsRequestDefaultDeviceEnum.earpiece.value,
53+
),
54+
))
55+
RtcMediaDevice(
56+
id: AudioSettingsRequestDefaultDeviceEnum.earpiece.value,
57+
label: AudioSettingsRequestDefaultDeviceEnum.earpiece.value
58+
.capitalizeFirstLetter(),
59+
kind: RtcMediaDeviceKind.audioOutput,
60+
),
61+
];
4462

4563
if (kind != null) {
4664
final devices = mediaDevices.where((d) => d.kind == kind);

packages/stream_video_flutter/lib/src/call_controls/controls/toggle_speakerphone_option.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:collection/collection.dart';
44
import 'package:flutter/material.dart';
55

66
import '../../../stream_video_flutter.dart';
7+
import '../../utils/extensions.dart';
78

89
// These are eyeballed device IDs for the speaker and earpiece.
910
// based on Android and iOS enumerated devices.
@@ -112,7 +113,3 @@ class _ToggleSpeakerState extends State<ToggleSpeakerphoneOption> {
112113
);
113114
}
114115
}
115-
116-
extension on String {
117-
bool equalsIgnoreCase(String other) => toUpperCase() == other.toUpperCase();
118-
}

packages/stream_video_flutter/lib/src/livestream/livestream_speakerphone_option.dart

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:collection/collection.dart';
44
import 'package:flutter/material.dart';
55

66
import '../../../stream_video_flutter.dart';
7+
import '../utils/extensions.dart';
78

89
/// A widget that represents a call control option to toggle if the
910
/// speakerphone is on or off.
@@ -122,7 +123,3 @@ class _ToggleSpeakerState extends State<LivestreamSpeakerphoneOption> {
122123
);
123124
}
124125
}
125-
126-
extension on String {
127-
bool equalsIgnoreCase(String other) => toUpperCase() == other.toUpperCase();
128-
}

packages/stream_video_flutter/lib/src/utils/extensions.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ extension StringExtension on String {
2020

2121
return resultBuffer.toString();
2222
}
23+
24+
bool equalsIgnoreCase(String other) => toUpperCase() == other.toUpperCase();
2325
}
2426

2527
/// Extensions on [List].

0 commit comments

Comments
 (0)