]> git.ipfire.org Git - thirdparty/shairport-sync.git/blob - audio_soundio.c
Remove more causes of warnings at -Wextra levels
[thirdparty/shairport-sync.git] / audio_soundio.c
1 #include "audio.h"
2 #include "common.h"
3 #include <memory.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7
8 #include <soundio/soundio.h>
9
10 int Fs;
11 long long starttime, samples_played;
12
13 struct SoundIoOutStream *outstream;
14 struct SoundIo *soundio;
15 struct SoundIoDevice *device;
16 struct SoundIoRingBuffer *ring_buffer = NULL;
17
18 static int min_int(int a, int b) { return (a < b) ? a : b; }
19
20 static void write_callback(struct SoundIoOutStream *outstream, int frame_count_min,
21 int frame_count_max) {
22 struct SoundIoChannelArea *areas;
23 // int frame_count;
24 int err;
25
26 char *read_ptr = soundio_ring_buffer_read_ptr(ring_buffer);
27 int fill_bytes = soundio_ring_buffer_fill_count(ring_buffer);
28 int fill_count = fill_bytes / outstream->bytes_per_frame;
29
30 debug(3, "[--->>] frame_count_min: %d , frame_count_max: %d , fill_bytes: %d , fill_count: %d , "
31 "outstream->bytes_per_frame: %d",
32 frame_count_min, frame_count_max, fill_bytes, fill_count, outstream->bytes_per_frame);
33
34 if (frame_count_min > fill_count) {
35 int frame_count = frame_count_min;
36 if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count))) {
37 debug(0, "[--->>] begin write error: %s", soundio_strerror(err));
38 }
39 for (int frame = 0; frame < frame_count; frame += 1) {
40 for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
41 memset(areas[ch].ptr, 0, outstream->bytes_per_sample);
42 areas[ch].ptr += areas[ch].step;
43 }
44 }
45 if ((err = soundio_outstream_end_write(outstream)))
46 debug(0, "[--->>] end write error: %s", soundio_strerror(err));
47 return;
48 }
49
50 int read_count = min_int(frame_count_max, fill_count);
51 int frames_left = read_count;
52
53 while (frames_left > 0) {
54 int frame_count = frames_left;
55
56 if ((err = soundio_outstream_begin_write(outstream, &areas, &frame_count)))
57 debug(0, "[--->>] begin write error: %s", soundio_strerror(err));
58
59 if (frame_count <= 0)
60 break;
61
62 for (int frame = 0; frame < frame_count; frame += 1) {
63 for (int ch = 0; ch < outstream->layout.channel_count; ch += 1) {
64 memcpy(areas[ch].ptr, read_ptr, outstream->bytes_per_sample);
65 areas[ch].ptr += areas[ch].step;
66 read_ptr += outstream->bytes_per_sample;
67 }
68 }
69
70 if ((err = soundio_outstream_end_write(outstream)))
71 debug(0, "[--->>] end write error: %s", soundio_strerror(err));
72
73 frames_left -= frame_count;
74 }
75
76 debug(3, "[--->>] Wrote: %d", read_count * outstream->bytes_per_frame);
77 soundio_ring_buffer_advance_read_ptr(ring_buffer, read_count * outstream->bytes_per_frame);
78 }
79
80 static void underflow_callback(__attribute__((unused)) struct SoundIoOutStream *outstream) {
81 static int count = 0;
82 debug(0, "underflow %d\n", ++count);
83 }
84
85 static int init(__attribute__((unused)) int argc, __attribute__((unused)) char **argv) {
86 int err;
87
88 config.audio_backend_buffer_desired_length = 2.0;
89 config.audio_backend_latency_offset = 0;
90
91 // get settings from settings file
92
93 // do the "general" audio options. Note, these options are in the "general" stanza!
94 parse_general_audio_options();
95
96 // get the specific settings
97
98 soundio = soundio_create();
99 if (!soundio) {
100 debug(0, "out of memory\n");
101 return 1;
102 }
103 if ((err = soundio_connect_backend(soundio, SoundIoBackendCoreAudio))) {
104 debug(0, "error connecting: %s", soundio_strerror(err));
105 return 1;
106 }
107 soundio_flush_events(soundio);
108
109 int default_out_device_index = soundio_default_output_device_index(soundio);
110 if (default_out_device_index < 0) {
111 debug(0, "no output device found");
112 return 1;
113 }
114
115 device = soundio_get_output_device(soundio, default_out_device_index);
116 if (!device) {
117 debug(0, "out of memory");
118 return 1;
119 }
120 debug(0, "Output device: %s\n", device->name);
121 return 0;
122 }
123
124 static void deinit(void) {
125 soundio_ring_buffer_destroy(ring_buffer);
126 soundio_device_unref(device);
127 soundio_destroy(soundio);
128 debug(0, "soundio audio deinit\n");
129 }
130
131 static void start(int sample_rate, int sample_format) {
132 Fs = sample_rate;
133 starttime = 0;
134 samples_played = 0;
135 int err;
136
137 debug(1, "soundion rate: %d, format: %d", sample_rate, sample_format);
138
139 // soundio_device_sort_channel_layouts(device);
140
141 outstream = soundio_outstream_create(device);
142 outstream->format = SoundIoFormatS16NE;
143 outstream->sample_rate = sample_rate;
144 outstream->layout.channel_count = 2;
145 outstream->write_callback = write_callback;
146 outstream->underflow_callback = underflow_callback;
147 // outstream->software_latency = 0;
148
149 if ((err = soundio_outstream_open(outstream))) {
150 debug(0, "unable to open device: %s", soundio_strerror(err));
151 }
152 if (outstream->layout_error)
153 debug(0, "unable to set channel layout: %s\n", soundio_strerror(outstream->layout_error));
154
155 int capacity = outstream->sample_rate * outstream->bytes_per_frame;
156 ring_buffer = soundio_ring_buffer_create(soundio, capacity);
157 if (!ring_buffer)
158 debug(0, "unable to create ring buffer: out of memory");
159 char *buf = soundio_ring_buffer_write_ptr(ring_buffer);
160 memset(buf, 0, capacity);
161 soundio_ring_buffer_advance_write_ptr(ring_buffer, capacity);
162
163 if ((err = soundio_outstream_start(outstream))) {
164 debug(0, "unable to start outstream: %s", soundio_strerror(err));
165 }
166
167 debug(1, "libsoundio output started\n");
168 }
169
170 static void play(short buf[], int samples) {
171 // int err;
172 int free_bytes = soundio_ring_buffer_free_count(ring_buffer);
173 int written_bytes = 0;
174 int write_bytes = 0;
175 int left_bytes = samples * outstream->bytes_per_frame;
176 char *write_ptr = soundio_ring_buffer_write_ptr(ring_buffer);
177
178 debug(3, "[<<---] samples: %d , size: %d", samples, left_bytes);
179 write_bytes = min_int(left_bytes, free_bytes);
180 debug(3, "[<<---] left_bytes: %d, write_bytes: %d, free_bytes: %d\n", left_bytes, write_bytes,
181 free_bytes);
182
183 if (write_bytes) {
184 memcpy(write_ptr, (char *)buf, write_bytes);
185 written_bytes += write_bytes;
186 soundio_ring_buffer_advance_write_ptr(ring_buffer, write_bytes);
187 debug(3, "[<<---] Written to buffer : %d\n", written_bytes);
188 }
189 }
190
191 static void parameters(audio_parameters *info) {
192 info->minimum_volume_dB = -30.0;
193 info->maximum_volume_dB = 0.0;
194 debug(2, "Parameters\n");
195 debug(2, "Current Volume dB: %f\n", info->current_volume_dB);
196 debug(2, "Minimum Volume dB: %d\n", info->minimum_volume_dB);
197 debug(2, "Maximum Volume dB: %d\n", info->maximum_volume_dB);
198 }
199
200 static void stop(void) {
201 soundio_outstream_destroy(outstream);
202 soundio_ring_buffer_clear(ring_buffer);
203 debug(1, "libsoundio output stopped\n");
204 }
205
206 static void flush(void) {
207 soundio_ring_buffer_clear(ring_buffer);
208 debug(1, "libsoundio output flushed\n");
209 }
210
211 static void help(void) { printf(" There are no options for libsoundio.\n"); }
212
213 audio_output audio_soundio = {.name = "soundio",
214 .help = &help,
215 .init = &init,
216 .deinit = &deinit,
217 .start = &start,
218 .stop = &stop,
219 .flush = &flush,
220 .delay = NULL,
221 .play = &play,
222 .volume = NULL,
223 .parameters = &parameters,
224 .mute = NULL};