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