Skip to content

Add the option to avoid clock-less time when switching from/to null sound device#5012

Open
trengginas wants to merge 2 commits into
masterfrom
copilot/null-snd-dev2-param
Open

Add the option to avoid clock-less time when switching from/to null sound device#5012
trengginas wants to merge 2 commits into
masterfrom
copilot/null-snd-dev2-param

Conversation

@trengginas

Copy link
Copy Markdown
Member

Summary

This PR adds a configurable null sound device API to avoid a clock-less transition window when switching audio paths, while preserving backward compatibility.

Use Case Scenario (iOS Call Hold/Resume)

On iOS, the audio device may be closed when a call is put on hold.
When that happens, RTP timestamp progression may pause because the clock source is no longer running.
When the call resumes, RTP timestamp generation can continue from the value before hold, which may cause discontinuity/jitter or dropped packet behavior.

A common workaround is to switch to null sound device during hold so the media clock keeps running and RTP timestamps continue to advance.
However, with the current switching path, there can still be a brief clock-less gap when transitioning between null sound device and actual sound device in either direction.
This PR addresses that by adding a configurable transition mode to preserve clock continuity during null <> real device handover.

Motivation

Switching to null sound device can briefly leave the conference bridge without a clock source. This change introduces an opt-in transition mode that prioritizes clock continuity.

What Changed

  • Added pjsua_null_snd_dev_param with default initializer support.
  • Added pjsua_set_null_snd_dev2(const pjsua_null_snd_dev_param *snd_param).
  • Kept pjsua_set_null_snd_dev() as a backward-compatible wrapper.
  • Implemented configurable transition handling in the audio subsystem.
  • Split sound-device close logic into clearer helper paths for device-only close versus full close.
  • Added internal runtime policy tracking for the transition behavior.
  • Updated PJSUA2 wrapper to expose setNullDev2(bool avoidClockGap).
  • Updated alternate backend signature/comments to stay API-compatible.
  • Updated documentation/comments to reference both null-sound APIs.

Behavior

  • avoid_clock_gap = PJ_FALSE:
    legacy behavior (close old path first, then start null clock).
  • avoid_clock_gap = PJ_TRUE:
    gap-avoid behavior (start null clock first, then stop old device).
  • The transition policy is one-shot and reset on the next open path so it does not persist unexpectedly.

Compatibility

Existing callers using pjsua_set_null_snd_dev() continue to work unchanged.
New behavior is opt-in via the new parameterized API.

Possible Negative Impact

When the new gap-avoid mode is enabled, there is a short overlap window where null clock is started before the previous sound path is fully closed. This avoids clock loss, but increases transition complexity and may expose edge races during rapid hold/resume toggles.

Scope Notes

Testing-only legacy app changes are intentionally excluded from this PR.

Testing

Not run in this branch.

@trengginas trengginas added this to the release-2.18 milestone Jun 10, 2026
@trengginas trengginas self-assigned this Jun 10, 2026
@trengginas trengginas changed the title Add the option Add the option to avoid clock-less time when switching from/to null sound device Jun 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds an opt-in, parameterized null sound device API in PJSUA to support “gapless” clock handover during null ⇄ real audio device transitions (notably for iOS hold/resume scenarios), while keeping the existing pjsua_set_null_snd_dev() API as a backward-compatible wrapper.

Changes:

  • Introduces pjsua_null_snd_dev_param + default initializer and new API pjsua_set_null_snd_dev2() to control gap-avoid behavior.
  • Refactors PJSUA audio device open/close paths to support overlap-based transitions and clearer teardown responsibilities.
  • Exposes the new behavior through the PJSUA2 AudDevManager::setNullDev2() wrapper and updates docs/alt backend stubs for API compatibility.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
pjsip/src/pjsua2/media.cpp Adds AudDevManager::setNullDev2(bool) wrapper calling pjsua_set_null_snd_dev2().
pjsip/src/pjsua-lib/pjsua_aud.c Implements pjsua_set_null_snd_dev2(), adds transition policy tracking, refactors close/open logic and introduces close_snd_port() helper.
pjsip/include/pjsua2/media.hpp Documents and declares setNullDev2(bool avoidClockGap) in PJSUA2 API.
pjsip/include/pjsua-lib/pjsua.h Adds new public param struct, default initializer, and pjsua_set_null_snd_dev2() declaration; updates docs to reference new API.
pjsip/include/pjsua-lib/pjsua_internal.h Adds internal runtime flag snd_avoid_clock_gap to track one-shot transition policy.
pjsip-apps/src/3rdparty_media_sample/alt_pjsua_aud.c Adds no-op stub for pjsua_set_null_snd_dev2() for the alt backend sample.

Comment thread pjsip/src/pjsua-lib/pjsua_aud.c Outdated
Comment thread pjsip/src/pjsua-lib/pjsua_aud.c
Comment on lines 1209 to +1211
* Set pjsua to use null sound device. The null sound device only provides
* the timing needed by the conference bridge, and will not interract with
* any hardware.
* any hardware. For configurable behavior, use setNullDev2().
Comment thread pjsip/include/pjsua-lib/pjsua.h
Comment thread pjsip/include/pjsua-lib/pjsua.h
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants