1 /* Sysdep Open Sound System sound mixer driver
2 
3    Copyright 2000 Hans de Goede, Mathis Rosenhauer
4 
5    This file and the acompanying files in this directory are free software;
6    you can redistribute them and/or modify them under the terms of the GNU
7    Library General Public License as published by the Free Software Foundation;
8    either version 2 of the License, or (at your option) any later version.
9 
10    These files are distributed in the hope that they will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public
16    License along with these files; see the file COPYING.LIB.  If not,
17    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18    Boston, MA 02111-1307, USA.
19 */
20 /* Changelog
21 Version 0.1, February 2000
22 -initial release based on oss.c by Hans de Goede (Mathis Rosenhauer)
23 */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <sys/ioctl.h>
31 #include <sys/stropts.h>
32 #include <sys/audioio.h>
33 #include "sysdep/sysdep_mixer.h"
34 #include "sysdep/sysdep_mixer_priv.h"
35 #include "sysdep/plugin_manager.h"
36 
37 /* our per instance private data struct */
38 struct sol_mixer_priv_data {
39 	int fd;
40 };
41 
42 /* public methods prototypes (static but exported through the sysdep_mixer or
43    plugin struct) */
44 static void *sol_mixer_create(const void *flags);
45 static void sol_mixer_destroy(struct sysdep_mixer_struct *mixer);
46 static int sol_mixer_set(struct sysdep_mixer_struct *mixer,
47 						 int channel, int left, int right);
48 static int sol_mixer_get(struct sysdep_mixer_struct *mixer,
49 						 int channel, int *left, int *right);
50 
51 /* public variables */
52 const struct plugin_struct sysdep_mixer_solaris = {
53 	"solaris",
54 	"sysdep_mixer",
55 	"Solaris mixer plugin",
56 	NULL, /* no options */
57 	NULL, /* no init */
58 	NULL, /* no exit */
59 	sol_mixer_create,
60 	3	  /* high priority */
61 };
62 
63 /* public methods (static but exported through the sysdep_mixer or plugin
64    struct) */
sol_mixer_create(const void * flags)65 static void *sol_mixer_create(const void *flags)
66 {
67 	struct sol_mixer_priv_data *priv = NULL;
68 	struct sysdep_mixer_struct *mixer = NULL;
69 	const struct sysdep_mixer_create_params *params = flags;
70 	const char *device = params->device;
71 
72 	/* allocate the mixer struct */
73 	if (!(mixer = calloc(1, sizeof(struct sysdep_mixer_struct))))
74 	{
75 		perror("error malloc failed for struct sysdep_mixer_struct\n");
76 		return NULL;
77 	}
78 
79 	/* alloc private data */
80 	if(!(priv = calloc(1, sizeof(struct sol_mixer_priv_data))))
81 	{
82 		perror("error malloc failed for struct sol_mixer_priv_data\n");
83 		sol_mixer_destroy(mixer);
84 		return NULL;
85 	}
86 
87 	/* fill in the functions and some data */
88 	priv->fd = -1;
89 	mixer->_priv = priv;
90 	mixer->set = sol_mixer_set;
91 	mixer->get = sol_mixer_get;
92 	mixer->destroy = sol_mixer_destroy;
93 
94 	/* open the mixer device */
95 	if (!device)
96 		device = getenv("AUDIODEV");
97 	if (!device)
98 		device = "/dev/audioctl";
99 
100 	if((priv->fd = open(device, O_RDWR)) < 0) {
101 		fprintf(stderr, "error: opening %s\n", device);
102 		sol_mixer_destroy(mixer);
103 		return NULL;
104 	}
105 
106 	/* are there more channels on other hardware as dbri? */
107 	mixer->channel_available[SYSDEP_MIXER_PCM1] = 1;
108 	return mixer;
109 }
110 
sol_mixer_destroy(struct sysdep_mixer_struct * mixer)111 static void sol_mixer_destroy(struct sysdep_mixer_struct *mixer)
112 {
113 	struct sol_mixer_priv_data *priv = mixer->_priv;
114 
115 	if(priv)
116 	{
117 		if(priv->fd >= 0)
118 			close(priv->fd);
119 
120 		free(priv);
121 	}
122 	free(mixer);
123 }
124 
sol_mixer_set(struct sysdep_mixer_struct * mixer,int channel,int left,int right)125 static int sol_mixer_set(struct sysdep_mixer_struct *mixer, int channel, int left, int right)
126 {
127 	audio_info_t info;
128 	struct sol_mixer_priv_data *priv = mixer->_priv;
129 	int maxvol = (left > right)? left: right;
130 
131 	AUDIO_INITINFO(&info);
132 
133 	info.play.gain = (maxvol * (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)) / 100 + AUDIO_MIN_GAIN;
134 	if (maxvol)
135 	{
136 		info.play.balance = (right - left) * (AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE);
137 		info.play.balance /= 2 * maxvol;
138 		info.play.balance += AUDIO_MID_BALANCE;
139 	}
140 
141 	if (ioctl(priv->fd, AUDIO_SETINFO, &info) < 0)
142 	{
143 		perror("error: AUDIO_SETINFO\n");
144 		return -1;
145 	}
146 	return 0;
147 }
148 
sol_mixer_get(struct sysdep_mixer_struct * mixer,int channel,int * left,int * right)149 static int sol_mixer_get(struct sysdep_mixer_struct *mixer, int channel, int *left, int *right)
150 {
151 	audio_info_t info;
152 	struct sol_mixer_priv_data *priv = mixer->_priv;
153 
154 	if (ioctl(priv->fd, AUDIO_GETINFO, &info) < 0)
155 	{
156 		perror("error: AUDIO_GETINFO\n");
157 		return -1;
158 	}
159 
160 	if (info.play.balance > AUDIO_MID_BALANCE)
161 	{
162 		*right = ((info.play.gain - AUDIO_MIN_GAIN) * 100) / (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN);
163 		*left = *right * ((AUDIO_RIGHT_BALANCE - (float)info.play.balance) / AUDIO_MID_BALANCE);
164 	}
165 	else
166 	{
167 		*left = ((info.play.gain - AUDIO_MIN_GAIN) * 100) / (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN);
168 		*right = *left * ((float)info.play.balance / AUDIO_MID_BALANCE);
169 	}
170 	return 0;
171 }
172 
173