Skip to content

Comments

RU-T47 Minor fix for voice call join#225

Merged
ucswift merged 2 commits intomasterfrom
develop
Feb 20, 2026
Merged

RU-T47 Minor fix for voice call join#225
ucswift merged 2 commits intomasterfrom
develop

Conversation

@ucswift
Copy link
Member

@ucswift ucswift commented Feb 20, 2026

Summary by CodeRabbit

  • New Features

    • Register Android foreground service at startup to improve background reliability and notification behavior.
  • Bug Fixes

    • Prevent concurrent voice connections and improve error recovery with clearer user alerts.
    • Refined permission flow with clearer guidance for microphone access and more robust audio session handling.
  • Performance

    • Reduced Bluetooth audio polling frequency to lower CPU use while preserving responsiveness.

@coderabbitai
Copy link

coderabbitai bot commented Feb 20, 2026

📝 Walkthrough
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The PR title 'RU-T47 Minor fix for voice call join' is vague and does not clearly convey the primary changes made, which involve significant refactoring of the connectToRoom method, addition of Android foreground service registration, and BLE polling interval adjustments. Revise the title to be more specific about the main changes, such as 'Refactor voice room connection flow with Android foreground service setup' or 'Improve voice call join robustness with concurrency guards and service registration'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch develop

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/stores/app/livekit-store.ts (1)

645-668: ⚠️ Potential issue | 🟠 Major

Room instance leaks on connection failure due to missing cleanup in catch block.

The room object created at line 451 with registered event listeners (lines 454-479) is only saved to state after a successful connect() call. If connection fails or any subsequent operation before state commit fails, the partially-initialized room is never cleaned up, leaking listeners and WebRTC resources.

The proposed fix has a critical scoping bug: room is declared with const inside the try block and is inaccessible in the catch block. The fix requires declaring room outside the try block:

Corrected fix — declare room before try block and disconnect on failure
      // Disconnect from current room if connected
      if (currentRoom) {
        currentRoom.disconnect();
      }

+     let room: Room | null = null;
+
      // Start the native audio session before connecting (required for production builds)
      // In dev builds, the audio session may persist across hot reloads, but in production
      // cold starts it must be explicitly started for WebRTC to function correctly
      if (Platform.OS !== 'web') {
        try {
          await AudioSession.startAudioSession();
          logger.info({
            message: 'Audio session started successfully',
          });
        } catch (audioSessionError) {
          logger.warn({
            message: 'Failed to start audio session - continuing with connection attempt',
            context: { error: audioSessionError },
          });
        }
      }

      // Create a new room
-     const room = new Room();
+     room = new Room();

      // Setup room event listeners
      room.on(RoomEvent.ParticipantConnected, (participant) => {

And in the catch block:

      } catch (error) {
        logger.error({
          message: 'Failed to connect to room',
          context: { error, roomName: roomInfo?.Name },
        });

+       // Clean up the partially-created room to release event listeners and WebRTC resources
+       if (room) {
+         try {
+           await room.disconnect();
+         } catch {
+           // room may not have connected — ignore
+         }
+       }
+
        // Stop audio session on failure since we started it above
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/stores/app/livekit-store.ts` around lines 645 - 668, The catch block
leaks the LiveKit Room because the room variable is declared inside the try so
it can't be cleaned up on error; move the room declaration (the variable used
when calling connect() and registering listeners — the same identifier created
around the connect flow) to outer scope before the try, and in the catch ensure
you call the room.disconnect() (or Room.disconnect/close equivalent) and remove
any registered event listeners for that room instance before exiting the error
path; keep the existing AudioSession.stopAudioSession() and set({ isConnecting:
false }) behavior but add the room cleanup and guard for room being non-null to
avoid the scoping bug.
🧹 Nitpick comments (1)
src/stores/app/livekit-store.ts (1)

397-408: Hardcoded English strings in Alert calls — missing i18n.

Lines 397, 407, 421-424, and 667 use hardcoded English strings in Alert.alert(). As per coding guidelines, "Ensure all text is wrapped in t() from react-i18next for translations with dictionary files stored in src/translations."

Also applies to: 421-425, 667-667

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/stores/app/livekit-store.ts` around lines 397 - 408, The Alert.alert
calls in livekit-store.ts (the blocks checking for missing server address and
missing token, and the other occurrences noted at 421-425 and 667) use hardcoded
English strings; replace those plain strings with translation lookups using
t(...) from react-i18next (or i18n.t(...) if you prefer non-hook usage in this
store), e.g. t('voice.connection_error') and t('voice.missing_token') style
keys, and add the corresponding keys/values to the JSON translation files under
src/translations; ensure you import or access the translator (e.g., const { t }
= useTranslation() or import i18n) at the top of the module and update each
Alert.alert call to use the translation keys instead of literal English text.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/stores/app/livekit-store.ts`:
- Around line 428-431: The code calls currentRoom.disconnect() without awaiting
it, risking overlapping teardown with the subsequent connectToRoom logic; change
the disconnect call in the connectToRoom flow to await currentRoom.disconnect()
(i.e., await currentRoom.disconnect()) so the old Room's Promise completes
before proceeding—follow the same pattern used in disconnectFromRoom and other
callers to ensure transports/listeners are fully torn down prior to starting the
new Room connection.

---

Outside diff comments:
In `@src/stores/app/livekit-store.ts`:
- Around line 645-668: The catch block leaks the LiveKit Room because the room
variable is declared inside the try so it can't be cleaned up on error; move the
room declaration (the variable used when calling connect() and registering
listeners — the same identifier created around the connect flow) to outer scope
before the try, and in the catch ensure you call the room.disconnect() (or
Room.disconnect/close equivalent) and remove any registered event listeners for
that room instance before exiting the error path; keep the existing
AudioSession.stopAudioSession() and set({ isConnecting: false }) behavior but
add the room cleanup and guard for room being non-null to avoid the scoping bug.

---

Nitpick comments:
In `@src/stores/app/livekit-store.ts`:
- Around line 397-408: The Alert.alert calls in livekit-store.ts (the blocks
checking for missing server address and missing token, and the other occurrences
noted at 421-425 and 667) use hardcoded English strings; replace those plain
strings with translation lookups using t(...) from react-i18next (or i18n.t(...)
if you prefer non-hook usage in this store), e.g. t('voice.connection_error')
and t('voice.missing_token') style keys, and add the corresponding keys/values
to the JSON translation files under src/translations; ensure you import or
access the translator (e.g., const { t } = useTranslation() or import i18n) at
the top of the module and update each Alert.alert call to use the translation
keys instead of literal English text.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/stores/app/livekit-store.ts (1)

645-668: ⚠️ Potential issue | 🟠 Major

Catch block may stop the audio session for an already-connected room.

After line 507, the room is committed to the store as connected (isConnected: true). If any unguarded await between lines 507 and 644 throws (e.g., playConnectToAudioRoomSound at line 579), the catch block at line 652-661 stops the audio session — but the room remains connected in the store. This leaves WebRTC running without an active audio session.

Consider either (a) wrapping post-commit calls like playConnectToAudioRoomSound in their own try-catch (consistent with other post-commit calls), or (b) skipping AudioSession.stopAudioSession() if the room was already committed.

Proposed fix — wrap the sound call in its own try-catch
      // Setup audio routing based on selected devices
      // This may change audio modes/focus, so it comes after media button init
      await setupAudioRouting(room);

-     await audioService.playConnectToAudioRoomSound();
+     try {
+       await audioService.playConnectToAudioRoomSound();
+     } catch (soundError) {
+       logger.warn({
+         message: 'Failed to play connection sound',
+         context: { error: soundError },
+       });
+     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/stores/app/livekit-store.ts` around lines 645 - 668, The catch currently
stops the AudioSession unconditionally which can tear down audio for a room
already committed as connected; to fix, wrap any post-commit awaits (e.g.,
playConnectToAudioRoomSound and similar calls between the commit/set that marks
isConnected true and the try/catch boundary) in their own try/catch blocks so
failures there don’t fall into the outer catch, and/or add a guard before
calling AudioSession.stopAudioSession() that checks the store’s current
connection state (e.g., read isConnected/room state or roomInfo) and skip
stopping the audio session if the room was already marked connected.
🧹 Nitpick comments (1)
src/stores/app/livekit-store.ts (1)

397-397: User-facing strings are not wrapped in t() for i18n.

Multiple Alert.alert calls in the changed lines use hardcoded English strings (e.g., 'Voice Connection Error', 'Voice Connection Failed'). This is a pre-existing pattern in the file, but the changed lines introduce additional instances.

As per coding guidelines, "Ensure all text is wrapped in t() from react-i18next for translations with dictionary files stored in src/translations".

Also applies to: 407-407, 421-424, 667-667

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/stores/app/livekit-store.ts` at line 397, The hardcoded user-facing
strings passed to Alert.alert (e.g., 'Voice Connection Error', 'Voice server
address is not available. Please try again later.', 'Voice Connection Failed',
etc.) must be wrapped with the i18n translator t() from react-i18next; update
each Alert.alert invocation in this file (search for Alert.alert usages around
the instances noted) to call t('your.key') for the title and message (and add
appropriate keys to the translations files in src/translations), import and use
the t function where needed (or obtain it from the existing i18n context/hooks
used elsewhere in this module) so all displayed text is localized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/stores/app/livekit-store.ts`:
- Around line 645-668: The catch currently stops the AudioSession
unconditionally which can tear down audio for a room already committed as
connected; to fix, wrap any post-commit awaits (e.g.,
playConnectToAudioRoomSound and similar calls between the commit/set that marks
isConnected true and the try/catch boundary) in their own try/catch blocks so
failures there don’t fall into the outer catch, and/or add a guard before
calling AudioSession.stopAudioSession() that checks the store’s current
connection state (e.g., read isConnected/room state or roomInfo) and skip
stopping the audio session if the room was already marked connected.

---

Duplicate comments:
In `@src/stores/app/livekit-store.ts`:
- Around line 428-431: The existing code did not await the
currentRoom.disconnect() call which could leave WebRTC transports and listeners
active during a new connection; update the disconnect path to await
currentRoom.disconnect() so the teardown completes before proceeding—make this
change where currentRoom is handled (referencing currentRoom.disconnect()) and
ensure it mirrors the awaited behavior used in disconnectFromRoom().

---

Nitpick comments:
In `@src/stores/app/livekit-store.ts`:
- Line 397: The hardcoded user-facing strings passed to Alert.alert (e.g.,
'Voice Connection Error', 'Voice server address is not available. Please try
again later.', 'Voice Connection Failed', etc.) must be wrapped with the i18n
translator t() from react-i18next; update each Alert.alert invocation in this
file (search for Alert.alert usages around the instances noted) to call
t('your.key') for the title and message (and add appropriate keys to the
translations files in src/translations), import and use the t function where
needed (or obtain it from the existing i18n context/hooks used elsewhere in this
module) so all displayed text is localized.

@ucswift
Copy link
Member Author

ucswift commented Feb 20, 2026

Approve

Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

This PR is approved.

@ucswift ucswift merged commit 76e13e6 into master Feb 20, 2026
19 of 20 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant