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