]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_voice.cpp
The Great Newline Fix
[taylor/freespace2.git] / src / network / multi_voice.cpp
1 /*
2  * $Logfile: /Freespace2/code/Network/multi_voice.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * $Log$
8  * Revision 1.2  2002/05/07 03:16:47  theoddone33
9  * The Great Newline Fix
10  *
11  * Revision 1.1.1.1  2002/05/03 03:28:10  root
12  * Initial import.
13  * 
14  * 
15  * 9     3/10/99 6:50p Dave
16  * Changed the way we buffer packets for all clients. Optimized turret
17  * fired packets. Did some weapon firing optimizations.
18  * 
19  * 8     3/09/99 6:24p Dave
20  * More work on object update revamping. Identified several sources of
21  * unnecessary bandwidth.
22  * 
23  * 7     1/08/99 4:42p Anoop
24  * Fixed memory overwrite problem.
25  * 
26  * 6     11/19/98 4:19p Dave
27  * Put IPX sockets back in psnet. Consolidated all multiplayer config
28  * files into one.
29  * 
30  * 5     11/19/98 8:03a Dave
31  * Full support for D3-style reliable sockets. Revamped packet lag/loss
32  * system, made it receiver side and at the lowest possible level.
33  * 
34  * 4     11/17/98 11:12a Dave
35  * Removed player identification by address. Now assign explicit id #'s.
36  * 
37  * 3     11/05/98 5:55p Dave
38  * Big pass at reducing #includes
39  * 
40  * 2     10/07/98 10:53a Dave
41  * Initial checkin.
42  * 
43  * 1     10/07/98 10:50a Dave
44  * 
45  * 43    6/16/98 4:22p Allender
46  * fix Net_player reference problem
47  * 
48  * 42    6/13/98 9:32p Mike
49  * Kill last character in file which caused "Find in Files" to report the
50  * file as "not a text file."
51  * 
52  * 41    6/13/98 6:01p Hoffoss
53  * Externalized all new (or forgot to be added) strings to all the code.
54  * 
55  * 40    6/13/98 3:19p Hoffoss
56  * NOX()ed out a bunch of strings that shouldn't be translated.
57  * 
58  * 39    6/12/98 2:49p Dave
59  * Patch 1.02 changes.
60  * 
61  * 38    5/27/98 4:14p Dave
62  * Spiffed up text display for voice status.
63  * 
64  * 37    5/27/98 1:15p Dave
65  * Change pxo login failure popup text. Put in message display of player
66  * who is currently doing voice.
67  * 
68  * 36    5/24/98 3:45a Dave
69  * Minor object update fixes. Justify channel information on PXO. Add a
70  * bunch of configuration stuff for the standalone.
71  * 
72  * 35    5/24/98 12:12a Frank
73  * Make sure recording clients don't ever send/store/handle packets past
74  * the limit of the accum buffer.
75  * 
76  * 34    5/22/98 9:35p Dave
77  * Put in channel based support for PXO. Put in "shutdown" button for
78  * standalone. UI tweaks for TvT
79  * 
80  * 33    5/20/98 2:24a Dave
81  * Fixed server side voice muting. Tweaked multi debrief/endgame
82  * sequencing a bit. Much friendlier for stats tossing/accepting now.
83  * 
84  * 32    4/25/98 2:02p Dave
85  * Put in multiplayer context help screens. Reworked ingame join ship
86  * select screen. Fixed places where network timestamps get hosed.
87  * 
88  * 31    4/21/98 4:44p Dave
89  * Implement Vasudan ships in multiplayer. Added a debug function to bash
90  * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
91  * problem in options screen. 
92  * 
93  * 30    4/17/98 5:27p Dave
94  * More work on the multi options screen. Fixed many minor ui todo bugs.
95  * 
96  * 29    4/09/98 11:01p Dave
97  * Put in new multi host options screen. Tweaked multiplayer options a
98  * bit.
99  * 
100  * 28    4/08/98 10:11a Dave
101  * Fixed a voice packet indexing problem.
102  * 
103  * 27    4/07/98 5:42p Dave
104  * Put in support for ui display of voice system status (recording,
105  * playing back, etc). Make sure main hall music is stopped before
106  * entering a multiplayer game via ingame join.
107  * 
108  * 26    4/04/98 4:22p Dave
109  * First rev of UDP reliable sockets is done. Seems to work well if not
110  * overly burdened.
111  * 
112  * 25    4/03/98 4:22p Allender
113  * Fixed a bug where voice recording was not cut off after MAX_TIME.
114  * 
115  * 24    4/03/98 1:03a Dave
116  * First pass at unreliable guaranteed delivery packets.
117  * 
118  * 23    3/30/98 6:27p Dave
119  * Put in a more official set of multiplayer options, including a system
120  * for distributing netplayer and settings.
121  * 
122  * 22    3/27/98 9:46a Dave
123  * Made default quality of sound 10.
124  * 
125  * 21    3/26/98 6:01p Dave
126  * Put in file checksumming routine in cfile. Made pilot pic xferring more
127  * robust. Cut header size of voice data packets in half. Put in
128  * restricted game host query system.
129  * 
130  * 20    3/25/98 8:36p Dave
131  * Removed potential bug spots from voice code.
132  * 
133  * 19    3/25/98 2:16p Dave
134  * Select random default image for newly created pilots. Fixed several
135  * multi-pause messaging bugs. Begin work on online help for multiplayer
136  * keys.
137  * 
138  * 18    3/24/98 5:00p Dave
139  * Fixed several ui bugs. Put in pre and post voice stream playback sound
140  * fx. Put in error specific popups for clients getting dropped from games
141  * through actions other than their own.
142  * 
143  * 17    3/23/98 7:18p Dave
144  * Converted voice to use streaming of packets as they are recorded.
145  * 
146  * 16    3/22/98 7:13p Lawrance
147  * Get streaming of recording voice working
148  * 
149  * 15    3/20/98 1:01p Dave
150  * Made the token system for multi_voice more reliable. Fixed a bug where
151  * standalones and other server who can't play sound don't route
152  * multi_voice correctly.
153  * 
154  * 14    3/19/98 5:05p Dave
155  * Put in support for targeted multiplayer text and voice messaging (all,
156  * friendly, hostile, individual).
157  * 
158  * 13    3/18/98 5:52p Dave
159  * Put in netgame password popup. Numerous ui changes. Laid groundwork for
160  * streamed multi_voice data.
161  * 
162  * 12    3/18/98 3:32p Dave
163  * Put in a hook for streamed rtvoice data from the rtvoice system.
164  * 
165  * 11    3/18/98 9:43a Dave
166  * Removed an uninitialized data warning.
167  * 
168  * 10    3/17/98 12:30a Dave
169  * Put in hud support for rtvoice. Several ui interface changes.
170  * 
171  * 9     3/16/98 2:35p Dave
172  * Numerous bug fixes. Made the "cue sound" sound play before incoming
173  * voice. 
174  * 
175  * 8     3/15/98 4:17p Dave
176  * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
177  * of network orientation matrices.
178  * 
179  * 7     3/04/98 4:36p Dave
180  * Fixed a compiler warning.
181  * 
182  * 6     2/26/98 6:01p Dave
183  * Made voice playback work correctly under NT.
184  * 
185  * 5     2/26/98 5:01p Dave
186  * Fixed a multi_voice_reset() bug.
187  * 
188  * 4     2/26/98 4:21p Dave
189  * More robust multiplayer voice.
190  * 
191  * 3     2/25/98 8:58p Dave
192  * Got first full implementation of multi voice done.
193  * 
194  * 2     2/24/98 11:56p Lawrance
195  * Change real-time voice code to provide the uncompressed size on decode.
196  * 
197  * 1     2/24/98 10:12p Dave
198  * Initial pass at multiplayer voice streaming.
199  *  
200  * $NoKeywords: $
201  */
202
203 #include "timer.h"
204 #include "key.h"
205 #include "freespace.h"
206 #include "gamesequence.h"
207 #include "multimsgs.h"
208 #include "multiutil.h"
209 #include "multi_voice.h"
210 #include "multi_pmsg.h"
211 #include "gamesnd.h"
212 #include "rtvoice.h"
213 #include "psnet.h"
214 #include "optionsmenumulti.h"
215 #include "stand_gui.h"
216 #include "multi.h"
217
218
219 // --------------------------------------------------------------------------------------------------
220 // MULTI VOICE DEFINES/VARS
221 //
222
223 // #define MULTI_VOICE_POST_DECOMPRESS                                                                  // when we're _not_ using streaming
224 #define MULTI_VOICE_PRE_DECOMPRESS                                                                              // when we _are_ using streaming
225
226 #define MULTI_VOICE_VERBOSE                                                                                             // keep this defined for verbose debug output
227
228 #define MULTI_VOICE_LOCAL_ECHO                                                                                  // keep this defined for local echo of recorded network voice
229
230 // flag indicating the status of the multi voice system
231 int Multi_voice_inited = 0;
232 int Multi_voice_can_record = 0;
233 int Multi_voice_can_play = 0;
234 int Multi_voice_send_mode = MULTI_MSG_NONE;                                                     // gotten from the multi_msg system when we start recording
235
236 // packet code defines
237 #define MV_CODE_GIVE_TOKEN                                                              0                                       // received player side - he now has the token to speak
238 #define MV_CODE_DENY_TOKEN                                                              1                                       // received player side - server has denied this request
239 #define MV_CODE_TAKE_TOKEN                                                              2                                       // received player side - the server is forcibly taking his token
240 #define MV_CODE_RELEASE_TOKEN                                                   3                                       // received server side - player is relinquishing token
241 #define MV_CODE_REQUEST_TOKEN                                                   4                                       // received server side - player is requesting token
242 #define MV_CODE_PLAYER_PREFS                                                    5                                       // received server side - player bitflags for who he'll receive from
243 #define MV_CODE_DATA                                                                            6                                       // sound data
244 #define MV_CODE_DATA_DUMMY                                                              7                                       // in place of a packet which has been deemed too large, so that receivers don't time out early
245
246 // default quality of sound
247 #define MV_DEFAULT_QOS                                                                  10                                      // default quality of sound
248 int Multi_voice_qos;                                                                                                                    // default quality of sound
249
250 // sounds added to the front and end of a playing voice stream (set to -1 if none are wanted)
251 #define MULTI_VOICE_PRE_SOUND                                                   SND_CUE_VOICE
252 #define MULTI_VOICE_POST_SOUND                                          SND_END_VOICE
253 int Multi_voice_pre_sound_size = 0;
254
255 // sound data
256
257 // NOTE : the following 2 defines should be used for reference only. they represent the worst case situation,
258 //                       sending voice to a specific target under IPX. you should use multi_voice_max_chunk_size(...) when 
259 //        determining if a given chunk will fit into an individual freespace packet
260 // max size of a data packet header (note, this changes as the code itself changes - should probably never use this except for reference)
261 #define MULTI_VOICE_MAX_HEADER_SIZE                                     22
262 // size of an individual chunk (CHUNK == block of data stuck into a packet), in the worst case of header size (see above)
263 #define MULTI_VOICE_MAX_CHUNK_SIZE                                      488
264
265 // total max size of an incoming or an outgoing uncompressed buffer (note this is probably too big, but we won't worry about that for now)
266 #define MULTI_VOICE_MAX_BUFFER_SIZE                                     ((1<<16)+(1<<14))               // 80k
267
268 // overall size of an total accum buffer for a stream
269 #define MULTI_VOICE_ACCUM_BUFFER_SIZE                           (1<<14)                                 // 16k
270
271 // how many accum buffers need to be in a total accum buffer
272 // NOTE : we reference MULTI_VOICE_MAX_CHUNK_SIZE here because it is worst case. ie, we'll always have enough
273 //        accum buffers in anything better than the worst case if we use MULTI_VOICE_MAX_CHUNK_SIZE
274 #define MULTI_VOICE_ACCUM_BUFFER_COUNT                          (MULTI_VOICE_ACCUM_BUFFER_SIZE / MULTI_VOICE_MAX_CHUNK_SIZE)
275
276 int Multi_voice_max_time;                                                                                                       // current maximum recording time
277 char *Multi_voice_record_buffer = NULL;                                                         // buffer for recording back voice
278 char *Multi_voice_playback_buffer = NULL;                                                               // buffer for processing the accum buffer and playing the result
279
280 // DEBUG CODE
281 #ifdef MULTI_VOICE_POST_DECOMPRESS
282         char Multi_voice_unpack_buffer[MULTI_VOICE_MAX_BUFFER_SIZE];
283 #endif
284
285 // the max amount of tokens we want to be floating about (max sound streams)
286 #define MULTI_VOICE_MAX_STREAMS                                         1
287
288 // voice algorithm stuff
289 // it would probably be good to base the timeout time on some multiple of our average ping to the server
290 #define MV_ALG_TIMEOUT  500                                                                                             // if start get new data for a window then a pause this long, play the window
291 int Multi_voice_stamps[MULTI_VOICE_MAX_STREAMS];
292
293 // NOTE : this should be > then MULTI_VOICE_MAX_TIME + the time for the data to come over a network connection!!
294 #define MULTI_VOICE_TOKEN_TIMEOUT                                       7000                            // timeout - server will take the token back if he does not hear from the guy in this amount of time
295
296 #define MULTI_VOICE_TOKEN_RELEASE_WAIT                          (1.0f)                  // wait 1 second
297
298 // the token index of a voice stream is set to one of these values, or the index of the player who has the token
299 #define MULTI_VOICE_TOKEN_INDEX_FREE                            -1                                      // the token (and the stream are free)
300 #define MULTI_VOICE_TOKEN_INDEX_RELEASED                        0xDEADBEAD              // the token has been released but the stream is still active
301
302 typedef struct voice_stream {           
303         int token_status;                                                                                                                       // status of the token (player index if a player has it) or one of the above defines
304         int token_stamp;                                                                                                                        // timestamp for the MULTI_VOICE_TOKEN_TIMEOUT
305
306         short stream_from;                                                                                                              // id of the player the stream is coming from
307
308         ubyte *accum_buffer[MULTI_VOICE_ACCUM_BUFFER_COUNT];                    // accum buffer
309         ubyte accum_buffer_flags[MULTI_VOICE_ACCUM_BUFFER_COUNT];       // flag indicating the existence of a given accum (sub)buffer
310         ushort accum_buffer_usize[MULTI_VOICE_ACCUM_BUFFER_COUNT];      // uncompressed size of the corresponding (sub)buffer
311         ushort accum_buffer_csize[MULTI_VOICE_ACCUM_BUFFER_COUNT];      // compressed size of the corresponding (sub)buffer
312         double accum_buffer_gain[MULTI_VOICE_ACCUM_BUFFER_COUNT];       // gain of the corresponding (sub)buffer
313                 
314         ubyte stream_id;                                                                                                                        // stream id #
315         fix stream_last_heard;                                                                                                  // last time we heard from this stream  
316
317         fix stream_start_time;                                                                                                  // time the stream started playing
318         int stream_snd_handle;                                                                                                  // sound playing instance handle
319         int stream_rtvoice_handle;                                                                                              // rtvoice buffer handle
320 } voice_stream;
321 voice_stream Multi_voice_stream[MULTI_VOICE_MAX_STREAMS];               // voice streams themselves
322
323 // player-side data
324 #define MULTI_VOICE_KEY                                                                 KEY_LAPOSTRO    // key used for realtime voice
325 int Multi_voice_keydown = 0;                                                                                            // is the record key currently being pressed
326 int Multi_voice_recording = 0;                                                                                  // flag indicating if we're currently recording or not
327 int Multi_voice_token = 0;                                                                                                      // if we currently have a token or not
328 int Multi_voice_recording_stamp = -1;                                                                   // how long we've been recording
329 ubyte Multi_voice_stream_id = 0;                                                                                        // stream id for the stream we're currently sending
330 int Multi_voice_current_stream_index = 0;                                                               // packet index of the currently recodring stream
331 int Multi_voice_current_stream_sent = -1;                                                               // index of packet we've sent up to
332
333 // server-side data
334 ubyte Multi_voice_next_stream_id = 0;                                                                   // kept on the server - given to the next valid token requester
335 int Multi_voice_player_prefs[MAX_PLAYERS];                                                      // player bitflag preferences
336
337 // voice status data - used for determing the result of multi_voice_status
338 #define MULTI_VOICE_DENIED_TIME                                         1000                            // how long to display the "denied" status
339 int Multi_voice_denied_stamp = -1;                                                                              // timestamp for when we got denied a token
340
341 // local muting preferences
342 int Multi_voice_local_prefs = 0xffffffff;
343
344
345 // --------------------------------------------------------------------------------------------------
346 // MULTI VOICE FORWARD DECLARATIONS
347 //
348
349 // process voice details as the server
350 void multi_voice_server_process();
351
352 // process voice details as a player (may also be the server)
353 void multi_voice_player_process();
354
355 // determine if the voice key is down this frame
356 int multi_voice_keydown();
357
358 // find the voice stream index by token player index
359 int multi_voice_find_token(int player_index);
360
361 // <server> gives the token to a given player
362 void multi_voice_give_token(int stream_index,int player_index);
363
364 // <server> takes the token from a given stream entry
365 void multi_voice_take_token(int stream_index);
366
367 // <server> tells the client he's been denied on this request
368 void multi_voice_deny_token(int player_index);
369
370 // <player> releases the token back to the server
371 void multi_voice_release_token();
372
373 // <player> requests the token from the server
374 void multi_voice_request_token();
375
376 // <server> process a request for the token
377 void multi_voice_process_token_request(int player_index);
378
379 // free up any memory which may have been malloced
380 void multi_voice_free_all();
381
382 // <player> send the currently recorded sound
383 void multi_voice_player_send_stream();
384
385 // process incoming sound data, return bytes processed
386 int multi_voice_process_data(ubyte *data, int player_index,int msg_mode,net_player *target);
387
388 // <server> increment the current stream id#
389 void multi_voice_inc_stream_id();
390
391 // flush any old sound stream data because we've started to receive data for a new stream
392 void multi_voice_flush_old_stream(int stream_index);
393
394 // route sound data through the server to all appropriate players
395 void multi_voice_route_data(ubyte *data, int packet_size,int player_index,int mode,net_player *target);
396
397 // find the stream to apply incoming sound data to, freeing up old ones as necessary
398 int multi_voice_get_stream(int stream_id);
399
400 // NOTE : these 4 functions can be arbitrarily written to perform in any way necessary. This way the algorithm is
401 //        completely seperate from the transport and token layers
402 // initialize the smart algorithm
403 void multi_voice_alg_init();
404
405 // process incoming sound data in whatever way necessary (this function should take care of playing data when necessary)
406 void multi_voice_alg_process_data(int player_index,int stream_index,ushort chunk_index,ushort chunk_size);              
407
408 // process existing streams
409 void multi_voice_alg_process_streams();
410
411 // we are going to flush the current stream because we have started to receive data for a new one. do something first
412 void multi_voice_alg_flush_old_stream(int stream_index);
413
414 // is the given sound stream playing (compares uncompressed sound size with current playback position)
415 int multi_voice_stream_playing(int stream_index);
416
417 // tack on a post voice sound (pass -1 for none)
418 // return final buffer size
419 int multi_voice_mix(int post_sound,char *data,int cur_size,int max_size);
420
421 // send a dummy packet in the place of a too-large data packet
422 void multi_voice_send_dummy_packet();
423
424 // process a dummy data packet
425 int multi_voice_process_data_dummy(ubyte *data);
426
427 // max size of a sound chunk which we can fit into a packet
428 int multi_voice_max_chunk_size(int msg_mode);
429
430 // process a player preferences packet, return bytes processed
431 int multi_voice_process_player_prefs(ubyte *data,int player_index);
432
433 // process and play the current window of sound stream data we have. reset the window for the next incoming data as well
434 void multi_voice_alg_play_window(int stream_index);
435
436 // send all pending voice packets
437 void multi_voice_client_send_pending();
438
439
440 // --------------------------------------------------------------------------------------------------
441 // MULTI VOICE FUNCTIONS
442 //
443
444 // initialize the multiplayer voice system
445 void multi_voice_init()
446 {
447         int idx,s_idx,pre_size,pre_sound;
448
449         // if the voice system is already initialized, just reset some stuff
450         if(Multi_voice_inited){
451                 multi_voice_reset();
452                 return;
453         }
454
455         // set the default quality of sound
456         Multi_voice_qos = MV_DEFAULT_QOS;
457
458         // if we're the standalone server, we can't record _or_ playback, but we can still route data and manage tokens
459         if(Game_mode & GM_STANDALONE_SERVER){
460                 Multi_voice_can_record = 0;
461                 Multi_voice_can_play = 0;
462         } else {
463                 // initialize the realtime voice module
464                 if(rtvoice_init_recording(Multi_voice_qos)){
465                         nprintf(("Network","MULTI VOICE : Error initializing rtvoice - recording will not be possible\n"));
466                         Multi_voice_can_record = 0;
467                 } else {
468                         Multi_voice_can_record = 1;
469                 }               
470
471                 if(rtvoice_init_playback()){            
472                         nprintf(("Network","MULTI VOICE : Error initializing rtvoice - playback will not be possible\n"));
473                         Multi_voice_can_play = 0;
474                 } else {
475                         Multi_voice_can_play = 1;
476                 }
477
478                 // _always_ set the quality of server
479                 multi_voice_set_vars(MV_DEFAULT_QOS,MULTI_VOICE_MAX_TIME);
480         }
481
482         // initialize player-side data
483         Multi_voice_token = 0;
484         Multi_voice_keydown = 0;
485         Multi_voice_recording = 0;      
486         Multi_voice_stream_id = 0;
487         Multi_voice_recording_stamp = -1;
488         Multi_voice_current_stream_index = 0;
489         Multi_voice_current_stream_sent = -1;
490
491         // initialize server-side data
492         memset(Multi_voice_player_prefs,0xff,sizeof(int)*MAX_PLAYERS);                          
493         Multi_voice_next_stream_id = 0;
494
495         Multi_voice_local_prefs = 0xffffffff;
496
497         // initialize the sound buffers
498         Multi_voice_record_buffer = NULL;       
499
500         Multi_voice_playback_buffer = NULL;
501         Multi_voice_pre_sound_size = 0;
502         if(Multi_voice_can_play){
503                 // attempt to allocate the buffer
504                 Multi_voice_playback_buffer = (char*)malloc(MULTI_VOICE_MAX_BUFFER_SIZE);
505                 if(Multi_voice_playback_buffer == NULL){
506                         nprintf(("Network","MULTI VOICE : Error allocating playback buffer - playback will not be possible\n"));                
507                         Multi_voice_can_play = 0;               
508                 } 
509
510                 // attempt to copy in the "pre" voice sound
511                 pre_sound = snd_load(&Snds[MULTI_VOICE_PRE_SOUND]);
512                 if(pre_sound != -1){
513                         // get the pre-sound size
514                         if((snd_size(pre_sound,&pre_size) != -1) && (pre_size < MULTI_VOICE_MAX_BUFFER_SIZE)){
515                                 snd_get_data(pre_sound,Multi_voice_playback_buffer);
516                                 Multi_voice_pre_sound_size = pre_size;
517                         } else {
518                                 Multi_voice_pre_sound_size = 0;
519                         }
520                 } else {
521                         Multi_voice_pre_sound_size = 0;
522                 }
523         }
524
525         // initialize the streams       
526         memset(Multi_voice_stream,0,sizeof(voice_stream) * MULTI_VOICE_MAX_STREAMS);    
527         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
528                 Multi_voice_stream[idx].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;
529                 Multi_voice_stream[idx].token_stamp = -1;               
530                 Multi_voice_stream[idx].stream_snd_handle = -1;
531
532                 // get a playback buffer handle
533                 if(Multi_voice_can_play){
534                         Multi_voice_stream[idx].stream_rtvoice_handle = -1;
535                         Multi_voice_stream[idx].stream_rtvoice_handle = rtvoice_create_playback_buffer();
536                         if(Multi_voice_stream[idx].stream_rtvoice_handle == -1){
537                                 nprintf(("Network","MULTI VOICE : Error getting rtvoice buffer handle - playback will not be possible!\n"));
538                                 multi_voice_free_all(); 
539
540                                 Multi_voice_can_play = 0;
541                         }
542                                         
543                         // allocate the accum buffer
544                         for(s_idx=0;s_idx<MULTI_VOICE_ACCUM_BUFFER_COUNT;s_idx++){
545                                 Multi_voice_stream[idx].accum_buffer[s_idx] = NULL;
546                                 Multi_voice_stream[idx].accum_buffer[s_idx] = (ubyte*)malloc(MULTI_VOICE_ACCUM_BUFFER_SIZE);
547                                 if(Multi_voice_stream[idx].accum_buffer[s_idx] == NULL){
548                                         nprintf(("Network","MULTI VOICE : Error allocating accum buffer - playback will not be possible\n"));
549                                         multi_voice_free_all();
550                                         
551                                         Multi_voice_can_play = 0;
552                                 }
553                         }
554                 }
555         }       
556
557         // initialize the default max time
558         Multi_voice_max_time = MULTI_VOICE_MAX_TIME;
559
560         // initialize voice status data
561         Multi_voice_denied_stamp = -1;
562         
563         // initialize the smart algorithm
564         multi_voice_alg_init(); 
565         
566         Multi_voice_inited = 1;
567 }
568
569 // shutdown the multiplayer voice system
570 void multi_voice_close()
571 {
572         int idx;
573         
574         // if the voice system isn't already initialized, don't do anything
575         if(!Multi_voice_inited){
576                 return;
577         }
578
579         // free up buffers
580         multi_voice_free_all();
581
582         // release all the rtvoice buffers
583         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
584                 if(Multi_voice_stream[idx].stream_rtvoice_handle != -1){
585                         rtvoice_free_playback_buffer(Multi_voice_stream[idx].stream_rtvoice_handle);
586                         Multi_voice_stream[idx].stream_rtvoice_handle = -1;
587                         Multi_voice_stream[idx].stream_snd_handle = -1;
588                 }
589         }
590
591         // close the realtime voice module
592         rtvoice_close_recording();
593         rtvoice_close_playback();
594
595         Multi_voice_inited = 0;
596 }
597
598 // reset between levels
599 void multi_voice_reset()
600 {
601         int idx;
602
603 #ifdef MULTI_VOICE_VERBOSE
604         nprintf(("Network","MULTI VOICE : Resetting\n"));
605 #endif
606
607         Assert(Multi_voice_inited);     
608
609         // if we're the standalone server, we can't record _or_ playback, but we can still route data and manage tokens
610         if(Game_mode & GM_STANDALONE_SERVER){
611                 Multi_voice_can_record = 0;
612                 Multi_voice_can_play = 0;
613         } 
614
615         // initialize player-side data
616         Multi_voice_token = 0;
617         Multi_voice_keydown = 0;
618         Multi_voice_recording = 0;      
619         Multi_voice_stream_id = 0;
620         Multi_voice_recording_stamp = -1;
621
622         // initialize server-side data
623         memset(Multi_voice_player_prefs,0xff,sizeof(int)*MAX_PLAYERS);                          
624         Multi_voice_local_prefs = 0xffffffff;
625         Multi_voice_next_stream_id = 0;
626
627         // initialize the sound buffers
628         Multi_voice_record_buffer = NULL;       
629         
630         // initialize the streams               
631         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
632                 Multi_voice_stream[idx].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;
633                 Multi_voice_stream[idx].token_stamp = -1;                                                       
634         }       
635         
636         // initialize the smart algorithm
637         multi_voice_alg_init(); 
638 }
639
640 // process all voice details
641 void multi_voice_process()
642 {
643         int idx;
644         
645         // don't do anything if the voice module is not initialized
646         if((!Multi_voice_inited) || !(Net_player->flags & NETINFO_FLAG_CONNECTED)){
647                 return;
648         }               
649
650         // send all pending voice packets
651         multi_voice_client_send_pending();
652
653         // find any playing sound streams which have finished and unmark them
654         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
655                 if((Multi_voice_stream[idx].stream_snd_handle != -1) && !multi_voice_stream_playing(idx)){
656                         Multi_voice_stream[idx].stream_snd_handle = -1;
657                 }
658         }
659
660         // process seperately as player or server
661         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
662                 multi_voice_server_process();
663         }
664
665         // all "players" do this, except the standalone who isn't a real player by definition
666         if(!(Game_mode & GM_STANDALONE_SERVER)){
667                 multi_voice_player_process();   
668         }
669
670         // everyont calls the general algorithm process function
671         multi_voice_alg_process_streams();
672 }
673
674 // voice settings debug console function
675 void multi_voice_dcf()
676 {
677         dc_get_arg(ARG_STRING);
678
679         // set the quality of sound
680         if (strcmp(Dc_arg, NOX("qos")) == 0) {
681                 dc_get_arg(ARG_INT);
682                 if(Dc_arg_type & ARG_INT){
683                         if((Dc_arg_int >= 1) && (Dc_arg_int <= 10) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
684                                 multi_voice_set_vars(Dc_arg_int,-1);
685                                 dc_printf("Quality of sound : %d\n",Dc_arg_int);
686                         }
687                 }
688         }
689 }
690
691 // the status of the voice system - use this to determine what bitmaps to display, etc see above MULTI_VOICE_STATUS_* defines
692 int multi_voice_status()
693 {
694         int idx;
695         int earliest;
696         fix earliest_time;
697         
698         // if the "denied" timestamp is set, return that as the status
699         if(Multi_voice_denied_stamp != -1){
700                 return MULTI_VOICE_STATUS_DENIED;
701         }
702
703         // if we're currently recording (has precedence over playing back a sound from somebody)
704         if(Multi_voice_recording){
705                 return MULTI_VOICE_STATUS_RECORDING;
706         }
707         
708         // find the stream which started playing the farthest back (if any)
709         earliest = -1;
710         earliest_time = -1;
711         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
712                 // if we found a playing stream
713                 if(Multi_voice_stream[idx].stream_snd_handle != -1){
714                         if((earliest == -1) || (Multi_voice_stream[idx].stream_start_time < earliest_time)){
715                                 earliest = idx;
716                                 earliest_time = Multi_voice_stream[idx].stream_start_time;
717                         }
718                 }
719         }
720         // if we found a stream
721         if(earliest != -1){
722                 return MULTI_VOICE_STATUS_PLAYING;
723         }
724
725         // system is idle
726         return MULTI_VOICE_STATUS_IDLE;
727 }
728
729 // update the qos if the current setting is different from the passed in value
730 void multi_voice_maybe_update_vars(int new_qos,int new_duration)
731 {
732         // if the current qos is different from the passed qos, set it
733         if((new_qos != Multi_voice_qos) || (new_duration != Multi_voice_max_time)){
734                 multi_voice_set_vars(new_qos,new_duration);
735         }
736 }
737
738
739 // --------------------------------------------------------------------------------------------------
740 // MULTI VOICE FORWARD DECLARATIONS
741 //
742
743 // process voice details as the server
744 void multi_voice_server_process()
745 {
746         int idx;
747
748         // process all the tokens for all the available streams
749         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
750                 switch(Multi_voice_stream[idx].token_status){
751                 // if the token is free, so is the stream - don't do anything
752                 case MULTI_VOICE_TOKEN_INDEX_FREE:
753                         break;
754
755                 // if the token has been released - check to see if the stream is "done" (ie, can be marked as FREE once again)
756                 case MULTI_VOICE_TOKEN_INDEX_RELEASED:
757                         // if the stream_last_heard var is -1, it means we never got sound from this guy so free the token up immediately
758                         if(Multi_voice_stream[idx].stream_last_heard == -1){
759                                 Multi_voice_stream[idx].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;                            
760
761 #ifdef MULTI_VOICE_VERBOSE
762                                 nprintf(("Network","MULTI VOICE : freeing released token (no packets)\n"));
763 #endif
764                         } 
765                         // if a sufficiently long amount of time has elapsed since he released the token, free it up
766                         else {
767                                 float t1,t2;
768                                 t1 = f2fl(Multi_voice_stream[idx].stream_last_heard);
769                                 t2 = f2fl(timer_get_fixed_seconds());
770                                 if((t2 - t1) >= MULTI_VOICE_TOKEN_RELEASE_WAIT){
771                                         Multi_voice_stream[idx].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;
772
773 #ifdef MULTI_VOICE_VERBOSE
774                                         nprintf(("Network","MULTI VOICE : freeing released token (time elapsed)\n"));
775 #endif
776                                 }
777                         }
778                         break;
779
780                 // if the token is still being held by a player
781                 default :
782                         // if the token timestamp has elapsed, take the token back
783                         if((Multi_voice_stream[idx].token_stamp != -1) && timestamp_elapsed(Multi_voice_stream[idx].token_stamp)){
784                                 Assert(Multi_voice_stream[idx].token_status != MULTI_VOICE_TOKEN_INDEX_FREE);
785                                 multi_voice_take_token(idx);
786                         }                               
787                         break;
788                 }
789         }
790
791         // for each netplayer, if his token wait timestamp is running, see if it has popped yet
792         for(idx=0;idx<MAX_PLAYERS;idx++){
793                 if(MULTI_CONNECTED(Net_players[idx]) && (Net_players[idx].s_info.voice_token_timestamp != -1) && timestamp_elapsed(Net_players[idx].s_info.voice_token_timestamp)){
794                         // unset it so that he can have the token again
795                         Net_players[idx].s_info.voice_token_timestamp = -1;
796                 }
797         }
798 }
799
800 // process voice details as a player (may also be the server)
801 void multi_voice_player_process()
802 {
803         // if the voice key is down for the first time this frame, send a request for the token
804         if(!Multi_voice_keydown && multi_voice_keydown() && Multi_voice_can_record && !(Netgame.options.flags & MSO_FLAG_NO_VOICE)){
805                 // mark the key as being down
806                 Multi_voice_keydown = 1;
807
808                 // send a request for a token
809                 multi_voice_request_token();
810
811 #ifdef MULTI_VOICE_VERBOSE
812                 nprintf(("Network","MULTI VOICE : Request\n"));
813 #endif
814         }       
815         
816         // if the key is still being pressed
817         if(Multi_voice_keydown && multi_voice_keydown() && Multi_voice_can_record){
818                 // if we have the token
819                 if(Multi_voice_token){                  
820                         // if we're not already recording, start recording
821                         if(!Multi_voice_recording){
822 #ifdef MULTI_VOICE_VERBOSE
823                                 nprintf(("Network","MULTI VOICE : RECORD %d\n",(int)Multi_voice_stream_id));
824 #endif  
825                                 // flush the old stream
826                                 multi_voice_flush_old_stream(0);
827
828                                 // start the recording process with the appropriate callback function
829                                 if(rtvoice_start_recording(multi_voice_process_next_chunk)){
830                                         nprintf(("Network","MULTI VOICE : Error initializing recording!\n"));                                   
831                                         return;
832                                 }
833                                 
834                                 // set myself to be recording
835                                 Multi_voice_recording = 1;
836
837                                 // set the time when I started recording
838                                 Multi_voice_recording_stamp = timestamp(Multi_voice_max_time);
839
840                                 // set the current packet/chunk index to 0
841                                 Multi_voice_current_stream_index = 0;
842                                 Multi_voice_current_stream_sent = 0;
843                                 
844                                 // get the proper messaging mode
845                                 if(Game_mode & GM_IN_MISSION){
846                                         // in mission, paused
847                                         if(gameseq_get_state() == GS_STATE_MULTI_PAUSED){
848                                                 Multi_voice_send_mode = MULTI_MSG_ALL;
849                                         } 
850                                         // in mission, unpaused
851                                         else {
852                                                 Multi_voice_send_mode = multi_msg_mode();
853                                         }
854                                 } else {
855                                         Multi_voice_send_mode = MULTI_MSG_ALL;
856                                 }
857                         }
858
859                         // if we've recorded the max time allowed, send the data
860                         if((Multi_voice_recording_stamp != -1) && timestamp_elapsed(Multi_voice_recording_stamp)){
861 #ifdef MULTI_VOICE_VERBOSE
862                                 nprintf(("Network","MULTI VOICE : timestamp popped"));
863 #endif
864                                 // mark me as no longer recording
865                                 Multi_voice_recording = 0;                      
866                                 Multi_voice_current_stream_sent = -1;
867
868                                 // stop the recording process
869                                 rtvoice_stop_recording();                               
870                                 
871 #ifdef MULTI_VOICE_POST_DECOMPRESS
872                                 multi_voice_player_send_stream();
873 #endif
874
875                                 // play my sound locally as well
876 #ifdef MULTI_VOICE_LOCAL_ECHO   
877                                 multi_voice_alg_play_window(0);
878 #endif
879                                 // release the token back to the server
880                                 multi_voice_release_token();
881                         }
882                 }
883         }
884         // if the key has been released
885         else if(Multi_voice_keydown && !multi_voice_keydown() && Multi_voice_can_record){
886 #ifdef MULTI_VOICE_VERBOSE
887                 nprintf(("Network","MULTI VOICE : Release\n"));
888 #endif
889
890                 // mark the kay as not being down
891                 Multi_voice_keydown = 0;
892         
893                 // if we were recording, send the data
894                 if(Multi_voice_recording){              
895                         // mark me as no longer recording
896                         Multi_voice_recording = 0;
897
898                         Multi_voice_current_stream_sent = -1;
899
900                         // stop the recording process
901                         rtvoice_stop_recording();                       
902                 
903 #ifdef MULTI_VOICE_POST_DECOMPRESS
904                         multi_voice_player_send_stream();                       
905 #endif
906
907                         // play my sound locally as well
908 #ifdef MULTI_VOICE_LOCAL_ECHO   
909                         multi_voice_alg_play_window(0);
910 #endif
911
912                         // release the token back to the server
913                         multi_voice_release_token();
914                 }               
915         }       
916
917         // if the "denied" timestamp is set, but has elapsed or the user has let up on the key, set it to -1
918         if((Multi_voice_denied_stamp != -1) && (timestamp_elapsed(Multi_voice_denied_stamp) || !multi_voice_keydown())){
919                 Multi_voice_denied_stamp = -1;
920         }
921 }
922
923 // determine if the voice key is down this frame
924 int multi_voice_keydown()
925 {
926         // if we're in the options screen, we should never allow the button to be pressed
927         if(gameseq_get_state() == GS_STATE_OPTIONS_MENU){
928                 return 0;
929         }
930
931         // if we're pre-game, we should just be checking the keyboard bitflags
932         if(!(Game_mode & GM_IN_MISSION)){       
933                 return (keyd_pressed[MULTI_VOICE_KEY] && !(keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT])) ? 1 : 0;
934         } 
935
936         // in-mission, paused - treat just like any other "chattable" screen.
937         if(gameseq_get_state() == GS_STATE_MULTI_PAUSED){
938                 return (keyd_pressed[MULTI_VOICE_KEY] && !(keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT])) ? 1 : 0;
939         }
940
941         // ingame, unpaused, rely on the multi-messaging system (ingame)
942         return multi_msg_voice_record();
943 }
944
945 // find the voice stream index by token player index
946 int multi_voice_find_token(int player_index)
947 {
948         int idx;
949
950         // look through all the existing streams
951         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
952                 if(Multi_voice_stream[idx].token_status == player_index){
953                         return idx;
954                 }
955         }
956
957         // couldn't find it
958         return -1;
959 }
960
961 // <server> gives the token to a given player
962 void multi_voice_give_token(int stream_index,int player_index)
963 {
964         ubyte data[10],code;
965         int packet_size = 0;
966         
967         // only the server should ever be here
968         Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
969
970         // set this player as having the token  
971         Multi_voice_stream[stream_index].token_status = player_index;
972         
973         // set the token timeout
974         Multi_voice_stream[stream_index].token_stamp = timestamp(MULTI_VOICE_TOKEN_TIMEOUT);
975
976         // set the stream id and increment the count
977         Multi_voice_stream[stream_index].stream_id = Multi_voice_next_stream_id;
978         multi_voice_inc_stream_id();
979
980         // set the last heard from time to -1 to indicate we've heard no sound from this guy
981         Multi_voice_stream[stream_index].stream_last_heard = -1;
982
983 #ifdef MULTI_VOICE_VERBOSE
984         nprintf(("Network","MULTI VOICE : GIVE TOKEN %d\n",(int)Multi_voice_next_stream_id));   
985 #endif
986
987         // if we're giving to ourself, don't send any data
988         if(Net_player == &Net_players[player_index]){
989                 Multi_voice_token = 1;
990
991                 Multi_voice_stream_id = Multi_voice_stream[stream_index].stream_id;
992         } else {
993                 // send the "give" packet to the guy
994                 BUILD_HEADER(VOICE_PACKET);
995                 code = MV_CODE_GIVE_TOKEN;
996                 ADD_DATA(code);
997
998                 // add the current stream id#
999                 ADD_DATA(Multi_voice_stream[stream_index].stream_id);
1000
1001                 // send reliably                
1002                 multi_io_send_reliable(&Net_players[player_index], data, packet_size);
1003         }       
1004 }
1005
1006 // <server> takes the token from a given player
1007 void multi_voice_take_token(int stream_index)
1008 {
1009         ubyte data[10],code;
1010         int packet_size = 0;
1011
1012         // only the server should ever be here
1013         Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);     
1014
1015         // if the index is -1, the token has probably been released to us "officially" already
1016         if((Multi_voice_stream[stream_index].token_status == MULTI_VOICE_TOKEN_INDEX_FREE) || (Multi_voice_stream[stream_index].token_status == MULTI_VOICE_TOKEN_INDEX_RELEASED)){
1017                 Multi_voice_stream[stream_index].token_stamp = -1;
1018                 return;
1019         }
1020
1021         // if i'm taking from myself, don't send any data
1022         if(Net_player == &Net_players[Multi_voice_stream[stream_index].token_status]){
1023                 Multi_voice_token = 0;
1024
1025                 // timestamp this guy so that he can't get the token back immediately
1026                 Net_player->s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1027         } else {
1028                 // send the "take" packet to the guy
1029                 BUILD_HEADER(VOICE_PACKET);
1030                 code = MV_CODE_TAKE_TOKEN;
1031                 ADD_DATA(code);
1032
1033                 // send reliably                
1034                 multi_io_send_reliable(&Net_players[Multi_voice_stream[stream_index].token_status], data, packet_size);
1035
1036                 // timestamp this guy so that he can't get the token back immediately
1037                 Net_players[Multi_voice_stream[stream_index].token_status].s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1038         }
1039
1040         // take the token back from the dude
1041         Multi_voice_stream[stream_index].token_status = MULTI_VOICE_TOKEN_INDEX_RELEASED;       
1042         Multi_voice_stream[stream_index].token_stamp = -1;
1043 }
1044
1045 // <server> tells the client he's been denied on this request
1046 void multi_voice_deny_token(int player_index)
1047 {
1048         ubyte data[10],code;
1049         int packet_size = 0;
1050
1051         // only the server should ever be here
1052         Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);     
1053         
1054
1055         // if i'm denying myself, set the denied timestamp
1056         if(Net_player == &Net_players[player_index]){   
1057                 Multi_voice_denied_stamp = timestamp(MULTI_VOICE_DENIED_TIME);          
1058         } else {
1059                 // send the "deny" packet to the guy
1060                 BUILD_HEADER(VOICE_PACKET);
1061                 code = MV_CODE_DENY_TOKEN;
1062                 ADD_DATA(code);
1063
1064                 // send reliably                
1065                 multi_io_send_reliable(&Net_players[player_index], data, packet_size);
1066         }
1067 }
1068
1069 // <player> releases the token back to the server
1070 void multi_voice_release_token()
1071 {
1072         ubyte data[10],code;
1073         int packet_size = 0;
1074
1075         // I don't have the token anymore
1076         Multi_voice_token = 0;
1077
1078         // if i'm the server, don't send any data
1079         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1080                 // mark the token as being released
1081                 int stream_index = multi_voice_find_token(MY_NET_PLAYER_NUM);
1082                 Multi_voice_stream[stream_index].token_status = MULTI_VOICE_TOKEN_INDEX_RELEASED;
1083                                 
1084                 // timestamp this guy so that he can't get the token back immediately
1085                 Net_player->s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1086         } else {
1087                 // send the "release" packet to the server
1088                 BUILD_HEADER(VOICE_PACKET);
1089                 code = MV_CODE_RELEASE_TOKEN;
1090                 ADD_DATA(code);
1091
1092                 // send reliably                
1093                 multi_io_send_reliable(Net_player, data, packet_size);
1094         }
1095 }
1096
1097 // <player> requests the token from the server
1098 void multi_voice_request_token()
1099 {
1100         ubyte data[10],code;
1101         int packet_size = 0;
1102
1103         // if i'm the server, process the request right now
1104         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1105                 multi_voice_process_token_request(MY_NET_PLAYER_NUM);
1106         } else {
1107                 // send the "request" packet to the server
1108                 BUILD_HEADER(VOICE_PACKET);
1109                 code = MV_CODE_REQUEST_TOKEN;
1110                 ADD_DATA(code);
1111
1112                 // send reliably                
1113                 multi_io_send_reliable(Net_player, data, packet_size);
1114         }
1115 }
1116
1117 // <player> sends hit bitflag settings (who he'll receive sound from, etc)
1118 void multi_voice_set_prefs(int pref_flags)
1119 {
1120         ubyte data[MAX_PACKET_SIZE],code;
1121         int idx;
1122         int packet_size = 0;
1123
1124         // set the local flags
1125         Multi_voice_local_prefs = pref_flags;
1126
1127         // if i'm the server, set the sound prefs right now
1128         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1129                 Multi_voice_player_prefs[MY_NET_PLAYER_NUM] = pref_flags;
1130         } else {
1131                 // send the prefs to the server
1132                 BUILD_HEADER(VOICE_PACKET);
1133                 code = MV_CODE_PLAYER_PREFS;
1134                 ADD_DATA(code);
1135
1136                 // add the address of all players being ignored
1137                 for(idx=0;idx<MAX_PLAYERS;idx++){
1138                         if(!(pref_flags & (1<<idx))){
1139                                 code = 0x0;
1140                                 ADD_DATA(code);
1141
1142                                 // add the player's id
1143                                 ADD_DATA(Net_players[idx].player_id);
1144                         }
1145                 }
1146                 // add final stop byte
1147                 code = 0xff;
1148                 ADD_DATA(code);
1149
1150                 // send reliably                
1151                 multi_io_send_reliable(Net_player, data, packet_size);
1152         }
1153 }
1154
1155 // set the default voice quality and duration (if server passes -1, he just broadcasts the qos to all clients)
1156 void multi_voice_set_vars(int qos,int duration)
1157 {                                       
1158         int need_update = 0;
1159         
1160         // make sure its in the right range
1161         if((qos > 0) && (qos <= 10)){
1162 #ifdef MULTI_VOICE_VERBOSE
1163                 nprintf(("Network","MULTI VOICE : SETTING QOS %d\n",qos));
1164 #endif 
1165
1166                 // set the default value
1167                 Multi_voice_qos = qos;          
1168
1169                 // set the value in the rtvoice module
1170                 rtvoice_set_qos(Multi_voice_qos);
1171
1172                 // update the netgame settings
1173                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){                                         
1174                         Netgame.options.voice_qos = (ubyte)Multi_voice_qos;
1175                         need_update = 1;                        
1176                 }
1177         }
1178
1179         // set the maximum duration
1180         if((duration > 0) && (duration <= MULTI_VOICE_MAX_TIME)){
1181 #ifdef MULTI_VOICE_VERBOSE
1182                 nprintf(("Network","MULTI VOICE : SETTING MAX RECORD TIME %d\n",duration));
1183 #endif
1184                 // set the default value
1185                 Multi_voice_max_time = duration;
1186
1187                 // update the netgame settings
1188                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1189                         Netgame.options.voice_record_time = duration;
1190                         need_update = 1;
1191                 }
1192         }       
1193
1194         // send an options update if necessary
1195         if(need_update && !(Game_mode & GM_STANDALONE_SERVER)){
1196                 multi_options_update_netgame();
1197         }
1198 }
1199
1200 // <server> process a request for the token
1201 void multi_voice_process_token_request(int player_index)
1202 {
1203         int stream_index,idx;
1204         
1205         // if we're not doing voice on this server, return now
1206         if(Netgame.options.flags & MSO_FLAG_NO_VOICE){
1207                 return;
1208         }
1209
1210         // if the player's token timestamp is not -1, can't give him the token
1211         if(Net_players[player_index].s_info.voice_token_timestamp != -1){
1212 #ifdef MULTI_VOICE_VERBOSE
1213                 nprintf(("Network","MULTI VOICE : Not giving token because player %s's timestamp hasn't elapsed yet!\n",Net_players[player_index].player->callsign));
1214                 nprintf(("Network","MULTI VOICE : token status %d\n",Multi_voice_stream[0].token_status));
1215 #endif
1216                 // deny the guy
1217                 multi_voice_deny_token(player_index);
1218                 return;
1219         }
1220
1221         // attempt to find a free token token
1222         stream_index = -1;
1223         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1224                 if(Multi_voice_stream[idx].token_status == MULTI_VOICE_TOKEN_INDEX_FREE){
1225                         multi_voice_give_token(idx,player_index);
1226                         return;
1227                 }
1228         }       
1229 }
1230
1231 // free up any memory which may have been malloced
1232 void multi_voice_free_all()
1233 {
1234         int idx,s_idx;
1235
1236         // free up the playback buffer
1237         if(Multi_voice_playback_buffer != NULL){
1238                 free(Multi_voice_playback_buffer);
1239                 Multi_voice_playback_buffer = NULL;
1240         }
1241
1242         // free up the accum buffers
1243         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1244                 for(s_idx=0;s_idx<MULTI_VOICE_ACCUM_BUFFER_COUNT;s_idx++){
1245                         if(Multi_voice_stream[idx].accum_buffer[s_idx] != NULL){
1246                                 free(Multi_voice_stream[idx].accum_buffer[s_idx]);
1247                                 Multi_voice_stream[idx].accum_buffer[s_idx] = NULL;
1248                         }
1249                 }
1250         }       
1251 }
1252
1253 // <player> send the currently recorded sound
1254 void multi_voice_player_send_stream()
1255 {
1256         ubyte data[MAX_PACKET_SIZE],code,*rbuf,msg_mode,chunk_index;
1257         ushort chunk_size,uc_size;
1258         int packet_size = 0;
1259         int sound_size,size_sent,uncompressed_size,target_index,max_chunk_size;
1260         float gain;
1261         double d_gain;
1262
1263         // we'd better not ever get here as we can't record voice
1264         Assert(Multi_voice_can_record);
1265
1266         // get the data 
1267         rtvoice_get_data((unsigned char**)&Multi_voice_record_buffer,&sound_size,&uncompressed_size,&d_gain);           
1268         gain = (float)d_gain;
1269
1270         msg_mode = (ubyte)Multi_voice_send_mode;
1271         // get the specific target if we're in MSG_TARGET mode
1272         target_index = -1;
1273         if(msg_mode == MULTI_MSG_TARGET){
1274                 if(Player_ai->target_objnum != -1){
1275                         target_index = multi_find_player_by_object(&Objects[Player_ai->target_objnum]);
1276                         if(target_index == -1){
1277                                 return;
1278                         }
1279                 } else {
1280                         return;
1281                 }
1282         }
1283
1284         // get the max chunk size
1285         max_chunk_size = multi_voice_max_chunk_size(Multi_voice_send_mode);
1286
1287         // go through the data and send all of it
1288         code = MV_CODE_DATA;
1289         chunk_index = 0;
1290         size_sent = 0;
1291         rbuf = (unsigned char*)Multi_voice_record_buffer;       
1292         while(size_sent < sound_size){
1293                 // build the header and add the opcode
1294                 BUILD_HEADER(VOICE_PACKET);
1295
1296                 // add the packet code type
1297                 ADD_DATA(code);
1298
1299                 // add the routing data and any necessary targeting information
1300                 ADD_DATA(msg_mode);
1301                 if(msg_mode == MULTI_MSG_TARGET){
1302                         ADD_DATA(Objects[Net_players[target_index].player->objnum].net_signature);
1303                 }
1304
1305                 // add my id#
1306                 ADD_DATA(Net_player->player_id);
1307
1308                 // add the current stream id#
1309                 ADD_DATA(Multi_voice_stream_id);
1310
1311                 Assert(uncompressed_size < MULTI_VOICE_MAX_BUFFER_SIZE);
1312                 uc_size = (ushort)uncompressed_size;
1313                 ADD_DATA(uc_size);
1314
1315                 // add the chunk index
1316                 ADD_DATA(chunk_index);
1317
1318                 // determine how much we are going to send in this packet
1319                 if((sound_size - size_sent) >= max_chunk_size){
1320                         chunk_size = (ushort)max_chunk_size;
1321                 } else {
1322                         chunk_size = (ushort)(sound_size - size_sent);
1323                 }
1324                 ADD_DATA(chunk_size);
1325
1326                 // add the gain
1327                 ADD_DATA(gain);
1328
1329                 // add the chunk of data                
1330                 memcpy(data+packet_size, rbuf,chunk_size);              
1331                 packet_size += chunk_size;
1332
1333                 // send to the server or rebroadcast if I _am_ the server
1334                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1335                         multi_voice_route_data(data,packet_size,MY_NET_PLAYER_NUM,(int)msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1336                 } else {                        
1337                         multi_io_send(Net_player, data, packet_size);
1338                 }
1339
1340                 // increment the chunk_index
1341                 chunk_index++;
1342
1343                 // increment bytes sent and the buffer
1344                 size_sent += (int)chunk_size;
1345                 rbuf += chunk_size;
1346         }       
1347 }
1348
1349 // process incoming sound data, return bytes processed
1350 int multi_voice_process_data(ubyte *data, int player_index,int msg_mode,net_player *target)
1351 {
1352         ubyte stream_id,chunk_index;
1353         ushort chunk_size,uc_size;      
1354         short who_from;
1355         int stream_index;
1356         float gain;
1357         int offset = 0;
1358
1359         // read in all packet data except for the sound chunk itself
1360         GET_DATA(who_from);
1361         GET_DATA(stream_id);
1362         GET_DATA(uc_size);
1363         GET_DATA(chunk_index);
1364         GET_DATA(chunk_size);
1365         GET_DATA(gain);                         
1366
1367         // if our netgame options are currently set for no voice, ignore the packet
1368         if((Netgame.options.flags & MSO_FLAG_NO_VOICE) || !Multi_options_g.std_voice){
1369                 offset += chunk_size;
1370                 return offset;
1371         }
1372
1373         // get a handle to a valid stream to be using, freeing old streams as necessary
1374         stream_index = multi_voice_get_stream((int)stream_id);  
1375
1376         // if this index is too high, flush the stream
1377         if(chunk_index >= MULTI_VOICE_ACCUM_BUFFER_COUNT){
1378 #ifdef MULTI_VOICE_VERBOSE
1379                 nprintf(("Network","MULTI VOICE : flushing stream because packet index is too high!!\n"));
1380 #endif
1381                 
1382                 // flush the stream
1383                 multi_voice_flush_old_stream(stream_index);
1384
1385                 // return bytes processed
1386                 offset += chunk_size;
1387                 return offset;
1388         }
1389
1390         // if we found a stream to work with
1391         if(stream_index != -1){
1392                 // set the id of where it came from
1393                 Multi_voice_stream[stream_index].stream_from = who_from;                
1394
1395                 // set the stream id#
1396                 Multi_voice_stream[stream_index].stream_id = stream_id;
1397
1398                 // set the gain
1399                 Multi_voice_stream[stream_index].accum_buffer_gain[chunk_index] = (double)gain;                 
1400
1401                 // set the stream uncompressed size size
1402                 Multi_voice_stream[stream_index].accum_buffer_usize[chunk_index] = uc_size;                     
1403
1404                 // set the token timestamp
1405                 Multi_voice_stream[stream_index].token_stamp = timestamp(MULTI_VOICE_TOKEN_TIMEOUT);
1406
1407                 // set the last heard time
1408                 Multi_voice_stream[stream_index].stream_last_heard = timer_get_fixed_seconds();
1409         
1410                 // copy the data and setup any other accum buffer data necessary
1411                 // ignore data if we can't play sounds
1412                 if(Multi_voice_can_play){
1413                         memcpy(Multi_voice_stream[stream_index].accum_buffer[chunk_index],data+offset,(int)chunk_size);
1414                 }
1415
1416                 Multi_voice_stream[stream_index].accum_buffer_flags[chunk_index] = 1;
1417                 Multi_voice_stream[stream_index].accum_buffer_csize[chunk_index] = chunk_size;                  
1418                         
1419                 // pass the data into the smart voice algorithm
1420                 if(player_index != -1){
1421                         multi_voice_alg_process_data(player_index,stream_index,chunk_index,chunk_size);         
1422                 }
1423         }
1424
1425         // increment the offset
1426         offset += (int)chunk_size;                                      
1427
1428         return offset;
1429 }
1430
1431 // <server> increment the current stream id#
1432 void multi_voice_inc_stream_id()
1433 {
1434         Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1435         
1436         if(Multi_voice_next_stream_id == 0xff){
1437                 Multi_voice_next_stream_id = 0;
1438         } else {
1439                 Multi_voice_next_stream_id++;
1440         }
1441 }
1442
1443 // flush any old sound stream data because we've started to receive data for a new stream
1444 void multi_voice_flush_old_stream(int stream_index)
1445 {               
1446 #ifdef MULTI_VOICE_VERBOSE
1447         nprintf(("Network","MULTI VOICE : old stream flush\n"));                
1448 #endif
1449
1450         // call the smart algorithm for flushing streams
1451         multi_voice_alg_flush_old_stream(stream_index);
1452         
1453         // clear all the accum buffer flags
1454         memset(Multi_voice_stream[stream_index].accum_buffer_flags,0,MULTI_VOICE_ACCUM_BUFFER_COUNT);
1455
1456         // clear the token 
1457         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1458                 multi_voice_take_token(stream_index);
1459         }
1460
1461         Multi_voice_stream[stream_index].token_stamp = -1;
1462         Multi_voice_stream[stream_index].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;
1463
1464         // timestamp the player
1465         Net_player->s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1466 }
1467
1468 // route sound data through the server to all appropriate players
1469 void multi_voice_route_data(ubyte *data, int packet_size,int player_index,int mode,net_player *target)
1470 {
1471         int idx;
1472
1473         // route the data to all other players
1474         switch(mode){
1475         case MULTI_MSG_ALL:
1476                 for(idx=0;idx<MAX_PLAYERS;idx++){
1477                         if(MULTI_CONNECTED( Net_players[idx] ) &&                                                                                                       // player is connected
1478                           ( &Net_players[idx] != &Net_players[player_index] ) &&                                                                // not the sending player
1479                           ( Net_player != &Net_players[idx] ) &&                                                                                                        // not me
1480                           ( Multi_voice_player_prefs[idx] & (1 << player_index) ) &&                                            // is accepting sound from this player
1481                           !( Net_players[idx].p_info.options.flags & MLO_FLAG_NO_VOICE ) ){                             // is accepting sound periods
1482                                                         
1483                                 multi_io_send(&Net_players[idx], data, packet_size);
1484                         }
1485                 }
1486                 break;
1487         
1488         case MULTI_MSG_FRIENDLY:
1489                 for(idx=0;idx<MAX_PLAYERS;idx++){
1490                         if(MULTI_CONNECTED( Net_players[idx] ) &&                                                                                                       // player is connected
1491                           ( &Net_players[idx] != &Net_players[player_index] ) &&                                                                // not the sending player
1492                           ( Net_player != &Net_players[idx] ) &&                                                                                                        // not me
1493                           ( Net_players[idx].p_info.team == Net_players[player_index].p_info.team ) &&// on the same team
1494                           ( Multi_voice_player_prefs[idx] & (1 << player_index) ) &&                                            // is accepting sound from the sender
1495                           !( Net_players[idx].p_info.options.flags & MLO_FLAG_NO_VOICE) ){                              // is accepting sound periods
1496                                                 
1497                                 multi_io_send(&Net_players[idx], data, packet_size);
1498                         }
1499                 }
1500                 break;
1501         case MULTI_MSG_HOSTILE:
1502                 for(idx=0;idx<MAX_PLAYERS;idx++){
1503                         if(MULTI_CONNECTED( Net_players[idx] ) &&                                                                                                       // player is connected
1504                           ( &Net_players[idx] != &Net_players[player_index] ) &&                                                                // not the sending player       
1505                           ( Net_player != &Net_players[idx] ) &&                                                                                                        // not me
1506                           ( Net_players[idx].p_info.team != Net_players[player_index].p_info.team ) &&// on the opposite team
1507                           ( Multi_voice_player_prefs[idx] & (1 << player_index) ) &&                                            // is accepting sound from the sender
1508                           !( Net_players[idx].p_info.options.flags & MLO_FLAG_NO_VOICE ) ){                             // is accepting sound periods
1509                                                         
1510                                 multi_io_send(&Net_players[idx], data, packet_size);
1511                         }
1512                 }
1513                 break;
1514         
1515         case MULTI_MSG_TARGET:
1516                 Assert(target != NULL);
1517                 if(!(target->p_info.options.flags & MLO_FLAG_NO_VOICE)){                                        
1518                         multi_io_send(target, data, packet_size);
1519                 }
1520                 break;
1521         }
1522 }
1523
1524 // find the stream to apply incoming sound data to, freeing up old ones as necessary
1525 int multi_voice_get_stream(int stream_id)
1526 {
1527         int idx,max_diff_index;
1528         fix cur_time,max_diff;
1529
1530         // first check to see if this stream exists
1531         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1532                 if(Multi_voice_stream[idx].stream_id == (ubyte)stream_id){
1533                         return idx;
1534                 }
1535         }
1536
1537         // if we got to this point, we didn't find the matching stream, so we should try and find an empty stream
1538         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1539                 if(Multi_voice_stream[idx].token_stamp == -1){
1540                         return idx;
1541                 }
1542         }
1543
1544 #ifdef MULTI_VOICE_VERBOSE
1545         nprintf(("Network","MULTI VOICE : going to blast old voice stream while looking for a free one - beware!!\n"));
1546 #endif
1547
1548         // if we got to this point, we should free up the oldest stream we have
1549         cur_time = timer_get_fixed_seconds();
1550         max_diff_index = -1;
1551         max_diff = -1;
1552         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1553                 if(((max_diff_index == -1) || ((cur_time - Multi_voice_stream[idx].stream_last_heard) > max_diff)) && (Multi_voice_stream[idx].token_stamp != -1)){
1554                         max_diff_index = idx;
1555                         max_diff = cur_time - Multi_voice_stream[idx].stream_last_heard;                        
1556                 }
1557         }
1558
1559         // if we found the oldest 
1560         if(max_diff_index != -1){
1561                 // flush the old stream
1562                 multi_voice_flush_old_stream(max_diff_index);           
1563                 
1564                 return max_diff_index;
1565         }
1566
1567         // some other fail condition
1568         return -1;
1569 }
1570
1571 // is the given sound stream playing (compares uncompressed sound size with current playback position)
1572 int multi_voice_stream_playing(int stream_index)
1573 {
1574         // if the handle is invalid, it can't be playing
1575         /*
1576         if(Multi_voice_stream[stream_index].stream_snd_handle < 0){
1577                 return 0;
1578         }
1579
1580         // if the sound is playing and the buffer is past the uncompressed size, its effectively done   
1581         if(ds_get_play_position(ds_get_channel(Multi_voice_stream[stream_index].stream_snd_handle)) >= (DWORD)Multi_voice_stream[stream_index].stream_uc_size){
1582                 return 1;
1583         }
1584         */
1585
1586         // not done yet
1587         return 0;
1588 }
1589
1590 // tack on pre and post sounds to a sound stream (pass -1 for either if no sound is wanted)
1591 // return final buffer size
1592 int multi_voice_mix(int post_sound,char *data,int cur_size,int max_size)
1593 {
1594         int post_size;
1595         
1596         // if the user passed -1 for both pre and post sounds, don't do a thing
1597         if(post_sound == -1){
1598                 return cur_size;
1599         }
1600
1601         // get the sizes of the additional sounds
1602         
1603         // post sound
1604         if(post_sound >= 0){
1605                 post_sound = snd_load(&Snds[post_sound]);
1606                 if(post_sound >= 0){
1607                         if(snd_size(post_sound,&post_size) == -1){
1608                                 post_size = 0;
1609                         }
1610                 } else {
1611                         post_size = 0;
1612                 }
1613         } else {
1614                 post_size = 0;
1615         }
1616                         
1617         // if we have a "post" sound to add
1618         if(post_size > 0){
1619                 if((max_size - cur_size) > post_size){
1620                         // copy in the sound
1621                         snd_get_data(post_sound,data + cur_size);
1622
1623                         // increment the cur_size
1624                         cur_size += post_size;
1625                 }
1626         }
1627
1628         // return the size of the new buffer
1629         return cur_size;
1630 }
1631
1632 // max size of a sound chunk which we can fit into a packet
1633 int multi_voice_max_chunk_size(int msg_mode)
1634 {
1635         int header_size;
1636
1637         // all headers contain the following data
1638         header_size =   1 +                                                                     // messaging mode
1639                                                 1 +                                                                     // stream id #
1640                                                 2 +                                                                     // packet uncompressed size
1641                                                 2 +                                                                     // compressed size
1642                                                 4;                                                                              // gain 
1643
1644         // if we're targeting a specific player
1645         if(msg_mode == MULTI_MSG_TARGET){
1646                 header_size += 2;                                                                       // targeted player's object net_signature
1647         }
1648         
1649         // if we're in IPX mode
1650         if(Psnet_my_addr.type == NET_IPX){
1651                 header_size += 10;                                                              // my address (10 bytes in IPX)         
1652         }
1653         // if we're in TCP mode
1654         else {
1655                 header_size +=  4;                                                                      // my address (4 bytes in TCP)
1656         }
1657
1658         // calculate max chunk size
1659         return (MAX_PACKET_SIZE -                                                       // max freespace packet size
1660                           1                                     -                                                       // packet type 
1661                           1                                     -                                                       // voice packet code subtype
1662                           header_size);                                                         // calculated header size
1663 }
1664
1665 // --------------------------------------------------------------------------------------------------
1666 // MULTI VOICE / RTVOICE INTERFACE
1667 //
1668
1669 // process the "next" chunk of standalone valid sound data from the rtvoice system
1670 void multi_voice_process_next_chunk()
1671 {                       
1672         int sound_size,uncompressed_size;       
1673         float gain;
1674         double d_gain;
1675         voice_stream *str;
1676
1677         // we'd better not ever get here is we can't record voice
1678         Assert(Multi_voice_can_record);
1679
1680         // get the data 
1681         rtvoice_get_data((unsigned char**)&Multi_voice_record_buffer,&sound_size,&uncompressed_size,&d_gain);           
1682         gain = (float)d_gain;
1683
1684         // if we've reached the max # of packets for this stream, bail
1685         if(Multi_voice_current_stream_index >= (MULTI_VOICE_ACCUM_BUFFER_COUNT - 1)){
1686                 nprintf(("Network","MULTI VOICE : Forcing stream to stop on the record size!!!\n"));
1687
1688                 // mark me as no longer recording
1689                 Multi_voice_recording = 0;                      
1690
1691                 Multi_voice_current_stream_sent = -1;
1692                                 
1693                 // stop the recording process
1694                 rtvoice_stop_recording();                               
1695                                 
1696 #ifdef MULTI_VOICE_POST_DECOMPRESS
1697                 multi_voice_player_send_stream();
1698 #endif
1699
1700                 // play my sound locally as well
1701 #ifdef MULTI_VOICE_LOCAL_ECHO   
1702                 multi_voice_alg_play_window(0);
1703 #endif
1704                 // release the token back to the server
1705                 multi_voice_release_token();
1706
1707                 // unset the timestamp so we don't still think we're still recording
1708                 Multi_voice_recording_stamp = -1;
1709
1710                 return;
1711         }
1712
1713         // pack the data locally as well (so I can hear myself)
1714         str = &Multi_voice_stream[0];
1715         memcpy(str->accum_buffer[Multi_voice_current_stream_index],Multi_voice_record_buffer,sound_size);
1716         str->stream_from = Net_player->player_id;       
1717         str->accum_buffer_flags[Multi_voice_current_stream_index] = 1;
1718         str->accum_buffer_usize[Multi_voice_current_stream_index] = (ushort)uncompressed_size;
1719         str->accum_buffer_csize[Multi_voice_current_stream_index] = (ushort)sound_size;
1720         str->accum_buffer_gain[Multi_voice_current_stream_index] = d_gain;      
1721
1722         // increment the stream index
1723         Multi_voice_current_stream_index++;
1724 }
1725
1726
1727 // --------------------------------------------------------------------------------------------------
1728 // MULTI VOICE PACKET HANDLERS
1729 //
1730
1731 // send a dummy packet in the place of a too-large data packet
1732 void multi_voice_send_dummy_packet()
1733 {
1734         ubyte data[10],code,msg_mode;
1735         int packet_size,target_index;   
1736
1737         // build the header and add the opcode
1738         BUILD_HEADER(VOICE_PACKET);
1739         code = (ubyte)MV_CODE_DATA_DUMMY;
1740         ADD_DATA(code);
1741
1742         msg_mode = (ubyte)Multi_voice_send_mode;
1743         // get the specific target if we're in MSG_TARGET mode
1744         target_index = -1;
1745         if(msg_mode == MULTI_MSG_TARGET){
1746                 if(Player_ai->target_objnum != -1){
1747                         target_index = multi_find_player_by_object(&Objects[Player_ai->target_objnum]);
1748                         if(target_index == -1){
1749                                 return;
1750                         }
1751                 } else {
1752                         return;
1753                 }
1754         }
1755         ADD_DATA(msg_mode);
1756         if(msg_mode == MULTI_MSG_TARGET){
1757                 ADD_DATA(Objects[Net_players[target_index].player->objnum].net_signature);
1758         }
1759
1760         // add the voice stream id
1761         ADD_DATA(Multi_voice_stream_id);
1762
1763         // send to the server or rebroadcast if I _am_ the server
1764         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1765                 multi_voice_route_data(data,packet_size,MY_NET_PLAYER_NUM,(int)msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1766         } else {                
1767                 multi_io_send(Net_player, data, packet_size);
1768         }       
1769 }
1770
1771 // process a dummy data packet
1772 int multi_voice_process_data_dummy(ubyte *data)
1773 {
1774         int offset = 0;
1775         int stream_index;
1776         ubyte stream_id;
1777
1778         // get the stream id
1779         GET_DATA(stream_id);
1780
1781         // get the proper stream index
1782         stream_index = multi_voice_get_stream((int)stream_id);
1783
1784         // set the token timestamp
1785         Multi_voice_stream[stream_index].token_stamp = timestamp(MULTI_VOICE_TOKEN_TIMEOUT);
1786
1787         // set the last heard time
1788         Multi_voice_stream[stream_index].stream_last_heard = timer_get_fixed_seconds();
1789
1790         // set the timeout timestamp
1791         Multi_voice_stamps[stream_index] = timestamp(MV_ALG_TIMEOUT);   
1792
1793         // return bytes processed
1794         return offset;
1795 }
1796
1797 // process a player preferences packet, return bytes processed
1798 int multi_voice_process_player_prefs(ubyte *data,int player_index)
1799 {
1800         ubyte val;
1801         int mute_index;
1802         short mute_id;
1803         int offset = 0;
1804
1805         // set all channels active
1806         Multi_voice_player_prefs[player_index] = 0xffffffff;
1807
1808         // get all muted players
1809         GET_DATA(val);
1810         while(val != 0xff){
1811                 GET_DATA(mute_id);
1812
1813                 // get the player to mute
1814                 mute_index = find_player_id(mute_id);
1815                 if(mute_index != -1){
1816 #ifdef MULTI_VOICE_VERBOSE
1817                         nprintf(("Network","Player %s muting player %s\n",Net_players[player_index].player->callsign,Net_players[mute_index].player->callsign));
1818 #endif
1819                         // mute the guy
1820                         Multi_voice_player_prefs[player_index] &= ~(1<<mute_index);
1821                 }
1822
1823                 // get the next stop value
1824                 GET_DATA(val);
1825         }
1826
1827         // return bytes processed
1828         return offset;
1829 }
1830
1831 // process an incoming voice packet of some kind or another
1832 void multi_voice_process_packet(ubyte *data, header *hinfo)
1833 {
1834         ubyte code,msg_mode;
1835         ushort target_sig;      
1836         int player_index,stream_index,target_index;     
1837         int offset = HEADER_LENGTH;     
1838
1839         // find out who is sending this data    
1840         player_index = find_player_id(hinfo->id);               
1841
1842         // get the opcode
1843         GET_DATA(code);
1844
1845         // process the packet
1846         switch(code){
1847         // I don't have the token anymore
1848         case MV_CODE_TAKE_TOKEN:
1849                 // we should never have the token if we cannot record
1850                 if(!Multi_voice_can_record){
1851                         Int3();
1852                 }
1853
1854                 Multi_voice_token = 0;
1855                 break;
1856
1857         // I have been denied the token
1858         case MV_CODE_DENY_TOKEN:
1859                 // set the "denied" timestamp
1860                 Multi_voice_denied_stamp = timestamp(MULTI_VOICE_DENIED_TIME);
1861                 break;
1862         
1863         // I now have the token
1864         case MV_CODE_GIVE_TOKEN:                
1865                 GET_DATA(Multi_voice_stream_id);
1866
1867                 // we should never get the token if we cannot record
1868                 if(!Multi_voice_can_record){
1869                         Int3();
1870                 }
1871
1872                 // if we no longer have the keydown, automatically release the token
1873                 if(!Multi_voice_keydown){
1874                         multi_voice_release_token();
1875                 } else {
1876                         Multi_voice_token = 1;
1877                 }
1878                 break;
1879
1880         // a request for the token from a player
1881         case MV_CODE_REQUEST_TOKEN:
1882                 if(player_index >= 0){
1883                         multi_voice_process_token_request(player_index);
1884                 }
1885                 break;
1886         
1887         // a player gave up the token
1888         case MV_CODE_RELEASE_TOKEN:             
1889                 if(player_index >= 0){
1890                         stream_index = multi_voice_find_token(player_index);
1891                 } else {
1892                         break;
1893                 }
1894                 
1895                 if(stream_index >= 0){
1896                         // set the token as having been released                
1897                         Multi_voice_stream[stream_index].token_status = MULTI_VOICE_TOKEN_INDEX_RELEASED;               
1898
1899                         // timestamp this guy so that he can't get the token back immediately
1900                         Net_players[player_index].s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1901                 } 
1902                 break;
1903
1904         // a player has set prefs for himself
1905         case MV_CODE_PLAYER_PREFS:
1906                 Assert(player_index != -1);             
1907                 offset += multi_voice_process_player_prefs(data+offset,player_index);
1908                 break;
1909
1910         // a data packet
1911         case MV_CODE_DATA:
1912 #ifdef MULTI_VOICE_VERBOSE
1913                 nprintf(("Network","VOICE : PROC DATA\n"));
1914 #endif
1915                 // get routing information
1916                 target_index = -1;
1917                 GET_DATA(msg_mode);
1918                 if(msg_mode == MULTI_MSG_TARGET){
1919                         GET_DATA(target_sig);
1920                         target_index = multi_find_player_by_net_signature(target_sig);
1921                         Assert(target_index != -1);
1922                 }
1923
1924                 offset += multi_voice_process_data(data+offset,player_index,msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1925
1926                 // if we're the server of the game, we should also route this data to all other players
1927                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1928                         multi_voice_route_data(data,offset,player_index,msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1929                 }
1930                 break;  
1931
1932         // a data dummy packet
1933         case MV_CODE_DATA_DUMMY:
1934 #ifdef MULTI_VOICE_VERBOSE
1935                 nprintf(("Network","VOICE : PROC DATA DUMMY\n"));
1936 #endif
1937                 // get routing information
1938                 target_index = -1;
1939                 GET_DATA(msg_mode);
1940                 if(msg_mode == MULTI_MSG_TARGET){
1941                         GET_DATA(target_sig);
1942                         target_index = multi_find_player_by_net_signature(target_sig);
1943                         Assert(target_index != -1);
1944                 }
1945
1946                 offset += multi_voice_process_data_dummy(data+offset);
1947
1948                 // if we're the server of the game, we should also route this data to all other players
1949                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1950                         multi_voice_route_data(data,offset,player_index,msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1951                 }
1952                 break;
1953         }
1954         PACKET_SET_SIZE();
1955 }
1956
1957 // send all pending voice packets
1958 void multi_voice_client_send_pending()
1959 {
1960         ubyte data[MAX_PACKET_SIZE],code;
1961         ubyte msg_mode,chunk_index;
1962         ushort uc_size,chunk_size;
1963         int max_chunk_size,sent,target_index;
1964         int packet_size;
1965         float gain;
1966         voice_stream *str;
1967         
1968         // if we're not recording
1969         if(!Multi_voice_recording || (Multi_voice_current_stream_sent < 0) || (Multi_voice_current_stream_sent > Multi_voice_current_stream_index)){
1970                 return;
1971         }
1972
1973         // stream all buffered up packets
1974         str = &Multi_voice_stream[0];
1975         while(Multi_voice_current_stream_sent < Multi_voice_current_stream_index){              
1976                 sent = Multi_voice_current_stream_sent++;
1977
1978                 // get the current messaging mode
1979                 msg_mode = (ubyte)Multi_voice_send_mode;                
1980
1981                 // if the size of this voice chunk will fit in the packet
1982                 max_chunk_size = multi_voice_max_chunk_size(Multi_voice_send_mode);
1983                 if(str->accum_buffer_csize[sent] > max_chunk_size){
1984 #ifdef MULTI_VOICE_VERBOSE
1985                         nprintf(("Network","MULTI VOICE : streamed packet size too large!!\n"));
1986 #endif
1987
1988                         Multi_voice_current_stream_sent++;
1989
1990                         // send a dummy data packet instead
1991                         multi_voice_send_dummy_packet();
1992                         
1993                         continue;
1994                 }
1995
1996 #ifdef MULTI_VOICE_VERBOSE
1997                 nprintf(("Network","MULTI VOICE : PACKET %d %d\n",(int)str->accum_buffer_csize[sent],(int)str->accum_buffer_usize[sent]));
1998 #endif
1999         
2000                 // get the specific target if we're in MSG_TARGET mode
2001                 target_index = -1;
2002                 if(msg_mode == MULTI_MSG_TARGET){
2003                         if(Player_ai->target_objnum != -1){
2004                                 target_index = multi_find_player_by_object(&Objects[Player_ai->target_objnum]);
2005                                 if(target_index == -1){
2006                                         return;
2007                                 }
2008                         } else {
2009                                 return;
2010                         }
2011                 }
2012
2013                 // go through the data and send all of it
2014                 code = MV_CODE_DATA;
2015                 chunk_index = 0;                
2016         
2017                 // if this packet is small enough to fit within a psnet data packet             
2018                 BUILD_HEADER(VOICE_PACKET);
2019
2020                 // add the packet code type
2021                 ADD_DATA(code);
2022
2023                 // add the routing data and any necessary targeting information
2024                 ADD_DATA(msg_mode);
2025                 if(msg_mode == MULTI_MSG_TARGET){
2026                         Assert(Game_mode & GM_IN_MISSION);
2027                         ADD_DATA(Objects[Net_players[target_index].player->objnum].net_signature);
2028                 }
2029
2030                 // add my address 
2031                 ADD_DATA(Net_player->player_id);
2032
2033                 // add the current stream id#
2034                 ADD_DATA(Multi_voice_stream_id);
2035
2036                 Assert(str->accum_buffer_usize[sent] < MULTI_VOICE_MAX_BUFFER_SIZE);
2037                 uc_size = (ushort)str->accum_buffer_usize[sent];
2038                 ADD_DATA(uc_size);
2039
2040                 // add the chunk index
2041                 chunk_index = (ubyte)sent;
2042                 ADD_DATA(chunk_index);
2043
2044                 // size of the sound data
2045                 chunk_size = (ushort)str->accum_buffer_csize[sent];             
2046                 ADD_DATA(chunk_size);
2047
2048                 // add the gain
2049                 gain = (float)str->accum_buffer_gain[sent];
2050                 ADD_DATA(gain);
2051
2052                 // add the chunk of data                
2053                 memcpy(data+packet_size, str->accum_buffer[sent],chunk_size);           
2054                 packet_size += chunk_size;
2055
2056                 // send to the server or rebroadcast if I _am_ the server
2057                 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){         
2058                         multi_voice_route_data(data,packet_size,MY_NET_PLAYER_NUM,(int)msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
2059                 } else {                        
2060                         multi_io_send(Net_player, data, packet_size);
2061                 }       
2062         }
2063 }
2064
2065
2066 // --------------------------------------------------------------------------------------------------
2067 // MULTI VOICE ALGORITHM stuff
2068 //
2069
2070 // process and play the current window of sound stream data we have. reset the window for the next incoming data as well
2071 void multi_voice_alg_play_window(int stream_index)
2072 {
2073         int idx,buffer_offset;  
2074         voice_stream *st;
2075
2076 #ifdef MULTI_VOICE_VERBOSE
2077         nprintf(("Network","MULTI VOICE : PLAYING STREAM %d\n",stream_index));
2078 #endif
2079
2080         // get a pointer to the stream
2081         st = &Multi_voice_stream[stream_index];
2082
2083         // don't play anything back if we can't hear sound
2084         if(Multi_voice_can_play){       
2085                 // first, pack all the accum buffers into the playback buffer
2086 #ifdef MULTI_VOICE_PRE_DECOMPRESS
2087                 buffer_offset = Multi_voice_pre_sound_size;
2088                 nprintf(("Network","VOICE : pre sound size %d\n",Multi_voice_pre_sound_size));
2089                 for(idx=0;idx<MULTI_VOICE_ACCUM_BUFFER_COUNT;idx++){
2090                         // if the flag is set, uncompress the data into the playback buffer
2091                         if(st->accum_buffer_flags[idx]){
2092                                 // first, uncompress the data
2093                                 rtvoice_uncompress(st->accum_buffer[idx],(int)st->accum_buffer_csize[idx],st->accum_buffer_gain[idx],(ubyte*)Multi_voice_playback_buffer+buffer_offset,st->accum_buffer_usize[idx]);
2094                         
2095                                 // increment the buffer offset
2096                                 buffer_offset += st->accum_buffer_usize[idx];
2097                         }
2098                 }                               
2099 #endif
2100 #ifdef MULTI_VOICE_POST_DECOMPRESS
2101                 buffer_offset = 0;
2102                 for(idx=0;idx<MULTI_VOICE_ACCUM_BUFFER_COUNT;idx++){
2103                         // if the flag is set, copy the data
2104                         if(st->accum_buffer_flags[idx]){
2105                                 memcpy(Multi_voice_unpack_buffer+buffer_offset,st->accum_buffer[idx],st->accum_buffer_csize[idx]);
2106                                 buffer_offset += st->accum_buffer_csize[idx];
2107                         }
2108                 }       
2109
2110                 // decompress the whole shebang
2111                 rtvoice_uncompress((ubyte*)Multi_voice_unpack_buffer,buffer_offset,st->accum_buffer_gain[0],(ubyte*)Multi_voice_playback_buffer,st->accum_buffer_usize[0]);
2112                 buffer_offset = st->accum_buffer_usize[0];
2113 #endif          
2114
2115                 // mix in the SND_CUE_VOICE and the SND_END_VOICE game sounds
2116                 buffer_offset = multi_voice_mix(MULTI_VOICE_POST_SOUND,Multi_voice_playback_buffer,buffer_offset,MULTI_VOICE_MAX_BUFFER_SIZE);
2117                         
2118                 Assert(Multi_voice_stream[stream_index].stream_rtvoice_handle != -1);
2119
2120                 // kill any previously playing sounds
2121                 rtvoice_stop_playback(Multi_voice_stream[stream_index].stream_rtvoice_handle);  
2122                 Multi_voice_stream[stream_index].stream_snd_handle = -1;
2123
2124                 // if we can play sound and we know who this is from, display it
2125                 if(Multi_voice_can_play){
2126                         char voice_msg[256];
2127                         int player_index = find_player_id(Multi_voice_stream[stream_index].stream_from);
2128
2129                         if(player_index != -1){
2130                                 memset(voice_msg,0,256);
2131                                 sprintf(voice_msg,XSTR("<%s is speaking>",712),Net_players[player_index].player->callsign);
2132
2133                                 // display a chat message (write to the correct spot - hud, standalone gui, chatbox, etc)
2134                                 multi_display_chat_msg(voice_msg,player_index,0);
2135                         }
2136                 }
2137         
2138                 // now call the rtvoice playback functions              
2139                 Multi_voice_stream[stream_index].stream_snd_handle = rtvoice_play_uncompressed(Multi_voice_stream[stream_index].stream_rtvoice_handle,(unsigned char*)Multi_voice_playback_buffer,buffer_offset);       
2140                 Multi_voice_stream[stream_index].stream_start_time = timer_get_fixed_seconds();
2141         }
2142         
2143         // unset the stamp so that its not "free"
2144         Multi_voice_stamps[stream_index] = -1;
2145
2146         // flush the stream (will also grab the token back, if the server)
2147         multi_voice_flush_old_stream(stream_index);
2148 }
2149
2150 // decision function which decides if we should play the current block of sound we have
2151 int multi_voice_alg_should_play(int stream_index)
2152 {
2153         // if the timestamp has expired, play the sound
2154         if((Multi_voice_stamps[stream_index] != -1) && timestamp_elapsed(Multi_voice_stamps[stream_index])){
2155 #ifdef MULTI_VOICE_VERBOSE
2156                 nprintf(("Network","MULTI VOICE : DECIDE, TIMEOUT\n"));         
2157 #endif
2158                 return 1;
2159         }
2160                         
2161         return 0;
2162 }
2163
2164 // process incoming sound data in whatever way necessary (this function should take care of playing data when necessary)
2165 void multi_voice_alg_process_data(int player_index,int stream_index,ushort chunk_index,ushort chunk_size)
2166 {
2167         // do this so we don't get compiler warnings
2168         chunk_index = 0;
2169         chunk_size = 0;
2170         player_index = 0;
2171
2172         // update the timestamp for this window
2173         Multi_voice_stamps[stream_index] = timestamp(MV_ALG_TIMEOUT);   
2174 }
2175
2176 // process existing streams
2177 void multi_voice_alg_process_streams()
2178 {
2179         int idx;
2180         int player_index;
2181
2182         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){                   
2183                 // determine if we should play this window of data
2184                 if((Multi_voice_stamps[idx] != -1) && multi_voice_alg_should_play(idx)){
2185                         // determine who this stream came from
2186                         player_index = find_player_id(Multi_voice_stream[idx].stream_from);                     
2187
2188                         // server should check his own settings here
2189                         if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && ((Net_player->p_info.options.flags & MLO_FLAG_NO_VOICE) || (player_index == -1) || !(Multi_voice_player_prefs[MY_NET_PLAYER_NUM] & (1<<player_index))) ){
2190                                 // unset the stamp so that its not "free"
2191                                 Multi_voice_stamps[idx] = -1;
2192
2193                                 // flush the stream (will also grab the token back, if the server)
2194                                 multi_voice_flush_old_stream(idx);
2195
2196                                 nprintf(("Network","Server not playing sound because of set options!\n"));
2197                         }
2198                         // play the current sound
2199                         else {                          
2200                                 multi_voice_alg_play_window(idx);                       
2201                         }
2202                 }
2203         }
2204 }
2205
2206 // we are going to flush the current stream because we have started to receive data for a new one. do something first
2207 void multi_voice_alg_flush_old_stream(int stream_index)
2208 {
2209         // just unset the heard from timestamp for now
2210         Multi_voice_stamps[stream_index] = -1;
2211 }
2212
2213 // initialize the smart algorithm
2214 void multi_voice_alg_init()
2215 {
2216         int idx;
2217
2218         for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
2219                 Multi_voice_stamps[idx] = -1;
2220         }
2221 }
2222
2223
2224 // --------------------------------------------------------------------------------------------------
2225 // MULTI VOICE TESTING FUNCTIONS
2226 //
2227
2228 #define MV_TEST_RECORD_TIME                             3000                                    // recording time in ms for testing voice
2229 int Multi_voice_test_record_stamp = -1;
2230 int Multi_voice_test_packet_tossed = 0;
2231
2232 // process the next chunk of voice data
2233 void multi_voice_test_process_next_chunk()
2234 {
2235         unsigned char *outbuf,*outbuf_raw;
2236         int compressed_size,uncompressed_size,raw_size;
2237         double gain;
2238         
2239         // if the test recording stamp is -1, we should stop
2240         if(Multi_voice_test_record_stamp == -1){
2241                 rtvoice_stop_recording();
2242                 return;
2243         }
2244
2245         // if the recording timestamp has elapsed, stop the whole thing
2246         if(timestamp_elapsed(Multi_voice_test_record_stamp)){
2247                 nprintf(("Network","Stopping voice test recording\n"));
2248
2249                 rtvoice_stop_recording();
2250
2251                 Multi_voice_test_record_stamp = -1;
2252                 Multi_voice_test_packet_tossed = 0;
2253                 return;
2254         }
2255
2256         // otherwise get the compressed and uncompressed data and do something interesting with it
2257         rtvoice_get_data(&outbuf,&compressed_size,&uncompressed_size,&gain,&outbuf_raw,&raw_size);      
2258
2259         // determine whether the packet would have been dropped
2260         if(compressed_size > multi_voice_max_chunk_size(MULTI_MSG_ALL)){
2261                 Multi_voice_test_packet_tossed = 1;
2262         } else {
2263                 Multi_voice_test_packet_tossed = 0;
2264         }
2265
2266         // send the raw output buffer to the voice options screen
2267         options_multi_set_voice_data(outbuf_raw,raw_size,outbuf,compressed_size,uncompressed_size,gain);
2268 }
2269
2270 // start recording voice locally for playback testing
2271 void multi_voice_test_record_start()
2272 {
2273         // if there is test recording going on already, don't do anything
2274         if(Multi_voice_test_record_stamp != -1){
2275                 return;
2276         }
2277
2278         // stop any playback which may be occuring
2279         rtvoice_stop_playback_all();
2280
2281         // stop any recording which may be occuring
2282         rtvoice_stop_recording();
2283
2284         // set the timestamp
2285         Multi_voice_test_record_stamp = timestamp(MV_TEST_RECORD_TIME);
2286
2287         // start the recording of voice
2288         rtvoice_start_recording(multi_voice_test_process_next_chunk);
2289 }
2290
2291 // force stop any recording voice test
2292 void multi_voice_test_record_stop()
2293 {
2294         Multi_voice_test_record_stamp = -1;
2295         Multi_voice_test_packet_tossed = 0;
2296         rtvoice_stop_recording();
2297 }
2298
2299 // return if the test recording is going on
2300 int multi_voice_test_recording()
2301 {
2302         return (Multi_voice_test_record_stamp == -1) ? 0 : 1;
2303 }
2304
2305 // call this function if multi_voice_test_recording() is true to process various odds and ends of the test recording
2306 void multi_voice_test_process()
2307 {
2308         // if we're not recording, do nothing
2309         if(Multi_voice_test_record_stamp == -1){
2310                 return;
2311         }
2312
2313         // check to see if the timestamp has elapsed
2314         if(timestamp_elapsed(Multi_voice_test_record_stamp)){
2315                 Multi_voice_test_record_stamp = -1;
2316                 Multi_voice_test_packet_tossed = 0;
2317         }
2318 }
2319
2320 // get a playback buffer handle (return -1 if none exist - bad)
2321 int multi_voice_test_get_playback_buffer()
2322 {
2323         // return voice stream 0
2324         Assert(Multi_voice_stream[0].stream_snd_handle == -1);
2325         Assert(Multi_voice_stream[0].stream_rtvoice_handle != -1);
2326
2327         return Multi_voice_stream[0].stream_rtvoice_handle;
2328 }
2329
2330 // return whether the last sampled chunk would have been too large to fit in a packet
2331 int multi_voice_test_packet_tossed()
2332 {
2333         return Multi_voice_test_packet_tossed;
2334 }