1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
#include "sound.h"
#include "common/strutil.h"
#include <fcntl.h>
#include <sndio.h>
static void close_hdl(struct sioctl_hdl** phdl) {
assert(phdl);
if (*phdl) {
sioctl_close(*phdl);
}
}
enum { MAX_CHANNEL_NUM = 8 };
typedef struct FFSoundDeviceBundle {
char name[SIOCTL_DISPLAYMAX];
double level[MAX_CHANNEL_NUM];
uint8_t iLevel;
bool mute[MAX_CHANNEL_NUM];
uint8_t iMute;
} FFSoundDeviceBundle;
static void enumerate_props(FFSoundDeviceBundle* bundle, struct sioctl_desc* desc, int val) {
if (!desc) {
return;
}
if (desc->type == SIOCTL_SEL) {
if (desc->display[0] != '\0' && ffStrEquals(desc->node0.name, "server")) {
ffStrCopy(bundle->name, desc->display, SIOCTL_DISPLAYMAX);
}
return;
}
if (desc->type != SIOCTL_NUM && desc->type != SIOCTL_SW) {
return;
}
if (!ffStrEquals(desc->node0.name, "output")) {
return;
}
if (ffStrEquals(desc->func, "level")) {
if (__builtin_expect(bundle->iLevel == MAX_CHANNEL_NUM, false)) {
return;
}
bundle->level[bundle->iLevel] = (double) val / (double) desc->maxval;
++bundle->iLevel;
} else if (ffStrEquals(desc->func, "mute")) {
if (__builtin_expect(bundle->iMute == MAX_CHANNEL_NUM, false)) {
return;
}
bundle->mute[bundle->iMute] = !!val;
++bundle->iMute;
}
}
const char* ffDetectSound(FFSoundOptions* options, FFlist* devices) {
FF_A_CLEANUP(close_hdl) struct sioctl_hdl* hdl = sioctl_open(SIO_DEVANY, SIOCTL_READ, 0);
if (!hdl) {
return "sio_open() failed";
}
FFSoundDeviceBundle bundle = {};
if (sioctl_ondesc(hdl, (void*) enumerate_props, &bundle) == 0) {
return "sioctl_ondesc() failed";
}
if (bundle.iLevel != bundle.iMute || bundle.iLevel == 0) {
return "Unexpected sioctl_ondesc() result";
}
FFSoundDevice* device = FF_LIST_ADD(FFSoundDevice, *devices);
ffStrbufInitS(&device->name, bundle.name);
ffStrbufInitS(&device->identifier, SIO_DEVANY);
ffStrbufInitStatic(&device->platformApi, "sndio");
device->volume = 0;
device->type = FF_SOUND_TYPE_ACTIVE | FF_SOUND_TYPE_MAIN;
double totalLevel = 0;
for (uint8_t i = 0; i < bundle.iLevel; ++i) {
if (!bundle.mute[i]) {
totalLevel += bundle.level[i];
}
}
device->volume = (uint8_t) ((totalLevel * 100 + bundle.iLevel / 2) / bundle.iLevel);
return NULL;
}
|