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