Release 971101
[wine] / multimedia / mixer.c
1 /*
2  * Sample MIXER Wine Driver for Linux
3  *
4  * Copyright 1997 Marcus Meissner
5  */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <sys/ioctl.h>
12 #include "windows.h"
13 #include "user.h"
14 #include "driver.h"
15 #include "mmsystem.h"
16
17 #ifdef linux
18 #include <linux/soundcard.h>
19 #elif __FreeBSD__
20 #include <machine/soundcard.h>
21 #endif
22
23 #include "stddebug.h"
24 #include "debug.h"
25
26 #define MIXER_DEV "/dev/mixer"
27
28 #ifdef SOUND_VERSION
29 #define IOCTL(a,b,c)            ioctl(a,b,&c)
30 #else
31 #define IOCTL(a,b,c)            (c = ioctl(a,b,c) )
32 #endif
33
34
35 /**************************************************************************
36  *                              MIX_GetDevCaps                  [internal]
37  */
38 static DWORD MIX_GetDevCaps(WORD wDevID, LPMIXERCAPS16 lpCaps, DWORD dwSize)
39 {
40 #ifdef linux
41         int             mixer,mask;
42         struct  mixer_info      mi;
43
44         dprintf_mmaux(stddeb,"MIX_GetDevCaps(%04X, %p, %lu);\n", wDevID, lpCaps, dwSize);
45         if (lpCaps == NULL) return MMSYSERR_NOTENABLED;
46         if ((mixer = open(MIXER_DEV, O_RDWR)) < 0) {
47                 dprintf_mmaux(stddeb,"MIX_GetDevCaps // mixer device not available !\n");
48                 return MMSYSERR_NOTENABLED;
49         }
50         if (ioctl(mixer, SOUND_MIXER_INFO, &mi) == -1) {
51                 close(mixer);
52                 perror("ioctl mixer SOUND_MIXER_INFO");
53                 return MMSYSERR_NOTENABLED;
54         }
55         fprintf(stderr,"SOUND_MIXER_INFO returns { \"%s\",\"%s\" }\n",mi.id,mi.name);
56         lpCaps->wMid = 0xAA;
57         lpCaps->wPid = 0x55;
58         lpCaps->vDriverVersion = 0x0100;
59         strcpy(lpCaps->szPname,mi.name);
60         if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &mask) == -1) {
61                 close(mixer);
62                 perror("ioctl mixer SOUND_MIXER_DEVMASK");
63                 return MMSYSERR_NOTENABLED;
64         }
65         /* FIXME: can the Linux Mixer differ between multiple mixertargets? */
66         lpCaps->cDestinations = 1;
67         lpCaps->fdwSupport = 0; /* No bits defined yet */
68
69         close(mixer);
70         return MMSYSERR_NOERROR;
71 #else
72         return MMSYSERR_NOTENABLED;
73 #endif
74 }
75
76 #ifdef linux
77 static char *sdlabels[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_LABELS;
78 static char *sdnames[SOUND_MIXER_NRDEVICES] = SOUND_DEVICE_NAMES;
79 #endif
80
81 /**************************************************************************
82  *                              MIX_GetLineInfo                 [internal]
83  */
84 static DWORD MIX_GetLineInfo(WORD wDevID, LPMIXERLINE16 lpml, DWORD fdwInfo)
85 {
86 #ifdef linux
87         int             mixer,i,j,devmask,recsrc,recmask;
88
89         dprintf_mmaux(stddeb,"MIX_GetDevLineInfo(%04X, %p, %lu);\n", wDevID, lpml, fdwInfo);
90         if (lpml == NULL) return MMSYSERR_NOTENABLED;
91         if ((mixer = open(MIXER_DEV, O_RDWR)) < 0)
92                 return MMSYSERR_NOTENABLED;
93
94         if (ioctl(mixer, SOUND_MIXER_READ_DEVMASK, &devmask) == -1) {
95                 close(mixer);
96                 perror("ioctl mixer SOUND_MIXER_DEVMASK");
97                 return MMSYSERR_NOTENABLED;
98         }
99         if (ioctl(mixer, SOUND_MIXER_READ_RECSRC, &recsrc) == -1) {
100                 close(mixer);
101                 perror("ioctl mixer SOUND_MIXER_RECSRC");
102                 return MMSYSERR_NOTENABLED;
103         }
104         if (ioctl(mixer, SOUND_MIXER_READ_RECMASK, &recmask) == -1) {
105                 close(mixer);
106                 perror("ioctl mixer SOUND_MIXER_RECMASK");
107                 return MMSYSERR_NOTENABLED;
108         }
109         lpml->cbStruct = sizeof(MIXERLINE16);
110         /* FIXME: set all the variables correctly... the lines below
111          * are very wrong...
112          */
113         lpml->fdwLine   = MIXERLINE_LINEF_ACTIVE;
114         lpml->cChannels = 2;
115
116         switch (fdwInfo & MIXER_GETLINEINFOF_QUERYMASK) {
117         case MIXER_GETLINEINFOF_DESTINATION:
118                 /* FIXME: Linux doesn't seem to support multiple outputs? 
119                  * So we have only one outputtype, Speaker.
120                  */
121                 lpml->dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
122                 /* we have all connections found in the devmask */
123                 lpml->cConnections = 0;
124                 for (j=0;j<31;j++)
125                         if (devmask & (1<<j))
126                                 lpml->cConnections++;
127                 break;
128         case MIXER_GETLINEINFOF_SOURCE:
129                 for (i=j=0;j<31;j++) {
130                         if (devmask & (1<<j)) {
131                                 if (lpml->dwSource == i)
132                                         break;
133                                 i++;
134                         }
135                 }
136                 strcpy(lpml->szShortName,sdlabels[i]);
137                 strcpy(lpml->szName,sdnames[i]);
138                 lpml->dwLineID = i;
139                 switch (i) {
140                 case SOUND_MIXER_SYNTH:
141                         lpml->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_SYNTHESIZER;
142                         lpml->fdwLine   |= MIXERLINE_LINEF_SOURCE;
143                         break;
144                 case SOUND_MIXER_CD:
145                         lpml->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_COMPACTDISC;
146                         lpml->fdwLine   |= MIXERLINE_LINEF_SOURCE;
147                         break;
148                 case SOUND_MIXER_LINE:
149                         lpml->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
150                         lpml->fdwLine   |= MIXERLINE_LINEF_SOURCE;
151                         break;
152                 case SOUND_MIXER_MIC:
153                         lpml->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
154                         lpml->fdwLine   |= MIXERLINE_LINEF_SOURCE;
155                         break;
156                 case SOUND_MIXER_PCM:
157                         lpml->dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
158                         lpml->fdwLine   |= MIXERLINE_LINEF_SOURCE;
159                         break;
160                 default:
161                         fprintf(stderr,"MIX_GetLineInfo:mixertype %d not handle.\n",i);
162                         break;
163                 }
164                 break;
165         case MIXER_GETLINEINFOF_LINEID:
166                 fprintf(stderr,"MIX_GetLineInfo: _LINEID (%ld) not implemented yet.\n",lpml->dwLineID);
167                 break;
168         case MIXER_GETLINEINFOF_COMPONENTTYPE:
169                 fprintf(stderr,"MIX_GetLineInfo: _COMPONENTTYPE not implemented yet.\n");
170                 break;
171         case MIXER_GETLINEINFOF_TARGETTYPE:
172                 fprintf(stderr,"MIX_GetLineInfo: _TARGETTYPE not implemented yet.\n");
173                 break;
174         }
175         lpml->Target.dwType = MIXERLINE_TARGETTYPE_AUX;
176         close(mixer);
177         return MMSYSERR_NOERROR;
178 #else
179         return MMSYSERR_NOTENABLED;
180 #endif
181 }
182
183 /**************************************************************************
184  *                              MIX_GetLineInfo                 [internal]
185  */
186 static DWORD MIX_Open(WORD wDevID, LPMIXEROPENDESC lpmod, DWORD flags)
187 {
188 #ifdef linux
189
190         dprintf_mmaux(stddeb,"MIX_Open(%04X, %p, %lu);\n",wDevID,lpmod,flags);
191         if (lpmod == NULL) return MMSYSERR_NOTENABLED;
192         /* hmm. We don't keep the mixer device open. So just pretend it works */
193         return MMSYSERR_NOERROR;
194 #else
195         return MMSYSERR_NOTENABLED;
196 #endif
197 }
198
199 /**************************************************************************
200  *                              mixMessage                      [sample driver]
201  */
202 DWORD mixMessage(WORD wDevID, WORD wMsg, DWORD dwUser, 
203                                         DWORD dwParam1, DWORD dwParam2)
204 {
205         dprintf_mmaux(stddeb,"mixMessage(%04X, %04X, %08lX, %08lX, %08lX);\n", 
206                         wDevID, wMsg, dwUser, dwParam1, dwParam2);
207         switch(wMsg) {
208         case MXDM_GETDEVCAPS:
209                 return MIX_GetDevCaps(wDevID,(LPMIXERCAPS16)dwParam1,dwParam2);
210         case MXDM_GETLINEINFO:
211                 return MIX_GetLineInfo(wDevID,(LPMIXERLINE16)dwParam1,dwParam2);
212         case MXDM_GETNUMDEVS:
213                 dprintf_mmsys(stddeb,"MIX_GetNumDevs() return 1;\n");
214                 return 1;
215         case MXDM_OPEN:
216                 return MIX_Open(wDevID,(LPMIXEROPENDESC)dwParam1,dwParam2);
217         default:
218                 dprintf_mmaux(stddeb,"mixMessage // unknown message %d!\n",wMsg);
219         }
220         return MMSYSERR_NOTSUPPORTED;
221 }