1 /* Sysdep Solaris sound dsp 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 and on the old xmame sound driver done by
23 Juan Antonio Martinez, Keith Hargrove, Mathis Rosenhauer and others.
24 (Mathis Rosenhauer)
25 */
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include <sys/types.h>
32 #include <sys/conf.h>
33 #include <sys/stat.h>
34 #include <sys/ioctl.h>
35 #include <sys/stropts.h>
36 #include <sys/audioio.h>
37 #include "sysdep/sysdep_dsp.h"
38 #include "sysdep/sysdep_dsp_priv.h"
39 #include "sysdep/plugin_manager.h"
40
41 /* our per instance private data struct */
42 struct sol_dsp_priv_data {
43 int fd;
44 unsigned int samples_written;
45 unsigned int buffer_samples;
46 };
47
48 /* public methods prototypes (static but exported through the sysdep_dsp or
49 plugin struct) */
50 static void *sol_dsp_create(const void *flags);
51 static void sol_dsp_destroy(struct sysdep_dsp_struct *dsp);
52 static int sol_dsp_get_freespace(struct sysdep_dsp_struct *dsp);
53 static int sol_dsp_write(struct sysdep_dsp_struct *dsp, unsigned char *data,
54 int count);
55
56 /* public variables */
57 const struct plugin_struct sysdep_dsp_solaris = {
58 "solaris",
59 "sysdep_dsp",
60 "Solaris DSP plugin",
61 NULL, /* no options */
62 NULL, /* no init */
63 NULL, /* no exit */
64 sol_dsp_create,
65 3 /* high priority */
66 };
67
68 /* private variables */
69 static int sol_dsp_bytes_per_sample[4] = SYSDEP_DSP_BYTES_PER_SAMPLE;
70
71 /* public methods (static but exported through the sysdep_dsp or plugin
72 struct) */
sol_dsp_create(const void * flags)73 static void *sol_dsp_create(const void *flags)
74 {
75 int i,j;
76 audio_info_t info; /* info about audio settings */
77 audio_device_t dev; /* info about audio hardware */
78 struct sol_dsp_priv_data *priv = NULL;
79 struct sysdep_dsp_struct *dsp = NULL;
80 const struct sysdep_dsp_create_params *params = flags;
81 const char *device = params->device;
82
83 /* allocate the dsp struct */
84 if (!(dsp = calloc(1, sizeof(struct sysdep_dsp_struct))))
85 {
86 perror("error malloc failed for struct sysdep_dsp_struct\n");
87 return NULL;
88 }
89
90 /* alloc private data */
91 if(!(priv = calloc(1, sizeof(struct sol_dsp_priv_data))))
92 {
93 perror("error malloc failed for struct sol_dsp_priv_data\n");
94 sol_dsp_destroy(dsp);
95 return NULL;
96 }
97
98 /* fill in the functions and some data */
99 priv->fd = -1;
100 priv->samples_written = 0;
101 dsp->_priv = priv;
102 dsp->get_freespace = sol_dsp_get_freespace;
103 dsp->write = sol_dsp_write;
104 dsp->destroy = sol_dsp_destroy;
105 dsp->hw_info.type = params->type;
106 dsp->hw_info.samplerate = params->samplerate;
107
108 /* open the sound device */
109 if (!device)
110 device = getenv("AUDIODEV");
111 if (!device)
112 device = "/dev/audio";
113
114 if((priv->fd = open(device, O_WRONLY)) < 0)
115 {
116 fprintf(stderr, "error: opening %s\n", device);
117 sol_dsp_destroy(dsp);
118 return NULL;
119 }
120
121 /* empty buffers before change config */
122 ioctl(priv->fd, AUDIO_DRAIN, 0); /* drain everything out */
123 ioctl(priv->fd, I_FLUSH, FLUSHRW); /* flush everything */
124
125 /* identify audio device. */
126 if(ioctl(priv->fd, AUDIO_GETDEV, &dev) < 0)
127 {
128 perror("error: cannot get sound device type\n");
129 sol_dsp_destroy(dsp);
130 return NULL;
131 }
132
133 fprintf(stderr, "info: sound device is a %s %s version %s\n",dev.config,dev.name,dev.version);
134
135 /* get audio parameters. */
136 if (ioctl(priv->fd, AUDIO_GETINFO, &info) < 0)
137 {
138 perror("AUDIO_GETINFO failed!\nRun with -nosound\n");
139 sol_dsp_destroy(dsp);
140 return NULL;
141 }
142
143 /* set the number of bits */
144 AUDIO_INITINFO(&info);
145
146 if (dsp->hw_info.type & SYSDEP_DSP_16BIT)
147 {
148 info.play.encoding = i = AUDIO_ENCODING_LINEAR;
149 info.play.precision = j = 16;
150 }
151 else
152 {
153 info.play.encoding = i = AUDIO_ENCODING_LINEAR8;
154 info.play.precision = j = 8;
155 }
156
157 if (ioctl(priv->fd, AUDIO_SETINFO, &info) < 0)
158 {
159 perror("error: AUDIO_SETINFO\n");
160 sol_dsp_destroy(dsp);
161 return NULL;
162 }
163 if ((info.play.encoding != i) || (info.play.precision != j))
164 {
165 if(dsp->hw_info.type & SYSDEP_DSP_16BIT)
166 {
167 fprintf(stderr, "warning: couldn't set sound to 16 bits,\ntrying again with 8 bits: ");
168 }
169 else
170 {
171 fprintf(stderr, "error: couldn't set sound to 8 bits,\n");
172 sol_dsp_destroy(dsp);
173 return NULL;
174 }
175 dsp->hw_info.type &= ~SYSDEP_DSP_16BIT;
176 info.play.precision = 8;
177 info.play.encoding = AUDIO_ENCODING_LINEAR8;
178 if (ioctl(priv->fd, AUDIO_SETINFO, &info) < 0)
179 {
180 perror("error: AUDIO_SETINFO\n");
181 sol_dsp_destroy(dsp);
182 return NULL;
183 }
184 if (info.play.precision != 8 || info.play.encoding != AUDIO_ENCODING_LINEAR8)
185 {
186 fprintf(stderr, "failed\n");
187 sol_dsp_destroy(dsp);
188 return NULL;
189 }
190 fprintf(stderr, "success\n");
191 }
192
193 /* set the number of channels */
194 info.play.channels = (dsp->hw_info.type & SYSDEP_DSP_STEREO)? 2:1;
195 if (ioctl(priv->fd, AUDIO_SETINFO, &info) < 0)
196 {
197 perror("error: AUDIO_SETINFO\n");
198 sol_dsp_destroy(dsp);
199 return NULL;
200 }
201 if(info.play.channels == 2)
202 dsp->hw_info.type |= SYSDEP_DSP_STEREO;
203 else
204 dsp->hw_info.type &= ~SYSDEP_DSP_STEREO;
205
206 /* set the samplerate and buffer size*/
207 info.play.sample_rate = dsp->hw_info.samplerate;
208 priv->buffer_samples = dsp->hw_info.samplerate * params->bufsize;
209 info.play.buffer_size = dsp->hw_info.bufsize = priv->buffer_samples * sol_dsp_bytes_per_sample[dsp->hw_info.type]; /* this seems to have no effect */
210 if (ioctl(priv->fd, AUDIO_SETINFO, &info) < 0)
211 {
212 perror("error: AUDIO_SETINFO\n");
213 sol_dsp_destroy(dsp);
214 return NULL;
215 }
216
217 dsp->hw_info.samplerate = info.play.sample_rate;
218 fprintf(stderr, "info: audiodevice %s set to %dbit linear %s %dHz\n",
219 dev.name, info.play.precision,
220 (info.play.channels & 2)? "stereo":"mono",
221 info.play.sample_rate);
222
223 return dsp;
224 }
225
sol_dsp_destroy(struct sysdep_dsp_struct * dsp)226 static void sol_dsp_destroy(struct sysdep_dsp_struct *dsp)
227 {
228 struct sol_dsp_priv_data *priv = dsp->_priv;
229
230 if(priv)
231 {
232 if(priv->fd >= 0)
233 close(priv->fd);
234 free(priv);
235 }
236 free(dsp);
237 }
238
sol_dsp_get_freespace(struct sysdep_dsp_struct * dsp)239 static int sol_dsp_get_freespace(struct sysdep_dsp_struct *dsp)
240 {
241 audio_info_t info;
242 struct sol_dsp_priv_data *priv = dsp->_priv;
243
244 if (ioctl(priv->fd, AUDIO_GETINFO, &info) < 0)
245 {
246 perror("error: AUDIO_GETINFO\n");
247 return -1;
248 }
249 return priv->buffer_samples - (priv->samples_written - info.play.samples);
250 }
251
sol_dsp_write(struct sysdep_dsp_struct * dsp,unsigned char * data,int count)252 static int sol_dsp_write(struct sysdep_dsp_struct *dsp, unsigned char *data, int count)
253 {
254 int result;
255 struct sol_dsp_priv_data *priv = dsp->_priv;
256 result = write(priv->fd, data, count * sol_dsp_bytes_per_sample[dsp->hw_info.type]);
257
258 if (result < 0)
259 return -1;
260
261 result /= sol_dsp_bytes_per_sample[dsp->hw_info.type];
262 priv->samples_written += result;
263 return result;
264 }
265