OnePlus Ace 6T: Symfonium LibusbExclusive is intermittent across multiple USB DACs

App version

Beta

Issue description

I am seeing an intermittent LibusbExclusive stability issue that appears specific to my OnePlus Ace 6T.

I tested the same general setup across three Android devices:

Lenovo Legion Y700
Motorola Stylus 5G (2024)
OnePlus Ace 6T

Only the OnePlus Ace 6T shows this issue. The Lenovo Y700 and Motorola Stylus 5G (2024) can use Symfonium LibusbExclusive normally with the tested DACs.

The issue also reproduces with multiple USB DACs on the Ace 6T:

Aune Yuki USB DAC — asynchronous isochronous output with feedback
Apple USB-C to 3.5 mm Headphone Jack Adapter — synchronous isochronous output without feedback

This does not appear to be a DAC compatibility problem. Each tested DAC has successfully entered and played through genuine Symfonium LibusbExclusive mode at least sometimes on the Ace 6T.

The problem is therefore not that exclusive mode cannot work. It is that exclusive-mode startup and playback are unreliable on this specific phone.

On successful attempts, Symfonium uses genuine LibusbExclusive direct playback: route=direct, audio completion counters increase, and the stream plays normally.

On failed attempts, Symfonium still opens a LibusbExclusive direct session, but playback remains at 0:00 or does not produce audible output. The log shows cases where completedBytes=0 and isoAudioBytes=0, the output queue remains full, and the session eventually times out. There are also ERROR_CODE_AUDIO_TRACK_INIT_FAILED failures.

Because the same Ace 6T reproduces the issue with both an async-feedback DAC and a sync/no-feedback DAC, while the Y700 and Motorola phone do not show this behavior, this appears to be an intermittent Ace 6T-specific LibusbExclusive lifecycle or host interaction issue rather than a problem with a particular DAC, cable, sample rate, or feedback mode.

Device type

Phone

Media provider

Navidrome

Steps to reproduce

Connect either an Aune Yuki USB DAC or an Apple USB-C to 3.5 mm Headphone Jack Adapter.
Select the USB DAC in Symfonium and enable LibusbExclusive playback.
Play local or Navidrome FLAC content.
Repeat playback starts, stop/start playback, and next/previous track actions.
During testing, physically unplug and reconnect the USB DAC, then select it again in Symfonium and retry LibusbExclusive playback.
Repeat this sequence several times.

Expected result:

Every LibusbExclusive attempt should enter direct USB playback and begin audio reliably.

Actual result:

Some attempts enter genuine direct exclusive playback and work normally.
Other attempts remain at 0:00, produce no audio, time out, or fail during AudioTrack initialization.

Additional information

Device:

OnePlus Ace 6T / PLR110 (OP6117L1)
Android 16

Symfonium:

15.0.0B9 (127781, arm64-v8a)

DACs tested:

Aune Yuki USB DAC, VID 0495:809f
Apple USB-C to 3.5 mm Headphone Jack Adapter, VID 05ac:110a

Important notes:

The same general setup was also tested on a Lenovo Legion Y700 and a Motorola phone. Only the Ace 6T shows this intermittent LibusbExclusive issue.
Genuine LibusbExclusive playback does succeed intermittently on the Ace 6T with both DACs.
The failure occurs with both async-feedback and sync/no-feedback USB audio devices.
UAPP Direct USB remains functional with the Aune Yuki on the same Ace 6T, cable, and port.
The attached log contains manual DAC unplug/reconnect actions. Therefore, USB_DEVICE_DETACHED entries in the log should not by themselves be interpreted as spontaneous disconnects caused by Symfonium.
The attached log contains both successful direct-exclusive sessions and failed sessions from the same phone.

I searched existing issues first

on

I understand that logs are mandatory

on

Log upload name / description

ace6t_libusbexclusive_multi_dac_full_debug_2026-07-05.log

Can you provide logs with multiple “stop then new playback session” attempts on the same DAC without plug/unplug to better see if it’s a topology issue or something else.

Attached log: debug-20260705_210150.zip

I ran the requested test on my OnePlus Ace 6T with the Apple USB-C to 3.5 mm Headphone Jack Adapter.

The adapter remained physically connected for the entire test. I did not unplug or reconnect it at any point.

The attached log contains no USB_DEVICE_DETACHED, USB_DEVICE_ATTACHED, or USB audio topology changed entries. This helps isolate repeated playback-session behavior from USB topology changes.

Within one uninterrupted physical USB connection, repeated LibusbExclusive sessions had mixed outcomes:

  1. 20:59:15 — 48 kHz / 24-bit / alt 1: failed
    positionUs=0, completedBytes=0, isoAudioBytes=0, queue full, activeTransfers=0.
  2. 20:59:33 — 44.1 kHz / 16-bit / alt 2: failed
    Same zero-completion signature.
  3. 20:59:44 — 48 kHz / 16-bit / alt 2: failed
    The released session shows 11 play calls, 11 pause calls, and 6 flush calls, but still completedBytes=0 and isoAudioBytes=0.
  4. 21:00:11 — 44.1 kHz / 16-bit / alt 2: succeeded as genuine LibusbExclusive playback
    audioPositionAdvancing appeared about 0.54 seconds after start. At 21:00:16, the diagnostic snapshot showed positionUs=4,480,000, completedBytes=790,272, isoAudioBytes=790,272, and activeTransfers=32. Subsequent snapshots continued to advance.
  5. 21:00:54 — 44.1 kHz / 16-bit / alt 2: failed again
    This was the same DAC, cable, port, and uninterrupted physical connection. It returned to zero audio completion.

The failed attempts were manually stopped/restarted for this test, so they do not always wait long enough to reach ERROR_CODE_TIMEOUT. The failure condition here is the direct session remaining at positionUs=0 with no accepted audio completions.

During the successful playback attempt, I pressed the phone’s physical volume up/down buttons.

Symfonium appeared to automatically clamp the LibusbExclusive hardware-volume value back to a lower remembered/safe target. In the log, the USB hardware-volume value is adjusted upward and then programmatically returned toward the previous target, for example:

Clamping libusb exclusive hardware volume to safe target …
current=47/48 target=46 … rememberedTarget=46

Because the volume kept being clamped back, I then held the Symfonium on-screen volume control at a higher level until that higher level was eventually applied successfully to the Apple adapter.

The successful LibusbExclusive playback had already started before I adjusted the volume, so I do not consider this volume behavior to be the cause of playback recovery or successful session startup.

However, the automatic clamp/reset behavior appears to come from Symfonium’s LibusbExclusive volume synchronization logic. The Apple USB-C to 3.5 mm adapter has no physical volume buttons or other user-operated controls. This appears to be a separate volume synchronization observation, rather than evidence about the zero-completion playback-start failures.

Try 127783 and in all cases provides new logs with it.

Attached log: SilverKnightKMA 127783 tachjim bunny

I tested the new build on my OnePlus Ace 6T with the TANCHJIM BUNNY DSP.

The remaining issue in this trace is concentrated in the initial startup phase.

At the beginning, there were several LibusbExclusive startup stalls. Most were zero-completion starts, and one attempt briefly progressed for about 240 ms before the transfer path stopped. The new diagnostic/recovery logic detected these cases after about 3 seconds and logged “AudioTrack write failed: -1”.

However, after the initial failed attempts, LibusbExclusive started working correctly at around 06:20:30.

From that point onward, I intentionally performed repeated Next and Seek actions, including transitions between 44.1 kHz and 48 kHz tracks. I did not observe further playback failures during that later stress sequence.

Try build 127785 and in all cases please provide new logs.

Attached log: SilverKnightKMA 127785 ace6t bunny

I tested beta 127785 with the TANCHJIM BUNNY DSP.

The new startup-stall recovery is a meaningful improvement.

The startup issue is still reproducible: the log contains multiple stuck direct-start attempts. Most are partial-start stalls rather than pure zero-completion starts: playback progresses briefly, some audio bytes are completed, then “activeTransfers” reaches 0 and the queue remains full.

However, the new recovery path now detaches the output, waits with increasing backoff, reopens the LibusbExclusive output, and eventually succeeds.

For example, the final 96 kHz failure sequence recovered successfully. After the final reopen, the session reached normal direct playback with increasing position/audio completion counters, “activeTransfers=32”, and no underruns. Playback continued normally until I stopped the test.

So the current behavior appears to be:

  • The underlying intermittent startup stall still occurs.
  • The new recovery mechanism can now recover automatically after several retries.
  • Recovery latency and retry count are still variable, so it is not fully stable yet.

One additional issue appeared twice during the test:

“libusb transfer cancel timed out [activeTransfers=1 timeoutMs=1000 feedbackActive=false]”

This occurred during pause/stop/reset handling and produced an ExoPlayer “Unexpected runtime error”.

Overall, this beta is much better than the previous one because recovery can now reach genuine LibusbExclusive playback again, but the initial transfer-stall condition and the transfer-cancel timeout remain.

Ok let’s try 127787 there’s now also a per dac warmup delay settings that you can use to see if it helps even more.

Attached log: SilverKnightKMA 127787 apple dongle

I tested the Apple USB-C adapter with the per-DAC startup warmup set to 1000 ms.

The setting is definitely applied in the log: the LibusbExclusive sessions consistently show startupWarmupDelayMs=1000.

However, it does not fully resolve the startup problem.

The same direct-start failure still occurs with the Apple adapter:

  • positionUs=0

  • isoAudioBytes=0

  • 32 or 33 transfer failures

  • lastTransferFailure=data-transfer-status

  • lastTransferFailureCode=2

  • activeTransfers=0

The recovery logic can still eventually recover playback, but the retry count is sometimes high. In one sequence, startup began failing around 11:45:40 and direct playback did not begin successfully until about 11:46:19, after repeated fast-fail/reopen cycles.

So the per-DAC 1000 ms delay is being applied, but it is not sufficient to eliminate the underlying startup-transfer failure. It may affect timing or recovery behavior, but the same failure signature remains.

Once playback finally starts, the direct session continues normally.

There was also one separate pause/stop lifecycle error near the beginning of the test:

libusb transfer cancel timed out [activeTransfers=1 timeoutMs=1000 feedbackActive=false]

This happened after an immediate pause of a newly started session, so I consider it separate from the startup-stall issue.

I also tested other warmup values manually, but I have not found a value that fully removes the startup failures so far.

Test beta 10 from the repo.

Attached log: SilverKnightKMA 127789 bunny

I tested the new 127789 build with the TANCHJIM BUNNY DSP.

Overall stability feels better than earlier builds. The “cannot start playback” issue still happens, but less often, and in this log I do not see a case where it gets permanently stuck without recovery.

There are still LibusbExclusive startup stalls. The remaining failure signature is still similar:

  • lastTransferFailure=data-transfer-status

  • lastTransferFailureCode=2

  • activeTransfers=0

  • full queue

  • short partial startup progress in many cases

However, the recovery behavior is better now. In all the failure clusters I observed, playback eventually recovered and audioPositionAdvancing appeared again.

In some cases it recovered automatically after retry/backoff. In other cases, user actions such as seek, next/previous track, or play/pause seemed to help trigger a successful recovery. So the recovery path appears functional, but the initial startup failure is still present.

I also tested a per-DAC warmup delay of 50 ms. The setting is definitely being applied in the log: later sessions show startupWarmupDelayMs=50. However, 50 ms does not fully eliminate the startup stalls. The same data-transfer-status / code 2 failure still appears with 50 ms enabled.

One important note: this log contains mixed warmup values because I was testing different settings. There are sessions with 5000 ms, 0 ms, and 50 ms. The 50 ms section still reproduces the failure, so 50 ms is not sufficient. I may need a more controlled test per warmup value to compare them cleanly.

The remaining major user-facing problem is volume synchronization.

The automatic LibusbExclusive hardware-volume behavior is still very noticeable and negatively affects the experience. The log shows repeated cases where the app clamps hardware volume back to a remembered/safe target, for example from higher user-set values back to target=32 / rememberedTarget=32.

This volume behavior feels more disruptive now than the startup issue, because startup usually recovers, while the volume keeps fighting the user’s intended level.

Ok let’s try build 127791 :slight_smile:

Attached log: 127791 SilverKnightKMA buny

I tested build 127791. The same two issues are still reproducible:

  1. LibusbExclusive startup can still fail with the same transfer failure signature:
    lastTransferFailure=data-transfer-status, lastTransferFailureCode=2, full queue, and activeTransfers=0.

    This also happens with startupWarmupDelayMs=50, so 50 ms does not eliminate the issue.

  2. The volume synchronization/clamping issue is still present.

    I did not intentionally adjust the volume, but Symfonium treated an Android stream-volume state as trusted and applied it to the LibusbExclusive hardware volume, reducing the hardware volume from 51 to 20.

There are also session-ready/retune cases where the hardware volume is clamped down automatically, including from 100 to 20, with activeUserTarget=null.

This is actually wanted and expected. Most dacs start at max volume, that’s dangerous and the android volume is applied to the dac for consistent volume and not loose ears because you switch to exclusive.

That explanation makes sense from a safety perspective.

If the intended design is that Android media volume is the source of truth, and Symfonium applies that value to the DAC hardware volume when entering LibusbExclusive mode, then I understand why the DAC hardware volume is clamped down instead of being left at max.

In that case, I will use the phone/Android media volume as the main volume control instead of trying to adjust the DAC hardware volume independently inside Symfonium.

The only remaining UX concern is that the in-app LibusbExclusive hardware volume control can feel confusing. From the user side, it looks like I can raise the hardware volume, but then Symfonium later overrides it back to the Android/entry-safe target. If that is expected, maybe the UI could make it clearer that Android media volume is the master volume, or ensure that changing the in-app exclusive volume also updates the active remembered target consistently.

The intended behavior is mostly on initial first play if the DAC volume is higher than Android volume then clamp. Then handle changes from Android and from the DAC until there’s a too large difference due to bug on my side then it clamp again.

That should not be a problem and is “supported” unfortunately there’s a million cases and DAC lags, not answering some calls, races, rounding and everything that I improve slowly. (Specially since I also support HID direct control for some dacs not just UAC2).

There’s some historical decision before handling HID, but I will probably rewrite the volume ownership later when I have more users feedback and can properly ensure that the DAC can be the reliable source of trust.

For those kind of issues and kind of “DAC” 50ms is probably still way too low.


Anyway please try again build 127793

Attached log: 127793 SilverKnightKMA bunny

From the user side, this build feels good.

I did not notice any real playback problem during normal listening. The log still shows two LibusbExclusive startup-stall detections, but the fallback/recovery path seems to handle them properly.

When the fallback happened, startup may have felt slightly slower, but it was not a problem from the user perspective. Playback recovered and continued normally.

The new compatibility fallback behavior looks effective here: after the startup failure, Symfonium reduced the transfer profile and direct playback became stable.

Volume behavior also feels good in this build. I did not experience the previous confusing volume drop/clamp behavior, and I am satisfied with the current volume handling.

Thanks. We finally did it :wink:

After 15 is out and I’ve gathered enough user data I’ll enable device quirks for that kind of cases to directly use the known working values. But working generic auto recoveries is more important for now.