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