diff --git a/configure.ac b/configure.ac index 0dbba26..81ec11f 100644 --- a/configure.ac +++ b/configure.ac @@ -93,7 +93,8 @@ fi AC_SUBST(OSS_CFLAGS) -AM_CONDITIONAL(ENABLE_OSS, test "$oss" = "yes") +AM_CONDITIONAL(ENABLE_OSS4, test "x${oss}" = xyes -o "x${oss}" = xv4) +AM_CONDITIONAL(ENABLE_OSS3, test "x${oss}" = xv3) DEFAULT_MIXERAPP="xterm -e 'alsamixer'" AC_ARG_WITH(default-mixerapp, diff --git a/src/Makefile.am b/src/Makefile.am index ff5a024..9934d3f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -5,11 +5,15 @@ LIBS = @GTK_LIBS@ @ALSA_LIBS@ @X11_LIBS@ @NOTIFY_LIBS@ -lm bin_PROGRAMS = volumeicon -if ENABLE_OSS -BACKEND = oss_backend.c oss_backend.h +if ENABLE_OSS4 +BACKEND = oss4_backend.c oss_backend.h +else +if ENABLE_OSS3 +BACKEND = oss3_backend.c oss_backend.h else BACKEND = alsa_backend.c alsa_backend.h alsa_volume_mapping.h alsa_volume_mapping.c endif +endif volumeicon_SOURCES = \ volumeicon.c \ diff --git a/src/oss3_backend.c b/src/oss3_backend.c new file mode 100644 index 0000000..191bbca --- /dev/null +++ b/src/oss3_backend.c @@ -0,0 +1,188 @@ +// +// Copyright (c) 2011 Maato +// Copyright (c) 2015-2017 Lars Engels +// Copyright (c) 2017 Dmitri Goutnik +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer +// in this position and unchanged. +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +// IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// + +#include OSS_HEADER +#include +#include +#include +#include +#include +#include + +#include "oss_backend.h" + +static const char *channel_labels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES; +static int m_mixer_fd = -1; +static GList *m_channel_names = NULL; +static char *m_channel; +static int m_channel_dev = 0; +static char *m_device = NULL; +static GList *m_device_names = NULL; + +gboolean +oss_setup(const gchar *card, const gchar *channel, void (*volume_changed) (int, gboolean)) +{ + // Make sure (for now) that the setup function only gets called once + static int oss_setup_called = 0; + assert(oss_setup_called == 0); + oss_setup_called++; + + g_list_free_full(m_channel_names, g_free); + m_channel_names = NULL; + g_list_free_full(m_device_names, g_free); + m_device_names = NULL; + + g_free(m_device); + m_device = g_strdup(card); + m_device_names = g_list_append(m_device_names, g_strdup(m_device)); + + // Get ahold of the mixer device + char *devmixer; + if ((devmixer = getenv("OSS_MIXERDEV")) == NULL) + devmixer = "/dev/mixer"; + if ((m_mixer_fd = open(devmixer, O_RDWR)) == -1) { + perror("Cannot open mixer"); + exit(EXIT_FAILURE); + } + + // Query mixer devices + int devmask = 0; + if (ioctl(m_mixer_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) { + perror("Cannot query devices"); + exit(EXIT_FAILURE); + } + + // Pupulate channel list + for (int i = 0; i < SOUND_MIXER_NRDEVICES; i++) { + if (!((1 << i) & devmask)) + continue; + m_channel_names = g_list_append(m_channel_names, g_strdup(channel_labels[i])); + } + + // Setup channel using the provided channel name + if (channel != NULL) + oss_set_channel(channel); + else if (channel == NULL && m_channel_names != NULL) + oss_set_channel((const gchar *)m_channel_names->data); + + return TRUE; +} + +const gchar * +oss_get_channel() +{ + return m_channel; +} + +void +oss_set_channel(const gchar *channel) +{ + assert(channel != NULL); + assert(m_mixer_fd != -1); + + if (g_strcmp0(channel, m_channel) == 0) + return; + + // Find channel dev index + int i; + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (g_strcmp0(channel, channel_labels[i]) == 0) + break; + + if (i < SOUND_MIXER_NRDEVICES) { + g_free(m_channel); + m_channel = g_strdup(channel); + m_channel_dev = i; + } +} + +const gchar * +oss_get_device() +{ + return m_device; +} + +const GList * +oss_get_channel_names() +{ + return m_channel_names; +} + +const GList * +oss_get_device_names() +{ + return m_device_names; +} + +int +oss_get_volume() +{ + assert(m_mixer_fd != -1); + + int current_volume; + if (ioctl(m_mixer_fd, MIXER_READ(m_channel_dev), ¤t_volume) == -1) { + perror("Cannot read volume"); + exit(EXIT_FAILURE); + } + + // Only the left channel is returned + return current_volume & 0x7f; +} + +void +oss_set_volume(int volume) +{ + assert(m_mixer_fd != -1); + volume = (volume < 0 ? 0 : (volume > 100 ? 100 : volume)); + + volume = (volume << 8) | volume; + if (ioctl(m_mixer_fd, MIXER_WRITE(m_channel_dev), &volume) == -1) { + perror("Cannot write volume"); + exit(EXIT_FAILURE); + } +} + +gboolean +oss_get_mute() +{ + assert(m_mixer_fd != -1); + + // TODO: see if there's a way to return real mute state + return oss_get_volume() == 0; +} + +void +oss_set_mute(gboolean mute) +{ + assert(m_mixer_fd != -1); + + // TODO: see if there's a way to toggle real mute + if (mute) { + oss_set_volume(0); + } +} diff --git a/src/oss_backend.c b/src/oss4_backend.c similarity index 98% rename from src/oss_backend.c rename to src/oss4_backend.c index 89c2358..e9c4129 100644 --- a/src/oss_backend.c +++ b/src/oss4_backend.c @@ -290,3 +290,13 @@ void oss_set_volume(int volume) if(volume == 100) m_actual_maxvalue = get_raw_value(); } + +const gchar * oss_get_device() +{ + return NULL; +} + +const GList * oss_get_device_names() +{ + return NULL; +} diff --git a/src/oss_backend.h b/src/oss_backend.h index 58d4683..998b18f 100644 --- a/src/oss_backend.h +++ b/src/oss_backend.h @@ -35,5 +35,7 @@ int oss_get_volume(); gboolean oss_get_mute(); const gchar *oss_get_channel(); const GList *oss_get_channel_names(); +const gchar *oss_get_device(); +const GList *oss_get_device_names(); #endif diff --git a/src/volumeicon.c b/src/volumeicon.c index 024000f..d54c21d 100644 --- a/src/volumeicon.c +++ b/src/volumeicon.c @@ -1389,6 +1389,8 @@ int main(int argc, char *argv[]) backend_get_mute = &oss_get_mute; backend_get_channel = &oss_get_channel; backend_get_channel_names = &oss_get_channel_names; + backend_get_device = &oss_get_device; + backend_get_device_names = &oss_get_device_names; #else backend_setup = &asound_setup; backend_set_channel = &asound_set_channel;