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