{"id":19429769,"url":"https://github.com/chayleaf/ihatelatency","last_synced_at":"2025-04-30T07:44:35.305Z","repository":{"id":259225342,"uuid":"877258495","full_name":"chayleaf/ihatelatency","owner":"chayleaf","description":"low-latency audio streaming server/client","archived":false,"fork":false,"pushed_at":"2024-11-01T14:03:34.000Z","size":36,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-30T14:03:55.962Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/chayleaf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-23T11:06:45.000Z","updated_at":"2025-02-23T03:07:31.000Z","dependencies_parsed_at":"2025-01-07T20:12:07.809Z","dependency_job_id":"b3b783fc-71f3-4984-9bf1-1aeb42262778","html_url":"https://github.com/chayleaf/ihatelatency","commit_stats":null,"previous_names":["chayleaf/ihatelatency"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chayleaf%2Fihatelatency","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chayleaf%2Fihatelatency/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chayleaf%2Fihatelatency/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/chayleaf%2Fihatelatency/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/chayleaf","download_url":"https://codeload.github.com/chayleaf/ihatelatency/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251664676,"owners_count":21624174,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-10T14:21:06.450Z","updated_at":"2025-04-30T07:44:35.281Z","avatar_url":"https://github.com/chayleaf.png","language":"Rust","readme":"# ihatelatency\n\nThis is a project I made for streaming audio from my PC to my phone,\nbecause other solutions were kinda annoying to deal with.\n\nCurrently, playback is handled via `cpal` for maximum compatibility, but\nrecording is handled via `pipewire` for minimum latency.\n\nUsage:\n\n```shell\n# on the device to stream audio from (server)\npactl load-module module-null-sink sink_name=remote\nihatelatency -l -a \u003clisten_address\u003e record -n remote\n# on the device to stream audio to (client)\nihatelatency -a \u003cserver_address\u003e play\n```\n\nRoles can be switched, the recording device is allowed to be the one to\nconnect to the playing server. The `-u` flag may be added to use UDP\ninstead of TCP. Note that for UDP the playback device must be the\nserver. Using UDP is currently recommended.\n\nFor TCP, the playback buffersize is autoadjusted based on how stable\nthe network is. The algorithm is pretty stupid, though I plan to improve\nit at some point. If you set the env var `RUST_LOG=trace`, the program\nwill print all xruns, and also constantly print the current buffer size.\nThis allows you to pick a buffer size by yourself - you can then pass it\nwith the `-s` flag for the `play` command. The bigger the buffer, the\nhigher the latency and the less xruns. With UDP, autoadjustment is\ndisabled (packet loss acts as autoadjustment instead).\n\nCurrently, `s16le`, `48000`, stereo is assumed, but it should be fairly\ntrivial to add support to sample rate selection (or sending it on\nconnection, except for UDP).\n\nAlso, currently the server can only handle one client at a time since I\ndon't have a need for streaming audio to multiple devices (and receiving\naudio from multiple devices is its own can of worms).\n\nYou may actually use other programs as players, like this:\n\n```shell\n# udp (most of these flags aren't required but may or may not decrease latency)\nffplay -nodisp -ac 2 -ar 48000 -analyzeduration 0 -probesize 32 -fflags nobuffer -flags low_delay -fflags discardcorrupt -f s16le -i \"udp://\u003clisten_address\u003e?listen=1\"\n\n# udp\nnc -u -l 0.0.0.0 \u003clisten_port\u003e | mpv --demuxer=rawaudio --no-cache --untimed --no-demuxer-thread --demuxer-rawaudio-rate=48000 -\n```\n\nOr as recorders, like this:\n\n```shell\n# udp\nffmpeg -f pulse -i \u003csink_name\u003e -ac 2 -f s16le udp://\u003cserver_address\u003e\n\n# tcp (please don't send pcm via udp netcat)\nparec --format=s16le -d \u003csink_name\u003e --latency-msec=1 --rate=48000 | nc \u003cserver_address\u003e \u003cserver_port\u003e\n```\n\nNonetheless, I guarantee that my program is at least as good as other\nprograms in terms of latency, the only other thing you can tune is\nnetwork settings, or sound server settings ([here's a post explaining how\nto do it for PulseAudio](https://juho.tykkala.fi/Pulseaudio-and-latency))\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchayleaf%2Fihatelatency","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fchayleaf%2Fihatelatency","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fchayleaf%2Fihatelatency/lists"}