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