int decode_vumeter(lua_State *L) { u32_t sample_accumulator[2]; sample_t *ptr; size_t samples_until_wrap; s16_t sample; s32_t sample_sq; size_t i, num_samples; num_samples = luaL_optinteger(L, 2, VUMETER_DEFAULT_SAMPLE_WINDOW); sample_accumulator[0] = 0; sample_accumulator[1] = 0; decode_audio_lock(); if (decode_audio->state & DECODE_STATE_RUNNING) { ptr = (sample_t *)(void *)(decode_fifo_buf + decode_audio->fifo.rptr); samples_until_wrap = BYTES_TO_SAMPLES(fifo_bytes_until_rptr_wrap(&decode_audio->fifo)); for (i=0; i<num_samples; i++) { sample = (*ptr++) >> 24; sample_sq = sample * sample; sample_accumulator[0] += sample_sq; sample = (*ptr++) >> 24; sample_sq = sample * sample; sample_accumulator[1] += sample_sq; samples_until_wrap -= 2; if (samples_until_wrap <= 0) { ptr = (sample_t *)(void *)decode_fifo_buf; } } }
static struct ast_frame *g719read(struct ast_filestream *s, int *whennext) { int res; /* Send a frame from the file to the appropriate channel */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); return NULL; } *whennext = s->fr.samples = BYTES_TO_SAMPLES(res); return &s->fr; }
static struct ast_frame *siren14read(struct ast_filestream *s, int *whennext) { int res; /* Send a frame from the file to the appropriate channel */ s->fr.frametype = AST_FRAME_VOICE; s->fr.subclass.codec = AST_FORMAT_SIREN14; s->fr.mallocd = 0; AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) ast_log(LOG_WARNING, "Short read (%d) (%s)!\n", res, strerror(errno)); return NULL; } *whennext = s->fr.samples = BYTES_TO_SAMPLES(res); return &s->fr; }
static struct ast_frame *g719read(struct ast_filestream *s, int *whennext) { size_t res; /* Send a frame from the file to the appropriate channel */ AST_FRAME_SET_BUFFER(&s->fr, s->buf, AST_FRIENDLY_OFFSET, BUF_SIZE); if ((res = fread(s->fr.data.ptr, 1, s->fr.datalen, s->f)) != s->fr.datalen) { if (res) { ast_log(LOG_WARNING, "Short read of %s data (expected %d bytes, read %zu): %s\n", ast_format_get_name(s->fr.subclass.format), s->fr.datalen, res, strerror(errno)); } return NULL; } *whennext = s->fr.samples = BYTES_TO_SAMPLES(res); return &s->fr; }
/* Called to copy samples to the decode fifo when we are doing * a transition - crossfade or fade in. This method applies gain * to both the new signal and the one that's already in the fifo. */ static void decode_transition_copy_bytes(sample_t *buffer, size_t nbytes) { sample_t sample, *sptr; int nsamples, s; size_t bytes_read; fft_fixed in_gain, out_gain; ASSERT_AUDIO_LOCKED(); while (nbytes) { bytes_read = SAMPLES_TO_BYTES(transition_sample_step - transition_samples_in_step); if (bytes_read > nbytes) { bytes_read = nbytes; } nsamples = BYTES_TO_SAMPLES(bytes_read); sptr = (sample_t *)(void *)(decode_fifo_buf + decode_audio->fifo.wptr); in_gain = transition_gain; out_gain = FIXED_ONE - in_gain; if (crossfade_started) { for (s=0; s<nsamples * 2; s++) { sample = fixed_mul(out_gain, *sptr); sample += fixed_mul(in_gain, *buffer++); *sptr++ = sample; } } else { for (s=0; s<nsamples * 2; s++) { *sptr++ = fixed_mul(in_gain, *buffer++); } } fifo_wptr_incby(&decode_audio->fifo, bytes_read); nbytes -= bytes_read; transition_samples_in_step += nsamples; while (transition_samples_in_step >= transition_sample_step) { transition_samples_in_step -= transition_sample_step; transition_gain += transition_gain_step; } } }
static off_t g719tell(struct ast_filestream *fs) { return BYTES_TO_SAMPLES(ftello(fs->f)); }
/* All and mighty connection handler. */ static void* rsd_thread(void *thread_data) { connection_t conn; void *data = NULL; wav_header_t w; wav_header_t w_orig; int resample = 0; int rc, written; void *buffer = NULL; #ifdef HAVE_SAMPLERATE SRC_STATE *resample_state = NULL; #else resampler_t *resample_state = NULL; #endif float *resample_buffer = NULL; resample_cb_state_t cb_data; connection_t *temp_conn = thread_data; conn.socket = temp_conn->socket; conn.ctl_socket = temp_conn->ctl_socket; conn.serv_ptr = 0; conn.rate_ratio = 1.0; conn.identity[0] = '\0'; free(temp_conn); if ( debug ) log_printf("Connection accepted, awaiting WAV header data ...\n"); /* Firstly, get the wave header with stream settings. */ rc = get_wav_header(conn, &w); if ( rc == -1 ) { close(conn.socket); close(conn.ctl_socket); log_printf("Couldn't read WAV header... Disconnecting.\n"); pthread_exit(NULL); } memcpy(&w_orig, &w, sizeof(wav_header_t)); if ( resample_freq > 0 && resample_freq != (int)w.sampleRate ) { w.sampleRate = resample_freq; w.bitsPerSample = w_orig.bitsPerSample == 32 ? 32 : 16; if (w_orig.bitsPerSample == 32) w.rsd_format = (is_little_endian()) ? RSD_S32_LE : RSD_S32_BE; else w.rsd_format = (is_little_endian()) ? RSD_S16_LE : RSD_S16_BE; resample = 1; conn.rate_ratio = (float)w.sampleRate * w.bitsPerSample / ((float)w_orig.sampleRate * w_orig.bitsPerSample); } if ( debug ) { log_printf("Successfully got WAV header ...\n"); pheader(&w_orig); if ( resample ) { log_printf("Resamples to:\n"); pheader(&w); } } if ( debug ) log_printf("Initializing %s ...\n", backend->backend); /* Sets up backend */ if ( backend->init(&data) < 0 ) { log_printf("Failed to initialize %s ...\n", backend->backend); goto rsd_exit; } /* Opens device with settings. */ if ( backend->open(data, &w) < 0 ) { log_printf("Failed to open audio driver ...\n"); goto rsd_exit; } backend_info_t backend_info; memset(&backend_info, 0, sizeof(backend_info)); backend->get_backend_info(data, &backend_info); if ( backend_info.chunk_size == 0 ) { log_printf("Couldn't get backend info ...\n"); goto rsd_exit; } if ( backend_info.resample ) { resample = 1; w.sampleRate = w.sampleRate * backend_info.ratio; conn.rate_ratio = backend_info.ratio; w.bitsPerSample = w_orig.bitsPerSample == 32 ? 32 : 16; if (w_orig.bitsPerSample == 32) w.rsd_format = (is_little_endian()) ? RSD_S32_LE : RSD_S32_BE; else w.rsd_format = (is_little_endian()) ? RSD_S16_LE : RSD_S16_BE; } size_t size = backend_info.chunk_size; size_t read_size = size; size_t buffer_size = (read_size > size) ? read_size : size; buffer = malloc(buffer_size); if ( buffer == NULL ) { log_printf("Could not allocate memory for buffer."); goto rsd_exit; } if ( resample ) { resample_buffer = malloc(BYTES_TO_SAMPLES(buffer_size, w.rsd_format) * sizeof(float)); if ( resample_buffer == NULL ) { log_printf("Could not allocate memory for buffer."); goto rsd_exit; } cb_data.format = w_orig.rsd_format; cb_data.data = data; cb_data.conn = &conn; cb_data.framesize = w_orig.numChannels * rsnd_format_to_bytes(w_orig.rsd_format); #ifdef HAVE_SAMPLERATE int err; resample_state = src_callback_new(resample_callback, src_converter, w.numChannels, &err, &cb_data); #else resample_state = resampler_new(resample_callback, (float)w.sampleRate/w_orig.sampleRate, w.numChannels, &cb_data); #endif if ( resample_state == NULL ) { log_printf("Could not initialize resampler."); goto rsd_exit; } } #define MAX_TCP_BUFSIZ (1 << 14) // We only bother with setting buffer size if we're doing TCP. if ( rsd_conn_type == RSD_CONN_TCP ) { int flag = 1; int bufsiz = backend_info.chunk_size * 32; if (bufsiz > MAX_TCP_BUFSIZ) bufsiz = MAX_TCP_BUFSIZ; setsockopt(conn.socket, SOL_SOCKET, SO_RCVBUF, CONST_CAST &bufsiz, sizeof(int)); if ( conn.ctl_socket ) { setsockopt(conn.ctl_socket, SOL_SOCKET, SO_RCVBUF, CONST_CAST &bufsiz, sizeof(int)); setsockopt(conn.ctl_socket, SOL_SOCKET, SO_SNDBUF, CONST_CAST &bufsiz, sizeof(int)); setsockopt(conn.ctl_socket, IPPROTO_TCP, TCP_NODELAY, CONST_CAST &flag, sizeof(int)); } setsockopt(conn.socket, IPPROTO_TCP, TCP_NODELAY, CONST_CAST &flag, sizeof(int)); } /* Now we can send backend info to client. */ if ( send_backend_info(conn, &backend_info) < 0 ) { log_printf("Failed to send backend info ...\n"); goto rsd_exit; } if ( debug ) log_printf("Initializing of %s successful ...\n", backend->backend); if ( debug ) { if ( resample ) { log_printf("Resampling active. %d Hz --> %d Hz ", (int)w_orig.sampleRate, (int)w.sampleRate); #ifdef HAVE_SAMPLERATE log_printf("(libsamplerate)\n"); #else log_printf("(internal quadratic resampler)\n"); #endif } } /* Recieve data, write to sound card. Rinse, repeat :') */ for(;;) { if ( strlen(conn.identity) > 0 && verbose ) { log_printf(" :: %s\n", conn.identity); conn.identity[0] = '\0'; } if ( resample ) { #ifdef HAVE_SAMPLERATE rc = src_callback_read(resample_state, (double)w.sampleRate/(double)w_orig.sampleRate, BYTES_TO_SAMPLES(size, w.rsd_format)/w.numChannels, resample_buffer); if (rsnd_format_to_bytes(w.rsd_format) == 4) src_float_to_int_array(resample_buffer, buffer, BYTES_TO_SAMPLES(size, w.rsd_format)); else src_float_to_short_array(resample_buffer, buffer, BYTES_TO_SAMPLES(size, w.rsd_format)); #else rc = resampler_cb_read(resample_state, BYTES_TO_SAMPLES(size, w.rsd_format)/w.numChannels, resample_buffer); if (rsnd_format_to_bytes(w.rsd_format) == 4) resampler_float_to_s32(buffer, resample_buffer, BYTES_TO_SAMPLES(size, w.rsd_format)); else resampler_float_to_s16(buffer, resample_buffer, BYTES_TO_SAMPLES(size, w.rsd_format)); #endif } else rc = receive_data(data, &conn, buffer, read_size); if ( rc <= 0 ) { if ( debug ) log_printf("Client closed connection.\n"); goto rsd_exit; } for ( written = 0; written < (int)size; ) { rc = backend->write(data, (const char*)buffer + written, size - written); if ( rc == 0 ) goto rsd_exit; written += rc; } } /* Cleanup */ rsd_exit: if ( debug ) log_printf("Closed connection.\n\n"); #ifdef _WIN32 #undef close #endif backend->close(data); #ifdef _WIN32 #define close(x) closesocket(x) #endif free(buffer); close(conn.socket); if (conn.ctl_socket) close(conn.ctl_socket); if (resample_state) { #ifdef HAVE_SAMPLERATE src_delete(resample_state); #else resampler_free(resample_state); #endif } free(resample_buffer); pthread_exit(NULL); }