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