Skip to content

Conversation

@Mayank4352
Copy link
Contributor

@Mayank4352 Mayank4352 commented Nov 13, 2025

Description

Allow Users to Select Preferred Speaker

Fixes #567

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

How Has This Been Tested?

Tested Locally using two devices for both rooms and calls

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules
  • I have checked my code and corrected any misspellings

Maintainer Checklist

@coderabbitai
Copy link

coderabbitai bot commented Nov 13, 2025

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

🎉 Welcome @Mayank4352!
Thank you for your pull request! Our team will review it soon. 🔍

  • Please ensure your PR follows the contribution guidelines. ✅
  • All automated tests should pass before merging. 🔄
  • If this PR fixes an issue, link it in the description. 🔗

We appreciate your contribution! 🚀

@Mayank4352
Copy link
Contributor Author

Hey @M4dhav, Kindly review this PR

@M4dhav M4dhav self-requested a review November 22, 2025 08:35
@M4dhav M4dhav added the enhancement New feature or request label Nov 22, 2025
Copy link
Contributor

@M4dhav M4dhav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please fix merge conflicts

@Mayank4352 Mayank4352 requested a review from M4dhav November 23, 2025 07:37
Copy link
Contributor

@M4dhav M4dhav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merge conflicts came in again after merging #610

@Mayank4352 Mayank4352 requested a review from M4dhav November 23, 2025 14:11
@M4dhav
Copy link
Contributor

M4dhav commented Jan 4, 2026

Can you please explain the implementation a bit? What enumeration does, how audio devices are discovered, etc

@Mayank4352
Copy link
Contributor Author

->The enumerateDevices() uses webrtc.navigator.mediaDevices.enumerateDevices() which queries for all available media devices (microphones, cameras, speakers).
->The results are then filtered to only include audio output devices (isAudioOutput) - this removes microphones and cameras.
->If no device is currently selected, it automatically picks the first available output device
->The controller polls for devices every 5 seconds which scans for Bluetooth, headset etc.
->selectAudioOutput() uses webrtc.Helper.selectAudioOutput(deviceId) to route audio to the chosen device at the system level.
->getDeviceName() and getDeviceIcon() parse device labels and return user-friendly names and icons

This is the main crux of the controller file, rest are the UI changes. I've made a simple data model that wraps WebRTC's MediaDeviceInfo which will Decouple the app from WebRTC's API, handles nullable fields (kind, groupId) with defaults and makes testing easier (we were able to create AudioDevice directly without WebRTC)

Comment on lines 186 to 215
return ElevatedButton.icon(
return ElevatedButton(
onPressed: () async {
await _deleteRoomDialog(
controller.isAdmin
? AppLocalizations.of(context)!.delete
: AppLocalizations.of(context)!.leave,
() async {
if (controller.isAdmin) {
if (liveKitController.isRecording.value == true) {
await controller.endLiveChapter();
} else {
customSnackbar(
AppLocalizations.of(context)!.error,
AppLocalizations.of(context)!.noRecordingError,
LogType.error,
);
}
} else {
await controller.leaveRoom();
}
},
);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color.fromARGB(255, 241, 108, 98),
backgroundColor: Colors.redAccent,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
),
icon: const Icon(Icons.exit_to_app),
label: Text(AppLocalizations.of(context)!.leaveButton),
child: const Icon(Icons.call_end, size: 24),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are there changes to the end call button?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make space the output change button as with the current size of end call button the ribbon was looking to cramped so i adjust it's size bit, also i saw that the color for the buttons was just a static color so i changed that to use the color from the theme

Comment on lines +266 to +272
Widget _buildAudioSettingsButton() {
return FloatingActionButton(
onPressed: () => showAudioDeviceSelector(context),
backgroundColor: Theme.of(context).colorScheme.secondary,
child: const Icon(Icons.settings_voice),
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why FloatingActionButton and not ElevatedButton.icon like the others?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used a FloatingActionButton initially while iterating on the layout, I'll switch it to an ElevatedButton.icon

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, @M4dhav after reviewing it, i believe the other widgets also use FAB, do you still want me to make it ElevatedButton.icon or should i keep it the way it is currently???

Comment on lines 192 to 216
return ElevatedButton.icon(
return ElevatedButton(
onPressed: () async {
await _deleteRoomDialog(
controller.appwriteRoom.isUserAdmin
? AppLocalizations.of(context)!.delete
: AppLocalizations.of(context)!.leave,
() async {
if (controller.appwriteRoom.isUserAdmin) {
await controller.deleteRoom();
} else {
await controller.leaveRoom();
}
},
);
},
style: ElevatedButton.styleFrom(
backgroundColor: const Color.fromARGB(255, 241, 108, 98),
backgroundColor: Colors.redAccent,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
),
),
icon: const Icon(Icons.exit_to_app),
label: Text(AppLocalizations.of(context)!.leaveButton),
child: const Icon(Icons.call_end, size: 24),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated changes to End Call button

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those are needed for the space to not look cramped, i just made some cosmetic changes in the icon for it to look more like a end call button, initially it used static color, i replaced that with the theme one

Comment on lines +296 to +302
Widget _buildAudioSettingsButton() {
return FloatingActionButton(
onPressed: () => showAudioDeviceSelector(context),
backgroundColor: Theme.of(context).colorScheme.onSecondary,
child: const Icon(Icons.volume_up),
);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why FAB

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix it, used it while playing around with UI

Comment on lines 251 to 253
if (!Get.isRegistered<AudioDeviceController>()) {
Get.put(AudioDeviceController());
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using GetX here, just instantiate an instance within the dialog, as you do not need dependency injection here

@Mayank4352 Mayank4352 requested a review from M4dhav January 7, 2026 09:43
Get.put(AudioDeviceController());
}
final controller = AudioDeviceController();
controller.refreshDevices();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

refreshDevices is async so await this call

Comment on lines 253 to 258
showModalBottomSheet(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => const AudioDeviceSelectorDialog(),
);
builder: (context) => AudioDeviceSelectorDialog(controller: controller),
).whenComplete(() => controller.dispose());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use GetX APIs to show the modal

IconButton(
icon: const Icon(Icons.close),
onPressed: () => Get.back(),
onPressed: () => Navigator.of(context).pop(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continue using Get.back

SizedBox(width: UiSizes.width_8),
ElevatedButton(
onPressed: () => Get.back(),
onPressed: () => Navigator.of(context).pop(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Continue using Get.back

@Mayank4352 Mayank4352 requested a review from M4dhav January 7, 2026 14:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Allow Users to Select Preferred Speaker and Microphone Options

2 participants