1 /*
2  * OSS audio output driver
3  *
4  * Original author: A'rpi
5  * Support for >2 output channels added 2001-11-25
6  * - Steve Davies <steve@daviesfam.org>
7  * Rozhuk Ivan <rozhuk.im@gmail.com> 2020
8  *
9  * This file is part of mpv.
10  *
11  * mpv is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * mpv is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with mpv.  If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 
30 #include <sys/ioctl.h>
31 #include <sys/soundcard.h>
32 #include <sys/stat.h>
33 #if defined(__DragonFly__) || defined(__FreeBSD__)
34 #include <sys/sysctl.h>
35 #endif
36 #include <sys/types.h>
37 
38 #include "config.h"
39 #include "audio/format.h"
40 #include "common/msg.h"
41 #include "options/options.h"
42 #include "osdep/endian.h"
43 #include "osdep/io.h"
44 #include "ao.h"
45 #include "internal.h"
46 
47 #ifndef AFMT_AC3
48 #define AFMT_AC3 -1
49 #endif
50 
51 #define PATH_DEV_DSP "/dev/dsp"
52 #define PATH_DEV_MIXER "/dev/mixer"
53 
54 struct priv {
55     int dsp_fd;
56     bool playing;
57     double bps; /* Bytes per second. */
58 };
59 
60 /* like alsa except for 6.1 and 7.1, from pcm/matrix_map.h */
61 static const struct mp_chmap oss_layouts[MP_NUM_CHANNELS + 1] = {
62     {0},                                        /* empty */
63     MP_CHMAP_INIT_MONO,                         /* mono */
64     MP_CHMAP2(FL, FR),                          /* stereo */
65     MP_CHMAP3(FL, FR, LFE),                     /* 2.1 */
66     MP_CHMAP4(FL, FR, BL, BR),                  /* 4.0 */
67     MP_CHMAP5(FL, FR, BL, BR, FC),              /* 5.0 */
68     MP_CHMAP6(FL, FR, BL, BR, FC, LFE),         /* 5.1 */
69     MP_CHMAP7(FL, FR, BL, BR, FC, LFE, BC),     /* 6.1 */
70     MP_CHMAP8(FL, FR, BL, BR, FC, LFE, SL, SR), /* 7.1 */
71 };
72 
73 #if !defined(AFMT_S32_NE) && defined(AFMT_S32_LE) && defined(AFMT_S32_BE)
74 #define AFMT_S32_NE AFMT_S32MP_SELECT_LE_BE(AFMT_S32_LE, AFMT_S32_BE)
75 #endif
76 
77 static const int format_table[][2] = {
78     {AFMT_U8,           AF_FORMAT_U8},
79     {AFMT_S16_NE,       AF_FORMAT_S16},
80 #ifdef AFMT_S32_NE
81     {AFMT_S32_NE,       AF_FORMAT_S32},
82 #endif
83 #ifdef AFMT_FLOAT
84     {AFMT_FLOAT,        AF_FORMAT_FLOAT},
85 #endif
86 #ifdef AFMT_MPEG
87     {AFMT_MPEG,         AF_FORMAT_S_MP3},
88 #endif
89     {-1, -1}
90 };
91 
92 #define MP_WARN_IOCTL_ERR(__ao) \
93     MP_WARN((__ao), "%s: ioctl() fail, err = %i: %s\n", \
94         __FUNCTION__, errno, strerror(errno))
95 
96 
97 static void uninit(struct ao *ao);
98 
99 
device_descr_get(size_t dev_idx,char * buf,size_t buf_size)100 static void device_descr_get(size_t dev_idx, char *buf, size_t buf_size)
101 {
102 #if defined(__DragonFly__) || defined(__FreeBSD__)
103     char dev_path[32];
104     size_t tmp = (buf_size - 1);
105 
106     snprintf(dev_path, sizeof(dev_path), "dev.pcm.%zu.%%desc", dev_idx);
107     if (sysctlbyname(dev_path, buf, &tmp, NULL, 0) != 0) {
108         tmp = 0;
109     }
110     buf[tmp] = 0x00;
111 #elif defined(SOUND_MIXER_INFO)
112     size_t tmp = 0;
113     char dev_path[32];
114     mixer_info mi;
115 
116     snprintf(dev_path, sizeof(dev_path), PATH_DEV_MIXER"%zu", dev_idx);
117     int fd = open(dev_path, O_RDONLY);
118     if (ioctl(fd, SOUND_MIXER_INFO, &mi) == 0) {
119         strncpy(buf, mi.name, buf_size);
120         tmp = (buf_size - 1);
121     }
122     close(fd);
123     buf[tmp] = 0x00;
124 #else
125     buf[0] = 0x00;
126 #endif
127 }
128 
format2oss(int format)129 static int format2oss(int format)
130 {
131     for (size_t i = 0; format_table[i][0] != -1; i++) {
132         if (format_table[i][1] == format)
133             return format_table[i][0];
134     }
135     return -1;
136 }
137 
try_format(struct ao * ao,int * format)138 static bool try_format(struct ao *ao, int *format)
139 {
140     struct priv *p = ao->priv;
141     int oss_format = format2oss(*format);
142 
143     if (oss_format == -1 && af_fmt_is_spdif(*format))
144         oss_format = AFMT_AC3;
145 
146     if (oss_format == -1) {
147         MP_VERBOSE(ao, "Unknown/not supported internal format: %s\n",
148             af_fmt_to_str(*format));
149         *format = 0;
150         return false;
151     }
152 
153     return (ioctl(p->dsp_fd, SNDCTL_DSP_SETFMT, &oss_format) != -1);
154 }
155 
init(struct ao * ao)156 static int init(struct ao *ao)
157 {
158     struct priv *p = ao->priv;
159     struct mp_chmap channels = ao->channels;
160     audio_buf_info info;
161     size_t i;
162     int format, samplerate, nchannels, reqchannels, trig = 0;
163     int best_sample_formats[AF_FORMAT_COUNT + 1];
164     const char *device = ((ao->device) ? ao->device : PATH_DEV_DSP);
165 
166     /* Opening device. */
167     MP_VERBOSE(ao, "Using '%s' audio device.\n", device);
168     p->dsp_fd = open(device, (O_WRONLY | O_CLOEXEC));
169     if (p->dsp_fd < 0) {
170         MP_ERR(ao, "Can't open audio device %s: %s.\n",
171             device, mp_strerror(errno));
172         goto err_out;
173     }
174 
175     /* Selecting sound format. */
176     format = af_fmt_from_planar(ao->format);
177     af_get_best_sample_formats(format, best_sample_formats);
178     for (i = 0; best_sample_formats[i]; i++) {
179         format = best_sample_formats[i];
180         if (try_format(ao, &format))
181             break;
182     }
183     if (!format) {
184         MP_ERR(ao, "Can't set sample format.\n");
185         goto err_out;
186     }
187     MP_VERBOSE(ao, "Sample format: %s\n", af_fmt_to_str(format));
188 
189     /* Channels count. */
190     if (af_fmt_is_spdif(format)) {
191         /* Probably could be fixed by setting number of channels;
192          * needs testing. */
193         if (channels.num != 2) {
194             MP_ERR(ao, "Format %s not implemented.\n", af_fmt_to_str(format));
195             goto err_out;
196         }
197     } else {
198         struct mp_chmap_sel sel = {0};
199         for (i = 0; i < MP_ARRAY_SIZE(oss_layouts); i++) {
200             mp_chmap_sel_add_map(&sel, &oss_layouts[i]);
201         }
202         if (!ao_chmap_sel_adjust(ao, &sel, &channels))
203             goto err_out;
204         nchannels = reqchannels = channels.num;
205         if (ioctl(p->dsp_fd, SNDCTL_DSP_CHANNELS, &nchannels) == -1) {
206             MP_ERR(ao, "Failed to set audio device to %d channels.\n",
207                 reqchannels);
208             goto err_out_ioctl;
209         }
210         if (nchannels != reqchannels) {
211             /* Update number of channels to OSS suggested value. */
212             if (!ao_chmap_sel_get_def(ao, &sel, &channels, nchannels))
213                 goto err_out;
214         }
215         MP_VERBOSE(ao, "Using %d channels (requested: %d).\n",
216             channels.num, reqchannels);
217     }
218 
219     /* Sample rate. */
220     samplerate = ao->samplerate;
221     if (ioctl(p->dsp_fd, SNDCTL_DSP_SPEED, &samplerate) == -1)
222         goto err_out_ioctl;
223     MP_VERBOSE(ao, "Using %d Hz samplerate.\n", samplerate);
224 
225     /* Get buffer size. */
226     if (ioctl(p->dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1)
227         goto err_out_ioctl;
228     /* See ao.c ao->sstride initializations and get_state(). */
229     ao->device_buffer = ((info.fragstotal * info.fragsize) /
230         af_fmt_to_bytes(format));
231     if (!af_fmt_is_planar(format)) {
232         ao->device_buffer /= channels.num;
233     }
234 
235     /* Do not start playback after data written. */
236     if (ioctl(p->dsp_fd, SNDCTL_DSP_SETTRIGGER, &trig) == -1)
237         goto err_out_ioctl;
238 
239     /* Update sound params. */
240     ao->format = format;
241     ao->samplerate = samplerate;
242     ao->channels = channels;
243     p->bps = (channels.num * samplerate * af_fmt_to_bytes(format));
244     p->playing = false;
245 
246     return 0;
247 
248 err_out_ioctl:
249     MP_WARN_IOCTL_ERR(ao);
250 err_out:
251     uninit(ao);
252     return -1;
253 }
254 
uninit(struct ao * ao)255 static void uninit(struct ao *ao)
256 {
257     struct priv *p = ao->priv;
258 
259     if (p->dsp_fd == -1)
260         return;
261     ioctl(p->dsp_fd, SNDCTL_DSP_HALT, NULL);
262     close(p->dsp_fd);
263     p->dsp_fd = -1;
264     p->playing = false;
265 }
266 
control(struct ao * ao,enum aocontrol cmd,void * arg)267 static int control(struct ao *ao, enum aocontrol cmd, void *arg)
268 {
269     struct priv *p = ao->priv;
270     ao_control_vol_t *vol = (ao_control_vol_t *)arg;
271     int v;
272 
273     if (p->dsp_fd < 0)
274         return CONTROL_ERROR;
275 
276     switch (cmd) {
277     case AOCONTROL_GET_VOLUME:
278         if (ioctl(p->dsp_fd, SNDCTL_DSP_GETPLAYVOL, &v) == -1) {
279             MP_WARN_IOCTL_ERR(ao);
280             return CONTROL_ERROR;
281         }
282         vol->right = ((v & 0xff00) >> 8);
283         vol->left = (v & 0x00ff);
284         return CONTROL_OK;
285     case AOCONTROL_SET_VOLUME:
286         v = ((int)vol->right << 8) | (int)vol->left;
287         if (ioctl(p->dsp_fd, SNDCTL_DSP_SETPLAYVOL, &v) == -1) {
288             MP_WARN_IOCTL_ERR(ao);
289             return CONTROL_ERROR;
290         }
291         return CONTROL_OK;
292     }
293 
294     return CONTROL_UNKNOWN;
295 }
296 
reset(struct ao * ao)297 static void reset(struct ao *ao)
298 {
299     struct priv *p = ao->priv;
300     int trig = 0;
301 
302     /* Clear buf and do not start playback after data written. */
303     p->playing = false;
304     if (ioctl(p->dsp_fd, SNDCTL_DSP_HALT, NULL) == -1 ||
305         ioctl(p->dsp_fd, SNDCTL_DSP_SETTRIGGER, &trig) == -1)
306     {
307         MP_WARN_IOCTL_ERR(ao);
308         MP_WARN(ao, "Force reinitialize audio device.\n");
309         uninit(ao);
310         init(ao);
311     }
312 }
313 
start(struct ao * ao)314 static void start(struct ao *ao)
315 {
316     struct priv *p = ao->priv;
317     int trig = PCM_ENABLE_OUTPUT;
318 
319     if (ioctl(p->dsp_fd, SNDCTL_DSP_SETTRIGGER, &trig) == -1) {
320         MP_WARN_IOCTL_ERR(ao);
321         return;
322     }
323     p->playing = true;
324 }
325 
audio_write(struct ao * ao,void ** data,int samples)326 static bool audio_write(struct ao *ao, void **data, int samples)
327 {
328     struct priv *p = ao->priv;
329     ssize_t rc;
330     const size_t size = (samples * ao->sstride);
331 
332     if (size == 0)
333         return true;
334 
335     while ((rc = write(p->dsp_fd, data[0], size)) == -1) {
336         if (errno == EINTR)
337 			continue;
338         MP_WARN(ao, "audio_write: write() fail, err = %i: %s.\n",
339             errno, strerror(errno));
340         p->playing = false;
341         return false;
342     }
343     if ((size_t)rc != size) {
344         MP_WARN(ao, "audio_write: unexpected partial write: required: %zu, written: %zu.\n",
345             size, (size_t)rc);
346         p->playing = false;
347         return false;
348     }
349 
350     return true;
351 }
352 
get_state(struct ao * ao,struct mp_pcm_state * state)353 static void get_state(struct ao *ao, struct mp_pcm_state *state)
354 {
355     struct priv *p = ao->priv;
356     audio_buf_info info;
357     int odelay;
358 
359     if (ioctl(p->dsp_fd, SNDCTL_DSP_GETOSPACE, &info) == -1 ||
360         ioctl(p->dsp_fd, SNDCTL_DSP_GETODELAY, &odelay) == -1)
361     {
362         MP_WARN_IOCTL_ERR(ao);
363         p->playing = false;
364         memset(state, 0x00, sizeof(struct mp_pcm_state));
365         state->delay = 0.0;
366         return;
367     }
368     state->free_samples = (info.bytes / ao->sstride);
369     state->queued_samples = (ao->device_buffer - state->free_samples);
370     state->delay = (odelay / p->bps);
371     state->playing = p->playing;
372 }
373 
list_devs(struct ao * ao,struct ao_device_list * list)374 static void list_devs(struct ao *ao, struct ao_device_list *list)
375 {
376     struct stat st;
377     char dev_path[32] = PATH_DEV_DSP, dev_descr[256] = "Default";
378     struct ao_device_desc dev = {.name = dev_path, .desc = dev_descr};
379 
380     if (stat(PATH_DEV_DSP, &st) == 0) {
381         ao_device_list_add(list, ao, &dev);
382     }
383 
384     /* Auto detect. */
385     for (size_t i = 0, fail_cnt = 0; fail_cnt < 8; i ++, fail_cnt ++) {
386         snprintf(dev_path, sizeof(dev_path), PATH_DEV_DSP"%zu", i);
387         if (stat(dev_path, &st) != 0)
388             continue;
389         device_descr_get(i, dev_descr, sizeof(dev_descr));
390         ao_device_list_add(list, ao, &dev);
391         fail_cnt = 0; /* Reset fail counter. */
392     }
393 }
394 
395 const struct ao_driver audio_out_oss = {
396     .name      = "oss",
397     .description = "OSS/ioctl audio output",
398     .init      = init,
399     .uninit    = uninit,
400     .control   = control,
401     .reset     = reset,
402     .start     = start,
403     .write     = audio_write,
404     .get_state = get_state,
405     .list_devs = list_devs,
406     .priv_size = sizeof(struct priv),
407     .priv_defaults = &(const struct priv) {
408         .dsp_fd = -1,
409         .playing = false,
410     },
411 };
412