Skip to content

fix(client-js): refuse initDevices() once devices are initialized - #281

Closed
mattieruth wants to merge 1 commit into
mainfrom
mrkb/init-devices-once
Closed

mattieruth wants to merge 1 commit into
mainfrom
mrkb/init-devices-once

Conversation

@mattieruth

@mattieruth mattieruth commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

initDevices() is intended to be called once, before connect(). The transports already enforce this: daily-js allows a single startCamera(), and DailyMediaManager.initialize() warns and returns if already initialized. PipecatClient did not, so a repeat call re-ran the full MediaState lifecycle against a transport that could not act on it, and a device that was 'blocked' fell back to 'uninitialized' or 'unknown'.

  • Initialization tracking. The client tracks whether the transport has initialized devices, set when initDevices() resolves or connect() succeeds (transports initialize media as part of connecting, including when every requested device is disabled and the implicit init is skipped). The flag is never reset, including on disconnect.
  • Repeat initDevices(). A later initDevices() logs a warning pointing at enableMic() / enableCam() and returns without touching the transport or MediaState. Those methods are now the documented way to retry a device that errored during init.
  • Failed init retry. A rejected initDevices() leaves the flag unset so the call can be retried, matching the transports, which allow another attempt when initialization never completed.
  • needsInit(). Returns false once initDevices() or connect() has succeeded, even if a requested device is still 'uninitialized' or errored, so connect() won't drive a second implicit init.

Fixes

Release Notes

client-js

Bug Fixes

  • PipecatClient.initDevices() is now one-time. After it resolves, or after connect() succeeds, further calls log a warning and return without calling the transport or changing mediaState. Previously a repeat call re-ran the MediaState lifecycle against a transport that couldn't initialize again, which could knock a "blocked" device back to "uninitialized" or "unknown". To retry or change a device after initialization, use enableMic(true) / enableCam(true). If initDevices() rejected, it can still be called again. needsInit() also returns false once devices are initialized. (80dd375)

initDevices() is intended to be called once, before connect(). The
transports already enforce this: daily-js allows a single startCamera(),
and DailyMediaManager.initialize() warns and returns if already
initialized. PipecatClient did not, so a repeat call re-ran the full
MediaState lifecycle against a transport that could not act on it, and
a device that was 'blocked' fell back to 'uninitialized' or 'unknown'.

Track whether the transport has initialized devices, set when
initDevices() resolves or connect() succeeds (transports initialize
media as part of connecting, including when every requested device is
disabled and the implicit init is skipped). A later initDevices() logs
a warning pointing at enableMic() / enableCam() and returns without
touching the transport or MediaState, and needsInit() returns false.

A rejected initDevices() leaves the flag unset so the call can be
retried, matching the transports, which allow another attempt when
initialization never completed.

Closes #280
Comment on lines +316 to +318
// part of connecting). Once a transport has initialized it can't do so
// again (daily-js allows a single startCamera()), so a later initDevices()
// is refused here rather than handed down. A rejected initDevices() leaves

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Just to confirm, is this true for all the transports ? Or could this approach cause some side effects in any of the other transports ?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think my question is like, after the disconnect, would any of the other transports require initDevices to be invoked again ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

thank you for asking this question. my memory was wrong on EVERY account. All the transports require initDevices differently. I'm going to close this and it's corresponding issue and look instead into seeing if I can remove the requirement of calling initDevices() at all. Make it more of a convenience. Stay tuned...

@mattieruth mattieruth closed this Nov 3, 2026
@mattieruth
mattieruth deleted the mrkb/init-devices-once branch November 3, 2026 20:11
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.

initDevices() should refuse repeat calls

2 participants