FS2_Open
Open source remastering of the Freespace 2 engine
rtvoice.cpp
Go to the documentation of this file.
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 
11 
12 #include "globalincs/pstypes.h"
13 #include "sound/ds.h"
14 #include "sound/dscap.h"
15 #include "sound/rtvoice.h"
16 #include "sound/sound.h"
17 
18 
19 typedef struct rtv_format
20 {
21  int nchannels;
23  int frequency;
24 } rtv_format;
25 
26 
27 #define MAX_RTV_FORMATS 5
28 static rtv_format Rtv_formats[MAX_RTV_FORMATS] =
29 {
30  {1, 8, 11025},
31  {1, 16, 11025},
32  {1, 8, 22050},
33  {1, 16, 22050},
34  {1, 8, 44100},
35 };
36 
37 static int Rtv_recording_format; // recording format, index into Rtv_formats[]
38 static int Rtv_playback_format; // playback format, index into Rtv_formats[]
39 
40 #define RTV_BUFFER_TIME 8 // length of buffer in seconds
41 
42 static int Rtv_recording_inited=0; // The input stream has been inited
43 static int Rtv_playback_inited=0; // The output stream has been inited
44 
45 static int Rtv_recording=0; // Voice is currently being recorded
46 
47 #define MAX_RTV_OUT_BUFFERS 1
48 #define RTV_OUT_FLAG_USED (1<<0)
49 typedef struct rtv_out_buffer
50 {
51  int ds_handle; // handle to directsound buffer
52  int flags; // see RTV_OUT_FLAG_ #defines above
54 static rtv_out_buffer Rtv_output_buffers[MAX_RTV_OUT_BUFFERS]; // data for output buffers
55 
56 //static struct t_CodeInfo Rtv_code_info; // Parms will need to be transmitted with packets
57 
58 // recording timer data
59 #ifdef _WIN32
60 static int Rtv_record_timer_id; // unique id for callback timer
61 #else
62 static SDL_TimerID Rtv_record_timer_id;
63 #endif
64 static int Rtv_callback_time; // callback time in ms
65 
67 
68 // recording/encoding buffers
69 static unsigned char *Rtv_capture_raw_buffer;
70 static unsigned char *Rtv_capture_compressed_buffer;
71 //static int Rtv_capture_compressed_buffer_size;
72 static int Rtv_capture_raw_buffer_size;
73 
74 // playback/decoding buffers
75 static unsigned char *Rtv_playback_uncompressed_buffer;
76 static int Rtv_playback_uncompressed_buffer_size;
77 
79 // RECORD/ENCODE
81 
82 #ifdef _WIN32
83 void CALLBACK TimeProc(unsigned int id, unsigned int msg, unsigned long userdata, unsigned long dw1, unsigned long dw2)
84 {
85  if ( !Rtv_callback ) {
86  return;
87  }
88 
89  nprintf(("Alan","In callback\n"));
90  Rtv_callback();
91 }
92 #else
93 Uint32 CALLBACK TimeProc(Uint32 interval, void *param)
94 {
95  if ( !Rtv_callback ) {
96  SDL_RemoveTimer(Rtv_record_timer_id);
97  Rtv_record_timer_id = NULL;
98 
99  return 0;
100  }
101 
102  mprintf(("In callback\n"));
103  Rtv_callback();
104 
105  if (Rtv_callback_time) {
106  return interval;
107  } else {
108  SDL_RemoveTimer(Rtv_record_timer_id);
109  Rtv_record_timer_id = NULL;
110 
111  return 0;
112  }
113 }
114 #endif
115 
116 // Try to pick the most appropriate recording format
117 //
118 // exit: 0 => success
119 // !0 => failure
121 {
122  int i;
123 
124  for (i=0; i<MAX_RTV_FORMATS; i++) {
125  if ( dscap_create_buffer(Rtv_formats[i].frequency, Rtv_formats[i].bits_per_sample, 1, RTV_BUFFER_TIME) == 0 ) {
127  Rtv_recording_format=i;
128  break;
129  }
130  }
131 
132  if ( i == MAX_RTV_FORMATS ) {
133  return -1;
134  }
135 
136  return 0;
137 }
138 
139 // input: qos => new quality of service (1..10)
140 void rtvoice_set_qos(int qos)
141 {
142  // TODO: Speex stuff
143 }
144 
145 // Init the recording portion of the real-time voice system
146 // input: qos => quality of service (1..10) 1 is highest compression, 10 is highest quality
147 // exit: 0 => success
148 // !0 => failure, recording not possible
150 {
151 #if 0
152  if ( !Rtv_recording_inited ) {
153  if ( rtvoice_pick_record_format() ) {
154  return -1;
155  }
156 
157  Rtv_capture_raw_buffer_size = Rtv_formats[Rtv_recording_format].frequency * (RTV_BUFFER_TIME) * fl2i(Rtv_formats[Rtv_recording_format].bits_per_sample/8.0f);
158 
159  if ( dscap_create_buffer(Rtv_formats[Rtv_recording_format].frequency, Rtv_formats[Rtv_recording_format].bits_per_sample, 1, RTV_BUFFER_TIME) ) {
160  return -1;
161  }
162 
163  // malloc out the voice data buffer for raw (uncompressed) recorded sound
164  if ( Rtv_capture_raw_buffer ) {
165  vm_free(Rtv_capture_raw_buffer);
166  Rtv_capture_raw_buffer=NULL;
167  }
168  Rtv_capture_raw_buffer = (unsigned char*)vm_malloc(Rtv_capture_raw_buffer_size);
169 
170  // malloc out voice data buffer for compressed recorded sound
171  if ( Rtv_capture_compressed_buffer ) {
172  vm_free(Rtv_capture_compressed_buffer);
173  Rtv_capture_compressed_buffer=NULL;
174  }
175  Rtv_capture_compressed_buffer_size=Rtv_capture_raw_buffer_size; // be safe and allocate same as uncompressed
176  Rtv_capture_compressed_buffer = (unsigned char*)vm_malloc(Rtv_capture_compressed_buffer_size);
177 
178  Rtv_recording_inited=1;
179  }
180  return 0;
181 #else
182  return -1;
183 #endif
184 }
185 
186 // Stop a stream from recording
188 {
189  if ( !Rtv_recording ) {
190  return;
191  }
192 
194 
195  if ( Rtv_record_timer_id ) {
196 #ifndef _WIN32
197  SDL_RemoveTimer(Rtv_record_timer_id);
198  Rtv_record_timer_id = NULL;
199 #else
200  timeKillEvent(Rtv_record_timer_id);
201  Rtv_record_timer_id = 0;
202 #endif
203  }
204 
205  Rtv_recording=0;
206 }
207 
208 // Close down the real-time voice recording system
210 {
211  if ( Rtv_recording ) {
213  }
214 
215  if ( Rtv_capture_raw_buffer ) {
216  vm_free(Rtv_capture_raw_buffer);
217  Rtv_capture_raw_buffer=NULL;
218  }
219 
220  if ( Rtv_capture_compressed_buffer ) {
221  vm_free(Rtv_capture_compressed_buffer);
222  Rtv_capture_compressed_buffer=NULL;
223  }
224 
226 
227  Rtv_recording_inited=0;
228 }
229 
230 // Open a stream for recording (recording begins immediately)
231 // exit: 0 => success
232 // !0 => failure
233 int rtvoice_start_recording( void (*user_callback)(), int callback_time )
234 {
235  if ( !dscap_supported() ) {
236  return -1;
237  }
238 
239  Assert(Rtv_recording_inited);
240 
241  if ( Rtv_recording ) {
242  return -1;
243  }
244 
245  if ( dscap_start_record() ) {
246  return -1;
247  }
248 
249  if ( user_callback ) {
250 #ifndef _WIN32
251  Rtv_record_timer_id = SDL_AddTimer(callback_time, TimeProc, NULL);
252 #else
253  Rtv_record_timer_id = timeSetEvent(callback_time, callback_time, TimeProc, 0, TIME_PERIODIC);
254 #endif
255  if ( !Rtv_record_timer_id ) {
257  return -1;
258  }
259  Rtv_callback = user_callback;
260  Rtv_callback_time = callback_time;
261  } else {
262  Rtv_callback = NULL;
263  Rtv_record_timer_id = 0;
264  }
265 
266  Rtv_recording=1;
267  return 0;
268 }
269 
270 // Retrieve the recorded voice data
271 // input: outbuf => output parameter, recorded voice stored here
272 // compressed_size => output parameter, size in bytes of recorded voice after compression
273 // uncompressed_size => output parameter, size in bytes of recorded voice before compression
274 // gain => output parameter, gain value which must be passed to decoder
275 // outbuf_raw => output optional parameter, pointer to the raw sound data making up the compressed chunk
276 // outbuf_size_raw => output optional parameter, size of the outbuf_raw buffer
277 //
278 // NOTE: function converts voice data into compressed format
279 void rtvoice_get_data(unsigned char **outbuf, int *size, double *gain)
280 {
281  int max_size __UNUSED, raw_size;
282  max_size = dscap_max_buffersize();
283 
284  *outbuf=NULL;
285 
286  raw_size = dscap_get_raw_data(Rtv_capture_raw_buffer, Rtv_capture_raw_buffer_size);
287 
288  // TODO: compress voice data
289 
290 // *gain = Rtv_code_info.Gain;
291  *size = raw_size;
292  *outbuf = Rtv_capture_raw_buffer;
293 }
294 
296 // DECODE/PLAYBACK
298 
299 // uncompress the data into PCM format
300 void rtvoice_uncompress(unsigned char *data_in, int size_in, double gain, unsigned char *data_out, int size_out)
301 {
302  if ( (data_in == NULL) || (size_in <= 0) ) {
303  return;
304  }
305 }
306 
307 // Close down the real-time voice playback system
309 {
310  if ( Rtv_playback_uncompressed_buffer ) {
311  vm_free(Rtv_playback_uncompressed_buffer);
312  Rtv_playback_uncompressed_buffer=NULL;
313  }
314 
315  Rtv_playback_inited=0;
316 }
317 
318 // Clear out the Rtv_output_buffers[] array
320 {
321  int i;
322 
323  for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
324  Rtv_output_buffers[i].flags=0;
325  Rtv_output_buffers[i].ds_handle=-1;
326  }
327 }
328 
329 // Init the playback portion of the real-time voice system
330 // exit: 0 => success
331 // !0 => failure, playback not possible
333 {
334  rtv_format *rtvf=NULL;
335 
336  if ( !Rtv_playback_inited ) {
337 
339 
340  Rtv_playback_format=0;
341  rtvf = &Rtv_formats[Rtv_playback_format];
342 
343  if ( Rtv_playback_uncompressed_buffer ) {
344  vm_free(Rtv_playback_uncompressed_buffer);
345  Rtv_playback_uncompressed_buffer=NULL;
346  }
347 
348  Rtv_playback_uncompressed_buffer_size = rtvf->frequency * (RTV_BUFFER_TIME) * fl2i(rtvf->bits_per_sample/8.0f);
349  Rtv_playback_uncompressed_buffer = (unsigned char*)vm_malloc(Rtv_playback_uncompressed_buffer_size);
350  Assert(Rtv_playback_uncompressed_buffer);
351 
352  Rtv_playback_inited=1;
353  }
354 
355  return 0;
356 }
357 
359 {
360  int i;
361 
362  for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
363  if ( !(Rtv_output_buffers[i].flags & RTV_OUT_FLAG_USED) ) {
364  break;
365  }
366  }
367 
368  if ( i == MAX_RTV_OUT_BUFFERS ) {
369  return -1;
370  }
371 
372  Rtv_output_buffers[i].flags |= RTV_OUT_FLAG_USED;
373  return i;
374 
375 }
376 
377 // Open a stream for real-time voice output
379 {
380  int index;
381  rtv_format *rtvf=NULL;
382 
383  rtvf = &Rtv_formats[Rtv_playback_format];
385 
386  if ( index == -1 ) {
387  Int3();
388  return -1;
389  }
390 
391  Rtv_output_buffers[index].ds_handle = ds_create_buffer(rtvf->frequency, rtvf->bits_per_sample, 1, RTV_BUFFER_TIME);
392  if ( Rtv_output_buffers[index].ds_handle == -1 ) {
393  return -1;
394  }
395 
396  return index;
397 }
398 
400 {
401  Assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
402 
403  if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
404  if ( Rtv_output_buffers[index].ds_handle != -1 ) {
405  ds_stop_easy(Rtv_output_buffers[index].ds_handle);
406  }
407  }
408 }
409 
411 {
412  int i;
413 
414  for ( i = 0; i < MAX_RTV_OUT_BUFFERS; i++ ) {
416  }
417 }
418 
419 // Close a stream that was opened for real-time voice output
421 {
422  Assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
423 
424  if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
425  Rtv_output_buffers[index].flags=0;
426  if ( Rtv_output_buffers[index].ds_handle != -1 ) {
427  ds_stop_easy(Rtv_output_buffers[index].ds_handle);
428  ds_unload_buffer(Rtv_output_buffers[index].ds_handle);
429  }
430  Rtv_output_buffers[index].ds_handle=-1;
431  }
432 }
433 
434 // Play sound data
435 // exit: >=0 => handle to playing sound
436 // -1 => error, voice not played
437 int rtvoice_play(int index, unsigned char *data, int size)
438 {
439  int ds_handle, rval;
440 
441  ds_handle = Rtv_output_buffers[index].ds_handle;
442 
443  // Stop any currently playing voice output
444  ds_stop_easy(ds_handle);
445 
446  // TODO: uncompress the data into PCM format
447 
448  // lock the data in
449  if ( ds_lock_data(ds_handle, data, size) ) {
450  return -1;
451  }
452 
453  // play the voice
455  rval = ds_play(ds_handle, -100, DS_MUST_PLAY, &enhanced_sound_data, Master_voice_volume, 0, 0);
456  return rval;
457 }
458 
#define __UNUSED
Definition: clang.h:23
int i
Definition: multi_pxo.cpp:466
#define vm_free(ptr)
Definition: pstypes.h:548
#define DS_MUST_PLAY
Definition: ds.h:40
int rtvoice_init_recording(int qos)
Definition: rtvoice.cpp:149
void rtvoice_free_playback_buffer(int index)
Definition: rtvoice.cpp:420
int dscap_max_buffersize()
Definition: dscap.cpp:183
int rtvoice_init_playback()
Definition: rtvoice.cpp:332
int ds_play(int sid, int snd_id, int priority, const EnhancedSoundData *enhanced_sound_data, float volume, float pan, int looping, bool is_voice_msg)
Definition: ds.cpp:1794
GLuint index
Definition: Glext.h:5608
void rtvoice_stop_recording()
Definition: rtvoice.cpp:187
int dscap_start_record()
Definition: dscap.cpp:132
Assert(pm!=NULL)
#define mprintf(args)
Definition: pstypes.h:238
void rtvoice_get_data(unsigned char **outbuf, int *size, double *gain)
Definition: rtvoice.cpp:279
GLclampf f
Definition: Glext.h:7097
#define RTV_OUT_FLAG_USED
Definition: rtvoice.cpp:48
GLsizeiptr size
Definition: Glext.h:5496
#define Int3()
Definition: pstypes.h:292
void rtvoice_set_qos(int qos)
Definition: rtvoice.cpp:140
int rtvoice_find_free_output_buffer()
Definition: rtvoice.cpp:358
void dscap_release_buffer()
Definition: dscap.cpp:59
int ds_create_buffer(int frequency, int bits_per_sample, int nchannels, int nseconds)
Definition: ds.cpp:1667
#define RTV_BUFFER_TIME
Definition: rtvoice.cpp:40
void rtvoice_close_recording()
Definition: rtvoice.cpp:209
#define nprintf(args)
Definition: pstypes.h:239
#define MAX_RTV_FORMATS
Definition: rtvoice.cpp:27
void(* Rtv_callback)()
Definition: rtvoice.cpp:66
int rtvoice_play(int index, unsigned char *data, int size)
Definition: rtvoice.cpp:437
int dscap_get_raw_data(unsigned char *outbuf, unsigned int max_size)
Definition: dscap.cpp:202
int dscap_stop_record()
Definition: dscap.cpp:152
int dscap_create_buffer(int freq, int bits_per_sample, int nchannels, int nseconds)
Definition: dscap.cpp:70
int dscap_supported()
Definition: dscap.cpp:122
void rtvoice_stop_playback(int index)
Definition: rtvoice.cpp:399
#define CALLBACK
Definition: config.h:75
void rtvoice_uncompress(unsigned char *data_in, int size_in, double gain, unsigned char *data_out, int size_out)
Definition: rtvoice.cpp:300
GLbitfield flags
Definition: Glext.h:6722
Uint32 CALLBACK TimeProc(Uint32 interval, void *param)
Definition: rtvoice.cpp:93
#define vm_malloc(size)
Definition: pstypes.h:547
typedef void(APIENTRY *PFNGLARRAYELEMENTEXTPROC)(GLint i)
int rtvoice_pick_record_format()
Definition: rtvoice.cpp:120
GLfloat param
Definition: Glext.h:5373
const unsigned int SND_ENHANCED_MAX_LIMIT
Definition: sound.cpp:35
#define fl2i(fl)
Definition: floating.h:33
int frequency
Definition: rtvoice.cpp:23
void rtvoice_close_playback()
Definition: rtvoice.cpp:308
void rtvoice_reset_out_buffers()
Definition: rtvoice.cpp:319
GLenum GLsizei GLenum GLenum const GLvoid * data
Definition: Gl.h:1509
void ds_stop_easy(int sid)
Definition: ds.cpp:1720
int nchannels
Definition: rtvoice.cpp:21
int rtvoice_create_playback_buffer()
Definition: rtvoice.cpp:378
void rtvoice_stop_playback_all()
Definition: rtvoice.cpp:410
#define MAX_RTV_OUT_BUFFERS
Definition: rtvoice.cpp:47
void ds_unload_buffer(int sid)
Definition: ds.cpp:1307
int ds_lock_data(int sid, unsigned char *data, int size)
Definition: ds.cpp:1698
int rtvoice_start_recording(void(*user_callback)(), int callback_time)
Definition: rtvoice.cpp:233
struct rtv_format rtv_format
float Master_voice_volume
Definition: sound.cpp:54
struct rtv_out_buffer rtv_out_buffer
int bits_per_sample
Definition: rtvoice.cpp:22