1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
|
/*
* Copyright (C) Volition, Inc. 1999. All rights reserved.
*
* All source code herein is the property of Volition, Inc. You may not sell
* or otherwise commercially exploit the source or things you created based on the
* source.
*
*/
#include "globalincs/pstypes.h"
#include "sound/sound.h"
#include "sound/ds.h"
#include "sound/dscap.h"
#include "sound/rtvoice.h"
typedef struct rtv_format
{
int nchannels;
int bits_per_sample;
int frequency;
} rtv_format;
#define MAX_RTV_FORMATS 5
static rtv_format Rtv_formats[MAX_RTV_FORMATS] =
{
{1, 8, 11025},
{1, 16, 11025},
{1, 8, 22050},
{1, 16, 22050},
{1, 8, 44100},
};
static int Rtv_recording_format; // recording format, index into Rtv_formats[]
static int Rtv_playback_format; // playback format, index into Rtv_formats[]
#define RTV_BUFFER_TIME 8 // length of buffer in seconds
static int Rtv_recording_inited=0; // The input stream has been inited
static int Rtv_playback_inited=0; // The output stream has been inited
static int Rtv_recording=0; // Voice is currently being recorded
#define MAX_RTV_OUT_BUFFERS 1
#define RTV_OUT_FLAG_USED (1<<0)
typedef struct rtv_out_buffer
{
int ds_handle; // handle to directsound buffer
int flags; // see RTV_OUT_FLAG_ #defines above
} rtv_out_buffer;
static rtv_out_buffer Rtv_output_buffers[MAX_RTV_OUT_BUFFERS]; // data for output buffers
//static struct t_CodeInfo Rtv_code_info; // Parms will need to be transmitted with packets
// recording timer data
#ifdef _WIN32
static int Rtv_record_timer_id; // unique id for callback timer
#else
static SDL_TimerID Rtv_record_timer_id;
#endif
static int Rtv_callback_time; // callback time in ms
void (*Rtv_callback)();
// recording/encoding buffers
static unsigned char *Rtv_capture_raw_buffer;
static unsigned char *Rtv_capture_compressed_buffer;
static int Rtv_capture_compressed_buffer_size;
static int Rtv_capture_raw_buffer_size;
// playback/decoding buffers
static unsigned char *Rtv_playback_uncompressed_buffer;
static int Rtv_playback_uncompressed_buffer_size;
/////////////////////////////////////////////////////////////////////////////////////////////////
// RECORD/ENCODE
/////////////////////////////////////////////////////////////////////////////////////////////////
#ifdef _WIN32
void CALLBACK TimeProc(unsigned int id, unsigned int msg, unsigned long userdata, unsigned long dw1, unsigned long dw2)
{
if ( !Rtv_callback ) {
return;
}
nprintf(("Alan","In callback\n"));
Rtv_callback();
}
#else
Uint32 CALLBACK TimeProc(Uint32 interval, void *param)
{
if ( !Rtv_callback ) {
SDL_RemoveTimer(Rtv_record_timer_id);
Rtv_record_timer_id = NULL;
return 0;
}
mprintf(("In callback\n"));
Rtv_callback();
if (Rtv_callback_time) {
return interval;
} else {
SDL_RemoveTimer(Rtv_record_timer_id);
Rtv_record_timer_id = NULL;
return 0;
}
}
#endif
// Try to pick the most appropriate recording format
//
// exit: 0 => success
// !0 => failure
int rtvoice_pick_record_format()
{
int i;
for (i=0; i<MAX_RTV_FORMATS; i++) {
if ( dscap_create_buffer(Rtv_formats[i].frequency, Rtv_formats[i].bits_per_sample, 1, RTV_BUFFER_TIME) == 0 ) {
dscap_release_buffer();
Rtv_recording_format=i;
break;
}
}
if ( i == MAX_RTV_FORMATS ) {
return -1;
}
return 0;
}
// input: qos => new quality of service (1..10)
void rtvoice_set_qos(int qos)
{
// TODO: Speex stuff
}
// Init the recording portion of the real-time voice system
// input: qos => quality of service (1..10) 1 is highest compression, 10 is highest quality
// exit: 0 => success
// !0 => failure, recording not possible
int rtvoice_init_recording(int qos)
{
#if 0
if ( !Rtv_recording_inited ) {
if ( rtvoice_pick_record_format() ) {
return -1;
}
Rtv_capture_raw_buffer_size = Rtv_formats[Rtv_recording_format].frequency * (RTV_BUFFER_TIME) * fl2i(Rtv_formats[Rtv_recording_format].bits_per_sample/8.0f);
if ( dscap_create_buffer(Rtv_formats[Rtv_recording_format].frequency, Rtv_formats[Rtv_recording_format].bits_per_sample, 1, RTV_BUFFER_TIME) ) {
return -1;
}
// malloc out the voice data buffer for raw (uncompressed) recorded sound
if ( Rtv_capture_raw_buffer ) {
vm_free(Rtv_capture_raw_buffer);
Rtv_capture_raw_buffer=NULL;
}
Rtv_capture_raw_buffer = (unsigned char*)vm_malloc(Rtv_capture_raw_buffer_size);
// malloc out voice data buffer for compressed recorded sound
if ( Rtv_capture_compressed_buffer ) {
vm_free(Rtv_capture_compressed_buffer);
Rtv_capture_compressed_buffer=NULL;
}
Rtv_capture_compressed_buffer_size=Rtv_capture_raw_buffer_size; // be safe and allocate same as uncompressed
Rtv_capture_compressed_buffer = (unsigned char*)vm_malloc(Rtv_capture_compressed_buffer_size);
Rtv_recording_inited=1;
}
return 0;
#else
return -1;
#endif
}
// Stop a stream from recording
void rtvoice_stop_recording()
{
if ( !Rtv_recording ) {
return;
}
dscap_stop_record();
if ( Rtv_record_timer_id ) {
#ifndef _WIN32
SDL_RemoveTimer(Rtv_record_timer_id);
Rtv_record_timer_id = NULL;
#else
timeKillEvent(Rtv_record_timer_id);
Rtv_record_timer_id = 0;
#endif
}
Rtv_recording=0;
}
// Close down the real-time voice recording system
void rtvoice_close_recording()
{
if ( Rtv_recording ) {
rtvoice_stop_recording();
}
if ( Rtv_capture_raw_buffer ) {
vm_free(Rtv_capture_raw_buffer);
Rtv_capture_raw_buffer=NULL;
}
if ( Rtv_capture_compressed_buffer ) {
vm_free(Rtv_capture_compressed_buffer);
Rtv_capture_compressed_buffer=NULL;
}
dscap_release_buffer();
Rtv_recording_inited=0;
}
// Open a stream for recording (recording begins immediately)
// exit: 0 => success
// !0 => failure
int rtvoice_start_recording( void (*user_callback)(), int callback_time )
{
if ( !dscap_supported() ) {
return -1;
}
Assert(Rtv_recording_inited);
if ( Rtv_recording ) {
return -1;
}
if ( dscap_start_record() ) {
return -1;
}
if ( user_callback ) {
#ifndef _WIN32
Rtv_record_timer_id = SDL_AddTimer(callback_time, TimeProc, NULL);
#else
Rtv_record_timer_id = timeSetEvent(callback_time, callback_time, TimeProc, 0, TIME_PERIODIC);
#endif
if ( !Rtv_record_timer_id ) {
dscap_stop_record();
return -1;
}
Rtv_callback = user_callback;
Rtv_callback_time = callback_time;
} else {
Rtv_callback = NULL;
Rtv_record_timer_id = 0;
}
Rtv_recording=1;
return 0;
}
// Retrieve the recorded voice data
// input: outbuf => output parameter, recorded voice stored here
// compressed_size => output parameter, size in bytes of recorded voice after compression
// uncompressed_size => output parameter, size in bytes of recorded voice before compression
// gain => output parameter, gain value which must be passed to decoder
// outbuf_raw => output optional parameter, pointer to the raw sound data making up the compressed chunk
// outbuf_size_raw => output optional parameter, size of the outbuf_raw buffer
//
// NOTE: function converts voice data into compressed format
void rtvoice_get_data(unsigned char **outbuf, int *size, double *gain)
{
int max_size, raw_size;
max_size = dscap_max_buffersize();
*outbuf=NULL;
raw_size = dscap_get_raw_data(Rtv_capture_raw_buffer, Rtv_capture_raw_buffer_size);
// TODO: compress voice data
// *gain = Rtv_code_info.Gain;
*size = raw_size;
*outbuf = Rtv_capture_raw_buffer;
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// DECODE/PLAYBACK
/////////////////////////////////////////////////////////////////////////////////////////////////
// uncompress the data into PCM format
void rtvoice_uncompress(unsigned char *data_in, int size_in, double gain, unsigned char *data_out, int size_out)
{
if ( (data_in == NULL) || (size_in <= 0) ) {
return;
}
}
// Close down the real-time voice playback system
void rtvoice_close_playback()
{
if ( Rtv_playback_uncompressed_buffer ) {
vm_free(Rtv_playback_uncompressed_buffer);
Rtv_playback_uncompressed_buffer=NULL;
}
Rtv_playback_inited=0;
}
// Clear out the Rtv_output_buffers[] array
void rtvoice_reset_out_buffers()
{
int i;
for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
Rtv_output_buffers[i].flags=0;
Rtv_output_buffers[i].ds_handle=-1;
}
}
// Init the playback portion of the real-time voice system
// exit: 0 => success
// !0 => failure, playback not possible
int rtvoice_init_playback()
{
rtv_format *rtvf=NULL;
if ( !Rtv_playback_inited ) {
rtvoice_reset_out_buffers();
Rtv_playback_format=0;
rtvf = &Rtv_formats[Rtv_playback_format];
if ( Rtv_playback_uncompressed_buffer ) {
vm_free(Rtv_playback_uncompressed_buffer);
Rtv_playback_uncompressed_buffer=NULL;
}
Rtv_playback_uncompressed_buffer_size = rtvf->frequency * (RTV_BUFFER_TIME) * fl2i(rtvf->bits_per_sample/8.0f);
Rtv_playback_uncompressed_buffer = (unsigned char*)vm_malloc(Rtv_playback_uncompressed_buffer_size);
Assert(Rtv_playback_uncompressed_buffer);
Rtv_playback_inited=1;
}
return 0;
}
int rtvoice_find_free_output_buffer()
{
int i;
for ( i=0; i<MAX_RTV_OUT_BUFFERS; i++ ) {
if ( !(Rtv_output_buffers[i].flags & RTV_OUT_FLAG_USED) ) {
break;
}
}
if ( i == MAX_RTV_OUT_BUFFERS ) {
return -1;
}
Rtv_output_buffers[i].flags |= RTV_OUT_FLAG_USED;
return i;
}
// Open a stream for real-time voice output
int rtvoice_create_playback_buffer()
{
int index;
rtv_format *rtvf=NULL;
rtvf = &Rtv_formats[Rtv_playback_format];
index = rtvoice_find_free_output_buffer();
if ( index == -1 ) {
Int3();
return -1;
}
Rtv_output_buffers[index].ds_handle = ds_create_buffer(rtvf->frequency, rtvf->bits_per_sample, 1, RTV_BUFFER_TIME);
if ( Rtv_output_buffers[index].ds_handle == -1 ) {
return -1;
}
return index;
}
void rtvoice_stop_playback(int index)
{
Assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
if ( Rtv_output_buffers[index].ds_handle != -1 ) {
ds_stop_easy(Rtv_output_buffers[index].ds_handle);
}
}
}
void rtvoice_stop_playback_all()
{
int i;
for ( i = 0; i < MAX_RTV_OUT_BUFFERS; i++ ) {
rtvoice_stop_playback(i);
}
}
// Close a stream that was opened for real-time voice output
void rtvoice_free_playback_buffer(int index)
{
Assert(index >=0 && index < MAX_RTV_OUT_BUFFERS);
if ( Rtv_output_buffers[index].flags & RTV_OUT_FLAG_USED ) {
Rtv_output_buffers[index].flags=0;
if ( Rtv_output_buffers[index].ds_handle != -1 ) {
ds_stop_easy(Rtv_output_buffers[index].ds_handle);
ds_unload_buffer(Rtv_output_buffers[index].ds_handle);
}
Rtv_output_buffers[index].ds_handle=-1;
}
}
// Play sound data
// exit: >=0 => handle to playing sound
// -1 => error, voice not played
int rtvoice_play(int index, unsigned char *data, int size)
{
int ds_handle, rval;
ds_handle = Rtv_output_buffers[index].ds_handle;
// Stop any currently playing voice output
ds_stop_easy(ds_handle);
// TODO: uncompress the data into PCM format
// lock the data in
if ( ds_lock_data(ds_handle, data, size) ) {
return -1;
}
// play the voice
rval = ds_play(ds_handle, -100, DS_MUST_PLAY, Master_voice_volume, 0, 0);
return rval;
}
|