2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Sound/rtvoice.cpp $
15 * C module file for real-time voice
18 * Revision 1.4 2002/06/09 04:41:27 relnev
19 * added copyright header
21 * Revision 1.3 2002/05/27 04:04:43 relnev
22 * 155 undefined references left
24 * Revision 1.2 2002/05/07 03:16:52 theoddone33
25 * The Great Newline Fix
27 * Revision 1.1.1.1 2002/05/03 03:28:10 root
31 * 2 10/07/98 10:54a Dave
34 * 1 10/07/98 10:51a Dave
36 * 24 4/24/98 2:17a Lawrance
37 * Clear out record buffer when recording begins
39 * 23 4/21/98 4:44p Dave
40 * Implement Vasudan ships in multiplayer. Added a debug function to bash
41 * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
42 * problem in options screen.
44 * 22 4/21/98 10:30a Dave
45 * allocate 8 second buffers for rtvoice
47 * 21 4/17/98 5:27p Dave
48 * More work on the multi options screen. Fixed many minor ui todo bugs.
50 * 20 4/17/98 10:38a Lawrance
51 * reduce num output streams to 1
53 * 19 3/25/98 9:56a Dave
54 * Increase buffer size to handle 8 seconds of voice data.
56 * 18 3/22/98 7:13p Lawrance
57 * Get streaming of recording voice working
59 * 17 3/09/98 5:22p Dave
60 * Fixed a rtvoice bug which caused bogus output when given size 0 input.
62 * 16 2/26/98 2:54p Lawrance
63 * Don't recreate capture buffer each time recording starts... just use
66 * 15 2/24/98 11:56p Lawrance
67 * Change real-time voice code to provide the uncompressed size on decode.
69 * 14 2/24/98 10:13p Dave
70 * Put in initial support for multiplayer voice streaming.
72 * 13 2/24/98 10:47a Lawrance
73 * Play voice through normal channels
75 * 12 2/23/98 6:54p Lawrance
76 * Make interface to real-time voice more generic and useful.
78 * 11 2/19/98 12:47a Lawrance
79 * Use a global code_info
81 * 10 2/16/98 7:31p Lawrance
82 * get compression/decompression of voice working
84 * 9 2/15/98 11:59p Lawrance
85 * Change the order of some code when opening a stream
87 * 8 2/15/98 11:10p Lawrance
88 * more work on real-time voice system
90 * 7 2/15/98 4:43p Lawrance
91 * work on real-time voice
93 * 6 2/09/98 8:07p Lawrance
94 * get buffer create working
96 * 5 2/04/98 6:08p Lawrance
97 * Read function pointers from dsound.dll, further work on
100 * 4 2/03/98 11:53p Lawrance
101 * Adding support for DirectSoundCapture
103 * 3 2/03/98 4:07p Lawrance
104 * check return codes from waveIn calls
106 * 2 1/31/98 5:48p Lawrance
107 * Start on real-time voice recording
115 #include "oal_capture.h"
119 typedef struct rtv_format
127 #define MAX_RTV_FORMATS 5
128 static rtv_format Rtv_formats[MAX_RTV_FORMATS] =
137 static int Rtv_do_compression=1; // flag to indicate whether compression should be done
138 static int Rtv_recording_format; // recording format, index into Rtv_formats[]
139 static int Rtv_playback_format; // playback format, index into Rtv_formats[]
141 #define RTV_BUFFER_TIME 8 // length of buffer in seconds
143 static int Rtv_recording_inited=0; // The input stream has been inited
144 static int Rtv_playback_inited=0; // The output stream has been inited
146 static int Rtv_recording=0; // Voice is currently being recorded
148 #define MAX_RTV_OUT_BUFFERS 1
149 #define RTV_OUT_FLAG_USED (1<<0)
150 typedef struct rtv_out_buffer
152 int buf_handle; // handle to sound buffer
153 int flags; // see RTV_OUT_FLAG_ #defines above
155 static rtv_out_buffer Rtv_output_buffers[MAX_RTV_OUT_BUFFERS]; // data for output buffers
157 static struct t_CodeInfo Rtv_code_info; // Parms will need to be transmitted with packets
159 // recording timer data
160 static SDL_TimerID Rtv_record_timer_id; // unique id for callback timer
161 static int Rtv_callback_time; // callback time in ms
163 void (*Rtv_callback)();
165 // recording/encoding buffers
166 static unsigned char *Rtv_capture_raw_buffer;
167 static unsigned char *Rtv_capture_compressed_buffer;
168 static int Rtv_capture_compressed_buffer_size;
169 static int Rtv_capture_raw_buffer_size;
171 static unsigned char *Encode_buffer1=NULL;
172 static unsigned char *Encode_buffer2=NULL;
174 // playback/decoding buffers
175 static unsigned char *Rtv_playback_uncompressed_buffer;
176 static int Rtv_playback_uncompressed_buffer_size;
178 static unsigned char *Decode_buffer=NULL;
179 static int Decode_buffer_size;
181 /////////////////////////////////////////////////////////////////////////////////////////////////
183 /////////////////////////////////////////////////////////////////////////////////////////////////
185 Uint32 TimeProc(Uint32 interval, void *param)
187 if ( !Rtv_callback ) {
188 SDL_RemoveTimer(Rtv_record_timer_id);
189 Rtv_record_timer_id = 0;
194 nprintf(("Alan","In callback\n"));
197 if (Rtv_callback_time) {
200 SDL_RemoveTimer(Rtv_record_timer_id);
201 Rtv_record_timer_id = 0;
207 // Try to pick the most appropriate recording format
209 // exit: 0 => success
211 int rtvoice_pick_record_format()
215 for (i=0; i<MAX_RTV_FORMATS; i++) {
216 if ( oal_capture_create_buffer(Rtv_formats[i].frequency, Rtv_formats[i].bits_per_sample, 1, RTV_BUFFER_TIME) == 0 ) {
217 oal_capture_release_buffer();
218 Rtv_recording_format=i;
223 if ( i == MAX_RTV_FORMATS ) {
230 // input: qos => new quality of service (1..10)
231 void rtvoice_set_qos(int qos)
233 InitEncoder(e_cCodec1, qos, Encode_buffer1, Encode_buffer2);
236 // Init the recording portion of the real-time voice system
237 // input: qos => quality of service (1..10) 1 is highest compression, 10 is highest quality
238 // exit: 0 => success
239 // !0 => failure, recording not possible
240 int rtvoice_init_recording(int qos)
242 if ( !Rtv_recording_inited ) {
243 if ( rtvoice_pick_record_format() ) {
247 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);
249 if ( Encode_buffer1 ) {
250 free(Encode_buffer1);
254 if ( oal_capture_create_buffer(Rtv_formats[Rtv_recording_format].frequency, Rtv_formats[Rtv_recording_format].bits_per_sample, 1, RTV_BUFFER_TIME) ) {
258 Encode_buffer1 = (unsigned char*)malloc(Rtv_capture_raw_buffer_size);
259 SDL_assert(Encode_buffer1);
261 if ( Encode_buffer2 ) {
262 free(Encode_buffer2);
265 Encode_buffer2 = (unsigned char*)malloc(Rtv_capture_raw_buffer_size);
266 SDL_assert(Encode_buffer2);
268 // malloc out the voice data buffer for raw (uncompressed) recorded sound
269 if ( Rtv_capture_raw_buffer ) {
270 free(Rtv_capture_raw_buffer);
271 Rtv_capture_raw_buffer=NULL;
273 Rtv_capture_raw_buffer = (unsigned char*)malloc(Rtv_capture_raw_buffer_size);
275 // malloc out voice data buffer for compressed recorded sound
276 if ( Rtv_capture_compressed_buffer ) {
277 free(Rtv_capture_compressed_buffer);
278 Rtv_capture_compressed_buffer=NULL;
280 Rtv_capture_compressed_buffer_size=Rtv_capture_raw_buffer_size; // be safe and allocate same as uncompressed
281 Rtv_capture_compressed_buffer = (unsigned char*)malloc(Rtv_capture_compressed_buffer_size);
283 InitEncoder(e_cCodec1, qos, Encode_buffer1, Encode_buffer2);
285 Rtv_recording_inited=1;
290 // Stop a stream from recording
291 void rtvoice_stop_recording()
293 if ( !Rtv_recording ) {
297 oal_capture_stop_record();
299 if ( Rtv_record_timer_id ) {
300 SDL_RemoveTimer(Rtv_record_timer_id);
301 Rtv_record_timer_id = 0;
307 // Close down the real-time voice recording system
308 void rtvoice_close_recording()
310 if ( Rtv_recording ) {
311 rtvoice_stop_recording();
314 if ( Encode_buffer1 ) {
315 free(Encode_buffer1);
319 if ( Encode_buffer2 ) {
320 free(Encode_buffer2);
324 if ( Rtv_capture_raw_buffer ) {
325 free(Rtv_capture_raw_buffer);
326 Rtv_capture_raw_buffer=NULL;
329 if ( Rtv_capture_compressed_buffer ) {
330 free(Rtv_capture_compressed_buffer);
331 Rtv_capture_compressed_buffer=NULL;
334 oal_capture_release_buffer();
336 Rtv_recording_inited=0;
339 // Open a stream for recording (recording begins immediately)
340 // exit: 0 => success
342 int rtvoice_start_recording( void (*user_callback)(), int callback_time )
344 if ( !oal_capture_supported() ) {
348 SDL_assert(Rtv_recording_inited);
350 if ( Rtv_recording ) {
354 if ( oal_capture_start_record() ) {
358 if ( user_callback ) {
359 Rtv_record_timer_id = SDL_AddTimer(callback_time, TimeProc, NULL);
361 if ( !Rtv_record_timer_id ) {
362 oal_capture_stop_record();
365 Rtv_callback = user_callback;
366 Rtv_callback_time = callback_time;
369 Rtv_record_timer_id = 0;
376 // compress voice data using specialized codec
377 int rtvoice_compress(unsigned char *data_in, int size_in, unsigned char *data_out, int size_out)
381 Rtv_code_info.Code = e_cCodec1;
382 Rtv_code_info.Gain = 0;
386 nprintf(("Network","RTVOICE => 0 bytes size in !\n"));
388 compressed_size = Encode(data_in, data_out, size_in, size_out, &Rtv_code_info);
390 nprintf(("SOUND","RTVOICE => Sound compressed to %d bytes (%0.2f percent)\n", compressed_size, (compressed_size*100.0f)/size_in));
393 return compressed_size;
396 // For 8-bit formats (unsigned, 0 to 255)
397 // For 16-bit formats (signed, -32768 to 32767)
398 int rtvoice_16to8(unsigned char *data, int size)
401 unsigned short sample16;
402 unsigned char sample8, *dest, *src;
404 SDL_assert(size%2 == 0);
409 for (i=0; i<size; i+=2) {
411 sample16 |= src[1] << 8;
414 sample8 = (unsigned char)(sample16>>8);
423 // Convert voice sample from 22KHz to 11KHz
424 int rtvoice_22to11(unsigned char *data, int size)
427 unsigned char *dest, *src;
432 for (i=0; i<size; i+=2) {
433 *(dest+new_size) = *(src+i);
440 // Convert voice data to 8bit, 11KHz if necessary
441 int rtvoice_maybe_convert_data(unsigned char *data, int size)
444 switch ( Rtv_recording_format ) {
449 // convert samples to 8 bit from 16 bit
450 new_size = rtvoice_16to8(data,new_size);
454 new_size = rtvoice_22to11(data,new_size);
457 // convert to 11Khz, 8 bit
458 new_size = rtvoice_16to8(data,new_size);
459 new_size = rtvoice_22to11(data,new_size);
462 Int3(); // should never happen
469 // Retrieve the recorded voice data
470 // input: outbuf => output parameter, recorded voice stored here
471 // compressed_size => output parameter, size in bytes of recorded voice after compression
472 // uncompressed_size => output parameter, size in bytes of recorded voice before compression
473 // gain => output parameter, gain value which must be passed to decoder
474 // outbuf_raw => output optional parameter, pointer to the raw sound data making up the compressed chunk
475 // outbuf_size_raw => output optional parameter, size of the outbuf_raw buffer
477 // NOTE: function converts voice data into compressed format
478 void rtvoice_get_data(unsigned char **outbuf, int *compressed_size, int *uncompressed_size, double *gain, unsigned char **outbuf_raw, int *outbuf_size_raw)
480 int max_size, raw_size, csize;
481 max_size = oal_capture_max_buffersize();
484 *uncompressed_size=0;
487 if ( max_size < 0 ) {
491 raw_size = oal_capture_get_raw_data(Rtv_capture_raw_buffer, max_size);
493 // convert data to 8bit, 11KHz if necessary
494 raw_size = rtvoice_maybe_convert_data(Rtv_capture_raw_buffer, raw_size);
495 *uncompressed_size=raw_size;
497 // compress voice data
498 if ( Rtv_do_compression ) {
499 csize = rtvoice_compress(Rtv_capture_raw_buffer, raw_size, Rtv_capture_compressed_buffer, Rtv_capture_compressed_buffer_size);
500 *gain = Rtv_code_info.Gain;
501 *compressed_size = csize;
502 *outbuf = Rtv_capture_compressed_buffer;
504 *gain = Rtv_code_info.Gain;
505 *compressed_size = raw_size;
506 *outbuf = Rtv_capture_raw_buffer;
509 // NOTE : if we are not doing compression, then the raw buffer and size are going to be the same as the compressed
512 // assign the raw buffer and size if necessary
513 if(outbuf_raw != NULL){
514 *outbuf_raw = Rtv_capture_raw_buffer;
516 if(outbuf_size_raw != NULL){
517 *outbuf_size_raw = raw_size;
521 /////////////////////////////////////////////////////////////////////////////////////////////////
523 /////////////////////////////////////////////////////////////////////////////////////////////////
525 // return the size that the decode buffer should be
526 int rtvoice_get_decode_buffer_size()
528 return Decode_buffer_size;
531 // uncompress the data into PCM format
532 void rtvoice_uncompress(unsigned char *data_in, int size_in, double gain, unsigned char *data_out, int size_out)
534 Rtv_code_info.Gain = gain;
535 Decode(&Rtv_code_info, data_in, data_out, size_in, size_out);
538 // Close down the real-time voice playback system
539 void rtvoice_close_playback()
541 if ( Decode_buffer ) {
546 if ( Rtv_playback_uncompressed_buffer ) {
547 free(Rtv_playback_uncompressed_buffer);
548 Rtv_playback_uncompressed_buffer=NULL;
551 Rtv_playback_inited=0;
554 // Clear out the Rtv_output_buffers[] array
555 void rtvoice_reset_out_buffers()
559 for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
560 Rtv_output_buffers[i].flags=0;
561 Rtv_output_buffers[i].buf_handle=-1;
565 // Init the playback portion of the real-time voice system
566 // exit: 0 => success
567 // !0 => failure, playback not possible
568 int rtvoice_init_playback()
570 rtv_format *rtvf=NULL;
572 if ( !Rtv_playback_inited ) {
574 rtvoice_reset_out_buffers();
576 Rtv_playback_format=0;
577 rtvf = &Rtv_formats[Rtv_playback_format];
578 Decode_buffer_size = rtvf->frequency * (RTV_BUFFER_TIME) * fl2i(rtvf->bits_per_sample/8.0f);
580 if ( Decode_buffer ) {
585 Decode_buffer = (unsigned char*)malloc(Decode_buffer_size);
586 SDL_assert(Decode_buffer);
588 if ( Rtv_playback_uncompressed_buffer ) {
589 free(Rtv_playback_uncompressed_buffer);
590 Rtv_playback_uncompressed_buffer=NULL;
593 Rtv_playback_uncompressed_buffer_size=Decode_buffer_size;
594 Rtv_playback_uncompressed_buffer = (unsigned char*)malloc(Rtv_playback_uncompressed_buffer_size);
595 SDL_assert(Rtv_playback_uncompressed_buffer);
597 InitDecoder(1, Decode_buffer);
599 Rtv_playback_inited=1;
605 int rtvoice_find_free_output_buffer()
609 for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
610 if ( !(Rtv_output_buffers[i].flags & RTV_OUT_FLAG_USED) ) {
615 if ( i == MAX_RTV_OUT_BUFFERS ) {
619 Rtv_output_buffers[i].flags |= RTV_OUT_FLAG_USED;
624 // Open a stream for real-time voice output
625 int rtvoice_create_playback_buffer()
628 rtv_format *rtvf=NULL;
630 rtvf = &Rtv_formats[Rtv_playback_format];
631 index = rtvoice_find_free_output_buffer();
638 Rtv_output_buffers[index].buf_handle = oal_create_buffer(rtvf->frequency, rtvf->bits_per_sample, 1, RTV_BUFFER_TIME);
639 if ( Rtv_output_buffers[index].buf_handle == -1 ) {
646 void rtvoice_stop_playback(int index)
648 SDL_assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
650 if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
651 if ( Rtv_output_buffers[index].buf_handle != -1 ) {
652 oal_stop_buffer(Rtv_output_buffers[index].buf_handle);
657 void rtvoice_stop_playback_all()
661 for ( i = 0; i < MAX_RTV_OUT_BUFFERS; i++ ) {
662 rtvoice_stop_playback(i);
666 // Close a stream that was opened for real-time voice output
667 void rtvoice_free_playback_buffer(int index)
669 SDL_assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
671 if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
672 Rtv_output_buffers[index].flags=0;
673 if ( Rtv_output_buffers[index].buf_handle != -1 ) {
674 oal_stop_buffer(Rtv_output_buffers[index].buf_handle);
675 oal_unload_buffer(Rtv_output_buffers[index].buf_handle);
677 Rtv_output_buffers[index].buf_handle=-1;
681 // Play compressed sound data
682 // exit: >=0 => handle to playing sound
683 // -1 => error, voice not played
684 int rtvoice_play_compressed(int index, unsigned char *data, int size, int uncompressed_size, double gain)
686 int buf_handle, rval;
688 buf_handle = Rtv_output_buffers[index].buf_handle;
690 // Stop any currently playing voice output
691 oal_stop_buffer(buf_handle);
693 SDL_assert(uncompressed_size <= Rtv_playback_uncompressed_buffer_size);
695 // uncompress the data into PCM format
696 if ( Rtv_do_compression ) {
697 rtvoice_uncompress(data, size, gain, Rtv_playback_uncompressed_buffer, uncompressed_size);
701 if ( oal_lock_data(buf_handle, Rtv_playback_uncompressed_buffer, uncompressed_size) ) {
706 rval = oal_play(buf_handle, -1, SND_PRIORITY_MUST_PLAY, Master_voice_volume, 0.0f, 0);
710 // Play uncompressed (raw) sound data
711 // exit: >=0 => handle to playing sound
712 // -1 => error, voice not played
713 int rtvoice_play_uncompressed(int index, unsigned char *data, int size)
715 int buf_handle, rval;
717 buf_handle = Rtv_output_buffers[index].buf_handle;
719 // Stop any currently playing voice output
720 oal_stop_buffer(buf_handle);
723 if ( oal_lock_data(buf_handle, data, size) ) {
728 rval = oal_play(buf_handle, -1, SND_PRIORITY_MUST_PLAY, Master_voice_volume, 0.0f, 0);