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