Skip to content

Commit 790f770

Browse files
committed
ao_oss: add hotplug support, improve list_devs
1 parent 33111f3 commit 790f770

1 file changed

Lines changed: 124 additions & 11 deletions

File tree

audio/out/ao_oss.c

Lines changed: 124 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Original author: A'rpi
55
* Support for >2 output channels added 2001-11-25
66
* - Steve Davies <steve@daviesfam.org>
7-
* Rozhuk Ivan <rozhuk.im@gmail.com> 2020-2023
7+
* Rozhuk Ivan <rozhuk.im@gmail.com> 2020-2026
88
*
99
* This file is part of mpv.
1010
*
@@ -25,33 +25,46 @@
2525
#include <errno.h>
2626
#include <fcntl.h>
2727
#include <stdio.h>
28+
#include <stdlib.h>
2829

2930
#include <sys/ioctl.h>
3031
#include <sys/soundcard.h>
3132
#include <sys/stat.h>
3233
#if defined(__DragonFly__) || defined(__FreeBSD__)
33-
#include <sys/sysctl.h>
34+
# include <sys/sysctl.h>
35+
# include <sys/socket.h>
36+
# include <sys/un.h>
37+
# include <string.h>
38+
# include <paths.h>
39+
# define DEVD_SOCK_PATH _PATH_VARRUN "devd.seqpacket.pipe"
40+
# define DEVD_EVENT_NOTIFY '!'
3441
#endif
3542
#include <sys/types.h>
43+
#include <dirent.h>
3644

3745
#include "audio/format.h"
3846
#include "common/common.h"
3947
#include "common/msg.h"
4048
#include "options/options.h"
4149
#include "osdep/endian.h"
4250
#include "osdep/io.h"
51+
#include "osdep/threads.h"
52+
#include "misc/natural_sort.h"
4353
#include "ao.h"
4454
#include "internal.h"
4555

4656
#ifndef AFMT_AC3
47-
#define AFMT_AC3 -1
57+
# define AFMT_AC3 -1
4858
#endif
4959

50-
#define PATH_DEV_DSP "/dev/dsp"
51-
#define PATH_DEV_MIXER "/dev/mixer"
60+
#define PATH_DEV_DSP "/dev/dsp"
61+
#define PATH_DEV_MIXER "/dev/mixer"
62+
63+
5264

5365
struct priv {
5466
int dsp_fd;
67+
int hotplug_fd;
5568
double bps; /* Bytes per second. */
5669
};
5770

@@ -361,8 +374,32 @@ static void get_state(struct ao *ao, struct mp_pcm_state *state)
361374
state->playing = (state->queued_samples != 0);
362375
}
363376

377+
static int mp_natural_sort_cmp_de(const struct dirent **a, const struct dirent **b)
378+
{
379+
return mp_natural_sort_cmp((*a)->d_name, (*b)->d_name);
380+
}
381+
382+
static int
383+
scandir_filter_cb(const struct dirent *de) {
384+
385+
if (de == NULL || de->d_fileno == 0)
386+
return 0;
387+
/* Only few types allowed. */
388+
switch (de->d_type) {
389+
case DT_CHR:
390+
case DT_LNK:
391+
break;
392+
default: /* Filter out all other. */
393+
return 0;
394+
}
395+
/* Allow only "dsp*". */
396+
return (de->d_namlen > 3 && memcmp("dsp", de->d_name, 3) == 0);
397+
}
398+
364399
static void list_devs(struct ao *ao, struct ao_device_list *list)
365400
{
401+
int rc, dev_idx;
402+
struct dirent **dirp = NULL;
366403
struct stat st;
367404
char dev_path[32] = PATH_DEV_DSP, dev_descr[256] = "Default";
368405
struct ao_device_desc dev = {.name = dev_path, .desc = dev_descr};
@@ -372,16 +409,87 @@ static void list_devs(struct ao *ao, struct ao_device_list *list)
372409
}
373410

374411
/* Auto detect. */
375-
for (size_t i = 0, fail_cnt = 0; fail_cnt < 8; i ++, fail_cnt ++) {
376-
snprintf(dev_path, sizeof(dev_path), PATH_DEV_DSP"%zu", i);
377-
if (stat(dev_path, &st) != 0)
378-
continue;
379-
device_descr_get(i, dev_descr, sizeof(dev_descr));
412+
rc = scandir("/dev", &dirp, scandir_filter_cb, mp_natural_sort_cmp_de);
413+
if (rc == -1 || dirp == NULL)
414+
return;
415+
for (size_t i = 0; i < (size_t)rc; i ++) {
416+
dev_idx = atoi((dirp[i]->d_name + 3));
417+
snprintf(dev_path, sizeof(dev_path), PATH_DEV_DSP"%i", dev_idx);
418+
device_descr_get((size_t)dev_idx, dev_descr, sizeof(dev_descr));
380419
ao_device_list_add(list, ao, &dev);
381-
fail_cnt = 0; /* Reset fail counter. */
420+
free(dirp[i]);
421+
}
422+
free(dirp);
423+
}
424+
425+
#ifdef DEVD_SOCK_PATH
426+
static void *hotplug_proc(void *data) {
427+
struct ao *ao = data;
428+
struct priv *p = ao->priv;
429+
ssize_t ios;
430+
uint8_t buf[4096];
431+
432+
mp_thread_set_name("ao/oss hotplug");
433+
mp_thread_detach(mp_thread_current_id());
434+
435+
for (;;) {
436+
ios = recv(p->hotplug_fd, buf, sizeof(buf), MSG_WAITALL);
437+
if (ios <= 0) {
438+
if (errno == EINTR)
439+
continue;
440+
break;
441+
}
442+
/* Check: is notify and system=DEVFS and subsystem=CDEV and cdev=dsp. */
443+
if (DEVD_EVENT_NOTIFY == buf[0] &&
444+
NULL != memmem(buf, (size_t)ios, "system=DEVFS", 12) &&
445+
NULL != memmem(buf, (size_t)ios, "subsystem=CDEV", 14) &&
446+
NULL != memmem(buf, (size_t)ios, "cdev=dsp", 8))
447+
{
448+
ao_hotplug_event(ao); /* Fire hotplug event! */
449+
}
382450
}
451+
452+
return NULL;
453+
}
454+
455+
static int hotplug_init(struct ao *ao)
456+
{
457+
struct priv *p = ao->priv;
458+
static const struct sockaddr_un sun = {
459+
.sun_len = sizeof(struct sockaddr_un),
460+
.sun_family = AF_UNIX,
461+
.sun_path = DEVD_SOCK_PATH
462+
};
463+
mp_thread tid;
464+
465+
p->hotplug_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
466+
if (p->hotplug_fd == -1)
467+
return -1;
468+
/* Attempt to connect to devd socket. */
469+
if (connect(p->hotplug_fd, (struct sockaddr*)&sun, sizeof(sun)) < 0 ||
470+
mp_thread_create(&tid, hotplug_proc, (void*)ao))
471+
{
472+
close(p->hotplug_fd);
473+
p->hotplug_fd = -1;
474+
MP_WARN(ao, "%s: fail to connect to devd socket or thread create: err = %i: %s\n", \
475+
__FUNCTION__, errno, mp_strerror(errno));
476+
return -1;
477+
}
478+
479+
return 0;
383480
}
384481

482+
static void hotplug_uninit(struct ao *ao)
483+
{
484+
struct priv *p = ao->priv;
485+
486+
if (p->hotplug_fd == -1)
487+
return;
488+
close(p->hotplug_fd);
489+
p->hotplug_fd = -1;
490+
}
491+
#endif
492+
385493
const struct ao_driver audio_out_oss = {
386494
.name = "oss",
387495
.description = "OSS/ioctl audio output",
@@ -393,8 +501,13 @@ const struct ao_driver audio_out_oss = {
393501
.write = audio_write,
394502
.get_state = get_state,
395503
.list_devs = list_devs,
504+
#ifdef DEVD_SOCK_PATH
505+
.hotplug_init = hotplug_init,
506+
.hotplug_uninit = hotplug_uninit,
507+
#endif
396508
.priv_size = sizeof(struct priv),
397509
.priv_defaults = &(const struct priv) {
398510
.dsp_fd = -1,
511+
.hotplug_fd = -1,
399512
},
400513
};

0 commit comments

Comments
 (0)