Skip to content

Commit bc069eb

Browse files
authored
feat: Noise cancellation feature (#873)
* Noise cancellation feature for Android * iOS Noise cancellation implementation addded * iOS fixes * tweak * bumped webrtc version * handling noise cancellation on not supported platforms * fix * updated webrtc dependencies * tweak * tweaks * linter fixes
1 parent 20cdb7d commit bc069eb

File tree

60 files changed

+1760
-206
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1760
-206
lines changed

dogfooding/android/app/build.gradle

+4-4
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,22 @@ android {
4444
ndkVersion = "27.0.12077973"
4545

4646
compileOptions {
47-
sourceCompatibility JavaVersion.VERSION_1_8
48-
targetCompatibility JavaVersion.VERSION_1_8
47+
sourceCompatibility JavaVersion.VERSION_17
48+
targetCompatibility JavaVersion.VERSION_17
4949
}
5050

5151
afterEvaluate { project ->
5252
if (project.hasProperty("kotlin")) {
5353
project.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
5454
kotlinOptions {
55-
jvmTarget = "1.8"
55+
jvmTarget = "17"
5656
}
5757
}
5858
}
5959
}
6060

6161
kotlinOptions {
62-
jvmTarget = '1.8'
62+
jvmTarget = '17'
6363
}
6464

6565
sourceSets {

dogfooding/lib/app/app.dart

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
55
// 📦 Package imports:
66
import 'package:firebase_core/firebase_core.dart';
77
import 'package:firebase_crashlytics/firebase_crashlytics.dart';
8-
import 'package:flutter/services.dart' show appFlavor;
98
import 'package:flutter_dogfooding/core/repos/token_service.dart';
109

1110
// 🌎 Project imports:

dogfooding/lib/di/injector.dart

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import 'package:share_plus/share_plus.dart';
99
import 'package:shared_preferences/shared_preferences.dart';
1010
import 'package:stream_chat_flutter/stream_chat_flutter.dart' hide User;
1111
import 'package:stream_video_flutter/stream_video_flutter.dart';
12+
import 'package:stream_video_noise_cancellation/noise_cancellation_audio_processor.dart';
1213
import 'package:stream_video_push_notification/stream_video_push_notification.dart';
1314

1415
import '../app/user_auth_controller.dart';
@@ -44,7 +45,7 @@ class AppInjector {
4445

4546
// Repositories
4647
locator.registerSingleton(
47-
TokenService(
48+
const TokenService(
4849
customEnvironmentLoader: customEnvironmentLoader,
4950
),
5051
);
@@ -159,11 +160,12 @@ StreamVideo _initStreamVideo(
159160
apiKey,
160161
user: user,
161162
tokenLoader: tokenLoader,
162-
options: const StreamVideoOptions(
163+
options: StreamVideoOptions(
163164
logPriority: Priority.verbose,
164165
muteAudioWhenInBackground: false,
165166
muteVideoWhenInBackground: false,
166167
keepConnectionsAliveWhenInBackground: true,
168+
audioProcessor: NoiseCancellationAudioProcessor(),
167169
),
168170
pushNotificationManagerProvider: StreamVideoPushNotificationManager.create(
169171
iosPushProvider: const StreamVideoPushProvider.apn(

dogfooding/lib/screens/call_screen.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import 'package:flutter_dogfooding/theme/app_palette.dart';
1212
import 'package:flutter_dogfooding/utils/feedback_dialog.dart';
1313
import 'package:flutter_dogfooding/widgets/badged_call_option.dart';
1414
import 'package:flutter_dogfooding/widgets/call_duration_title.dart';
15-
import 'package:flutter_dogfooding/widgets/settings_menu.dart';
15+
import 'package:flutter_dogfooding/widgets/settings_menu/settings_menu.dart';
1616
import 'package:flutter_dogfooding/widgets/share_call_card.dart';
1717
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
1818
import 'package:stream_video_flutter/stream_video_flutter.dart' hide User;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_dogfooding/theme/app_palette.dart';
3+
import 'package:flutter_dogfooding/widgets/settings_menu/settings_menu.dart';
4+
import 'package:flutter_dogfooding/widgets/settings_menu/standard_action_menu_item.dart';
5+
import 'package:stream_video_flutter/stream_video_flutter.dart';
6+
7+
class ClosedCaptionsMenuItem extends StatelessWidget {
8+
const ClosedCaptionsMenuItem({
9+
super.key,
10+
required this.widget,
11+
});
12+
13+
final SettingsMenu widget;
14+
15+
@override
16+
Widget build(BuildContext context) {
17+
return StreamBuilder(
18+
stream: widget.call.state.asStream(),
19+
builder: (context, snapshot) {
20+
if (snapshot.hasData) {
21+
final callState = snapshot.data as CallState;
22+
23+
if (callState.settings.transcription.closedCaptionMode ==
24+
ClosedCaptionSettingsMode.disabled) {
25+
return const SizedBox.shrink();
26+
}
27+
28+
return Column(
29+
children: [
30+
const SizedBox(height: 16),
31+
StandardActionMenuItem(
32+
icon: callState.isCaptioning
33+
? Icons.closed_caption_sharp
34+
: Icons.closed_caption_disabled_sharp,
35+
label: 'Toggle Closed Caption',
36+
trailing: Text(
37+
callState.isCaptioning ? 'On' : 'Off',
38+
style: TextStyle(
39+
color: callState.isCaptioning
40+
? AppColorPalette.appGreen
41+
: null,
42+
),
43+
),
44+
onPressed: () {
45+
if (!callState.isCaptioning) {
46+
widget.call.startClosedCaptions();
47+
} else {
48+
widget.call.stopClosedCaptions();
49+
}
50+
},
51+
),
52+
],
53+
);
54+
}
55+
56+
return const SizedBox.shrink();
57+
});
58+
}
59+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_dogfooding/theme/app_palette.dart';
3+
import 'package:flutter_dogfooding/widgets/settings_menu/standard_action_menu_item.dart';
4+
import 'package:stream_video_flutter/stream_video_flutter.dart';
5+
6+
class NoiseCancellationMenuItem extends StatefulWidget {
7+
const NoiseCancellationMenuItem({
8+
super.key,
9+
required this.call,
10+
});
11+
12+
final Call call;
13+
14+
@override
15+
State<NoiseCancellationMenuItem> createState() =>
16+
_NoiseCancellationMenuItemState();
17+
}
18+
19+
class _NoiseCancellationMenuItemState extends State<NoiseCancellationMenuItem> {
20+
@override
21+
Widget build(BuildContext context) {
22+
return StreamBuilder(
23+
stream: widget.call.state.asStream(),
24+
builder: (context, snapshot) {
25+
if (snapshot.hasData) {
26+
final callState = snapshot.data as CallState;
27+
28+
if (callState.settings.audio.noiseCancellation?.mode ==
29+
NoiceCancellationSettingsMode.disabled) {
30+
return const SizedBox.shrink();
31+
}
32+
33+
return Column(
34+
children: [
35+
const SizedBox(height: 16),
36+
StandardActionMenuItem(
37+
icon: callState.isAudioProcessing
38+
? Icons.hearing
39+
: Icons.hearing_disabled,
40+
label: 'Toggle Noise Cancellation',
41+
trailing: Text(
42+
callState.isAudioProcessing ? 'On' : 'Off',
43+
style: TextStyle(
44+
color: callState.isAudioProcessing
45+
? AppColorPalette.appGreen
46+
: null,
47+
),
48+
),
49+
onPressed: () {
50+
if (!callState.isAudioProcessing) {
51+
widget.call.startAudioProcessing();
52+
} else {
53+
widget.call.stopAudioProcessing();
54+
}
55+
},
56+
),
57+
],
58+
);
59+
}
60+
61+
return const SizedBox.shrink();
62+
});
63+
}
64+
}

0 commit comments

Comments
 (0)