]> icculus.org git repositories - taylor/freespace2.git/blob - src/sound/rtvoice.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / sound / rtvoice.cpp
1 /*
2  * $Logfile: /Freespace2/code/Sound/rtvoice.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * C module file for real-time voice
8  *
9  * $Log$
10  * Revision 1.2  2002/05/07 03:16:52  theoddone33
11  * The Great Newline Fix
12  *
13  * Revision 1.1.1.1  2002/05/03 03:28:10  root
14  * Initial import.
15  *
16  * 
17  * 2     10/07/98 10:54a Dave
18  * Initial checkin.
19  * 
20  * 1     10/07/98 10:51a Dave
21  * 
22  * 24    4/24/98 2:17a Lawrance
23  * Clear out record buffer when recording begins
24  * 
25  * 23    4/21/98 4:44p Dave
26  * Implement Vasudan ships in multiplayer. Added a debug function to bash
27  * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
28  * problem in options screen. 
29  * 
30  * 22    4/21/98 10:30a Dave
31  * allocate 8 second buffers for rtvoice
32  * 
33  * 21    4/17/98 5:27p Dave
34  * More work on the multi options screen. Fixed many minor ui todo bugs.
35  * 
36  * 20    4/17/98 10:38a Lawrance
37  * reduce num output streams to 1
38  * 
39  * 19    3/25/98 9:56a Dave
40  * Increase buffer size to handle 8 seconds of voice data.
41  * 
42  * 18    3/22/98 7:13p Lawrance
43  * Get streaming of recording voice working
44  * 
45  * 17    3/09/98 5:22p Dave
46  * Fixed a rtvoice bug which caused bogus output when given size 0 input.
47  * 
48  * 16    2/26/98 2:54p Lawrance
49  * Don't recreate capture buffer each time recording starts... just use
50  * one.
51  * 
52  * 15    2/24/98 11:56p Lawrance
53  * Change real-time voice code to provide the uncompressed size on decode.
54  * 
55  * 14    2/24/98 10:13p Dave
56  * Put in initial support for multiplayer voice streaming.
57  * 
58  * 13    2/24/98 10:47a Lawrance
59  * Play voice through normal channels
60  * 
61  * 12    2/23/98 6:54p Lawrance
62  * Make interface to real-time voice more generic and useful.
63  * 
64  * 11    2/19/98 12:47a Lawrance
65  * Use a global code_info
66  * 
67  * 10    2/16/98 7:31p Lawrance
68  * get compression/decompression of voice working
69  * 
70  * 9     2/15/98 11:59p Lawrance
71  * Change the order of some code when opening a stream
72  * 
73  * 8     2/15/98 11:10p Lawrance
74  * more work on real-time voice system
75  * 
76  * 7     2/15/98 4:43p Lawrance
77  * work on real-time voice
78  * 
79  * 6     2/09/98 8:07p Lawrance
80  * get buffer create working
81  * 
82  * 5     2/04/98 6:08p Lawrance
83  * Read function pointers from dsound.dll, further work on
84  * DirectSoundCapture.
85  * 
86  * 4     2/03/98 11:53p Lawrance
87  * Adding support for DirectSoundCapture
88  * 
89  * 3     2/03/98 4:07p Lawrance
90  * check return codes from waveIn calls
91  * 
92  * 2     1/31/98 5:48p Lawrance
93  * Start on real-time voice recording
94  *
95  * $NoKeywords: $
96  */
97
98 #include "pstypes.h"
99 #include "sound.h"
100 #include "ds.h"
101 #include "dscap.h"
102 #include "codec1.h"
103 #include "rtvoice.h"
104
105 typedef struct rtv_format
106 {
107         int nchannels;
108         int bits_per_sample;
109         int frequency;
110 } rtv_format;
111
112
113 #define MAX_RTV_FORMATS 5
114 static rtv_format Rtv_formats[MAX_RTV_FORMATS] = 
115 {
116         {1,     8,              11025},
117         {1,     16,     11025},
118         {1,     8,              22050},
119         {1,     16,     22050},
120         {1,     8,              44100},
121 };
122
123 static int Rtv_do_compression=1;                                        // flag to indicate whether compression should be done          
124 static int Rtv_recording_format;                                        // recording format, index into Rtv_formats[]
125 static int Rtv_playback_format;                                 // playback format, index into Rtv_formats[]
126
127 #define RTV_BUFFER_TIME         8                                               // length of buffer in seconds  
128
129 static int Rtv_recording_inited=0;                              // The input stream has been inited
130 static int Rtv_playback_inited=0;                               // The output stream has been inited
131
132 static int Rtv_recording=0;                                             // Voice is currently being recorded
133
134 #define MAX_RTV_OUT_BUFFERS     1
135 #define RTV_OUT_FLAG_USED               (1<<0)
136 typedef struct rtv_out_buffer
137 {
138         int ds_handle;          // handle to directsound buffer
139         int flags;                      // see RTV_OUT_FLAG_ #defines above
140 } rtv_out_buffer;
141 static rtv_out_buffer Rtv_output_buffers[MAX_RTV_OUT_BUFFERS];          // data for output buffers
142
143 static struct   t_CodeInfo Rtv_code_info;               // Parms will need to be transmitted with packets
144
145 // recording timer data
146 static int Rtv_record_timer_id;         // unique id for callback timer
147 static int Rtv_callback_time;                   // callback time in ms
148
149 void (*Rtv_callback)();
150
151 // recording/encoding buffers
152 static unsigned char *Rtv_capture_raw_buffer;
153 static unsigned char *Rtv_capture_compressed_buffer;
154 static int Rtv_capture_compressed_buffer_size;
155 static int Rtv_capture_raw_buffer_size;
156
157 static unsigned char    *Encode_buffer1=NULL;
158 static unsigned char    *Encode_buffer2=NULL;
159
160 // playback/decoding buffers
161 static unsigned char *Rtv_playback_uncompressed_buffer;
162 static int Rtv_playback_uncompressed_buffer_size;
163
164 static unsigned char *Decode_buffer=NULL;
165 static int Decode_buffer_size;
166
167 /////////////////////////////////////////////////////////////////////////////////////////////////
168 // RECORD/ENCODE
169 /////////////////////////////////////////////////////////////////////////////////////////////////
170
171 void CALLBACK TimeProc(unsigned int id, unsigned int msg, unsigned long userdata, unsigned long dw1, unsigned long dw2)
172 {
173         if ( !Rtv_callback ) {
174                 return;
175         }
176
177         nprintf(("Alan","In callback\n"));
178         Rtv_callback();
179 }
180
181 // Try to pick the most appropriate recording format
182 //
183 // exit:        0       =>              success
184 //                      !0      =>              failure
185 int rtvoice_pick_record_format()
186 {
187         int i;
188
189         for (i=0; i<MAX_RTV_FORMATS; i++) {
190                 if ( dscap_create_buffer(Rtv_formats[i].frequency, Rtv_formats[i].bits_per_sample, 1, RTV_BUFFER_TIME) == 0 ) {
191                         dscap_release_buffer();
192                         Rtv_recording_format=i;
193                         break;
194                 }
195         }
196
197         if ( i == MAX_RTV_FORMATS ) {
198                 return -1;
199         }
200
201         return 0;
202 }
203
204 // input:       qos => new quality of service (1..10)
205 void rtvoice_set_qos(int qos)
206 {
207         InitEncoder(e_cCodec1, qos, Encode_buffer1, Encode_buffer2);
208 }
209
210 // Init the recording portion of the real-time voice system
211 // input:       qos     => quality of service (1..10) 1 is highest compression, 10 is highest quality
212 //      exit:   0       =>      success
213 //                      !0      =>      failure, recording not possible
214 int rtvoice_init_recording(int qos)
215 {
216         if ( !Rtv_recording_inited ) {
217                 if ( rtvoice_pick_record_format() ) {
218                         return -1;
219                 }
220
221                 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);
222
223                 if ( Encode_buffer1 ) {
224                         free(Encode_buffer1);
225                         Encode_buffer1=NULL;
226                 }
227
228                 if ( dscap_create_buffer(Rtv_formats[Rtv_recording_format].frequency, Rtv_formats[Rtv_recording_format].bits_per_sample, 1, RTV_BUFFER_TIME) ) {
229                         return -1;
230                 }
231
232                 Encode_buffer1 = (unsigned char*)malloc(Rtv_capture_raw_buffer_size);
233                 Assert(Encode_buffer1);
234
235                 if ( Encode_buffer2 ) {
236                         free(Encode_buffer2);
237                         Encode_buffer2=NULL;
238                 }
239                 Encode_buffer2 = (unsigned char*)malloc(Rtv_capture_raw_buffer_size);
240                 Assert(Encode_buffer2);
241
242                 // malloc out the voice data buffer for raw (uncompressed) recorded sound
243                 if ( Rtv_capture_raw_buffer ) {
244                         free(Rtv_capture_raw_buffer);
245                         Rtv_capture_raw_buffer=NULL;
246                 }
247                 Rtv_capture_raw_buffer = (unsigned char*)malloc(Rtv_capture_raw_buffer_size);
248
249                 // malloc out voice data buffer for compressed recorded sound
250                 if ( Rtv_capture_compressed_buffer ) {
251                         free(Rtv_capture_compressed_buffer);
252                         Rtv_capture_compressed_buffer=NULL;
253                 }
254                 Rtv_capture_compressed_buffer_size=Rtv_capture_raw_buffer_size; // be safe and allocate same as uncompressed
255                 Rtv_capture_compressed_buffer = (unsigned char*)malloc(Rtv_capture_compressed_buffer_size);
256
257                 InitEncoder(e_cCodec1, qos, Encode_buffer1, Encode_buffer2);
258
259                 Rtv_recording_inited=1;
260         }
261         return 0;
262 }
263
264 // Stop a stream from recording
265 void rtvoice_stop_recording()
266 {
267         if ( !Rtv_recording ) {
268                 return;
269         }
270
271         dscap_stop_record();
272
273         if ( Rtv_record_timer_id ) {
274                 timeKillEvent(Rtv_record_timer_id);
275                 Rtv_record_timer_id = 0;
276         }
277
278         Rtv_recording=0;
279 }
280
281 // Close down the real-time voice recording system
282 void rtvoice_close_recording()
283 {
284         if ( Rtv_recording ) {
285                 rtvoice_stop_recording();
286         }
287
288         if ( Encode_buffer1 ) {
289                 free(Encode_buffer1);
290                 Encode_buffer1=NULL;
291         }
292
293         if ( Encode_buffer2 ) {
294                 free(Encode_buffer2);
295                 Encode_buffer2=NULL;
296         }
297
298         if ( Rtv_capture_raw_buffer ) {
299                 free(Rtv_capture_raw_buffer);
300                 Rtv_capture_raw_buffer=NULL;
301         }
302
303         if ( Rtv_capture_compressed_buffer ) {
304                 free(Rtv_capture_compressed_buffer);
305                 Rtv_capture_compressed_buffer=NULL;
306         }
307
308         Rtv_recording_inited=0;
309 }
310
311 // Open a stream for recording (recording begins immediately)
312 // exit:        0       =>      success
313 //                      !0      =>      failure
314 int rtvoice_start_recording( void (*user_callback)(), int callback_time ) 
315 {
316         if ( !dscap_supported() ) {
317                 return -1;
318         }
319
320         Assert(Rtv_recording_inited);
321
322         if ( Rtv_recording ) {
323                 return -1;
324         }
325
326         if ( dscap_start_record() ) {
327                 return -1;
328         }
329
330         if ( user_callback ) {
331                 Rtv_record_timer_id = timeSetEvent(callback_time, callback_time, TimeProc, 0, TIME_PERIODIC);
332                 if ( !Rtv_record_timer_id ) {
333                         dscap_stop_record();
334                         return -1;
335                 }
336                 Rtv_callback = user_callback;
337                 Rtv_callback_time = callback_time;
338         } else {
339                 Rtv_callback = NULL;
340                 Rtv_record_timer_id = 0;
341         }
342
343         Rtv_recording=1;
344         return 0;
345 }
346
347 // compress voice data using specialized codec
348 int rtvoice_compress(unsigned char *data_in, int size_in, unsigned char *data_out, int size_out)
349 {
350         int             compressed_size;
351         
352         Rtv_code_info.Code = e_cCodec1;
353         Rtv_code_info.Gain = 0;
354
355         compressed_size = 0;
356         if(size_in <= 0){
357                 nprintf(("Network","RTVOICE => 0 bytes size in !\n"));          
358         } else {
359                 compressed_size = Encode(data_in, data_out, size_in, size_out, &Rtv_code_info);
360
361                 nprintf(("SOUND","RTVOICE => Sound compressed to %d bytes (%0.2f percent)\n", compressed_size, (compressed_size*100.0f)/size_in));
362         }
363
364         return compressed_size;
365 }
366
367 // For 8-bit formats (unsigned, 0 to 255)
368 // For 16-bit formats (signed, -32768 to 32767)
369 int rtvoice_16to8(unsigned char *data, int size)
370 {
371         int i;
372         unsigned short  sample16;
373         unsigned char   sample8, *dest, *src;
374
375         Assert(size%2 == 0);
376
377         dest = data;
378         src = data;
379
380         for (i=0; i<size; i+=2) {
381                 sample16  = src[0];
382                 sample16 |= src[1] << 8;
383
384                 sample16 += 32768;
385                 sample8 = (unsigned char)(sample16>>8);
386
387                 *dest++ = sample8;
388                 src += 2;
389         }
390
391         return (size>>1);
392 }
393
394 // Convert voice sample from 22KHz to 11KHz
395 int rtvoice_22to11(unsigned char *data, int size)
396 {
397         int i, new_size=0;
398         unsigned char *dest, *src;
399
400         dest=data;
401         src=data;
402
403         for (i=0; i<size; i+=2) {
404                 *(dest+new_size) = *(src+i);
405                 new_size++;
406         }
407
408         return new_size; 
409 }
410
411 // Convert voice data to 8bit, 11KHz if necessary
412 int rtvoice_maybe_convert_data(unsigned char *data, int size)
413 {
414         int new_size=size;
415         switch ( Rtv_recording_format ) {
416         case 0:
417                 // do nothing
418                 break;
419         case 1:
420                 // convert samples to 8 bit from 16 bit
421                 new_size = rtvoice_16to8(data,new_size);
422                 break;
423         case 2:
424                 // convert to 11KHz
425                 new_size = rtvoice_22to11(data,new_size);
426                 break;
427         case 3:
428                 // convert to 11Khz, 8 bit
429                 new_size = rtvoice_16to8(data,new_size);
430                 new_size = rtvoice_22to11(data,new_size);
431                 break;
432         default:
433                 Int3(); // should never happen
434                 break;
435         }
436
437         return new_size;
438 }
439
440 // Retrieve the recorded voice data
441 // input:       outbuf                                  =>              output parameter, recorded voice stored here
442 //                              compressed_size         =>              output parameter, size in bytes of recorded voice after compression
443 //                              uncompressed_size               =>              output parameter, size in bytes of recorded voice before compression
444 //                              gain                                            =>              output parameter, gain value which must be passed to decoder
445 //                              outbuf_raw                              =>              output optional parameter, pointer to the raw sound data making up the compressed chunk
446 //                              outbuf_size_raw         =>              output optional parameter, size of the outbuf_raw buffer
447 //
448 // NOTE: function converts voice data into compressed format
449 void rtvoice_get_data(unsigned char **outbuf, int *compressed_size, int *uncompressed_size, double *gain, unsigned char **outbuf_raw, int *outbuf_size_raw)
450 {
451         int max_size, raw_size, csize;
452         max_size = dscap_max_buffersize();
453
454         *compressed_size=0;
455         *uncompressed_size=0;
456         *outbuf=NULL;
457
458         if ( max_size < 0 ) {
459                 return;
460         }       
461         
462         raw_size = dscap_get_raw_data(Rtv_capture_raw_buffer, max_size);
463
464         // convert data to 8bit, 11KHz if necessary
465         raw_size = rtvoice_maybe_convert_data(Rtv_capture_raw_buffer, raw_size);
466         *uncompressed_size=raw_size;
467
468         // compress voice data
469         if ( Rtv_do_compression ) {
470                 csize = rtvoice_compress(Rtv_capture_raw_buffer, raw_size, Rtv_capture_compressed_buffer, Rtv_capture_compressed_buffer_size);
471                 *gain = Rtv_code_info.Gain;
472                 *compressed_size = csize;
473                 *outbuf = Rtv_capture_compressed_buffer;                
474         } else {
475                 *gain = Rtv_code_info.Gain;
476                 *compressed_size = raw_size;
477                 *outbuf = Rtv_capture_raw_buffer;
478         }
479
480         // NOTE : if we are not doing compression, then the raw buffer and size are going to be the same as the compressed
481         //        buffer and size
482
483         // assign the raw buffer and size if necessary
484         if(outbuf_raw != NULL){
485                 *outbuf_raw = Rtv_capture_raw_buffer;
486         }
487         if(outbuf_size_raw != NULL){
488                 *outbuf_size_raw = raw_size;
489         }
490 }
491
492 /////////////////////////////////////////////////////////////////////////////////////////////////
493 // DECODE/PLAYBACK
494 /////////////////////////////////////////////////////////////////////////////////////////////////
495
496 // return the size that the decode buffer should be
497 int rtvoice_get_decode_buffer_size()
498 {
499         return Decode_buffer_size;
500 }
501
502 // uncompress the data into PCM format
503 void rtvoice_uncompress(unsigned char *data_in, int size_in, double gain, unsigned char *data_out, int size_out)
504 {
505         Rtv_code_info.Gain = gain;
506         Decode(&Rtv_code_info, data_in, data_out, size_in, size_out);
507 }
508
509 // Close down the real-time voice playback system
510 void rtvoice_close_playback()
511 {
512         if ( Decode_buffer ) {
513                 free(Decode_buffer);
514                 Decode_buffer=NULL;
515         }
516
517         if ( Rtv_playback_uncompressed_buffer ) {
518                 free(Rtv_playback_uncompressed_buffer);
519                 Rtv_playback_uncompressed_buffer=NULL;
520         }
521
522         Rtv_playback_inited=0;
523 }
524
525 // Clear out the Rtv_output_buffers[] array
526 void rtvoice_reset_out_buffers()
527 {
528         int i;
529         
530         for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
531                 Rtv_output_buffers[i].flags=0;
532                 Rtv_output_buffers[i].ds_handle=-1;
533         }
534 }
535
536 // Init the playback portion of the real-time voice system
537 //      exit:   0       =>      success
538 //                      !0      =>      failure, playback not possible
539 int rtvoice_init_playback()
540 {
541         rtv_format      *rtvf=NULL;
542
543         if ( !Rtv_playback_inited ) {
544
545                 rtvoice_reset_out_buffers();
546
547                 Rtv_playback_format=0;
548                 rtvf = &Rtv_formats[Rtv_playback_format];
549                 Decode_buffer_size = rtvf->frequency * (RTV_BUFFER_TIME) * fl2i(rtvf->bits_per_sample/8.0f);
550
551                 if ( Decode_buffer ) {
552                         free(Decode_buffer);
553                         Decode_buffer=NULL;
554                 }
555
556                 Decode_buffer = (unsigned char*)malloc(Decode_buffer_size);
557                 Assert(Decode_buffer);
558
559                 if ( Rtv_playback_uncompressed_buffer ) {
560                         free(Rtv_playback_uncompressed_buffer);
561                         Rtv_playback_uncompressed_buffer=NULL;
562                 }
563
564                 Rtv_playback_uncompressed_buffer_size=Decode_buffer_size;
565                 Rtv_playback_uncompressed_buffer = (unsigned char*)malloc(Rtv_playback_uncompressed_buffer_size);
566                 Assert(Rtv_playback_uncompressed_buffer);
567
568                 InitDecoder(1, Decode_buffer); 
569
570                 Rtv_playback_inited=1;
571         }
572
573         return 0;
574 }
575
576 int rtvoice_find_free_output_buffer()
577 {
578         int i;
579
580         for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
581                 if ( !(Rtv_output_buffers[i].flags & RTV_OUT_FLAG_USED) ) {
582                         break;
583                 }
584         }
585
586         if ( i == MAX_RTV_OUT_BUFFERS ) {
587                 return -1;
588         }
589
590         Rtv_output_buffers[i].flags |= RTV_OUT_FLAG_USED;
591         return i;
592          
593 }
594
595 // Open a stream for real-time voice output
596 int rtvoice_create_playback_buffer()
597 {
598         int                     index;
599         rtv_format      *rtvf=NULL;
600
601         rtvf = &Rtv_formats[Rtv_playback_format];
602         index = rtvoice_find_free_output_buffer();
603
604         if ( index == -1 ) {
605                 Int3();
606                 return -1;
607         }
608         
609         Rtv_output_buffers[index].ds_handle = ds_create_buffer(rtvf->frequency, rtvf->bits_per_sample, 1, RTV_BUFFER_TIME);
610         if ( Rtv_output_buffers[index].ds_handle == -1 ) {
611                 return -1;
612         }
613
614         return 0;
615 }
616
617 void rtvoice_stop_playback(int index)
618 {
619         Assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
620
621         if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
622                 if ( Rtv_output_buffers[index].ds_handle != -1 ) {
623                         ds_stop_easy(Rtv_output_buffers[index].ds_handle);
624                 }
625         }
626 }
627
628 void rtvoice_stop_playback_all()
629 {
630         int i;
631
632         for ( i = 0; i < MAX_RTV_OUT_BUFFERS; i++ ) {
633                 rtvoice_stop_playback(i);
634         }
635 }
636
637 // Close a stream that was opened for real-time voice output
638 void rtvoice_free_playback_buffer(int index)
639 {
640         Assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
641
642         if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
643                 Rtv_output_buffers[index].flags=0;
644                 if ( Rtv_output_buffers[index].ds_handle != -1 ) {
645                         ds_stop_easy(Rtv_output_buffers[index].ds_handle);
646                         ds_unload_buffer(Rtv_output_buffers[index].ds_handle, -1);
647                 }
648                 Rtv_output_buffers[index].ds_handle=-1;
649         }
650 }
651
652 // Play compressed sound data
653 // exit:        >=0     =>      handle to playing sound
654 //                      -1              =>      error, voice not played
655 int rtvoice_play_compressed(int index, unsigned char *data, int size, int uncompressed_size, double gain)
656 {
657         int ds_handle, rval;
658
659         ds_handle = Rtv_output_buffers[index].ds_handle;
660
661         // Stop any currently playing voice output
662         ds_stop_easy(ds_handle);
663
664         Assert(uncompressed_size <= Rtv_playback_uncompressed_buffer_size);
665
666         // uncompress the data into PCM format
667         if ( Rtv_do_compression ) {
668                 rtvoice_uncompress(data, size, gain, Rtv_playback_uncompressed_buffer, uncompressed_size);
669         }
670
671         // lock the data in
672         if ( ds_lock_data(ds_handle, Rtv_playback_uncompressed_buffer, uncompressed_size) ) {
673                 return -1;
674         }
675
676         // play the voice
677         rval = ds_play(ds_handle, -1, -100, DS_MUST_PLAY, ds_convert_volume(Master_voice_volume), 0, 0);
678         return rval;
679 }
680
681 // Play uncompressed (raw) sound data
682 // exit:        >=0     =>      handle to playing sound
683 //                      -1              =>      error, voice not played
684 int rtvoice_play_uncompressed(int index, unsigned char *data, int size)
685 {
686         int ds_handle, rval;
687
688         ds_handle = Rtv_output_buffers[index].ds_handle;
689
690         // Stop any currently playing voice output
691         ds_stop_easy(ds_handle);
692
693         // lock the data in
694         if ( ds_lock_data(ds_handle, data, size) ) {
695                 return -1;
696         }
697
698         // play the voice
699         rval = ds_play(ds_handle, -1, -100, DS_MUST_PLAY, ds_convert_volume(Master_voice_volume), 0, 0);
700         return rval;
701 }
702