]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/oal_capture.cpp
work around OpenAL hang on Win when closing device in capture_init()
[taylor/freespace2.git] / src / sound / oal_capture.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9
10 #include <string>
11
12 #include "pstypes.h"
13 #include "oal.h"
14 #include "osregistry.h"
15
16
17 static int OAL_capture_recording = 0;
18
19 struct capture_buffer {
20         uint samples_per_second;
21         uint bits_per_sample;
22         uint n_channels;
23         uint block_align;
24
25         ALenum format;
26         ALsizei buffer_size;
27 };
28
29 static capture_buffer Capture;
30
31 static ALCdevice *al_capture_device = NULL;
32 static std::string CaptureDevice;
33
34
35 void oal_capture_release_buffer()
36 {
37         if (al_capture_device != NULL) {
38                 alcCaptureCloseDevice(al_capture_device);
39                 al_capture_device = NULL;
40         }
41 }
42
43 // create a capture buffer with the specified format
44 // exit:        0       ->              buffer created successfully
45 //                      !0      ->              error creating the buffer
46 int oal_capture_create_buffer(int freq, int bits_per_sample, int nchannels, int nseconds)
47 {
48         ALenum al_format = AL_FORMAT_MONO8;
49         ALsizei buf_size = freq * nseconds;
50
51         SDL_assert( (nchannels == 1) || (nchannels == 2) );
52         SDL_assert( (bits_per_sample == 8) || (bits_per_sample == 16) );
53
54         if ( !oal_is_initted() ) {
55                 return -1;
56         }
57
58         if (nchannels == 1) {
59                 if (bits_per_sample == 8)  {
60                         al_format = AL_FORMAT_MONO8;
61                 } else if (bits_per_sample == 16) {
62                         al_format = AL_FORMAT_MONO16;
63                 }
64         } else if (nchannels == 2) {
65                 if (bits_per_sample == 8) {
66                         al_format = AL_FORMAT_STEREO8;
67                 } else if (bits_per_sample == 16) {
68                         al_format = AL_FORMAT_STEREO16;
69                 }
70         }
71
72         al_capture_device = alcCaptureOpenDevice(CaptureDevice.c_str(), freq, al_format, buf_size);
73
74         if (al_capture_device == NULL) {
75                 return -1;
76         }
77
78         if ( alcGetError(al_capture_device) != ALC_NO_ERROR ) {
79                 alcCaptureCloseDevice(al_capture_device);
80
81                 return -1;
82         }
83
84         Capture.format = al_format;
85         Capture.bits_per_sample = bits_per_sample;
86         Capture.n_channels = nchannels;
87         Capture.samples_per_second = freq;
88         Capture.block_align = (nchannels * bits_per_sample) / 8;
89
90         return 0;
91 }
92
93 void oal_capture_init()
94 {
95         const char *ptr = NULL;
96         ALCdevice *tdevice = NULL;
97
98         ptr = os_config_read_string("Audio", "CaptureDevice", "default");
99
100         if ( ptr && !SDL_strcasecmp(ptr, "default") ) {
101                 ptr = NULL;
102         }
103
104         tdevice = alcCaptureOpenDevice(ptr, 11025, AL_FORMAT_MONO8, 11025 * 2);
105
106         if (tdevice == NULL) {
107                 tdevice = alcCaptureOpenDevice(NULL, 11025, AL_FORMAT_MONO8, 11025 * 2);
108
109                 if (tdevice == NULL) {
110                         mprintf(("  Capture device  : * Unavailable *\n"));
111
112                         return;
113                 }
114         }
115
116         if ( alcGetError(tdevice) != ALC_NO_ERROR ) {
117                 mprintf(("  Capture device  : * Unavailable *\n"));
118                 alcCaptureCloseDevice(tdevice);
119
120                 return;
121         }
122
123         ptr = alcGetString(tdevice, ALC_CAPTURE_DEVICE_SPECIFIER);
124         SDL_assert( ptr );
125
126         mprintf(("  Capture device  : %s\n", ptr));
127
128         CaptureDevice = ptr;
129
130         // this gets around hang-on-close bug on Windows
131         alcCaptureStart(tdevice);
132         alcCaptureStop(tdevice);
133
134         alcCaptureCloseDevice(tdevice);
135 }
136
137 int oal_capture_supported()
138 {
139         return oal_is_initted();
140 }
141
142 // start recording into the buffer
143 int oal_capture_start_record()
144 {
145         if ( !oal_is_initted() ) {
146                 return -1;
147         }
148
149         if (OAL_capture_recording) {
150                 return -1;
151         }
152
153         alcCaptureStart(al_capture_device);
154
155         OAL_capture_recording = 1;
156
157 //      nprintf(("Alan","RTVOICE => start record\n"));
158
159         return 0;
160 }
161
162 // stop recording into the buffer
163 int oal_capture_stop_record()
164 {
165         if ( !oal_is_initted() ) {
166                 return -1;
167         }
168
169         if ( !OAL_capture_recording ) {
170                 return -1;
171         }
172
173         alcCaptureStop(al_capture_device);
174
175         OAL_capture_recording = 0;
176
177 //      nprintf(("Alan","RTVOICE => stop record\n"));
178
179         return 0;
180 }
181
182 void oal_capture_close()
183 {
184         oal_capture_stop_record();
185
186         if (al_capture_device != NULL) {
187                 alcCaptureCloseDevice(al_capture_device);
188                 al_capture_device = NULL;
189         }
190 }
191
192 // return the max buffer size
193 int oal_capture_max_buffersize()
194 {
195         if ( !oal_is_initted() ) {
196                 return 0;
197         }
198
199         ALCsizei num_samples = 0;
200
201         alcGetIntegerv(al_capture_device, ALC_CAPTURE_SAMPLES, sizeof(ALCsizei), &num_samples);
202
203         if (alcGetError(al_capture_device) != ALC_NO_ERROR) {
204                 return 0;
205         }
206
207         return (num_samples * Capture.block_align);
208 }
209
210 // retrieve the recorded voice data
211 int oal_capture_get_raw_data(ubyte *outbuf, uint max_size)
212 {
213         if ( !oal_is_initted() ) {
214                 return 0;
215         }
216
217         if (outbuf == NULL) {
218                 return 0;
219         }
220
221         ALCsizei num_samples = 0;
222
223         alcGetIntegerv(al_capture_device, ALC_CAPTURE_SAMPLES, sizeof(ALCsizei), &num_samples);
224
225         if (num_samples <= 0) {
226                 return 0;
227         }
228
229         ALCsizei max_buf_size = min(num_samples, ALsizei(max_size / Capture.block_align));
230
231         alcCaptureSamples(al_capture_device, outbuf, max_buf_size);
232
233         if (alcGetError(al_capture_device) != ALC_NO_ERROR) {
234                 return 0;
235         }
236
237         return (int)max_buf_size * Capture.block_align;
238 }