Skip to content

Reduce mutex contention and increase socket buffers#50

Open
andresgit763 wants to merge 3 commits into
philippe44:masterfrom
andresgit763:fix/raop-streamer-improvements
Open

Reduce mutex contention and increase socket buffers#50
andresgit763 wants to merge 3 commits into
philippe44:masterfrom
andresgit763:fix/raop-streamer-improvements

Conversation

@andresgit763

Copy link
Copy Markdown

Summary

  • ALAC decode outside mutex: Move alac_decode() call before pthread_mutex_lock(&ctx->ab_mutex) in buffer_put_packet. Decode into a VLA stack buffer, then memcpy under the lock. This reduces contention with the HTTP serving thread that also holds ab_mutex.
  • Socket buffers: Increase SO_SNDBUF from 128KB to 256KB on the listener socket. Also apply SO_SNDBUF to the accepted HTTP socket in http_thread_func (was only set on the listener, not the accepted connection).

Test plan

  • Verified audio playback works correctly on Sonos Play:1
  • No buffer underruns observed during testing
  • VLA size uses ctx->frame_size * 2 (frame_size int16_t samples × 2 channels)

Related: philippe44/AirConnect#582

- Move ALAC decode outside ab_mutex in buffer_put_packet to reduce
  contention with HTTP serving thread
- Increase SO_SNDBUF from 128KB to 256KB on listener socket
- Apply SO_SNDBUF 256KB on accepted HTTP socket (was missing)
Inspired by swyh-rs streaming architecture:

- Add TransferMode.dlna.org: Streaming header to HTTP responses,
  telling DLNA renderers to use streaming transfer mode
- Change Server header from HairTunes to AirConnect
- Replace pure-zero silence frames with faint noise (~2 LSB white
  noise) to prevent FLAC decoder stalls on some renderers
@andresgit763

Copy link
Copy Markdown
Author

Added a second commit with improvements inspired by swyh-rs:

  • TransferMode.dlna.org: Streaming header: Added to HTTP responses so DLNA renderers use streaming mode instead of download mode
  • Server header: Changed from "HairTunes" to "AirConnect"
  • Noise injection: Replaced memset(0) silence with faint ~2 LSB white noise to prevent FLAC decoder stalls

Comment thread src/raop_streamer.c

/*---------------------------------------------------------------------------*/
static void buffer_put_packet(raopst_t* ctx, seq_t seqno, unsigned rtptime, bool first, char* data, int len) {
// decode ALAC outside mutex to reduce contention with HTTP thread

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I understand the point but I have to check that I'm not using that on some lower-end CPU where memory copy is not cheap

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Have you noticed that being an issue IRL?

Comment thread src/raop_streamer.c Outdated
}

kd_add(resp, "Server", "HairTunes");
kd_add(resp, "Server", "AirConnect");

@philippe44 philippe44 May 3, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

No, this lib is not specific to AirConnect

Comment thread src/raop_streamer.c
kd_add(resp, "Server", "HairTunes");
kd_add(resp, "Server", "AirConnect");
kd_add(resp, "Content-Type", encoder_mimetype(ctx->encoder));
kd_add(resp, "TransferMode.dlna.org", "Streaming");

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

You are challenging my memory here ... I would have to re-read UPnP specs to see is this is correct. As you probably know, UPnP is a consistency disaster so I'm always worried to break something

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Oh, you can't do that here. This is a generic HTTP request that works for Chromecast and UPnP. You can't have UPnP headers.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I have a callback for that (sorry, but it just came back to me, I have not modified this code in a bit). So I'll do a modification in AirConnect

libraop is a shared library, not specific to AirConnect.
@andresgit763 andresgit763 force-pushed the fix/raop-streamer-improvements branch from 009d81c to 563c22a Compare May 3, 2026 20:17
Comment thread src/raop_streamer.c
} while (ctx->http_listener < 0 && port.count < port_range);

int i = 128*1024;
int i = 256*1024;

@philippe44 philippe44 May 4, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Is this an observed issue or is this "just in case"? Because I think 128k is plenty for audio

Comment thread src/raop_streamer.c
if (!curframe->ready) {
LOG_DEBUG("[%p]: created zero frame at %d (W:%hu R:%hu)", ctx, now - playtime, ctx->ab_write, ctx->ab_read);
memset(curframe->data, 0, ctx->frame_size * 4);
// inject faint noise (~2 LSB) instead of pure silence to prevent FLAC decoder stalls

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I've never heard about "flac stalls" issue. Can you elaborate?

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.

2 participants