+ oss_close(); /* might not have been paused */
+}
+
+/** @brief Channel names */
+static const char *oss_channels[] = SOUND_DEVICE_NAMES;
+
+static int oss_mixer_find_channel(const char *channel) {
+ if(!channel[strspn(channel, "0123456789")])
+ return atoi(channel);
+ else {
+ for(unsigned n = 0; n < sizeof oss_channels / sizeof *oss_channels; ++n)
+ if(!strcmp(oss_channels[n], channel))
+ return n;
+ return -1;
+ }
+}
+
+static void oss_open_mixer(void) {
+ const char *mixer = uaudio_get("mixer-device", "/dev/mixer");
+ /* TODO infer mixer-device from device */
+ if((oss_mixer_fd = open(mixer, O_RDWR, 0)) < 0)
+ disorder_fatal(errno, "error opening %s", mixer);
+ const char *channel = uaudio_get("mixer-channel", "pcm");
+ oss_mixer_channel = oss_mixer_find_channel(channel);
+ if(oss_mixer_channel < 0)
+ disorder_fatal(0, "no such channel as '%s'", channel);
+}
+
+static void oss_close_mixer(void) {
+ close(oss_mixer_fd);
+ oss_mixer_fd = -1;
+}
+
+static void oss_get_volume(int *left, int *right) {
+ int r;
+
+ *left = *right = 0;
+ if(ioctl(oss_mixer_fd, SOUND_MIXER_READ(oss_mixer_channel), &r) < 0)
+ disorder_error(errno, "error getting volume");
+ else {
+ *left = r & 0xff;
+ *right = (r >> 8) & 0xff;
+ }
+}
+
+static void oss_set_volume(int *left, int *right) {
+ int r = (*left & 0xff) + (*right & 0xff) * 256;
+ if(ioctl(oss_mixer_fd, SOUND_MIXER_WRITE(oss_mixer_channel), &r) == -1)
+ disorder_error(errno, "error setting volume");
+ else if(ioctl(oss_mixer_fd, SOUND_MIXER_READ(oss_mixer_channel), &r) < 0)
+ disorder_error(errno, "error getting volume");
+ else {
+ *left = r & 0xff;
+ *right = (r >> 8) & 0xff;
+ }
+}
+
+static void oss_configure(void) {
+ uaudio_set("device", config->device);
+ uaudio_set("mixer-device", config->mixer);
+ uaudio_set("mixer-channel", config->channel);