2 * $Logfile: /Freespace2/code/Network/multi_voice.cpp $
8 * Revision 1.2 2002/05/07 03:16:47 theoddone33
9 * The Great Newline Fix
11 * Revision 1.1.1.1 2002/05/03 03:28:10 root
15 * 9 3/10/99 6:50p Dave
16 * Changed the way we buffer packets for all clients. Optimized turret
17 * fired packets. Did some weapon firing optimizations.
19 * 8 3/09/99 6:24p Dave
20 * More work on object update revamping. Identified several sources of
21 * unnecessary bandwidth.
23 * 7 1/08/99 4:42p Anoop
24 * Fixed memory overwrite problem.
26 * 6 11/19/98 4:19p Dave
27 * Put IPX sockets back in psnet. Consolidated all multiplayer config
30 * 5 11/19/98 8:03a Dave
31 * Full support for D3-style reliable sockets. Revamped packet lag/loss
32 * system, made it receiver side and at the lowest possible level.
34 * 4 11/17/98 11:12a Dave
35 * Removed player identification by address. Now assign explicit id #'s.
37 * 3 11/05/98 5:55p Dave
38 * Big pass at reducing #includes
40 * 2 10/07/98 10:53a Dave
43 * 1 10/07/98 10:50a Dave
45 * 43 6/16/98 4:22p Allender
46 * fix Net_player reference problem
48 * 42 6/13/98 9:32p Mike
49 * Kill last character in file which caused "Find in Files" to report the
50 * file as "not a text file."
52 * 41 6/13/98 6:01p Hoffoss
53 * Externalized all new (or forgot to be added) strings to all the code.
55 * 40 6/13/98 3:19p Hoffoss
56 * NOX()ed out a bunch of strings that shouldn't be translated.
58 * 39 6/12/98 2:49p Dave
61 * 38 5/27/98 4:14p Dave
62 * Spiffed up text display for voice status.
64 * 37 5/27/98 1:15p Dave
65 * Change pxo login failure popup text. Put in message display of player
66 * who is currently doing voice.
68 * 36 5/24/98 3:45a Dave
69 * Minor object update fixes. Justify channel information on PXO. Add a
70 * bunch of configuration stuff for the standalone.
72 * 35 5/24/98 12:12a Frank
73 * Make sure recording clients don't ever send/store/handle packets past
74 * the limit of the accum buffer.
76 * 34 5/22/98 9:35p Dave
77 * Put in channel based support for PXO. Put in "shutdown" button for
78 * standalone. UI tweaks for TvT
80 * 33 5/20/98 2:24a Dave
81 * Fixed server side voice muting. Tweaked multi debrief/endgame
82 * sequencing a bit. Much friendlier for stats tossing/accepting now.
84 * 32 4/25/98 2:02p Dave
85 * Put in multiplayer context help screens. Reworked ingame join ship
86 * select screen. Fixed places where network timestamps get hosed.
88 * 31 4/21/98 4:44p Dave
89 * Implement Vasudan ships in multiplayer. Added a debug function to bash
90 * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
91 * problem in options screen.
93 * 30 4/17/98 5:27p Dave
94 * More work on the multi options screen. Fixed many minor ui todo bugs.
96 * 29 4/09/98 11:01p Dave
97 * Put in new multi host options screen. Tweaked multiplayer options a
100 * 28 4/08/98 10:11a Dave
101 * Fixed a voice packet indexing problem.
103 * 27 4/07/98 5:42p Dave
104 * Put in support for ui display of voice system status (recording,
105 * playing back, etc). Make sure main hall music is stopped before
106 * entering a multiplayer game via ingame join.
108 * 26 4/04/98 4:22p Dave
109 * First rev of UDP reliable sockets is done. Seems to work well if not
112 * 25 4/03/98 4:22p Allender
113 * Fixed a bug where voice recording was not cut off after MAX_TIME.
115 * 24 4/03/98 1:03a Dave
116 * First pass at unreliable guaranteed delivery packets.
118 * 23 3/30/98 6:27p Dave
119 * Put in a more official set of multiplayer options, including a system
120 * for distributing netplayer and settings.
122 * 22 3/27/98 9:46a Dave
123 * Made default quality of sound 10.
125 * 21 3/26/98 6:01p Dave
126 * Put in file checksumming routine in cfile. Made pilot pic xferring more
127 * robust. Cut header size of voice data packets in half. Put in
128 * restricted game host query system.
130 * 20 3/25/98 8:36p Dave
131 * Removed potential bug spots from voice code.
133 * 19 3/25/98 2:16p Dave
134 * Select random default image for newly created pilots. Fixed several
135 * multi-pause messaging bugs. Begin work on online help for multiplayer
138 * 18 3/24/98 5:00p Dave
139 * Fixed several ui bugs. Put in pre and post voice stream playback sound
140 * fx. Put in error specific popups for clients getting dropped from games
141 * through actions other than their own.
143 * 17 3/23/98 7:18p Dave
144 * Converted voice to use streaming of packets as they are recorded.
146 * 16 3/22/98 7:13p Lawrance
147 * Get streaming of recording voice working
149 * 15 3/20/98 1:01p Dave
150 * Made the token system for multi_voice more reliable. Fixed a bug where
151 * standalones and other server who can't play sound don't route
152 * multi_voice correctly.
154 * 14 3/19/98 5:05p Dave
155 * Put in support for targeted multiplayer text and voice messaging (all,
156 * friendly, hostile, individual).
158 * 13 3/18/98 5:52p Dave
159 * Put in netgame password popup. Numerous ui changes. Laid groundwork for
160 * streamed multi_voice data.
162 * 12 3/18/98 3:32p Dave
163 * Put in a hook for streamed rtvoice data from the rtvoice system.
165 * 11 3/18/98 9:43a Dave
166 * Removed an uninitialized data warning.
168 * 10 3/17/98 12:30a Dave
169 * Put in hud support for rtvoice. Several ui interface changes.
171 * 9 3/16/98 2:35p Dave
172 * Numerous bug fixes. Made the "cue sound" sound play before incoming
175 * 8 3/15/98 4:17p Dave
176 * Fixed oberver hud problems. Put in handy netplayer macros. Reduced size
177 * of network orientation matrices.
179 * 7 3/04/98 4:36p Dave
180 * Fixed a compiler warning.
182 * 6 2/26/98 6:01p Dave
183 * Made voice playback work correctly under NT.
185 * 5 2/26/98 5:01p Dave
186 * Fixed a multi_voice_reset() bug.
188 * 4 2/26/98 4:21p Dave
189 * More robust multiplayer voice.
191 * 3 2/25/98 8:58p Dave
192 * Got first full implementation of multi voice done.
194 * 2 2/24/98 11:56p Lawrance
195 * Change real-time voice code to provide the uncompressed size on decode.
197 * 1 2/24/98 10:12p Dave
198 * Initial pass at multiplayer voice streaming.
205 #include "freespace.h"
206 #include "gamesequence.h"
207 #include "multimsgs.h"
208 #include "multiutil.h"
209 #include "multi_voice.h"
210 #include "multi_pmsg.h"
214 #include "optionsmenumulti.h"
215 #include "stand_gui.h"
219 // --------------------------------------------------------------------------------------------------
220 // MULTI VOICE DEFINES/VARS
223 // #define MULTI_VOICE_POST_DECOMPRESS // when we're _not_ using streaming
224 #define MULTI_VOICE_PRE_DECOMPRESS // when we _are_ using streaming
226 #define MULTI_VOICE_VERBOSE // keep this defined for verbose debug output
228 #define MULTI_VOICE_LOCAL_ECHO // keep this defined for local echo of recorded network voice
230 // flag indicating the status of the multi voice system
231 int Multi_voice_inited = 0;
232 int Multi_voice_can_record = 0;
233 int Multi_voice_can_play = 0;
234 int Multi_voice_send_mode = MULTI_MSG_NONE; // gotten from the multi_msg system when we start recording
236 // packet code defines
237 #define MV_CODE_GIVE_TOKEN 0 // received player side - he now has the token to speak
238 #define MV_CODE_DENY_TOKEN 1 // received player side - server has denied this request
239 #define MV_CODE_TAKE_TOKEN 2 // received player side - the server is forcibly taking his token
240 #define MV_CODE_RELEASE_TOKEN 3 // received server side - player is relinquishing token
241 #define MV_CODE_REQUEST_TOKEN 4 // received server side - player is requesting token
242 #define MV_CODE_PLAYER_PREFS 5 // received server side - player bitflags for who he'll receive from
243 #define MV_CODE_DATA 6 // sound data
244 #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
246 // default quality of sound
247 #define MV_DEFAULT_QOS 10 // default quality of sound
248 int Multi_voice_qos; // default quality of sound
250 // sounds added to the front and end of a playing voice stream (set to -1 if none are wanted)
251 #define MULTI_VOICE_PRE_SOUND SND_CUE_VOICE
252 #define MULTI_VOICE_POST_SOUND SND_END_VOICE
253 int Multi_voice_pre_sound_size = 0;
257 // NOTE : the following 2 defines should be used for reference only. they represent the worst case situation,
258 // sending voice to a specific target under IPX. you should use multi_voice_max_chunk_size(...) when
259 // determining if a given chunk will fit into an individual freespace packet
260 // max size of a data packet header (note, this changes as the code itself changes - should probably never use this except for reference)
261 #define MULTI_VOICE_MAX_HEADER_SIZE 22
262 // size of an individual chunk (CHUNK == block of data stuck into a packet), in the worst case of header size (see above)
263 #define MULTI_VOICE_MAX_CHUNK_SIZE 488
265 // 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)
266 #define MULTI_VOICE_MAX_BUFFER_SIZE ((1<<16)+(1<<14)) // 80k
268 // overall size of an total accum buffer for a stream
269 #define MULTI_VOICE_ACCUM_BUFFER_SIZE (1<<14) // 16k
271 // how many accum buffers need to be in a total accum buffer
272 // NOTE : we reference MULTI_VOICE_MAX_CHUNK_SIZE here because it is worst case. ie, we'll always have enough
273 // accum buffers in anything better than the worst case if we use MULTI_VOICE_MAX_CHUNK_SIZE
274 #define MULTI_VOICE_ACCUM_BUFFER_COUNT (MULTI_VOICE_ACCUM_BUFFER_SIZE / MULTI_VOICE_MAX_CHUNK_SIZE)
276 int Multi_voice_max_time; // current maximum recording time
277 char *Multi_voice_record_buffer = NULL; // buffer for recording back voice
278 char *Multi_voice_playback_buffer = NULL; // buffer for processing the accum buffer and playing the result
281 #ifdef MULTI_VOICE_POST_DECOMPRESS
282 char Multi_voice_unpack_buffer[MULTI_VOICE_MAX_BUFFER_SIZE];
285 // the max amount of tokens we want to be floating about (max sound streams)
286 #define MULTI_VOICE_MAX_STREAMS 1
288 // voice algorithm stuff
289 // it would probably be good to base the timeout time on some multiple of our average ping to the server
290 #define MV_ALG_TIMEOUT 500 // if start get new data for a window then a pause this long, play the window
291 int Multi_voice_stamps[MULTI_VOICE_MAX_STREAMS];
293 // NOTE : this should be > then MULTI_VOICE_MAX_TIME + the time for the data to come over a network connection!!
294 #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
296 #define MULTI_VOICE_TOKEN_RELEASE_WAIT (1.0f) // wait 1 second
298 // the token index of a voice stream is set to one of these values, or the index of the player who has the token
299 #define MULTI_VOICE_TOKEN_INDEX_FREE -1 // the token (and the stream are free)
300 #define MULTI_VOICE_TOKEN_INDEX_RELEASED 0xDEADBEAD // the token has been released but the stream is still active
302 typedef struct voice_stream {
303 int token_status; // status of the token (player index if a player has it) or one of the above defines
304 int token_stamp; // timestamp for the MULTI_VOICE_TOKEN_TIMEOUT
306 short stream_from; // id of the player the stream is coming from
308 ubyte *accum_buffer[MULTI_VOICE_ACCUM_BUFFER_COUNT]; // accum buffer
309 ubyte accum_buffer_flags[MULTI_VOICE_ACCUM_BUFFER_COUNT]; // flag indicating the existence of a given accum (sub)buffer
310 ushort accum_buffer_usize[MULTI_VOICE_ACCUM_BUFFER_COUNT]; // uncompressed size of the corresponding (sub)buffer
311 ushort accum_buffer_csize[MULTI_VOICE_ACCUM_BUFFER_COUNT]; // compressed size of the corresponding (sub)buffer
312 double accum_buffer_gain[MULTI_VOICE_ACCUM_BUFFER_COUNT]; // gain of the corresponding (sub)buffer
314 ubyte stream_id; // stream id #
315 fix stream_last_heard; // last time we heard from this stream
317 fix stream_start_time; // time the stream started playing
318 int stream_snd_handle; // sound playing instance handle
319 int stream_rtvoice_handle; // rtvoice buffer handle
321 voice_stream Multi_voice_stream[MULTI_VOICE_MAX_STREAMS]; // voice streams themselves
324 #define MULTI_VOICE_KEY KEY_LAPOSTRO // key used for realtime voice
325 int Multi_voice_keydown = 0; // is the record key currently being pressed
326 int Multi_voice_recording = 0; // flag indicating if we're currently recording or not
327 int Multi_voice_token = 0; // if we currently have a token or not
328 int Multi_voice_recording_stamp = -1; // how long we've been recording
329 ubyte Multi_voice_stream_id = 0; // stream id for the stream we're currently sending
330 int Multi_voice_current_stream_index = 0; // packet index of the currently recodring stream
331 int Multi_voice_current_stream_sent = -1; // index of packet we've sent up to
334 ubyte Multi_voice_next_stream_id = 0; // kept on the server - given to the next valid token requester
335 int Multi_voice_player_prefs[MAX_PLAYERS]; // player bitflag preferences
337 // voice status data - used for determing the result of multi_voice_status
338 #define MULTI_VOICE_DENIED_TIME 1000 // how long to display the "denied" status
339 int Multi_voice_denied_stamp = -1; // timestamp for when we got denied a token
341 // local muting preferences
342 int Multi_voice_local_prefs = 0xffffffff;
345 // --------------------------------------------------------------------------------------------------
346 // MULTI VOICE FORWARD DECLARATIONS
349 // process voice details as the server
350 void multi_voice_server_process();
352 // process voice details as a player (may also be the server)
353 void multi_voice_player_process();
355 // determine if the voice key is down this frame
356 int multi_voice_keydown();
358 // find the voice stream index by token player index
359 int multi_voice_find_token(int player_index);
361 // <server> gives the token to a given player
362 void multi_voice_give_token(int stream_index,int player_index);
364 // <server> takes the token from a given stream entry
365 void multi_voice_take_token(int stream_index);
367 // <server> tells the client he's been denied on this request
368 void multi_voice_deny_token(int player_index);
370 // <player> releases the token back to the server
371 void multi_voice_release_token();
373 // <player> requests the token from the server
374 void multi_voice_request_token();
376 // <server> process a request for the token
377 void multi_voice_process_token_request(int player_index);
379 // free up any memory which may have been malloced
380 void multi_voice_free_all();
382 // <player> send the currently recorded sound
383 void multi_voice_player_send_stream();
385 // process incoming sound data, return bytes processed
386 int multi_voice_process_data(ubyte *data, int player_index,int msg_mode,net_player *target);
388 // <server> increment the current stream id#
389 void multi_voice_inc_stream_id();
391 // flush any old sound stream data because we've started to receive data for a new stream
392 void multi_voice_flush_old_stream(int stream_index);
394 // route sound data through the server to all appropriate players
395 void multi_voice_route_data(ubyte *data, int packet_size,int player_index,int mode,net_player *target);
397 // find the stream to apply incoming sound data to, freeing up old ones as necessary
398 int multi_voice_get_stream(int stream_id);
400 // NOTE : these 4 functions can be arbitrarily written to perform in any way necessary. This way the algorithm is
401 // completely seperate from the transport and token layers
402 // initialize the smart algorithm
403 void multi_voice_alg_init();
405 // process incoming sound data in whatever way necessary (this function should take care of playing data when necessary)
406 void multi_voice_alg_process_data(int player_index,int stream_index,ushort chunk_index,ushort chunk_size);
408 // process existing streams
409 void multi_voice_alg_process_streams();
411 // we are going to flush the current stream because we have started to receive data for a new one. do something first
412 void multi_voice_alg_flush_old_stream(int stream_index);
414 // is the given sound stream playing (compares uncompressed sound size with current playback position)
415 int multi_voice_stream_playing(int stream_index);
417 // tack on a post voice sound (pass -1 for none)
418 // return final buffer size
419 int multi_voice_mix(int post_sound,char *data,int cur_size,int max_size);
421 // send a dummy packet in the place of a too-large data packet
422 void multi_voice_send_dummy_packet();
424 // process a dummy data packet
425 int multi_voice_process_data_dummy(ubyte *data);
427 // max size of a sound chunk which we can fit into a packet
428 int multi_voice_max_chunk_size(int msg_mode);
430 // process a player preferences packet, return bytes processed
431 int multi_voice_process_player_prefs(ubyte *data,int player_index);
433 // process and play the current window of sound stream data we have. reset the window for the next incoming data as well
434 void multi_voice_alg_play_window(int stream_index);
436 // send all pending voice packets
437 void multi_voice_client_send_pending();
440 // --------------------------------------------------------------------------------------------------
441 // MULTI VOICE FUNCTIONS
444 // initialize the multiplayer voice system
445 void multi_voice_init()
447 int idx,s_idx,pre_size,pre_sound;
449 // if the voice system is already initialized, just reset some stuff
450 if(Multi_voice_inited){
455 // set the default quality of sound
456 Multi_voice_qos = MV_DEFAULT_QOS;
458 // if we're the standalone server, we can't record _or_ playback, but we can still route data and manage tokens
459 if(Game_mode & GM_STANDALONE_SERVER){
460 Multi_voice_can_record = 0;
461 Multi_voice_can_play = 0;
463 // initialize the realtime voice module
464 if(rtvoice_init_recording(Multi_voice_qos)){
465 nprintf(("Network","MULTI VOICE : Error initializing rtvoice - recording will not be possible\n"));
466 Multi_voice_can_record = 0;
468 Multi_voice_can_record = 1;
471 if(rtvoice_init_playback()){
472 nprintf(("Network","MULTI VOICE : Error initializing rtvoice - playback will not be possible\n"));
473 Multi_voice_can_play = 0;
475 Multi_voice_can_play = 1;
478 // _always_ set the quality of server
479 multi_voice_set_vars(MV_DEFAULT_QOS,MULTI_VOICE_MAX_TIME);
482 // initialize player-side data
483 Multi_voice_token = 0;
484 Multi_voice_keydown = 0;
485 Multi_voice_recording = 0;
486 Multi_voice_stream_id = 0;
487 Multi_voice_recording_stamp = -1;
488 Multi_voice_current_stream_index = 0;
489 Multi_voice_current_stream_sent = -1;
491 // initialize server-side data
492 memset(Multi_voice_player_prefs,0xff,sizeof(int)*MAX_PLAYERS);
493 Multi_voice_next_stream_id = 0;
495 Multi_voice_local_prefs = 0xffffffff;
497 // initialize the sound buffers
498 Multi_voice_record_buffer = NULL;
500 Multi_voice_playback_buffer = NULL;
501 Multi_voice_pre_sound_size = 0;
502 if(Multi_voice_can_play){
503 // attempt to allocate the buffer
504 Multi_voice_playback_buffer = (char*)malloc(MULTI_VOICE_MAX_BUFFER_SIZE);
505 if(Multi_voice_playback_buffer == NULL){
506 nprintf(("Network","MULTI VOICE : Error allocating playback buffer - playback will not be possible\n"));
507 Multi_voice_can_play = 0;
510 // attempt to copy in the "pre" voice sound
511 pre_sound = snd_load(&Snds[MULTI_VOICE_PRE_SOUND]);
513 // get the pre-sound size
514 if((snd_size(pre_sound,&pre_size) != -1) && (pre_size < MULTI_VOICE_MAX_BUFFER_SIZE)){
515 snd_get_data(pre_sound,Multi_voice_playback_buffer);
516 Multi_voice_pre_sound_size = pre_size;
518 Multi_voice_pre_sound_size = 0;
521 Multi_voice_pre_sound_size = 0;
525 // initialize the streams
526 memset(Multi_voice_stream,0,sizeof(voice_stream) * MULTI_VOICE_MAX_STREAMS);
527 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
528 Multi_voice_stream[idx].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;
529 Multi_voice_stream[idx].token_stamp = -1;
530 Multi_voice_stream[idx].stream_snd_handle = -1;
532 // get a playback buffer handle
533 if(Multi_voice_can_play){
534 Multi_voice_stream[idx].stream_rtvoice_handle = -1;
535 Multi_voice_stream[idx].stream_rtvoice_handle = rtvoice_create_playback_buffer();
536 if(Multi_voice_stream[idx].stream_rtvoice_handle == -1){
537 nprintf(("Network","MULTI VOICE : Error getting rtvoice buffer handle - playback will not be possible!\n"));
538 multi_voice_free_all();
540 Multi_voice_can_play = 0;
543 // allocate the accum buffer
544 for(s_idx=0;s_idx<MULTI_VOICE_ACCUM_BUFFER_COUNT;s_idx++){
545 Multi_voice_stream[idx].accum_buffer[s_idx] = NULL;
546 Multi_voice_stream[idx].accum_buffer[s_idx] = (ubyte*)malloc(MULTI_VOICE_ACCUM_BUFFER_SIZE);
547 if(Multi_voice_stream[idx].accum_buffer[s_idx] == NULL){
548 nprintf(("Network","MULTI VOICE : Error allocating accum buffer - playback will not be possible\n"));
549 multi_voice_free_all();
551 Multi_voice_can_play = 0;
557 // initialize the default max time
558 Multi_voice_max_time = MULTI_VOICE_MAX_TIME;
560 // initialize voice status data
561 Multi_voice_denied_stamp = -1;
563 // initialize the smart algorithm
564 multi_voice_alg_init();
566 Multi_voice_inited = 1;
569 // shutdown the multiplayer voice system
570 void multi_voice_close()
574 // if the voice system isn't already initialized, don't do anything
575 if(!Multi_voice_inited){
580 multi_voice_free_all();
582 // release all the rtvoice buffers
583 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
584 if(Multi_voice_stream[idx].stream_rtvoice_handle != -1){
585 rtvoice_free_playback_buffer(Multi_voice_stream[idx].stream_rtvoice_handle);
586 Multi_voice_stream[idx].stream_rtvoice_handle = -1;
587 Multi_voice_stream[idx].stream_snd_handle = -1;
591 // close the realtime voice module
592 rtvoice_close_recording();
593 rtvoice_close_playback();
595 Multi_voice_inited = 0;
598 // reset between levels
599 void multi_voice_reset()
603 #ifdef MULTI_VOICE_VERBOSE
604 nprintf(("Network","MULTI VOICE : Resetting\n"));
607 Assert(Multi_voice_inited);
609 // if we're the standalone server, we can't record _or_ playback, but we can still route data and manage tokens
610 if(Game_mode & GM_STANDALONE_SERVER){
611 Multi_voice_can_record = 0;
612 Multi_voice_can_play = 0;
615 // initialize player-side data
616 Multi_voice_token = 0;
617 Multi_voice_keydown = 0;
618 Multi_voice_recording = 0;
619 Multi_voice_stream_id = 0;
620 Multi_voice_recording_stamp = -1;
622 // initialize server-side data
623 memset(Multi_voice_player_prefs,0xff,sizeof(int)*MAX_PLAYERS);
624 Multi_voice_local_prefs = 0xffffffff;
625 Multi_voice_next_stream_id = 0;
627 // initialize the sound buffers
628 Multi_voice_record_buffer = NULL;
630 // initialize the streams
631 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
632 Multi_voice_stream[idx].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;
633 Multi_voice_stream[idx].token_stamp = -1;
636 // initialize the smart algorithm
637 multi_voice_alg_init();
640 // process all voice details
641 void multi_voice_process()
645 // don't do anything if the voice module is not initialized
646 if((!Multi_voice_inited) || !(Net_player->flags & NETINFO_FLAG_CONNECTED)){
650 // send all pending voice packets
651 multi_voice_client_send_pending();
653 // find any playing sound streams which have finished and unmark them
654 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
655 if((Multi_voice_stream[idx].stream_snd_handle != -1) && !multi_voice_stream_playing(idx)){
656 Multi_voice_stream[idx].stream_snd_handle = -1;
660 // process seperately as player or server
661 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
662 multi_voice_server_process();
665 // all "players" do this, except the standalone who isn't a real player by definition
666 if(!(Game_mode & GM_STANDALONE_SERVER)){
667 multi_voice_player_process();
670 // everyont calls the general algorithm process function
671 multi_voice_alg_process_streams();
674 // voice settings debug console function
675 void multi_voice_dcf()
677 dc_get_arg(ARG_STRING);
679 // set the quality of sound
680 if (strcmp(Dc_arg, NOX("qos")) == 0) {
682 if(Dc_arg_type & ARG_INT){
683 if((Dc_arg_int >= 1) && (Dc_arg_int <= 10) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
684 multi_voice_set_vars(Dc_arg_int,-1);
685 dc_printf("Quality of sound : %d\n",Dc_arg_int);
691 // the status of the voice system - use this to determine what bitmaps to display, etc see above MULTI_VOICE_STATUS_* defines
692 int multi_voice_status()
698 // if the "denied" timestamp is set, return that as the status
699 if(Multi_voice_denied_stamp != -1){
700 return MULTI_VOICE_STATUS_DENIED;
703 // if we're currently recording (has precedence over playing back a sound from somebody)
704 if(Multi_voice_recording){
705 return MULTI_VOICE_STATUS_RECORDING;
708 // find the stream which started playing the farthest back (if any)
711 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
712 // if we found a playing stream
713 if(Multi_voice_stream[idx].stream_snd_handle != -1){
714 if((earliest == -1) || (Multi_voice_stream[idx].stream_start_time < earliest_time)){
716 earliest_time = Multi_voice_stream[idx].stream_start_time;
720 // if we found a stream
722 return MULTI_VOICE_STATUS_PLAYING;
726 return MULTI_VOICE_STATUS_IDLE;
729 // update the qos if the current setting is different from the passed in value
730 void multi_voice_maybe_update_vars(int new_qos,int new_duration)
732 // if the current qos is different from the passed qos, set it
733 if((new_qos != Multi_voice_qos) || (new_duration != Multi_voice_max_time)){
734 multi_voice_set_vars(new_qos,new_duration);
739 // --------------------------------------------------------------------------------------------------
740 // MULTI VOICE FORWARD DECLARATIONS
743 // process voice details as the server
744 void multi_voice_server_process()
748 // process all the tokens for all the available streams
749 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
750 switch(Multi_voice_stream[idx].token_status){
751 // if the token is free, so is the stream - don't do anything
752 case MULTI_VOICE_TOKEN_INDEX_FREE:
755 // if the token has been released - check to see if the stream is "done" (ie, can be marked as FREE once again)
756 case MULTI_VOICE_TOKEN_INDEX_RELEASED:
757 // if the stream_last_heard var is -1, it means we never got sound from this guy so free the token up immediately
758 if(Multi_voice_stream[idx].stream_last_heard == -1){
759 Multi_voice_stream[idx].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;
761 #ifdef MULTI_VOICE_VERBOSE
762 nprintf(("Network","MULTI VOICE : freeing released token (no packets)\n"));
765 // if a sufficiently long amount of time has elapsed since he released the token, free it up
768 t1 = f2fl(Multi_voice_stream[idx].stream_last_heard);
769 t2 = f2fl(timer_get_fixed_seconds());
770 if((t2 - t1) >= MULTI_VOICE_TOKEN_RELEASE_WAIT){
771 Multi_voice_stream[idx].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;
773 #ifdef MULTI_VOICE_VERBOSE
774 nprintf(("Network","MULTI VOICE : freeing released token (time elapsed)\n"));
780 // if the token is still being held by a player
782 // if the token timestamp has elapsed, take the token back
783 if((Multi_voice_stream[idx].token_stamp != -1) && timestamp_elapsed(Multi_voice_stream[idx].token_stamp)){
784 Assert(Multi_voice_stream[idx].token_status != MULTI_VOICE_TOKEN_INDEX_FREE);
785 multi_voice_take_token(idx);
791 // for each netplayer, if his token wait timestamp is running, see if it has popped yet
792 for(idx=0;idx<MAX_PLAYERS;idx++){
793 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)){
794 // unset it so that he can have the token again
795 Net_players[idx].s_info.voice_token_timestamp = -1;
800 // process voice details as a player (may also be the server)
801 void multi_voice_player_process()
803 // if the voice key is down for the first time this frame, send a request for the token
804 if(!Multi_voice_keydown && multi_voice_keydown() && Multi_voice_can_record && !(Netgame.options.flags & MSO_FLAG_NO_VOICE)){
805 // mark the key as being down
806 Multi_voice_keydown = 1;
808 // send a request for a token
809 multi_voice_request_token();
811 #ifdef MULTI_VOICE_VERBOSE
812 nprintf(("Network","MULTI VOICE : Request\n"));
816 // if the key is still being pressed
817 if(Multi_voice_keydown && multi_voice_keydown() && Multi_voice_can_record){
818 // if we have the token
819 if(Multi_voice_token){
820 // if we're not already recording, start recording
821 if(!Multi_voice_recording){
822 #ifdef MULTI_VOICE_VERBOSE
823 nprintf(("Network","MULTI VOICE : RECORD %d\n",(int)Multi_voice_stream_id));
825 // flush the old stream
826 multi_voice_flush_old_stream(0);
828 // start the recording process with the appropriate callback function
829 if(rtvoice_start_recording(multi_voice_process_next_chunk)){
830 nprintf(("Network","MULTI VOICE : Error initializing recording!\n"));
834 // set myself to be recording
835 Multi_voice_recording = 1;
837 // set the time when I started recording
838 Multi_voice_recording_stamp = timestamp(Multi_voice_max_time);
840 // set the current packet/chunk index to 0
841 Multi_voice_current_stream_index = 0;
842 Multi_voice_current_stream_sent = 0;
844 // get the proper messaging mode
845 if(Game_mode & GM_IN_MISSION){
846 // in mission, paused
847 if(gameseq_get_state() == GS_STATE_MULTI_PAUSED){
848 Multi_voice_send_mode = MULTI_MSG_ALL;
850 // in mission, unpaused
852 Multi_voice_send_mode = multi_msg_mode();
855 Multi_voice_send_mode = MULTI_MSG_ALL;
859 // if we've recorded the max time allowed, send the data
860 if((Multi_voice_recording_stamp != -1) && timestamp_elapsed(Multi_voice_recording_stamp)){
861 #ifdef MULTI_VOICE_VERBOSE
862 nprintf(("Network","MULTI VOICE : timestamp popped"));
864 // mark me as no longer recording
865 Multi_voice_recording = 0;
866 Multi_voice_current_stream_sent = -1;
868 // stop the recording process
869 rtvoice_stop_recording();
871 #ifdef MULTI_VOICE_POST_DECOMPRESS
872 multi_voice_player_send_stream();
875 // play my sound locally as well
876 #ifdef MULTI_VOICE_LOCAL_ECHO
877 multi_voice_alg_play_window(0);
879 // release the token back to the server
880 multi_voice_release_token();
884 // if the key has been released
885 else if(Multi_voice_keydown && !multi_voice_keydown() && Multi_voice_can_record){
886 #ifdef MULTI_VOICE_VERBOSE
887 nprintf(("Network","MULTI VOICE : Release\n"));
890 // mark the kay as not being down
891 Multi_voice_keydown = 0;
893 // if we were recording, send the data
894 if(Multi_voice_recording){
895 // mark me as no longer recording
896 Multi_voice_recording = 0;
898 Multi_voice_current_stream_sent = -1;
900 // stop the recording process
901 rtvoice_stop_recording();
903 #ifdef MULTI_VOICE_POST_DECOMPRESS
904 multi_voice_player_send_stream();
907 // play my sound locally as well
908 #ifdef MULTI_VOICE_LOCAL_ECHO
909 multi_voice_alg_play_window(0);
912 // release the token back to the server
913 multi_voice_release_token();
917 // if the "denied" timestamp is set, but has elapsed or the user has let up on the key, set it to -1
918 if((Multi_voice_denied_stamp != -1) && (timestamp_elapsed(Multi_voice_denied_stamp) || !multi_voice_keydown())){
919 Multi_voice_denied_stamp = -1;
923 // determine if the voice key is down this frame
924 int multi_voice_keydown()
926 // if we're in the options screen, we should never allow the button to be pressed
927 if(gameseq_get_state() == GS_STATE_OPTIONS_MENU){
931 // if we're pre-game, we should just be checking the keyboard bitflags
932 if(!(Game_mode & GM_IN_MISSION)){
933 return (keyd_pressed[MULTI_VOICE_KEY] && !(keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT])) ? 1 : 0;
936 // in-mission, paused - treat just like any other "chattable" screen.
937 if(gameseq_get_state() == GS_STATE_MULTI_PAUSED){
938 return (keyd_pressed[MULTI_VOICE_KEY] && !(keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT])) ? 1 : 0;
941 // ingame, unpaused, rely on the multi-messaging system (ingame)
942 return multi_msg_voice_record();
945 // find the voice stream index by token player index
946 int multi_voice_find_token(int player_index)
950 // look through all the existing streams
951 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
952 if(Multi_voice_stream[idx].token_status == player_index){
961 // <server> gives the token to a given player
962 void multi_voice_give_token(int stream_index,int player_index)
967 // only the server should ever be here
968 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
970 // set this player as having the token
971 Multi_voice_stream[stream_index].token_status = player_index;
973 // set the token timeout
974 Multi_voice_stream[stream_index].token_stamp = timestamp(MULTI_VOICE_TOKEN_TIMEOUT);
976 // set the stream id and increment the count
977 Multi_voice_stream[stream_index].stream_id = Multi_voice_next_stream_id;
978 multi_voice_inc_stream_id();
980 // set the last heard from time to -1 to indicate we've heard no sound from this guy
981 Multi_voice_stream[stream_index].stream_last_heard = -1;
983 #ifdef MULTI_VOICE_VERBOSE
984 nprintf(("Network","MULTI VOICE : GIVE TOKEN %d\n",(int)Multi_voice_next_stream_id));
987 // if we're giving to ourself, don't send any data
988 if(Net_player == &Net_players[player_index]){
989 Multi_voice_token = 1;
991 Multi_voice_stream_id = Multi_voice_stream[stream_index].stream_id;
993 // send the "give" packet to the guy
994 BUILD_HEADER(VOICE_PACKET);
995 code = MV_CODE_GIVE_TOKEN;
998 // add the current stream id#
999 ADD_DATA(Multi_voice_stream[stream_index].stream_id);
1002 multi_io_send_reliable(&Net_players[player_index], data, packet_size);
1006 // <server> takes the token from a given player
1007 void multi_voice_take_token(int stream_index)
1009 ubyte data[10],code;
1010 int packet_size = 0;
1012 // only the server should ever be here
1013 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1015 // if the index is -1, the token has probably been released to us "officially" already
1016 if((Multi_voice_stream[stream_index].token_status == MULTI_VOICE_TOKEN_INDEX_FREE) || (Multi_voice_stream[stream_index].token_status == MULTI_VOICE_TOKEN_INDEX_RELEASED)){
1017 Multi_voice_stream[stream_index].token_stamp = -1;
1021 // if i'm taking from myself, don't send any data
1022 if(Net_player == &Net_players[Multi_voice_stream[stream_index].token_status]){
1023 Multi_voice_token = 0;
1025 // timestamp this guy so that he can't get the token back immediately
1026 Net_player->s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1028 // send the "take" packet to the guy
1029 BUILD_HEADER(VOICE_PACKET);
1030 code = MV_CODE_TAKE_TOKEN;
1034 multi_io_send_reliable(&Net_players[Multi_voice_stream[stream_index].token_status], data, packet_size);
1036 // timestamp this guy so that he can't get the token back immediately
1037 Net_players[Multi_voice_stream[stream_index].token_status].s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1040 // take the token back from the dude
1041 Multi_voice_stream[stream_index].token_status = MULTI_VOICE_TOKEN_INDEX_RELEASED;
1042 Multi_voice_stream[stream_index].token_stamp = -1;
1045 // <server> tells the client he's been denied on this request
1046 void multi_voice_deny_token(int player_index)
1048 ubyte data[10],code;
1049 int packet_size = 0;
1051 // only the server should ever be here
1052 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1055 // if i'm denying myself, set the denied timestamp
1056 if(Net_player == &Net_players[player_index]){
1057 Multi_voice_denied_stamp = timestamp(MULTI_VOICE_DENIED_TIME);
1059 // send the "deny" packet to the guy
1060 BUILD_HEADER(VOICE_PACKET);
1061 code = MV_CODE_DENY_TOKEN;
1065 multi_io_send_reliable(&Net_players[player_index], data, packet_size);
1069 // <player> releases the token back to the server
1070 void multi_voice_release_token()
1072 ubyte data[10],code;
1073 int packet_size = 0;
1075 // I don't have the token anymore
1076 Multi_voice_token = 0;
1078 // if i'm the server, don't send any data
1079 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1080 // mark the token as being released
1081 int stream_index = multi_voice_find_token(MY_NET_PLAYER_NUM);
1082 Multi_voice_stream[stream_index].token_status = MULTI_VOICE_TOKEN_INDEX_RELEASED;
1084 // timestamp this guy so that he can't get the token back immediately
1085 Net_player->s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1087 // send the "release" packet to the server
1088 BUILD_HEADER(VOICE_PACKET);
1089 code = MV_CODE_RELEASE_TOKEN;
1093 multi_io_send_reliable(Net_player, data, packet_size);
1097 // <player> requests the token from the server
1098 void multi_voice_request_token()
1100 ubyte data[10],code;
1101 int packet_size = 0;
1103 // if i'm the server, process the request right now
1104 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1105 multi_voice_process_token_request(MY_NET_PLAYER_NUM);
1107 // send the "request" packet to the server
1108 BUILD_HEADER(VOICE_PACKET);
1109 code = MV_CODE_REQUEST_TOKEN;
1113 multi_io_send_reliable(Net_player, data, packet_size);
1117 // <player> sends hit bitflag settings (who he'll receive sound from, etc)
1118 void multi_voice_set_prefs(int pref_flags)
1120 ubyte data[MAX_PACKET_SIZE],code;
1122 int packet_size = 0;
1124 // set the local flags
1125 Multi_voice_local_prefs = pref_flags;
1127 // if i'm the server, set the sound prefs right now
1128 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1129 Multi_voice_player_prefs[MY_NET_PLAYER_NUM] = pref_flags;
1131 // send the prefs to the server
1132 BUILD_HEADER(VOICE_PACKET);
1133 code = MV_CODE_PLAYER_PREFS;
1136 // add the address of all players being ignored
1137 for(idx=0;idx<MAX_PLAYERS;idx++){
1138 if(!(pref_flags & (1<<idx))){
1142 // add the player's id
1143 ADD_DATA(Net_players[idx].player_id);
1146 // add final stop byte
1151 multi_io_send_reliable(Net_player, data, packet_size);
1155 // set the default voice quality and duration (if server passes -1, he just broadcasts the qos to all clients)
1156 void multi_voice_set_vars(int qos,int duration)
1158 int need_update = 0;
1160 // make sure its in the right range
1161 if((qos > 0) && (qos <= 10)){
1162 #ifdef MULTI_VOICE_VERBOSE
1163 nprintf(("Network","MULTI VOICE : SETTING QOS %d\n",qos));
1166 // set the default value
1167 Multi_voice_qos = qos;
1169 // set the value in the rtvoice module
1170 rtvoice_set_qos(Multi_voice_qos);
1172 // update the netgame settings
1173 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1174 Netgame.options.voice_qos = (ubyte)Multi_voice_qos;
1179 // set the maximum duration
1180 if((duration > 0) && (duration <= MULTI_VOICE_MAX_TIME)){
1181 #ifdef MULTI_VOICE_VERBOSE
1182 nprintf(("Network","MULTI VOICE : SETTING MAX RECORD TIME %d\n",duration));
1184 // set the default value
1185 Multi_voice_max_time = duration;
1187 // update the netgame settings
1188 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1189 Netgame.options.voice_record_time = duration;
1194 // send an options update if necessary
1195 if(need_update && !(Game_mode & GM_STANDALONE_SERVER)){
1196 multi_options_update_netgame();
1200 // <server> process a request for the token
1201 void multi_voice_process_token_request(int player_index)
1203 int stream_index,idx;
1205 // if we're not doing voice on this server, return now
1206 if(Netgame.options.flags & MSO_FLAG_NO_VOICE){
1210 // if the player's token timestamp is not -1, can't give him the token
1211 if(Net_players[player_index].s_info.voice_token_timestamp != -1){
1212 #ifdef MULTI_VOICE_VERBOSE
1213 nprintf(("Network","MULTI VOICE : Not giving token because player %s's timestamp hasn't elapsed yet!\n",Net_players[player_index].player->callsign));
1214 nprintf(("Network","MULTI VOICE : token status %d\n",Multi_voice_stream[0].token_status));
1217 multi_voice_deny_token(player_index);
1221 // attempt to find a free token token
1223 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1224 if(Multi_voice_stream[idx].token_status == MULTI_VOICE_TOKEN_INDEX_FREE){
1225 multi_voice_give_token(idx,player_index);
1231 // free up any memory which may have been malloced
1232 void multi_voice_free_all()
1236 // free up the playback buffer
1237 if(Multi_voice_playback_buffer != NULL){
1238 free(Multi_voice_playback_buffer);
1239 Multi_voice_playback_buffer = NULL;
1242 // free up the accum buffers
1243 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1244 for(s_idx=0;s_idx<MULTI_VOICE_ACCUM_BUFFER_COUNT;s_idx++){
1245 if(Multi_voice_stream[idx].accum_buffer[s_idx] != NULL){
1246 free(Multi_voice_stream[idx].accum_buffer[s_idx]);
1247 Multi_voice_stream[idx].accum_buffer[s_idx] = NULL;
1253 // <player> send the currently recorded sound
1254 void multi_voice_player_send_stream()
1256 ubyte data[MAX_PACKET_SIZE],code,*rbuf,msg_mode,chunk_index;
1257 ushort chunk_size,uc_size;
1258 int packet_size = 0;
1259 int sound_size,size_sent,uncompressed_size,target_index,max_chunk_size;
1263 // we'd better not ever get here as we can't record voice
1264 Assert(Multi_voice_can_record);
1267 rtvoice_get_data((unsigned char**)&Multi_voice_record_buffer,&sound_size,&uncompressed_size,&d_gain);
1268 gain = (float)d_gain;
1270 msg_mode = (ubyte)Multi_voice_send_mode;
1271 // get the specific target if we're in MSG_TARGET mode
1273 if(msg_mode == MULTI_MSG_TARGET){
1274 if(Player_ai->target_objnum != -1){
1275 target_index = multi_find_player_by_object(&Objects[Player_ai->target_objnum]);
1276 if(target_index == -1){
1284 // get the max chunk size
1285 max_chunk_size = multi_voice_max_chunk_size(Multi_voice_send_mode);
1287 // go through the data and send all of it
1288 code = MV_CODE_DATA;
1291 rbuf = (unsigned char*)Multi_voice_record_buffer;
1292 while(size_sent < sound_size){
1293 // build the header and add the opcode
1294 BUILD_HEADER(VOICE_PACKET);
1296 // add the packet code type
1299 // add the routing data and any necessary targeting information
1301 if(msg_mode == MULTI_MSG_TARGET){
1302 ADD_DATA(Objects[Net_players[target_index].player->objnum].net_signature);
1306 ADD_DATA(Net_player->player_id);
1308 // add the current stream id#
1309 ADD_DATA(Multi_voice_stream_id);
1311 Assert(uncompressed_size < MULTI_VOICE_MAX_BUFFER_SIZE);
1312 uc_size = (ushort)uncompressed_size;
1315 // add the chunk index
1316 ADD_DATA(chunk_index);
1318 // determine how much we are going to send in this packet
1319 if((sound_size - size_sent) >= max_chunk_size){
1320 chunk_size = (ushort)max_chunk_size;
1322 chunk_size = (ushort)(sound_size - size_sent);
1324 ADD_DATA(chunk_size);
1329 // add the chunk of data
1330 memcpy(data+packet_size, rbuf,chunk_size);
1331 packet_size += chunk_size;
1333 // send to the server or rebroadcast if I _am_ the server
1334 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1335 multi_voice_route_data(data,packet_size,MY_NET_PLAYER_NUM,(int)msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1337 multi_io_send(Net_player, data, packet_size);
1340 // increment the chunk_index
1343 // increment bytes sent and the buffer
1344 size_sent += (int)chunk_size;
1349 // process incoming sound data, return bytes processed
1350 int multi_voice_process_data(ubyte *data, int player_index,int msg_mode,net_player *target)
1352 ubyte stream_id,chunk_index;
1353 ushort chunk_size,uc_size;
1359 // read in all packet data except for the sound chunk itself
1361 GET_DATA(stream_id);
1363 GET_DATA(chunk_index);
1364 GET_DATA(chunk_size);
1367 // if our netgame options are currently set for no voice, ignore the packet
1368 if((Netgame.options.flags & MSO_FLAG_NO_VOICE) || !Multi_options_g.std_voice){
1369 offset += chunk_size;
1373 // get a handle to a valid stream to be using, freeing old streams as necessary
1374 stream_index = multi_voice_get_stream((int)stream_id);
1376 // if this index is too high, flush the stream
1377 if(chunk_index >= MULTI_VOICE_ACCUM_BUFFER_COUNT){
1378 #ifdef MULTI_VOICE_VERBOSE
1379 nprintf(("Network","MULTI VOICE : flushing stream because packet index is too high!!\n"));
1383 multi_voice_flush_old_stream(stream_index);
1385 // return bytes processed
1386 offset += chunk_size;
1390 // if we found a stream to work with
1391 if(stream_index != -1){
1392 // set the id of where it came from
1393 Multi_voice_stream[stream_index].stream_from = who_from;
1395 // set the stream id#
1396 Multi_voice_stream[stream_index].stream_id = stream_id;
1399 Multi_voice_stream[stream_index].accum_buffer_gain[chunk_index] = (double)gain;
1401 // set the stream uncompressed size size
1402 Multi_voice_stream[stream_index].accum_buffer_usize[chunk_index] = uc_size;
1404 // set the token timestamp
1405 Multi_voice_stream[stream_index].token_stamp = timestamp(MULTI_VOICE_TOKEN_TIMEOUT);
1407 // set the last heard time
1408 Multi_voice_stream[stream_index].stream_last_heard = timer_get_fixed_seconds();
1410 // copy the data and setup any other accum buffer data necessary
1411 // ignore data if we can't play sounds
1412 if(Multi_voice_can_play){
1413 memcpy(Multi_voice_stream[stream_index].accum_buffer[chunk_index],data+offset,(int)chunk_size);
1416 Multi_voice_stream[stream_index].accum_buffer_flags[chunk_index] = 1;
1417 Multi_voice_stream[stream_index].accum_buffer_csize[chunk_index] = chunk_size;
1419 // pass the data into the smart voice algorithm
1420 if(player_index != -1){
1421 multi_voice_alg_process_data(player_index,stream_index,chunk_index,chunk_size);
1425 // increment the offset
1426 offset += (int)chunk_size;
1431 // <server> increment the current stream id#
1432 void multi_voice_inc_stream_id()
1434 Assert(Net_player->flags & NETINFO_FLAG_AM_MASTER);
1436 if(Multi_voice_next_stream_id == 0xff){
1437 Multi_voice_next_stream_id = 0;
1439 Multi_voice_next_stream_id++;
1443 // flush any old sound stream data because we've started to receive data for a new stream
1444 void multi_voice_flush_old_stream(int stream_index)
1446 #ifdef MULTI_VOICE_VERBOSE
1447 nprintf(("Network","MULTI VOICE : old stream flush\n"));
1450 // call the smart algorithm for flushing streams
1451 multi_voice_alg_flush_old_stream(stream_index);
1453 // clear all the accum buffer flags
1454 memset(Multi_voice_stream[stream_index].accum_buffer_flags,0,MULTI_VOICE_ACCUM_BUFFER_COUNT);
1457 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1458 multi_voice_take_token(stream_index);
1461 Multi_voice_stream[stream_index].token_stamp = -1;
1462 Multi_voice_stream[stream_index].token_status = MULTI_VOICE_TOKEN_INDEX_FREE;
1464 // timestamp the player
1465 Net_player->s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1468 // route sound data through the server to all appropriate players
1469 void multi_voice_route_data(ubyte *data, int packet_size,int player_index,int mode,net_player *target)
1473 // route the data to all other players
1476 for(idx=0;idx<MAX_PLAYERS;idx++){
1477 if(MULTI_CONNECTED( Net_players[idx] ) && // player is connected
1478 ( &Net_players[idx] != &Net_players[player_index] ) && // not the sending player
1479 ( Net_player != &Net_players[idx] ) && // not me
1480 ( Multi_voice_player_prefs[idx] & (1 << player_index) ) && // is accepting sound from this player
1481 !( Net_players[idx].p_info.options.flags & MLO_FLAG_NO_VOICE ) ){ // is accepting sound periods
1483 multi_io_send(&Net_players[idx], data, packet_size);
1488 case MULTI_MSG_FRIENDLY:
1489 for(idx=0;idx<MAX_PLAYERS;idx++){
1490 if(MULTI_CONNECTED( Net_players[idx] ) && // player is connected
1491 ( &Net_players[idx] != &Net_players[player_index] ) && // not the sending player
1492 ( Net_player != &Net_players[idx] ) && // not me
1493 ( Net_players[idx].p_info.team == Net_players[player_index].p_info.team ) &&// on the same team
1494 ( Multi_voice_player_prefs[idx] & (1 << player_index) ) && // is accepting sound from the sender
1495 !( Net_players[idx].p_info.options.flags & MLO_FLAG_NO_VOICE) ){ // is accepting sound periods
1497 multi_io_send(&Net_players[idx], data, packet_size);
1501 case MULTI_MSG_HOSTILE:
1502 for(idx=0;idx<MAX_PLAYERS;idx++){
1503 if(MULTI_CONNECTED( Net_players[idx] ) && // player is connected
1504 ( &Net_players[idx] != &Net_players[player_index] ) && // not the sending player
1505 ( Net_player != &Net_players[idx] ) && // not me
1506 ( Net_players[idx].p_info.team != Net_players[player_index].p_info.team ) &&// on the opposite team
1507 ( Multi_voice_player_prefs[idx] & (1 << player_index) ) && // is accepting sound from the sender
1508 !( Net_players[idx].p_info.options.flags & MLO_FLAG_NO_VOICE ) ){ // is accepting sound periods
1510 multi_io_send(&Net_players[idx], data, packet_size);
1515 case MULTI_MSG_TARGET:
1516 Assert(target != NULL);
1517 if(!(target->p_info.options.flags & MLO_FLAG_NO_VOICE)){
1518 multi_io_send(target, data, packet_size);
1524 // find the stream to apply incoming sound data to, freeing up old ones as necessary
1525 int multi_voice_get_stream(int stream_id)
1527 int idx,max_diff_index;
1528 fix cur_time,max_diff;
1530 // first check to see if this stream exists
1531 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1532 if(Multi_voice_stream[idx].stream_id == (ubyte)stream_id){
1537 // if we got to this point, we didn't find the matching stream, so we should try and find an empty stream
1538 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1539 if(Multi_voice_stream[idx].token_stamp == -1){
1544 #ifdef MULTI_VOICE_VERBOSE
1545 nprintf(("Network","MULTI VOICE : going to blast old voice stream while looking for a free one - beware!!\n"));
1548 // if we got to this point, we should free up the oldest stream we have
1549 cur_time = timer_get_fixed_seconds();
1550 max_diff_index = -1;
1552 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
1553 if(((max_diff_index == -1) || ((cur_time - Multi_voice_stream[idx].stream_last_heard) > max_diff)) && (Multi_voice_stream[idx].token_stamp != -1)){
1554 max_diff_index = idx;
1555 max_diff = cur_time - Multi_voice_stream[idx].stream_last_heard;
1559 // if we found the oldest
1560 if(max_diff_index != -1){
1561 // flush the old stream
1562 multi_voice_flush_old_stream(max_diff_index);
1564 return max_diff_index;
1567 // some other fail condition
1571 // is the given sound stream playing (compares uncompressed sound size with current playback position)
1572 int multi_voice_stream_playing(int stream_index)
1574 // if the handle is invalid, it can't be playing
1576 if(Multi_voice_stream[stream_index].stream_snd_handle < 0){
1580 // if the sound is playing and the buffer is past the uncompressed size, its effectively done
1581 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){
1590 // tack on pre and post sounds to a sound stream (pass -1 for either if no sound is wanted)
1591 // return final buffer size
1592 int multi_voice_mix(int post_sound,char *data,int cur_size,int max_size)
1596 // if the user passed -1 for both pre and post sounds, don't do a thing
1597 if(post_sound == -1){
1601 // get the sizes of the additional sounds
1604 if(post_sound >= 0){
1605 post_sound = snd_load(&Snds[post_sound]);
1606 if(post_sound >= 0){
1607 if(snd_size(post_sound,&post_size) == -1){
1617 // if we have a "post" sound to add
1619 if((max_size - cur_size) > post_size){
1620 // copy in the sound
1621 snd_get_data(post_sound,data + cur_size);
1623 // increment the cur_size
1624 cur_size += post_size;
1628 // return the size of the new buffer
1632 // max size of a sound chunk which we can fit into a packet
1633 int multi_voice_max_chunk_size(int msg_mode)
1637 // all headers contain the following data
1638 header_size = 1 + // messaging mode
1640 2 + // packet uncompressed size
1641 2 + // compressed size
1644 // if we're targeting a specific player
1645 if(msg_mode == MULTI_MSG_TARGET){
1646 header_size += 2; // targeted player's object net_signature
1649 // if we're in IPX mode
1650 if(Psnet_my_addr.type == NET_IPX){
1651 header_size += 10; // my address (10 bytes in IPX)
1653 // if we're in TCP mode
1655 header_size += 4; // my address (4 bytes in TCP)
1658 // calculate max chunk size
1659 return (MAX_PACKET_SIZE - // max freespace packet size
1661 1 - // voice packet code subtype
1662 header_size); // calculated header size
1665 // --------------------------------------------------------------------------------------------------
1666 // MULTI VOICE / RTVOICE INTERFACE
1669 // process the "next" chunk of standalone valid sound data from the rtvoice system
1670 void multi_voice_process_next_chunk()
1672 int sound_size,uncompressed_size;
1677 // we'd better not ever get here is we can't record voice
1678 Assert(Multi_voice_can_record);
1681 rtvoice_get_data((unsigned char**)&Multi_voice_record_buffer,&sound_size,&uncompressed_size,&d_gain);
1682 gain = (float)d_gain;
1684 // if we've reached the max # of packets for this stream, bail
1685 if(Multi_voice_current_stream_index >= (MULTI_VOICE_ACCUM_BUFFER_COUNT - 1)){
1686 nprintf(("Network","MULTI VOICE : Forcing stream to stop on the record size!!!\n"));
1688 // mark me as no longer recording
1689 Multi_voice_recording = 0;
1691 Multi_voice_current_stream_sent = -1;
1693 // stop the recording process
1694 rtvoice_stop_recording();
1696 #ifdef MULTI_VOICE_POST_DECOMPRESS
1697 multi_voice_player_send_stream();
1700 // play my sound locally as well
1701 #ifdef MULTI_VOICE_LOCAL_ECHO
1702 multi_voice_alg_play_window(0);
1704 // release the token back to the server
1705 multi_voice_release_token();
1707 // unset the timestamp so we don't still think we're still recording
1708 Multi_voice_recording_stamp = -1;
1713 // pack the data locally as well (so I can hear myself)
1714 str = &Multi_voice_stream[0];
1715 memcpy(str->accum_buffer[Multi_voice_current_stream_index],Multi_voice_record_buffer,sound_size);
1716 str->stream_from = Net_player->player_id;
1717 str->accum_buffer_flags[Multi_voice_current_stream_index] = 1;
1718 str->accum_buffer_usize[Multi_voice_current_stream_index] = (ushort)uncompressed_size;
1719 str->accum_buffer_csize[Multi_voice_current_stream_index] = (ushort)sound_size;
1720 str->accum_buffer_gain[Multi_voice_current_stream_index] = d_gain;
1722 // increment the stream index
1723 Multi_voice_current_stream_index++;
1727 // --------------------------------------------------------------------------------------------------
1728 // MULTI VOICE PACKET HANDLERS
1731 // send a dummy packet in the place of a too-large data packet
1732 void multi_voice_send_dummy_packet()
1734 ubyte data[10],code,msg_mode;
1735 int packet_size,target_index;
1737 // build the header and add the opcode
1738 BUILD_HEADER(VOICE_PACKET);
1739 code = (ubyte)MV_CODE_DATA_DUMMY;
1742 msg_mode = (ubyte)Multi_voice_send_mode;
1743 // get the specific target if we're in MSG_TARGET mode
1745 if(msg_mode == MULTI_MSG_TARGET){
1746 if(Player_ai->target_objnum != -1){
1747 target_index = multi_find_player_by_object(&Objects[Player_ai->target_objnum]);
1748 if(target_index == -1){
1756 if(msg_mode == MULTI_MSG_TARGET){
1757 ADD_DATA(Objects[Net_players[target_index].player->objnum].net_signature);
1760 // add the voice stream id
1761 ADD_DATA(Multi_voice_stream_id);
1763 // send to the server or rebroadcast if I _am_ the server
1764 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1765 multi_voice_route_data(data,packet_size,MY_NET_PLAYER_NUM,(int)msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1767 multi_io_send(Net_player, data, packet_size);
1771 // process a dummy data packet
1772 int multi_voice_process_data_dummy(ubyte *data)
1778 // get the stream id
1779 GET_DATA(stream_id);
1781 // get the proper stream index
1782 stream_index = multi_voice_get_stream((int)stream_id);
1784 // set the token timestamp
1785 Multi_voice_stream[stream_index].token_stamp = timestamp(MULTI_VOICE_TOKEN_TIMEOUT);
1787 // set the last heard time
1788 Multi_voice_stream[stream_index].stream_last_heard = timer_get_fixed_seconds();
1790 // set the timeout timestamp
1791 Multi_voice_stamps[stream_index] = timestamp(MV_ALG_TIMEOUT);
1793 // return bytes processed
1797 // process a player preferences packet, return bytes processed
1798 int multi_voice_process_player_prefs(ubyte *data,int player_index)
1805 // set all channels active
1806 Multi_voice_player_prefs[player_index] = 0xffffffff;
1808 // get all muted players
1813 // get the player to mute
1814 mute_index = find_player_id(mute_id);
1815 if(mute_index != -1){
1816 #ifdef MULTI_VOICE_VERBOSE
1817 nprintf(("Network","Player %s muting player %s\n",Net_players[player_index].player->callsign,Net_players[mute_index].player->callsign));
1820 Multi_voice_player_prefs[player_index] &= ~(1<<mute_index);
1823 // get the next stop value
1827 // return bytes processed
1831 // process an incoming voice packet of some kind or another
1832 void multi_voice_process_packet(ubyte *data, header *hinfo)
1834 ubyte code,msg_mode;
1836 int player_index,stream_index,target_index;
1837 int offset = HEADER_LENGTH;
1839 // find out who is sending this data
1840 player_index = find_player_id(hinfo->id);
1845 // process the packet
1847 // I don't have the token anymore
1848 case MV_CODE_TAKE_TOKEN:
1849 // we should never have the token if we cannot record
1850 if(!Multi_voice_can_record){
1854 Multi_voice_token = 0;
1857 // I have been denied the token
1858 case MV_CODE_DENY_TOKEN:
1859 // set the "denied" timestamp
1860 Multi_voice_denied_stamp = timestamp(MULTI_VOICE_DENIED_TIME);
1863 // I now have the token
1864 case MV_CODE_GIVE_TOKEN:
1865 GET_DATA(Multi_voice_stream_id);
1867 // we should never get the token if we cannot record
1868 if(!Multi_voice_can_record){
1872 // if we no longer have the keydown, automatically release the token
1873 if(!Multi_voice_keydown){
1874 multi_voice_release_token();
1876 Multi_voice_token = 1;
1880 // a request for the token from a player
1881 case MV_CODE_REQUEST_TOKEN:
1882 if(player_index >= 0){
1883 multi_voice_process_token_request(player_index);
1887 // a player gave up the token
1888 case MV_CODE_RELEASE_TOKEN:
1889 if(player_index >= 0){
1890 stream_index = multi_voice_find_token(player_index);
1895 if(stream_index >= 0){
1896 // set the token as having been released
1897 Multi_voice_stream[stream_index].token_status = MULTI_VOICE_TOKEN_INDEX_RELEASED;
1899 // timestamp this guy so that he can't get the token back immediately
1900 Net_players[player_index].s_info.voice_token_timestamp = timestamp(Netgame.options.voice_token_wait);
1904 // a player has set prefs for himself
1905 case MV_CODE_PLAYER_PREFS:
1906 Assert(player_index != -1);
1907 offset += multi_voice_process_player_prefs(data+offset,player_index);
1912 #ifdef MULTI_VOICE_VERBOSE
1913 nprintf(("Network","VOICE : PROC DATA\n"));
1915 // get routing information
1918 if(msg_mode == MULTI_MSG_TARGET){
1919 GET_DATA(target_sig);
1920 target_index = multi_find_player_by_net_signature(target_sig);
1921 Assert(target_index != -1);
1924 offset += multi_voice_process_data(data+offset,player_index,msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1926 // if we're the server of the game, we should also route this data to all other players
1927 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1928 multi_voice_route_data(data,offset,player_index,msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1932 // a data dummy packet
1933 case MV_CODE_DATA_DUMMY:
1934 #ifdef MULTI_VOICE_VERBOSE
1935 nprintf(("Network","VOICE : PROC DATA DUMMY\n"));
1937 // get routing information
1940 if(msg_mode == MULTI_MSG_TARGET){
1941 GET_DATA(target_sig);
1942 target_index = multi_find_player_by_net_signature(target_sig);
1943 Assert(target_index != -1);
1946 offset += multi_voice_process_data_dummy(data+offset);
1948 // if we're the server of the game, we should also route this data to all other players
1949 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
1950 multi_voice_route_data(data,offset,player_index,msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
1957 // send all pending voice packets
1958 void multi_voice_client_send_pending()
1960 ubyte data[MAX_PACKET_SIZE],code;
1961 ubyte msg_mode,chunk_index;
1962 ushort uc_size,chunk_size;
1963 int max_chunk_size,sent,target_index;
1968 // if we're not recording
1969 if(!Multi_voice_recording || (Multi_voice_current_stream_sent < 0) || (Multi_voice_current_stream_sent > Multi_voice_current_stream_index)){
1973 // stream all buffered up packets
1974 str = &Multi_voice_stream[0];
1975 while(Multi_voice_current_stream_sent < Multi_voice_current_stream_index){
1976 sent = Multi_voice_current_stream_sent++;
1978 // get the current messaging mode
1979 msg_mode = (ubyte)Multi_voice_send_mode;
1981 // if the size of this voice chunk will fit in the packet
1982 max_chunk_size = multi_voice_max_chunk_size(Multi_voice_send_mode);
1983 if(str->accum_buffer_csize[sent] > max_chunk_size){
1984 #ifdef MULTI_VOICE_VERBOSE
1985 nprintf(("Network","MULTI VOICE : streamed packet size too large!!\n"));
1988 Multi_voice_current_stream_sent++;
1990 // send a dummy data packet instead
1991 multi_voice_send_dummy_packet();
1996 #ifdef MULTI_VOICE_VERBOSE
1997 nprintf(("Network","MULTI VOICE : PACKET %d %d\n",(int)str->accum_buffer_csize[sent],(int)str->accum_buffer_usize[sent]));
2000 // get the specific target if we're in MSG_TARGET mode
2002 if(msg_mode == MULTI_MSG_TARGET){
2003 if(Player_ai->target_objnum != -1){
2004 target_index = multi_find_player_by_object(&Objects[Player_ai->target_objnum]);
2005 if(target_index == -1){
2013 // go through the data and send all of it
2014 code = MV_CODE_DATA;
2017 // if this packet is small enough to fit within a psnet data packet
2018 BUILD_HEADER(VOICE_PACKET);
2020 // add the packet code type
2023 // add the routing data and any necessary targeting information
2025 if(msg_mode == MULTI_MSG_TARGET){
2026 Assert(Game_mode & GM_IN_MISSION);
2027 ADD_DATA(Objects[Net_players[target_index].player->objnum].net_signature);
2031 ADD_DATA(Net_player->player_id);
2033 // add the current stream id#
2034 ADD_DATA(Multi_voice_stream_id);
2036 Assert(str->accum_buffer_usize[sent] < MULTI_VOICE_MAX_BUFFER_SIZE);
2037 uc_size = (ushort)str->accum_buffer_usize[sent];
2040 // add the chunk index
2041 chunk_index = (ubyte)sent;
2042 ADD_DATA(chunk_index);
2044 // size of the sound data
2045 chunk_size = (ushort)str->accum_buffer_csize[sent];
2046 ADD_DATA(chunk_size);
2049 gain = (float)str->accum_buffer_gain[sent];
2052 // add the chunk of data
2053 memcpy(data+packet_size, str->accum_buffer[sent],chunk_size);
2054 packet_size += chunk_size;
2056 // send to the server or rebroadcast if I _am_ the server
2057 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2058 multi_voice_route_data(data,packet_size,MY_NET_PLAYER_NUM,(int)msg_mode,(target_index == -1) ? NULL : &Net_players[target_index]);
2060 multi_io_send(Net_player, data, packet_size);
2066 // --------------------------------------------------------------------------------------------------
2067 // MULTI VOICE ALGORITHM stuff
2070 // process and play the current window of sound stream data we have. reset the window for the next incoming data as well
2071 void multi_voice_alg_play_window(int stream_index)
2073 int idx,buffer_offset;
2076 #ifdef MULTI_VOICE_VERBOSE
2077 nprintf(("Network","MULTI VOICE : PLAYING STREAM %d\n",stream_index));
2080 // get a pointer to the stream
2081 st = &Multi_voice_stream[stream_index];
2083 // don't play anything back if we can't hear sound
2084 if(Multi_voice_can_play){
2085 // first, pack all the accum buffers into the playback buffer
2086 #ifdef MULTI_VOICE_PRE_DECOMPRESS
2087 buffer_offset = Multi_voice_pre_sound_size;
2088 nprintf(("Network","VOICE : pre sound size %d\n",Multi_voice_pre_sound_size));
2089 for(idx=0;idx<MULTI_VOICE_ACCUM_BUFFER_COUNT;idx++){
2090 // if the flag is set, uncompress the data into the playback buffer
2091 if(st->accum_buffer_flags[idx]){
2092 // first, uncompress the data
2093 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]);
2095 // increment the buffer offset
2096 buffer_offset += st->accum_buffer_usize[idx];
2100 #ifdef MULTI_VOICE_POST_DECOMPRESS
2102 for(idx=0;idx<MULTI_VOICE_ACCUM_BUFFER_COUNT;idx++){
2103 // if the flag is set, copy the data
2104 if(st->accum_buffer_flags[idx]){
2105 memcpy(Multi_voice_unpack_buffer+buffer_offset,st->accum_buffer[idx],st->accum_buffer_csize[idx]);
2106 buffer_offset += st->accum_buffer_csize[idx];
2110 // decompress the whole shebang
2111 rtvoice_uncompress((ubyte*)Multi_voice_unpack_buffer,buffer_offset,st->accum_buffer_gain[0],(ubyte*)Multi_voice_playback_buffer,st->accum_buffer_usize[0]);
2112 buffer_offset = st->accum_buffer_usize[0];
2115 // mix in the SND_CUE_VOICE and the SND_END_VOICE game sounds
2116 buffer_offset = multi_voice_mix(MULTI_VOICE_POST_SOUND,Multi_voice_playback_buffer,buffer_offset,MULTI_VOICE_MAX_BUFFER_SIZE);
2118 Assert(Multi_voice_stream[stream_index].stream_rtvoice_handle != -1);
2120 // kill any previously playing sounds
2121 rtvoice_stop_playback(Multi_voice_stream[stream_index].stream_rtvoice_handle);
2122 Multi_voice_stream[stream_index].stream_snd_handle = -1;
2124 // if we can play sound and we know who this is from, display it
2125 if(Multi_voice_can_play){
2126 char voice_msg[256];
2127 int player_index = find_player_id(Multi_voice_stream[stream_index].stream_from);
2129 if(player_index != -1){
2130 memset(voice_msg,0,256);
2131 sprintf(voice_msg,XSTR("<%s is speaking>",712),Net_players[player_index].player->callsign);
2133 // display a chat message (write to the correct spot - hud, standalone gui, chatbox, etc)
2134 multi_display_chat_msg(voice_msg,player_index,0);
2138 // now call the rtvoice playback functions
2139 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);
2140 Multi_voice_stream[stream_index].stream_start_time = timer_get_fixed_seconds();
2143 // unset the stamp so that its not "free"
2144 Multi_voice_stamps[stream_index] = -1;
2146 // flush the stream (will also grab the token back, if the server)
2147 multi_voice_flush_old_stream(stream_index);
2150 // decision function which decides if we should play the current block of sound we have
2151 int multi_voice_alg_should_play(int stream_index)
2153 // if the timestamp has expired, play the sound
2154 if((Multi_voice_stamps[stream_index] != -1) && timestamp_elapsed(Multi_voice_stamps[stream_index])){
2155 #ifdef MULTI_VOICE_VERBOSE
2156 nprintf(("Network","MULTI VOICE : DECIDE, TIMEOUT\n"));
2164 // process incoming sound data in whatever way necessary (this function should take care of playing data when necessary)
2165 void multi_voice_alg_process_data(int player_index,int stream_index,ushort chunk_index,ushort chunk_size)
2167 // do this so we don't get compiler warnings
2172 // update the timestamp for this window
2173 Multi_voice_stamps[stream_index] = timestamp(MV_ALG_TIMEOUT);
2176 // process existing streams
2177 void multi_voice_alg_process_streams()
2182 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
2183 // determine if we should play this window of data
2184 if((Multi_voice_stamps[idx] != -1) && multi_voice_alg_should_play(idx)){
2185 // determine who this stream came from
2186 player_index = find_player_id(Multi_voice_stream[idx].stream_from);
2188 // server should check his own settings here
2189 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))) ){
2190 // unset the stamp so that its not "free"
2191 Multi_voice_stamps[idx] = -1;
2193 // flush the stream (will also grab the token back, if the server)
2194 multi_voice_flush_old_stream(idx);
2196 nprintf(("Network","Server not playing sound because of set options!\n"));
2198 // play the current sound
2200 multi_voice_alg_play_window(idx);
2206 // we are going to flush the current stream because we have started to receive data for a new one. do something first
2207 void multi_voice_alg_flush_old_stream(int stream_index)
2209 // just unset the heard from timestamp for now
2210 Multi_voice_stamps[stream_index] = -1;
2213 // initialize the smart algorithm
2214 void multi_voice_alg_init()
2218 for(idx=0;idx<MULTI_VOICE_MAX_STREAMS;idx++){
2219 Multi_voice_stamps[idx] = -1;
2224 // --------------------------------------------------------------------------------------------------
2225 // MULTI VOICE TESTING FUNCTIONS
2228 #define MV_TEST_RECORD_TIME 3000 // recording time in ms for testing voice
2229 int Multi_voice_test_record_stamp = -1;
2230 int Multi_voice_test_packet_tossed = 0;
2232 // process the next chunk of voice data
2233 void multi_voice_test_process_next_chunk()
2235 unsigned char *outbuf,*outbuf_raw;
2236 int compressed_size,uncompressed_size,raw_size;
2239 // if the test recording stamp is -1, we should stop
2240 if(Multi_voice_test_record_stamp == -1){
2241 rtvoice_stop_recording();
2245 // if the recording timestamp has elapsed, stop the whole thing
2246 if(timestamp_elapsed(Multi_voice_test_record_stamp)){
2247 nprintf(("Network","Stopping voice test recording\n"));
2249 rtvoice_stop_recording();
2251 Multi_voice_test_record_stamp = -1;
2252 Multi_voice_test_packet_tossed = 0;
2256 // otherwise get the compressed and uncompressed data and do something interesting with it
2257 rtvoice_get_data(&outbuf,&compressed_size,&uncompressed_size,&gain,&outbuf_raw,&raw_size);
2259 // determine whether the packet would have been dropped
2260 if(compressed_size > multi_voice_max_chunk_size(MULTI_MSG_ALL)){
2261 Multi_voice_test_packet_tossed = 1;
2263 Multi_voice_test_packet_tossed = 0;
2266 // send the raw output buffer to the voice options screen
2267 options_multi_set_voice_data(outbuf_raw,raw_size,outbuf,compressed_size,uncompressed_size,gain);
2270 // start recording voice locally for playback testing
2271 void multi_voice_test_record_start()
2273 // if there is test recording going on already, don't do anything
2274 if(Multi_voice_test_record_stamp != -1){
2278 // stop any playback which may be occuring
2279 rtvoice_stop_playback_all();
2281 // stop any recording which may be occuring
2282 rtvoice_stop_recording();
2284 // set the timestamp
2285 Multi_voice_test_record_stamp = timestamp(MV_TEST_RECORD_TIME);
2287 // start the recording of voice
2288 rtvoice_start_recording(multi_voice_test_process_next_chunk);
2291 // force stop any recording voice test
2292 void multi_voice_test_record_stop()
2294 Multi_voice_test_record_stamp = -1;
2295 Multi_voice_test_packet_tossed = 0;
2296 rtvoice_stop_recording();
2299 // return if the test recording is going on
2300 int multi_voice_test_recording()
2302 return (Multi_voice_test_record_stamp == -1) ? 0 : 1;
2305 // call this function if multi_voice_test_recording() is true to process various odds and ends of the test recording
2306 void multi_voice_test_process()
2308 // if we're not recording, do nothing
2309 if(Multi_voice_test_record_stamp == -1){
2313 // check to see if the timestamp has elapsed
2314 if(timestamp_elapsed(Multi_voice_test_record_stamp)){
2315 Multi_voice_test_record_stamp = -1;
2316 Multi_voice_test_packet_tossed = 0;
2320 // get a playback buffer handle (return -1 if none exist - bad)
2321 int multi_voice_test_get_playback_buffer()
2323 // return voice stream 0
2324 Assert(Multi_voice_stream[0].stream_snd_handle == -1);
2325 Assert(Multi_voice_stream[0].stream_rtvoice_handle != -1);
2327 return Multi_voice_stream[0].stream_rtvoice_handle;
2330 // return whether the last sampled chunk would have been too large to fit in a packet
2331 int multi_voice_test_packet_tossed()
2333 return Multi_voice_test_packet_tossed;