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