1 /*
2 *
3 * ao_aixs.c AIX (5.1)
4 *
5 * Original Copyright (C) Stefan Tibus - August 2002
6 *
7 * libao is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
10 * any later version.
11 *
12 * libao is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Make; see the file COPYING. If not, write to
19 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 ********************************************************************
22
23 last mod: $Id: ao_aixs.c 17718 2010-12-06 20:09:29Z xiphmont $
24
25 ********************************************************************/
26
27 #ifdef HAVE_SYS_AUDIO_H
28
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/audio.h>
38
39 #include <ao/ao.h>
40 #include <ao/plugin.h>
41
42
43 /*
44 * default audio device to be used,
45 * possible options:
46 * /dev/paud0/1 on PCI machines with the Crystal chipset
47 * /dev/baud0/1 on MCA machines with the Crystal chipset
48 * /dev/acpa0/1 on MCA machines with the ACPA
49 */
50 #ifndef AO_AIX_DEFAULT_DEV
51 #define AO_AIX_DEFAULT_DEV "/dev/baud0/1"
52 #define AO_AIX_DEFAULT_DEV2 "/dev/paud0/1"
53 #define AO_AIX_DEFAULT_DEV3 "/dev/acpa0/1"
54 #endif
55
56
57 static char *ao_aixs_options[] = {"dev","id","matrix","verbose","quiet","debug"};
58 ao_info ao_aixs_info = {
59 AO_TYPE_LIVE,
60 "AIX audio driver output",
61 "aixs",
62 "Stefan Tibus <sjti@gmx.net>",
63 "Outputs to the AIX audio system.",
64 AO_FMT_NATIVE,
65 20,
66 ao_aixs_options,
67 sizeof(ao_aixs_options)/sizeof(*ao_aixs_options)
68 };
69
70
71 typedef struct ao_aixs_internal {
72 char *dev;
73 int id;
74 int fd;
75 } ao_aixs_internal;
76
77
ao_aixs_test()78 int ao_aixs_test()
79 {
80 int fd;
81
82 fd = open(AO_AIX_DEFAULT_DEV, O_WRONLY);
83 if(fd<0)
84 fd = open(AO_AIX_DEFAULT_DEV2, O_WRONLY);
85 if(fd<0)
86 fd = open(AO_AIX_DEFAULT_DEV3, O_WRONLY);
87 if(fd<0)
88 return 0; /* Cannot use this plugin with default parameters */
89
90 close(fd);
91 return 1; /* This plugin works in default mode */
92 }
93
94
ao_aixs_driver_info(void)95 ao_info *ao_aixs_driver_info(void)
96 {
97 return &ao_aixs_info;
98 }
99
100
ao_aixs_device_init(ao_device * device)101 int ao_aixs_device_init(ao_device *device)
102 {
103 ao_aixs_internal *internal;
104
105 internal = (ao_aixs_internal *) calloc(1,sizeof(ao_aixs_internal));
106
107 if (internal == NULL)
108 return 0; /* Could not initialize device memory */
109
110 device->internal = internal;
111 device->output_matrix_order = AO_OUTPUT_MATRIX_FIXED;
112
113 return 1; /* Memory alloc successful */
114 }
115
ao_aixs_set_option(ao_device * device,const char * key,const char * value)116 int ao_aixs_set_option(ao_device *device, const char *key, const char *value)
117 {
118 ao_aixs_internal *internal = (ao_aixs_internal *) device->internal;
119
120 if (!strcmp(key, "dev")) {
121 if(internal->dev)
122 free(internal->dev);
123 internal->dev = strdup(value);
124 }
125 if (!strcmp(key, "id")) {
126 internal->id = atoi(value);
127 if(internal->dev)
128 free(internal->dev);
129 internal->dev = NULL;
130 }
131
132 return 1;
133 }
134
135
ao_aixs_open(ao_device * device,ao_sample_format * format)136 int ao_aixs_open(ao_device *device, ao_sample_format *format)
137 {
138 ao_aixs_internal *internal = (ao_aixs_internal *) device->internal;
139
140 audio_init init;
141 audio_control control;
142 audio_change change;
143
144 if(!internal->dev){
145 char buffer[80];
146 int fd;
147
148 sprintf(buffer,"/dev/baud%d/1",id);
149 fd = open(buffer, O_WRONLY);
150 if(fd<0){
151 sprintf(buffer,"/dev/paud%d/1",id);
152 fd = open(buffer, O_WRONLY);
153 }
154 if(fd<0){
155 sprintf(buffer,"/dev/acpa%d/1",id);
156 fd = open(buffer, O_WRONLY);
157 }
158 if(fd<0) return 0;
159 internal->fd = fd;
160 internal->dev = strdup(buffer);
161 }else
162 if ( (internal->fd = open(internal->dev, O_WRONLY)) < 0 )
163 return 0;
164
165 init.srate = format->rate;
166 init.bits_per_sample = format->bits;
167 init.channels = device->output_channels;
168 init.mode = AUDIO_PCM;
169 init.flags = AUDIO_BIG_ENDIAN | AUDIO_TWOS_COMPLEMENT;
170 init.operation = AUDIO_PLAY;
171
172 if (ioctl(internal->fd, AUDIO_INIT, &init) < 0) {
173 close(internal->fd);
174 return 0; /* Unsupported audio format */
175 }
176
177 change.balance = 0x3fff0000;
178 change.volume = 0x3fff0000;
179 change.monitor = AUDIO_IGNORE;
180 change.input = AUDIO_IGNORE;
181 change.output = AUDIO_OUTPUT_1;
182
183 control.ioctl_request = AUDIO_CHANGE;
184 control.position = 0;
185 control.request_info = &change;
186
187 if (ioctl(internal->fd, AUDIO_CONTROL, &control) < 0) {
188 close(internal->fd);
189 return 0;
190 }
191
192 control.ioctl_request = AUDIO_START;
193 control.request_info = NULL;
194
195 if (ioctl(internal->fd, AUDIO_CONTROL, &control) < 0) {
196 close(internal->fd);
197 return 0;
198 }
199
200 device->driver_byte_format = AO_FMT_NATIVE;
201 if(!device->inter_matrix){
202 /* set up matrix such that users are warned about > stereo playback */
203 if(device->output_channels<=2)
204 device->inter_matrix=strdup("L,R");
205 //else no matrix, which results in a warning
206 }
207
208 return 1;
209 }
210
211
ao_aixs_play(ao_device * device,const char * output_samples,uint_32 num_bytes)212 int ao_aixs_play(ao_device *device, const char *output_samples,
213 uint_32 num_bytes)
214 {
215 ao_aixs_internal *internal = (ao_aixs_internal *) device->internal;
216
217 if (write(internal->fd, output_samples, num_bytes) < 0)
218 return 0;
219 else
220 return 1;
221 }
222
223
ao_aixs_close(ao_device * device)224 int ao_aixs_close(ao_device *device)
225 {
226 ao_aixs_internal *internal = (ao_aixs_internal *) device->internal;
227
228 if(internal->fd)
229 close(internal->fd);
230 internal->fd=-1;
231 return 1;
232 }
233
234
ao_aixs_device_clear(ao_device * device)235 void ao_aixs_device_clear(ao_device *device)
236 {
237 ao_aixs_internal *internal = (ao_aixs_internal *) device->internal;
238
239 if(internal->dev)
240 free(internal->dev);
241 free(internal);
242 device->internal = NULL;
243 }
244
245 ao_functions ao_aixs = {
246 ao_aixs_test,
247 ao_aixs_driver_info,
248 ao_aixs_device_init,
249 ao_aixs_set_option,
250 ao_aixs_open,
251 ao_aixs_play,
252 ao_aixs_close,
253 ao_aixs_device_clear
254 };
255
256 #endif
257