Ported @Pagten's target latency patch to pulseaudio IVSHMEM
Unified · Split
| @@ -1,5 +1,5 @@ | |||
| 1 | CC=gcc | 1 | CC=gcc |
| 2 | CFLAGS = -Wall | 2 | CFLAGS = -Wall -O2 |
| 3 | 3 | ||
| 4 | scream-pulse: scream-ivshmem-pulse.c | 4 | scream-pulse: scream-ivshmem-pulse.c |
| 5 | $(CC) $(CFLAGS) -o scream-ivshmem-pulse scream-ivshmem-pulse.c -lpulse-simple -lpulse | 5 | $(CC) $(CFLAGS) -o scream-ivshmem-pulse scream-ivshmem-pulse.c -lpulse-simple -lpulse |
| @@ -20,7 +20,10 @@ · 19 unmodified lines | |||
| 20 | static void show_usage(const char *arg0) | 20 | static void show_usage(const char *arg0) |
| 21 | { | 21 | { |
| 22 | fprintf(stderr, "\n"); | 22 | fprintf(stderr, "\n"); |
| 23 | fprintf(stderr, "Usage: %s <ivshmem device path>\n", arg0); | 23 | fprintf(stderr, "Usage: %s <ivshmem device path> [-t <latency>]\n", arg0); |
| 24 | fprintf(stderr, "\n"); | ||
| 25 | fprintf(stderr, " All command line options are optional.\n"); | ||
| 26 | fprintf(stderr, " -t <latency>: Target latency in milliseconds. Defaults to 50ms.\n"); | ||
| 24 | fprintf(stderr, "\n"); | 27 | fprintf(stderr, "\n"); |
| 25 | exit(1); | 28 | exit(1); |
| 26 | } | 29 | } |
| @@ -61,7 +64,7 @@ struct shmheader { · 34 unmodified lines | |||
| 61 | }; | 64 | }; |
| 62 | 65 | ||
| 63 | int main(int argc, char*argv[]) { | 66 | int main(int argc, char*argv[]) { |
| 64 | if (argc != 2) { | 67 | if (argc < 2) { |
| 65 | show_usage(argv[0]); | 68 | show_usage(argv[0]); |
| 66 | } | 69 | } |
| 67 | 70 | ||
| @@ -72,12 +75,32 @@ int main(int argc, char*argv[]) { · 4 unmodified lines | |||
| 72 | pa_simple *s; | 75 | pa_simple *s; |
| 73 | pa_sample_spec ss; | 76 | pa_sample_spec ss; |
| 74 | pa_channel_map channel_map; | 77 | pa_channel_map channel_map; |
| 78 | pa_buffer_attr buffer_attr; | ||
| 75 | 79 | ||
| 76 | unsigned char cur_sample_rate = 0; | 80 | unsigned char cur_sample_rate = 0; |
| 77 | unsigned char cur_sample_size = 0; | 81 | unsigned char cur_sample_size = 0; |
| 78 | unsigned char cur_channels = 2; | 82 | unsigned char cur_channels = 2; |
| 79 | uint16_t cur_channel_map = 0x0003; | 83 | uint16_t cur_channel_map = 0x0003; |
| 84 | |||
| 85 | int target_latency_ms = 50; | ||
| 80 | 86 | ||
| 87 | int opt; | ||
| 88 | while ((opt = getopt(argc, argv, "t:h")) != -1) { | ||
| 89 | switch (opt) { | ||
| 90 | case 't': | ||
| 91 | target_latency_ms = atoi(optarg); | ||
| 92 | if (target_latency_ms < 0) show_usage(argv[0]); | ||
| 93 | break; | ||
| 94 | default: | ||
| 95 | show_usage(argv[0]); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | if (1+optind < argc) { | ||
| 99 | fprintf(stderr, "Expected argument after options\n"); | ||
| 100 | show_usage(argv[0]); | ||
| 101 | } | ||
| 102 | |||
| 103 | |||
| 81 | // Opportunistic call to renice us, so we can keep up under | 104 | // Opportunistic call to renice us, so we can keep up under |
| 82 | // higher load conditions. This may fail when run as non-root. | 105 | // higher load conditions. This may fail when run as non-root. |
| 83 | setpriority(PRIO_PROCESS, 0, -11); | 106 | setpriority(PRIO_PROCESS, 0, -11); |
| @@ -92,6 +115,14 @@ int main(int argc, char*argv[]) { · 8 unmodified lines | |||
| 92 | ss.format = PA_SAMPLE_S16LE; | 115 | ss.format = PA_SAMPLE_S16LE; |
| 93 | ss.rate = 44100; | 116 | ss.rate = 44100; |
| 94 | ss.channels = cur_channels; | 117 | ss.channels = cur_channels; |
| 118 | |||
| 119 | // set buffer size for requested latency | ||
| 120 | buffer_attr.maxlength = (uint32_t)-1; | ||
| 121 | buffer_attr.tlength = pa_usec_to_bytes((pa_usec_t)target_latency_ms * 1000u, &ss); | ||
| 122 | buffer_attr.prebuf = (uint32_t)-1; | ||
| 123 | buffer_attr.minreq = (uint32_t)-1; | ||
| 124 | buffer_attr.fragsize = (uint32_t)-1; | ||
| 125 | |||
| 95 | s = pa_simple_new(NULL, | 126 | s = pa_simple_new(NULL, |
| 96 | "Scream", | 127 | "Scream", |
| 97 | PA_STREAM_PLAYBACK, | 128 | PA_STREAM_PLAYBACK, |
| @@ -99,7 +130,7 @@ int main(int argc, char*argv[]) { · 1 unmodified line | |||
| 99 | "Audio", | 130 | "Audio", |
| 100 | &ss, | 131 | &ss, |
| 101 | &channel_map, | 132 | &channel_map, |
| 102 | NULL, | 133 | &buffer_attr, |
| 103 | &error | 134 | &error |
| 104 | ); | 135 | ); |
| 105 | if (!s) { | 136 | if (!s) { |
| @@ -220,7 +251,11 @@ int main(int argc, char*argv[]) { · 114 unmodified lines | |||
| 220 | } | 251 | } |
| 221 | 252 | ||
| 222 | if (ss.rate > 0) { | 253 | if (ss.rate > 0) { |
| 254 | // sample spec has changed, so the playback buffer size for the requested latency must be recalculated as well | ||
| 255 | buffer_attr.tlength = pa_usec_to_bytes((pa_usec_t)target_latency_ms * 1000, &ss); | ||
| 256 | |||
| 223 | if (s) pa_simple_free(s); | 257 | if (s) pa_simple_free(s); |
| 258 | |||
| 224 | s = pa_simple_new(NULL, | 259 | s = pa_simple_new(NULL, |
| 225 | "Scream", | 260 | "Scream", |
| 226 | PA_STREAM_PLAYBACK, | 261 | PA_STREAM_PLAYBACK, |
| @@ -228,7 +263,7 @@ int main(int argc, char*argv[]) { · 1 unmodified line | |||
| 228 | "Audio", | 263 | "Audio", |
| 229 | &ss, | 264 | &ss, |
| 230 | &channel_map, | 265 | &channel_map, |
| 231 | NULL, | 266 | &buffer_attr, |
| 232 | NULL | 267 | NULL |
| 233 | ); | 268 | ); |
| 234 | if (s) { | 269 | if (s) { |