32 |
32 |
*
|
33 |
33 |
*/
|
34 |
34 |
|
|
35 |
#define HAVE_OSSV4
|
|
36 |
|
35 |
37 |
#ifdef HAVE_CONFIG_H
|
36 |
38 |
#include <config.h>
|
37 |
39 |
#endif
|
... | ... | |
122 |
124 |
int mode;
|
123 |
125 |
|
124 |
126 |
int mixer_fd;
|
|
127 |
|
|
128 |
#ifdef HAVE_OSSV4
|
|
129 |
int mixer_dev;
|
|
130 |
int mixer_sink_control;
|
|
131 |
int mixer_source_control;
|
|
132 |
int mixer_cmax;
|
|
133 |
int mixer_dsp_fd;
|
|
134 |
oss_mixext sink_mixext;
|
|
135 |
oss_mixext source_mixext;
|
|
136 |
#else
|
125 |
137 |
int mixer_devmask;
|
|
138 |
#endif
|
126 |
139 |
|
127 |
140 |
int nfrags, frag_size, orig_frag_size;
|
128 |
141 |
|
... | ... | |
197 |
210 |
} else {
|
198 |
211 |
|
199 |
212 |
if (enable_bits)
|
|
213 |
#ifdef HAVE_OSSV4
|
|
214 |
if (ioctl(u->fd, SNDCTL_DSP_SYNC, NULL) < 0)
|
|
215 |
pa_log_warn("SNDCTL_DSP_SYNC: %s", pa_cstrerror(errno));
|
|
216 |
#else
|
200 |
217 |
if (ioctl(u->fd, SNDCTL_DSP_POST, NULL) < 0)
|
201 |
218 |
pa_log_warn("SNDCTL_DSP_POST: %s", pa_cstrerror(errno));
|
|
219 |
#endif
|
202 |
220 |
|
203 |
221 |
if (!quick) {
|
204 |
222 |
/*
|
... | ... | |
817 |
835 |
return 0;
|
818 |
836 |
}
|
819 |
837 |
|
|
838 |
#ifdef HAVE_OSSV4
|
|
839 |
|
|
840 |
static const char *
|
|
841 |
mixer_ext_type_get_name (int type)
|
|
842 |
{
|
|
843 |
switch (type) {
|
|
844 |
case MIXT_DEVROOT:
|
|
845 |
return "Device root entry";
|
|
846 |
case MIXT_GROUP:
|
|
847 |
return "Controller group";
|
|
848 |
case MIXT_ONOFF:
|
|
849 |
return "On/Off switch";
|
|
850 |
case MIXT_ENUM:
|
|
851 |
return "Enumeration control";
|
|
852 |
case MIXT_MONOSLIDER:
|
|
853 |
return "Mono slider (0-255)";
|
|
854 |
case MIXT_STEREOSLIDER:
|
|
855 |
return "Stereo slider (0-255)";
|
|
856 |
case MIXT_MESSAGE:
|
|
857 |
return "Textual message";
|
|
858 |
case MIXT_MONOVU:
|
|
859 |
return "Mono VU meter value";
|
|
860 |
case MIXT_STEREOVU:
|
|
861 |
return "Stereo VU meter value";
|
|
862 |
case MIXT_MONOPEAK:
|
|
863 |
return "Mono VU meter peak value";
|
|
864 |
case MIXT_STEREOPEAK:
|
|
865 |
return "Stereo VU meter peak value";
|
|
866 |
case MIXT_RADIOGROUP:
|
|
867 |
return "Radio button group";
|
|
868 |
case MIXT_MARKER:
|
|
869 |
/* Separator between normal and extension entries */
|
|
870 |
return "Separator";
|
|
871 |
case MIXT_VALUE:
|
|
872 |
return "Decimal value entry";
|
|
873 |
case MIXT_HEXVALUE:
|
|
874 |
return "Hex value entry";
|
|
875 |
case MIXT_SLIDER:
|
|
876 |
return "Mono slider (31-bit value range)";
|
|
877 |
case MIXT_3D:
|
|
878 |
return "3D";
|
|
879 |
case MIXT_MONOSLIDER16:
|
|
880 |
return "Mono slider (0-32767)";
|
|
881 |
case MIXT_STEREOSLIDER16:
|
|
882 |
return "Stereo slider (0-32767)";
|
|
883 |
case MIXT_MUTE:
|
|
884 |
return "Mute switch";
|
|
885 |
default:
|
|
886 |
break;
|
|
887 |
}
|
|
888 |
|
|
889 |
return "Unknown";
|
|
890 |
}
|
|
891 |
|
|
892 |
void
|
|
893 |
mixer_showflags (int flags)
|
|
894 |
{
|
|
895 |
struct
|
|
896 |
{
|
|
897 |
int flag;
|
|
898 |
char nick[16];
|
|
899 |
} all_flags[] = {
|
|
900 |
/* first the important ones */
|
|
901 |
{
|
|
902 |
MIXF_MAINVOL, "MAINVOL"}, {
|
|
903 |
MIXF_PCMVOL, "PCMVOL"}, {
|
|
904 |
MIXF_RECVOL, "RECVOL"}, {
|
|
905 |
MIXF_MONVOL, "MONVOL"}, {
|
|
906 |
MIXF_DESCR, "DESCR"},
|
|
907 |
|
|
908 |
/* now the rest in the right order */
|
|
909 |
{
|
|
910 |
MIXF_READABLE, "READABLE"}, {
|
|
911 |
MIXF_WRITEABLE, "WRITABLE"}, {
|
|
912 |
MIXF_POLL, "POLL"}, {
|
|
913 |
MIXF_HZ, "HZ"}, {
|
|
914 |
MIXF_STRING, "STRING"}, {
|
|
915 |
MIXF_DYNAMIC, "DYNAMIC"}, {
|
|
916 |
MIXF_OKFAIL, "OKFAIL"}, {
|
|
917 |
MIXF_FLAT, "FLAT"}, {
|
|
918 |
MIXF_LEGACY, "LEGACY"}, {
|
|
919 |
MIXF_CENTIBEL, "CENTIBEL"}, {
|
|
920 |
MIXF_DECIBEL, "DECIBEL"}, {
|
|
921 |
MIXF_WIDE, "WIDE"}
|
|
922 |
};
|
|
923 |
int num_flags = (sizeof (all_flags) / sizeof ((all_flags)[0]));
|
|
924 |
int i;
|
|
925 |
|
|
926 |
if (flags == 0) {
|
|
927 |
pa_log_debug (" flags : None");
|
|
928 |
return;
|
|
929 |
}
|
|
930 |
|
|
931 |
for (i=0; i < num_flags; i++) {
|
|
932 |
if ((flags & all_flags[i].flag)) {
|
|
933 |
pa_log_debug (" flag : %s", all_flags[i].nick);
|
|
934 |
flags &= ~all_flags[i].flag; /* unset */
|
|
935 |
}
|
|
936 |
}
|
|
937 |
|
|
938 |
/* Unknown flags? */
|
|
939 |
if (flags != 0) {
|
|
940 |
pa_log_debug (" flag : ????");
|
|
941 |
}
|
|
942 |
|
|
943 |
return;
|
|
944 |
}
|
|
945 |
|
820 |
946 |
static void sink_get_volume(pa_sink *s) {
|
821 |
947 |
struct userdata *u;
|
822 |
948 |
|
823 |
949 |
pa_assert_se(u = s->userdata);
|
824 |
950 |
|
|
951 |
if (pa_oss_get_volume(u->mixer_dsp_fd, &(u->sink_mixext), &s->sample_spec, &s->real_volume) >= 0)
|
|
952 |
return;
|
|
953 |
|
|
954 |
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
|
|
955 |
}
|
|
956 |
|
|
957 |
static void sink_set_volume(pa_sink *s) {
|
|
958 |
struct userdata *u;
|
|
959 |
|
|
960 |
pa_assert_se(u = s->userdata);
|
|
961 |
|
|
962 |
if (pa_oss_set_volume(u->mixer_dsp_fd, &(u->sink_mixext), &s->sample_spec, &s->real_volume) >= 0)
|
|
963 |
return;
|
|
964 |
|
|
965 |
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
|
|
966 |
}
|
|
967 |
|
|
968 |
static void source_get_volume(pa_source *s) {
|
|
969 |
struct userdata *u;
|
|
970 |
|
|
971 |
pa_assert_se(u = s->userdata);
|
|
972 |
|
|
973 |
if (pa_oss_get_volume(u->mixer_dsp_fd, &(u->source_mixext), &s->sample_spec, &s->real_volume) >= 0)
|
|
974 |
return;
|
|
975 |
|
|
976 |
pa_log_info("Device doesn't support reading mixer settings: %s", pa_cstrerror(errno));
|
|
977 |
}
|
|
978 |
|
|
979 |
static void source_set_volume(pa_source *s) {
|
|
980 |
struct userdata *u;
|
|
981 |
|
|
982 |
pa_assert_se(u = s->userdata);
|
|
983 |
|
|
984 |
if (pa_oss_set_volume(u->mixer_dsp_fd, &(u->source_mixext), &s->sample_spec, &s->real_volume) >= 0)
|
|
985 |
return;
|
|
986 |
|
|
987 |
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
|
|
988 |
}
|
|
989 |
|
|
990 |
#else
|
|
991 |
|
|
992 |
static void sink_get_volume(pa_sink *s) {
|
|
993 |
struct userdata *u;
|
|
994 |
|
|
995 |
pa_assert_se(u = s->userdata);
|
|
996 |
|
825 |
997 |
pa_assert(u->mixer_devmask & (SOUND_MASK_VOLUME|SOUND_MASK_PCM));
|
826 |
998 |
|
827 |
999 |
if (u->mixer_devmask & SOUND_MASK_VOLUME)
|
... | ... | |
888 |
1060 |
|
889 |
1061 |
pa_log_info("Device doesn't support writing mixer settings: %s", pa_cstrerror(errno));
|
890 |
1062 |
}
|
|
1063 |
#endif
|
891 |
1064 |
|
892 |
1065 |
static void thread_func(void *userdata) {
|
893 |
1066 |
struct userdata *u = userdata;
|
... | ... | |
1170 |
1343 |
|
1171 |
1344 |
int pa__init(pa_module*m) {
|
1172 |
1345 |
|
|
1346 |
#ifdef HAVE_OSSV4
|
|
1347 |
struct oss_sysinfo si = { {0,}, };
|
|
1348 |
struct oss_mixerinfo mi = { 0, };
|
|
1349 |
#endif
|
|
1350 |
|
1173 |
1351 |
struct audio_buf_info info;
|
1174 |
1352 |
struct userdata *u = NULL;
|
1175 |
1353 |
const char *dev;
|
... | ... | |
1267 |
1445 |
m->userdata = u;
|
1268 |
1446 |
u->fd = fd;
|
1269 |
1447 |
u->mixer_fd = -1;
|
|
1448 |
#ifndef HAVE_OSSV4
|
1270 |
1449 |
u->mixer_devmask = 0;
|
|
1450 |
#endif
|
1271 |
1451 |
u->use_getospace = u->use_getispace = true;
|
1272 |
1452 |
u->use_getodelay = true;
|
1273 |
1453 |
u->mode = mode;
|
... | ... | |
1441 |
1621 |
if ((u->mixer_fd = pa_oss_open_mixer_for_device(u->device_name)) >= 0) {
|
1442 |
1622 |
bool do_close = true;
|
1443 |
1623 |
|
|
1624 |
#ifdef HAVE_OSSV4
|
|
1625 |
#define IGNORE_DEV 1
|
|
1626 |
int i;
|
|
1627 |
|
|
1628 |
u->mixer_dsp_fd = -1;
|
|
1629 |
|
|
1630 |
if (ioctl (u->mixer_fd, SNDCTL_SYSINFO, &si) < 0) {
|
|
1631 |
pa_log_debug ("SNDCTL_SYSINFO failed");
|
|
1632 |
goto fail;
|
|
1633 |
}
|
|
1634 |
|
|
1635 |
i = pa_oss_get_device_number(u->device_name);
|
|
1636 |
if (i >= 0 && i < si.nummixers) {
|
|
1637 |
mi.dev = i;
|
|
1638 |
if (ioctl (u->mixer_fd, SNDCTL_MIXERINFO, &mi) < 0) {
|
|
1639 |
pa_log_debug("SNDCTL_MIXERINFO failed");
|
|
1640 |
goto fail;
|
|
1641 |
}
|
|
1642 |
}
|
|
1643 |
|
|
1644 |
if (i < si.nummixers) {
|
|
1645 |
struct stat sbuf;
|
|
1646 |
|
|
1647 |
if ((stat(mi.devnode, &sbuf) != 0) ||
|
|
1648 |
((sbuf.st_mode & S_IFCHR) == 0)) {
|
|
1649 |
pa_log("Failed to get mixer dsp device.");
|
|
1650 |
i = si.nummixers;
|
|
1651 |
}
|
|
1652 |
}
|
|
1653 |
|
|
1654 |
if (i < si.nummixers &&
|
|
1655 |
(u->mixer_dsp_fd = pa_oss_open_mixer(mi.devnode)) >= 0) {
|
|
1656 |
|
|
1657 |
/* Will cause for loop to exit if not filled in by OSS */
|
|
1658 |
u->mixer_cmax = -1;
|
|
1659 |
if (ioctl(u->mixer_dsp_fd, SNDCTL_MIX_NREXT, &u->mixer_cmax) < 0) {
|
|
1660 |
pa_log("Failed to get max control.");
|
|
1661 |
goto fail;
|
|
1662 |
}
|
|
1663 |
|
|
1664 |
pa_log_debug ("Opened mixer device %d with %d controls\n",
|
|
1665 |
mi.dev, mi.nrext);
|
|
1666 |
|
|
1667 |
u->mixer_sink_control = -1;
|
|
1668 |
u->mixer_source_control = -1;
|
|
1669 |
|
|
1670 |
for (i=0; i < u->mixer_cmax; i++) {
|
|
1671 |
memset (&(u->sink_mixext), 0, sizeof (oss_mixext));
|
|
1672 |
|
|
1673 |
#ifdef IGNORE_DEV
|
|
1674 |
/* This will cause dev to be ignored */
|
|
1675 |
u->sink_mixext.dev = -1;
|
|
1676 |
#else
|
|
1677 |
u->sink_mixext.dev = mi.dev;
|
|
1678 |
#endif
|
|
1679 |
|
|
1680 |
/*
|
|
1681 |
* The real way to pick a control on a mixer is with this
|
|
1682 |
* number. Note that control numbers are unique across all
|
|
1683 |
* mixers. So dev can just be ignored. When dev is included
|
|
1684 |
* it will only be used to check for correct dev from
|
|
1685 |
* userland. But it will not be used to select a mixer.
|
|
1686 |
*/
|
|
1687 |
u->sink_mixext.ctrl = i;
|
|
1688 |
|
|
1689 |
pa_log_debug ("Control %d", u->sink_mixext.ctrl);
|
|
1690 |
|
|
1691 |
if (ioctl (u->mixer_dsp_fd, SNDCTL_MIX_EXTINFO,
|
|
1692 |
&(u->sink_mixext)) < 0) {
|
|
1693 |
pa_log_debug ("SNDCTL_MIX_EXTINFO failed");
|
|
1694 |
continue;
|
|
1695 |
}
|
|
1696 |
|
|
1697 |
pa_log_debug (" name : %s", u->sink_mixext.extname);
|
|
1698 |
pa_log_debug (" type : %s (%d)",
|
|
1699 |
mixer_ext_type_get_name (u->sink_mixext.type),
|
|
1700 |
u->sink_mixext.type);
|
|
1701 |
pa_log_debug (" maxval : %d", u->sink_mixext.maxvalue);
|
|
1702 |
pa_log_debug (" parent : %d", u->sink_mixext.parent);
|
|
1703 |
mixer_showflags (u->sink_mixext.flags);
|
|
1704 |
|
|
1705 |
if ((u->sink_mixext.flags & MIXF_PCMVOL)) {
|
|
1706 |
pa_log_debug ("First PCM control: %d", i);
|
|
1707 |
u->mixer_sink_control = i;
|
|
1708 |
break;
|
|
1709 |
}
|
|
1710 |
|
|
1711 |
/*
|
|
1712 |
* Note that MIXF_MAINVOL may not be an exclusive single
|
|
1713 |
* control. For example on AudioHD there will be one for each
|
|
1714 |
* output jack (Green, Black, Orange...). So to really do a
|
|
1715 |
* master volume you would need to do all MIXF_MAINVOL at the
|
|
1716 |
* same time...
|
|
1717 |
*/
|
|
1718 |
if (((u->sink_mixext.flags & MIXF_MAINVOL)) &&
|
|
1719 |
u->mixer_sink_control == -1) {
|
|
1720 |
pa_log_debug ("First main volume control: %d", i);
|
|
1721 |
u->mixer_sink_control = i;
|
|
1722 |
}
|
|
1723 |
}
|
|
1724 |
|
|
1725 |
if (u->mixer_sink_control != -1) {
|
|
1726 |
pa_log_debug ("Setting OSS sink callbacks.");
|
|
1727 |
pa_sink_set_get_volume_callback(u->sink, sink_get_volume);
|
|
1728 |
pa_sink_set_set_volume_callback(u->sink, sink_set_volume);
|
|
1729 |
u->sink->n_volume_steps = 101;
|
|
1730 |
do_close = false;
|
|
1731 |
} else {
|
|
1732 |
pa_log_debug ("Not setting OSS sink callbacks.");
|
|
1733 |
}
|
|
1734 |
|
|
1735 |
for (i=0; i < mi.nrext; i++) {
|
|
1736 |
memset (&(u->source_mixext), 0, sizeof (oss_mixext));
|
|
1737 |
#ifdef IGNORE_DEV
|
|
1738 |
/* This will cause dev to be ignored */
|
|
1739 |
u->source_mixext.dev = -1;
|
|
1740 |
#else
|
|
1741 |
u->source_mixext.dev = mi.dev;
|
|
1742 |
#endif
|
|
1743 |
/*
|
|
1744 |
* The real way to pick a control on a mixer is with this
|
|
1745 |
* number. Note that control numbers are unique across all
|
|
1746 |
* mixers. So dev can just be ignored. When dev is included
|
|
1747 |
* it will only be used to check for correct dev from userland.
|
|
1748 |
* But it will not be used to select a mixer.
|
|
1749 |
*/
|
|
1750 |
u->source_mixext.ctrl = i;
|
|
1751 |
|
|
1752 |
pa_log_debug ("Control %d", u->source_mixext.ctrl);
|
|
1753 |
|
|
1754 |
if (ioctl (u->mixer_dsp_fd, SNDCTL_MIX_EXTINFO,
|
|
1755 |
&(u->source_mixext)) == -1) {
|
|
1756 |
pa_log_debug ("SNDCTL_MIX_EXTINFO failed");
|
|
1757 |
continue;
|
|
1758 |
}
|
|
1759 |
|
|
1760 |
pa_log_debug (" name : %s", u->source_mixext.extname);
|
|
1761 |
pa_log_debug (" type : %s (%d)",
|
|
1762 |
mixer_ext_type_get_name (u->source_mixext.type),
|
|
1763 |
u->source_mixext.type);
|
|
1764 |
pa_log_debug (" maxval : %d", u->source_mixext.maxvalue);
|
|
1765 |
pa_log_debug (" parent : %d", u->source_mixext.parent);
|
|
1766 |
mixer_showflags (u->source_mixext.flags);
|
|
1767 |
|
|
1768 |
/*
|
|
1769 |
* There may be more then one MIXF_RECVOL on a mixer. In fact
|
|
1770 |
* for audioHD the can be three (line-in, mix-in, and cd-in).
|
|
1771 |
* For a master gain it may be good to adjust all...
|
|
1772 |
*/
|
|
1773 |
if ((u->source_mixext.flags & MIXF_RECVOL)) {
|
|
1774 |
pa_log_debug ("First REC control: %d", i);
|
|
1775 |
u->mixer_source_control = i;
|
|
1776 |
break;
|
|
1777 |
}
|
|
1778 |
}
|
|
1779 |
|
|
1780 |
if (u->mixer_source_control != -1) {
|
|
1781 |
pa_log_debug ("Setting OSS source callbacks.");
|
|
1782 |
pa_source_set_get_volume_callback(u->source, source_get_volume);
|
|
1783 |
pa_source_set_set_volume_callback(u->source, source_set_volume);
|
|
1784 |
u->source->n_volume_steps = 101;
|
|
1785 |
do_close = false;
|
|
1786 |
} else {
|
|
1787 |
pa_log_debug ("Not setting OSS source callbacks.");
|
|
1788 |
}
|
|
1789 |
|
|
1790 |
if (do_close == true) {
|
|
1791 |
pa_close(u->mixer_dsp_fd);
|
|
1792 |
u->mixer_dsp_fd = -1;
|
|
1793 |
}
|
|
1794 |
}
|
|
1795 |
|
|
1796 |
#else
|
1444 |
1797 |
if (ioctl(u->mixer_fd, SOUND_MIXER_READ_DEVMASK, &u->mixer_devmask) < 0)
|
1445 |
1798 |
pa_log_warn("SOUND_MIXER_READ_DEVMASK failed: %s", pa_cstrerror(errno));
|
1446 |
1799 |
else {
|
... | ... | |
1460 |
1813 |
do_close = false;
|
1461 |
1814 |
}
|
1462 |
1815 |
}
|
|
1816 |
#endif
|
1463 |
1817 |
|
1464 |
1818 |
if (do_close) {
|
1465 |
1819 |
pa_close(u->mixer_fd);
|
1466 |
1820 |
u->mixer_fd = -1;
|
|
1821 |
#ifndef HAVE_OSSV4
|
1467 |
1822 |
u->mixer_devmask = 0;
|
|
1823 |
#endif
|
1468 |
1824 |
}
|
1469 |
1825 |
}
|
1470 |
1826 |
|
... | ... | |
1583 |
1939 |
if (u->fd >= 0)
|
1584 |
1940 |
pa_close(u->fd);
|
1585 |
1941 |
|
|
1942 |
#ifdef HAVE_OSSV4
|
|
1943 |
if (u->mixer_dsp_fd >= 0)
|
|
1944 |
pa_close(u->mixer_dsp_fd);
|
|
1945 |
#endif
|
1586 |
1946 |
if (u->mixer_fd >= 0)
|
1587 |
1947 |
pa_close(u->mixer_fd);
|
1588 |
1948 |
|
1589 |
|
-- pulseaudio-13.0/src/modules/oss/oss-util.c-orig Fri Jul 13 14:06:14 2018
|
|
1949 |
++ pulseaudio-13.0/src/modules/oss/oss-util.c Tue Sep 8 10:19:33 2020
|
... | ... | |
246 |
246 |
return 0;
|
247 |
247 |
}
|
248 |
248 |
|
|
249 |
#ifdef HAVE_OSSV4
|
|
250 |
static int
|
|
251 |
oss4_mixer_slider_pack_volume (oss_mixext *mixext, int channels, const pa_cvolume *volume)
|
|
252 |
{
|
|
253 |
int val = 0;
|
|
254 |
int lvol = 0;
|
|
255 |
int rvol = 0;
|
|
256 |
int lval = 0;
|
|
257 |
int rval = 0;
|
|
258 |
|
|
259 |
switch (mixext->type) {
|
|
260 |
case MIXT_MONOSLIDER:
|
|
261 |
case MIXT_MONOSLIDER16:
|
|
262 |
case MIXT_SLIDER:
|
|
263 |
lvol = volume->values[0] > PA_VOLUME_NORM ? PA_VOLUME_NORM : volume->values[0];
|
|
264 |
val = (lvol*mixext->maxvalue)/PA_VOLUME_NORM;
|
|
265 |
break;
|
|
266 |
|
|
267 |
case MIXT_STEREOSLIDER:
|
|
268 |
lvol = volume->values[0] > PA_VOLUME_NORM ? PA_VOLUME_NORM : volume->values[0];
|
|
269 |
lval = (lvol*mixext->maxvalue)/PA_VOLUME_NORM;
|
|
270 |
if (channels >= 2) {
|
|
271 |
rvol = volume->values[1] > PA_VOLUME_NORM ? PA_VOLUME_NORM : volume->values[1];
|
|
272 |
rval = (rvol*mixext->maxvalue)/PA_VOLUME_NORM;
|
|
273 |
}
|
|
274 |
|
|
275 |
val = ((rval & 0xff) << 8) | (lval & 0xff);
|
|
276 |
break;
|
|
277 |
|
|
278 |
case MIXT_STEREOSLIDER16:
|
|
279 |
lvol = volume->values[0] > PA_VOLUME_NORM ? PA_VOLUME_NORM : volume->values[0];
|
|
280 |
lval = (lvol*mixext->maxvalue)/PA_VOLUME_NORM;
|
|
281 |
if (channels >= 2) {
|
|
282 |
rvol = volume->values[1] > PA_VOLUME_NORM ? PA_VOLUME_NORM : volume->values[1];
|
|
283 |
rval = (rvol*mixext->maxvalue)/PA_VOLUME_NORM;
|
|
284 |
}
|
|
285 |
|
|
286 |
val = ((rval & 0xffff) << 16) | (lval & 0xffff);
|
|
287 |
|
|
288 |
break;
|
|
289 |
|
|
290 |
default:
|
|
291 |
return 0;
|
|
292 |
}
|
|
293 |
|
|
294 |
return val;
|
|
295 |
}
|
|
296 |
|
|
297 |
static void
|
|
298 |
oss4_mixer_slider_unpack_volume (oss_mixext *mixext, int v, pa_cvolume * volume)
|
|
299 |
{
|
|
300 |
uint32_t val, vol;
|
|
301 |
|
|
302 |
val = (uint32_t) v;
|
|
303 |
switch (mixext->type) {
|
|
304 |
case MIXT_SLIDER:
|
|
305 |
vol = val;
|
|
306 |
volume->values[0] = PA_CLAMP_VOLUME((vol * PA_VOLUME_NORM) / mixext->maxvalue);
|
|
307 |
if (volume->channels >= 2) {
|
|
308 |
volume->values[1] = volume->values[0];
|
|
309 |
}
|
|
310 |
break;
|
|
311 |
case MIXT_MONOSLIDER:
|
|
312 |
/* oss repeats the value in the upper bits, as if it was stereo */
|
|
313 |
vol = val & 0x00ff;
|
|
314 |
volume->values[0] = PA_CLAMP_VOLUME((vol * PA_VOLUME_NORM) / mixext->maxvalue);
|
|
315 |
if (volume->channels >= 2) {
|
|
316 |
volume->values[1] = volume->values[0];
|
|
317 |
}
|
|
318 |
break;
|
|
319 |
case MIXT_MONOSLIDER16:
|
|
320 |
/* oss repeats the value in the upper bits, as if it was stereo */
|
|
321 |
vol = val & 0x0000ffff;
|
|
322 |
volume->values[0] = PA_CLAMP_VOLUME((vol * PA_VOLUME_NORM) / mixext->maxvalue);
|
|
323 |
if (volume->channels >= 2) {
|
|
324 |
volume->values[1] = volume->values[0];
|
|
325 |
}
|
|
326 |
break;
|
|
327 |
case MIXT_STEREOSLIDER:
|
|
328 |
vol = (val & 0x00ff);
|
|
329 |
volume->values[0] = PA_CLAMP_VOLUME((vol * PA_VOLUME_NORM) / mixext->maxvalue);
|
|
330 |
if (volume->channels >= 2) {
|
|
331 |
vol = (val & 0xff00) >> 8;
|
|
332 |
volume->values[1] = PA_CLAMP_VOLUME((vol * PA_VOLUME_NORM) / mixext->maxvalue);
|
|
333 |
}
|
|
334 |
break;
|
|
335 |
case MIXT_STEREOSLIDER16:
|
|
336 |
vol = (val & 0x0000ffff);
|
|
337 |
volume->values[0] = PA_CLAMP_VOLUME((vol * PA_VOLUME_NORM) / mixext->maxvalue);
|
|
338 |
if (volume->channels >= 2) {
|
|
339 |
vol = (val & 0xffff0000) >> 16;
|
|
340 |
volume->values[1] = PA_CLAMP_VOLUME((vol * PA_VOLUME_NORM) / mixext->maxvalue);
|
|
341 |
}
|
|
342 |
break;
|
|
343 |
default:
|
|
344 |
return;
|
|
345 |
}
|
|
346 |
}
|
|
347 |
|
|
348 |
static int
|
|
349 |
oss4_mixer_get_control_val (int fd, oss_mixext *mixext, int *val)
|
|
350 |
{
|
|
351 |
oss_mixer_value ossval = { 0, };
|
|
352 |
|
|
353 |
/* ossval.dev = mixext->dev; */
|
|
354 |
ossval.dev = -1; /* if -1 on entry then is ignored */
|
|
355 |
/*
|
|
356 |
* The real way to pick a control on a mixer is with this number.
|
|
357 |
* Note that control numbers are uniq across all mixers. So dev
|
|
358 |
* can just be ignored. When dev is included it will only be used
|
|
359 |
* to check for correct dev from userland. But it will not be used
|
|
360 |
* to select a mixer.
|
|
361 |
*/
|
|
362 |
ossval.ctrl = mixext->ctrl;
|
|
363 |
ossval.timestamp = mixext->timestamp;
|
|
364 |
|
|
365 |
if (ioctl (fd, SNDCTL_MIX_READ, &ossval) == -1) {
|
|
366 |
pa_log_debug ("SNDCTL_MIX_READ failed");
|
|
367 |
*val = 0;
|
|
368 |
return -1;
|
|
369 |
}
|
|
370 |
|
|
371 |
*val = ossval.value;
|
|
372 |
pa_log_debug ("got value 0x%08x from %s", *val, mixext->extname);
|
|
373 |
return 0;
|
|
374 |
}
|
|
375 |
|
|
376 |
static int
|
|
377 |
oss4_mixer_set_control_val (int fd, oss_mixext *mixext, int val)
|
|
378 |
{
|
|
379 |
oss_mixer_value ossval = { 0, };
|
|
380 |
|
|
381 |
/* ossval.dev = mixext->dev; */
|
|
382 |
ossval.dev = -1; /* if -1 on entry then is ignored */
|
|
383 |
/*
|
|
384 |
* The real way to pick a control on a mixer is with this number.
|
|
385 |
* Note that control numbers are uniq across all mixers. So dev
|
|
386 |
* can just be ignored. When dev is included it will only be used
|
|
387 |
* to check for correct dev from userland. But it will not be used
|
|
388 |
* to select a mixer.
|
|
389 |
*/
|
|
390 |
ossval.ctrl = mixext->ctrl;
|
|
391 |
ossval.timestamp = mixext->timestamp;
|
|
392 |
ossval.value = val;
|
|
393 |
|
|
394 |
if (ioctl (fd, SNDCTL_MIX_WRITE, &ossval) == -1) {
|
|
395 |
pa_log_debug ("SNDCTL_MIX_WRITE failed");
|
|
396 |
return -1;
|
|
397 |
}
|
|
398 |
|
|
399 |
pa_log_debug ("set value 0x%08x on %s", val, mixext->extname);
|
|
400 |
return 0;
|
|
401 |
}
|
|
402 |
|
|
403 |
int pa_oss_get_volume(int fd, oss_mixext *mixext, const pa_sample_spec *ss, pa_cvolume *volume) {
|
|
404 |
int v = 0;
|
|
405 |
|
|
406 |
if (oss4_mixer_get_control_val (fd, mixext, &v) != 0) {
|
|
407 |
pa_log_debug ("Getting volume failed");
|
|
408 |
return -1;
|
|
409 |
}
|
|
410 |
|
|
411 |
pa_cvolume_reset(volume, ss->channels);
|
|
412 |
|
|
413 |
oss4_mixer_slider_unpack_volume (mixext, v, volume);
|
|
414 |
|
|
415 |
return 0;
|
|
416 |
}
|
|
417 |
|
|
418 |
int pa_oss_set_volume(int fd, oss_mixext *mixext, const pa_sample_spec *ss, const pa_cvolume *volume) {
|
|
419 |
int val = 0;
|
|
420 |
|
|
421 |
val = oss4_mixer_slider_pack_volume (mixext, ss->channels, volume);
|
|
422 |
|
|
423 |
if (oss4_mixer_set_control_val (fd, mixext, val) != 0) {
|
|
424 |
pa_log_debug ("Setting volume failed");
|
|
425 |
return -1;
|
|
426 |
}
|
|
427 |
|
|
428 |
return 0;
|
|
429 |
}
|
|
430 |
|
|
431 |
#else
|
|
432 |
|
249 |
433 |
int pa_oss_get_volume(int fd, unsigned long mixer, const pa_sample_spec *ss, pa_cvolume *volume) {
|
250 |
434 |
char cv[PA_CVOLUME_SNPRINT_VERBOSE_MAX];
|
251 |
435 |
unsigned vol;
|
... | ... | |
288 |
472 |
pa_log_debug("Wrote mixer settings: %s", pa_cvolume_snprint(cv, sizeof(cv), volume));
|
289 |
473 |
return 0;
|
290 |
474 |
}
|
|
475 |
#endif
|
291 |
476 |
|
292 |
477 |
static int get_device_number(const char *dev) {
|
293 |
|
const char *p, *e;
|
|
478 |
const char *p;
|
294 |
479 |
char *rp = NULL;
|
295 |
480 |
int r;
|
296 |
481 |
|
297 |
|
if (!(p = rp = pa_readlink(dev))) {
|
|
482 |
p = strchr(dev, '\0') - 1;
|
|
483 |
|
|
484 |
if (*p >= '0' && *p <= '9') {
|
|
485 |
p = dev;
|
|
486 |
}
|
|
487 |
else {
|
|
488 |
/* We need to resolve the symlink */
|
|
489 |
if (!(p = rp = pa_readlink(dev))) {
|
298 |
490 |
#ifdef ENOLINK
|
299 |
|
if (errno != EINVAL && errno != ENOLINK) {
|
|
491 |
if (errno != EINVAL && errno != ENOLINK) {
|
300 |
492 |
#else
|
301 |
|
if (errno != EINVAL) {
|
|
493 |
if (errno != EINVAL) {
|
302 |
494 |
#endif
|
303 |
|
r = -1;
|
304 |
|
goto finish;
|
305 |
|
}
|
|
495 |
r = -1;
|
|
496 |
goto finish;
|
|
497 |
}
|
306 |
498 |
|
307 |
|
p = dev;
|
|
499 |
}
|
308 |
500 |
}
|
309 |
501 |
|
310 |
|
if ((e = strrchr(p, '/')))
|
311 |
|
p = e+1;
|
|
502 |
p = strchr(p, '\0') - 1;
|
312 |
503 |
|
313 |
|
if (p == 0) {
|
314 |
|
r = 0;
|
315 |
|
goto finish;
|
316 |
|
}
|
317 |
|
|
318 |
|
p = strchr(p, 0) -1;
|
319 |
|
|
320 |
504 |
if (*p >= '0' && *p <= '9') {
|
321 |
505 |
r = *p - '0';
|
322 |
506 |
goto finish;
|
... | ... | |
329 |
513 |
return r;
|
330 |
514 |
}
|
331 |
515 |
|
|
516 |
int pa_oss_get_device_number(const char *dev) {
|
|
517 |
return (get_device_number(dev));
|
|
518 |
}
|
|
519 |
|
332 |
520 |
int pa_oss_get_hw_description(const char *dev, char *name, size_t l) {
|
333 |
521 |
FILE *f;
|
334 |
522 |
int n, r = -1;
|
... | ... | |
357 |
545 |
line[strcspn(line, "\r\n")] = 0;
|
358 |
546 |
|
359 |
547 |
if (!b) {
|
360 |
|
b = pa_streq(line, "Audio devices:");
|
|
548 |
b = pa_streq(line, "Audio Devices:");
|
361 |
549 |
continue;
|
362 |
550 |
}
|
363 |
551 |
|
... | ... | |
386 |
574 |
return r;
|
387 |
575 |
}
|
388 |
576 |
|
389 |
|
static int open_mixer(const char *mixer) {
|
|
577 |
int pa_oss_open_mixer(const char *mixer) {
|
390 |
578 |
int fd;
|
391 |
579 |
|
|
580 |
pa_log_debug ("Opening device %s", mixer);
|
|
581 |
|
392 |
582 |
if ((fd = pa_open_cloexec(mixer, O_RDWR|O_NDELAY, 0)) >= 0)
|
393 |
583 |
return fd;
|
394 |
584 |
|
... | ... | |
400 |
590 |
char *fn;
|
401 |
591 |
int fd;
|
402 |
592 |
|
403 |
|
if ((n = get_device_number(device)) < 0)
|
|
593 |
if ((n = get_device_number(device)) < 0) {
|
|
594 |
pa_log_warn ("Cannot find number for device '%s'", device);
|
404 |
595 |
return -1;
|
|
596 |
}
|
405 |
597 |
|
406 |
|
if (n == 0)
|
407 |
|
if ((fd = open_mixer("/dev/mixer")) >= 0)
|
408 |
|
return fd;
|
409 |
|
|
410 |
598 |
fn = pa_sprintf_malloc("/dev/mixer%i", n);
|
411 |
|
fd = open_mixer(fn);
|
|
599 |
fd = pa_oss_open_mixer(fn);
|
412 |
600 |
pa_xfree(fn);
|
413 |
601 |
|
414 |
602 |
if (fd < 0)
|
415 |
|
-- pulseaudio-13.0/src/modules/oss/oss-util.h-orig Fri Jul 13 14:06:14 2018
|
|
603 |
++ pulseaudio-13.0/src/modules/oss/oss-util.h Tue Sep 8 11:08:51 2020
|
... | ... | |
29 |
29 |
|
30 |
30 |
int pa_oss_set_fragments(int fd, int frags, int frag_size);
|
31 |
31 |
|
|
32 |
#define HAVE_OSSV4
|
|
33 |
|
|
34 |
#ifdef HAVE_OSSV4
|
|
35 |
int pa_oss_set_volume(int fd, oss_mixext *mixext, const pa_sample_spec *ss, const pa_cvolume *volume);
|
|
36 |
int pa_oss_get_volume(int fd, oss_mixext *mixext, const pa_sample_spec *ss, pa_cvolume *volume);
|
|
37 |
|
|
38 |
#else
|
|
39 |
|
32 |
40 |
int pa_oss_set_volume(int fd, unsigned long mixer, const pa_sample_spec *ss, const pa_cvolume *volume);
|
33 |
41 |
int pa_oss_get_volume(int fd, unsigned long mixer, const pa_sample_spec *ss, pa_cvolume *volume);
|
|
42 |
#endif
|
34 |
43 |
|
35 |
44 |
int pa_oss_get_hw_description(const char *dev, char *name, size_t l);
|
36 |
45 |
|
|
46 |
int pa_oss_get_device_number(const char *dev);
|
37 |
47 |
int pa_oss_open_mixer_for_device(const char *device);
|
|
48 |
int pa_oss_open_mixer(const char *device);
|
38 |
49 |
|
39 |
50 |
#endif
|