const char *module_name,
const char *voice_name,
_In_ unsigned int rate,
- _In_ unsigned int interval, switch_speech_flag_t *flags, _In_opt_ switch_memory_pool_t *pool);
+ _In_ unsigned int interval,
+ _In_ unsigned int channels,
+ switch_speech_flag_t *flags, _In_opt_ switch_memory_pool_t *pool);
/*!
\brief Feed text to the TTS module
\param sh the speech handle to feed
uint32_t native_rate;
/*! the number of channels */
uint32_t channels;
+ uint32_t real_channels;
/*! integer representation of the format */
unsigned int format;
/*! integer representation of the sections */
/*! the name of the interface */
const char *interface_name;
/*! function to open the speech interface */
- switch_status_t (*speech_open) (switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags);
+ switch_status_t (*speech_open) (switch_speech_handle_t *sh, const char *voice_name, int rate, int channels, switch_speech_flag_t *flags);
/*! function to close the speech interface */
switch_status_t (*speech_close) (switch_speech_handle_t *, switch_speech_flag_t *flags);
/*! function to feed audio to the ASR */
uint32_t rate;
uint32_t speed;
uint32_t samples;
+ uint32_t channels;
+ uint32_t real_channels;
char voice[80];
char *engine;
/*! module specific param */
int bits_per_second;
/*! number of microseconds of media in one packet (ptime * 1000) */
int microseconds_per_packet;
+ /*! stereo */
+ int stereo;
/*! private data for the codec module to store handle specific info */
void *private_info;
uint32_t to_len;
/*! the total size of the to buffer */
uint32_t to_size;
+ /*! the number of channels */
+ int channels;
} switch_audio_resampler_t;
SWITCH_DECLARE(uint32_t) switch_merge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples);
SWITCH_DECLARE(uint32_t) switch_unmerge_sln(int16_t *data, uint32_t samples, int16_t *other_data, uint32_t other_samples);
-SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t channels);
+SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t orig_channels, uint32_t channels);
SWITCH_END_EXTERN_C
#endif
switch_mutex_t *flag_mutex;
uint32_t rate;
uint32_t interval;
+ uint32_t channels;
switch_mutex_t *mutex;
conference_member_t *members;
conference_member_t *floor_holder;
conference_obj_t *conference = (conference_obj_t *) obj;
conference_member_t *imember, *omember;
uint32_t samples = switch_samples_per_packet(conference->rate, conference->interval);
- uint32_t bytes = samples * 2;
+ uint32_t bytes = samples * 2 * conference->channels;
uint8_t ready = 0, total = 0;
switch_timer_t timer = { 0 };
switch_event_t *event;
while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT)) {
switch_size_t file_sample_len = samples;
- switch_size_t file_data_len = samples * 2;
+ switch_size_t file_data_len = samples * 2 * conference->channels;
int has_file_data = 0, members_with_video = 0;
uint32_t conf_energy = 0;
int nomoh = 0;
- conference_member_t *floor_holder, *video_bridge_members[2] = { 0 };
-
+ conference_member_t *floor_holder, *video_bridge_members[2] = { 0 };
+
/* Sync the conference to a single timing source */
if (switch_core_timer_next(&timer) != SWITCH_STATUS_SUCCESS) {
switch_set_flag(conference, CFLAG_DESTRUCT);
conference->fnode->leadin--;
} else if (!conference->fnode->done) {
file_sample_len = samples;
+
if (conference->fnode->type == NODE_TYPE_SPEECH) {
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_BLOCKING;
-
+
if (switch_core_speech_read_tts(conference->fnode->sh, file_frame, &file_data_len, &flags) == SWITCH_STATUS_SUCCESS) {
- file_sample_len = file_data_len / 2;
+ file_sample_len = file_data_len / 2 / conference->fnode->sh->channels;
+
} else {
file_sample_len = file_data_len = 0;
}
} else {
if (has_file_data) {
switch_size_t x;
-
- for (x = 0; x < file_sample_len; x++) {
+ for (x = 0; x < file_sample_len * conference->channels; x++) {
int32_t z;
int16_t *muxed;
muxed[x] = (int16_t) z;
}
} else {
- memcpy(file_frame, async_file_frame, file_sample_len * 2);
+ memcpy(file_frame, async_file_frame, file_sample_len * 2 * conference->channels);
has_file_data = 1;
}
}
}
}
-
+
if (ready || has_file_data) {
/* Use more bits in the main_frame to preserve the exact sum of the audio samples. */
- int main_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 };
- int16_t write_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 };
+ int main_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
+ int16_t write_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
/* Init the main frame with file data if there is any. */
bptr = (int16_t *) file_frame;
if (has_file_data && file_sample_len) {
+
for (x = 0; x < bytes / 2; x++) {
- if (x <= file_sample_len) {
+ if (x <= file_sample_len * conference->channels) {
main_frame[x] = (int32_t) bptr[x];
} else {
memset(&main_frame[x], 255, sizeof(main_frame[x]));
+ //printf("FUCCCK %d <= %ld (%ld/%d)\n", x, file_sample_len * conference->channels, file_sample_len, conference->channels);
}
}
}
}
bptr = (int16_t *) omember->frame;
- for (x = 0; x < bytes / 2; x++) {
+
+ for (x = 0; x < bytes / 2 ; x++) {
z = main_frame[x];
+
/* bptr[x] represents my own contribution to this audio sample */
if (switch_test_flag(omember, MFLAG_HAS_AUDIO) && x <= omember->read / 2) {
z -= (int32_t) bptr[x];
}
+static void member_check_channels(switch_frame_t *frame, conference_member_t *member, switch_bool_t in)
+{
+ if (member->conference->channels != member->read_impl.number_of_channels) {
+ uint32_t rlen;
+ int from, to;
+
+ if (in) {
+ to = member->conference->channels;
+ from = member->read_impl.number_of_channels;
+ } else {
+ from = member->conference->channels;
+ to = member->read_impl.number_of_channels;
+ }
+
+ rlen = frame->datalen / 2 / from;
+
+ switch_mux_channels((int16_t *) frame->data, rlen, from, to);
+
+ frame->datalen = rlen * 2 * to;
+ }
+}
/* marshall frames from the call leg to the conference thread for muxing to other call legs */
break;
}
+ member_check_channels(read_frame, member, SWITCH_TRUE);
+
if (switch_channel_test_flag(channel, CF_VIDEO) && !switch_test_flag(member, MFLAG_ACK_VIDEO)) {
switch_set_flag_locked(member, MFLAG_ACK_VIDEO);
switch_channel_clear_flag(channel, CF_VIDEO_ECHO);
switch_change_sln_volume_granular(read_frame->data, read_frame->datalen / 2, member->agc_volume_in_level);
}
- if ((samples = read_frame->datalen / sizeof(*data))) {
+ if ((samples = read_frame->datalen / sizeof(*data) / member->read_impl.number_of_channels)) {
for (i = 0; i < samples; i++) {
energy += abs(data[j]);
j += member->read_impl.number_of_channels;
int16_t *bptr = (int16_t *) read_frame->data;
int len = (int) read_frame->datalen;
- switch_resample_process(read_resampler, bptr, len / 2);
- memcpy(member->resample_out, read_resampler->to, read_resampler->to_len * 2);
- len = read_resampler->to_len * 2;
+ switch_resample_process(read_resampler, bptr, len / 2 / member->conference->channels);
+ memcpy(member->resample_out, read_resampler->to, read_resampler->to_len * 2 * member->conference->channels);
+ len = read_resampler->to_len * 2 * member->conference->channels;
datalen = len;
data = member->resample_out;
} else {
static void member_add_file_data(conference_member_t *member, int16_t *data, switch_size_t file_data_len)
{
- switch_size_t file_sample_len = file_data_len / 2;
- int16_t file_frame[SWITCH_RECOMMENDED_BUFFER_SIZE / 2] = { 0 };
+ switch_size_t file_sample_len;
+ int16_t file_frame[SWITCH_RECOMMENDED_BUFFER_SIZE] = { 0 };
switch_mutex_lock(member->fnode_mutex);
goto done;
}
+ file_sample_len = file_data_len / 2 / member->conference->channels;
+
/* if we are done, clean it up */
if (member->fnode->done) {
conference_file_node_t *fnode;
} else {
if (member->fnode->type == NODE_TYPE_SPEECH) {
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_BLOCKING;
-
+
if (switch_core_speech_read_tts(member->fnode->sh, file_frame, &file_data_len, &flags) == SWITCH_STATUS_SUCCESS) {
- file_sample_len = file_data_len / 2;
+ file_sample_len = file_data_len / 2 / member->conference->channels;
} else {
file_sample_len = file_data_len = 0;
}
} else if (member->fnode->type == NODE_TYPE_FILE) {
switch_core_file_read(&member->fnode->fh, file_frame, &file_sample_len);
- file_data_len = file_sample_len * 2;
+ file_data_len = file_sample_len * 2 * member->fnode->fh.channels;
}
if (file_sample_len <= 0) {
switch_change_sln_volume(file_frame, (uint32_t)file_sample_len, member->volume_out_level);
}
- for (i = 0; i < (int)file_sample_len; i++) {
+ for (i = 0; i < (int)file_sample_len * member->conference->channels; i++) {
if (member->fnode->mux) {
sample = data[i] + file_frame[i];
switch_normalize_to_16bit(sample);
//csamples = samples;
tsamples = member->orig_read_impl.samples_per_packet;
low_count = 0;
- bytes = samples * 2;
+ bytes = samples * 2 * member->conference->channels;
call_list = NULL;
cp = NULL;
switch_assert(member->conference != NULL);
- flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 10;
+ flush_len = switch_samples_per_packet(member->conference->rate, member->conference->interval) * 10 * member->conference->channels;
if (switch_core_timer_init(&timer, member->conference->timer_name, interval, tsamples, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Timer Setup Failed. Conference Cannot Start\n");
mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer);
use_timer = 1;
-
+
if (mux_used) {
if (mux_used < bytes) {
if (++low_count >= 5) {
low_count = 0;
if ((write_frame.datalen = (uint32_t) switch_buffer_read(use_buffer, write_frame.data, bytes))) {
if (write_frame.datalen) {
- write_frame.samples = write_frame.datalen / 2;
+ write_frame.samples = write_frame.datalen / 2 / member->conference->channels;
if( !switch_test_flag(member, MFLAG_CAN_HEAR)) {
memset(write_frame.data, 255, write_frame.datalen);
if (member->fnode) {
member_add_file_data(member, write_frame.data, write_frame.datalen);
}
+
+ member_check_channels(&write_frame, member, SWITCH_FALSE);
+
if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
switch_mutex_unlock(member->audio_out_mutex);
break;
memset(write_frame.data, 255, write_frame.datalen);
write_frame.timestamp = timer.samplecount;
member_add_file_data(member, write_frame.data, write_frame.datalen);
+ member_check_channels(&write_frame, member, SWITCH_FALSE);
if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
break;
write_frame.samples = samples;
write_frame.timestamp = timer.samplecount;
+ member_check_channels(&write_frame, member, SWITCH_FALSE);
+
if (switch_core_session_write_frame(member->session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
break;
return NULL;
}
- data_buf_len = samples * sizeof(int16_t);
+ data_buf_len = samples * sizeof(int16_t) * conference->channels;
switch_zmalloc(data_buf, data_buf_len);
switch_mutex_lock(globals.hash_mutex);
fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
if (switch_core_file_open(&fh,
- rec->path, (uint8_t) 1, conference->rate, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT,
+ rec->path, (uint8_t) conference->channels, conference->rate, SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT,
rec->pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening File [%s]\n", rec->path);
/* Open the file */
fnode->fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
- if (switch_core_file_open(&fnode->fh, file, (uint8_t) 1, conference->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, pool) !=
+ if (switch_core_file_open(&fnode->fh, file, (uint8_t) conference->channels, conference->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT, pool) !=
SWITCH_STATUS_SUCCESS) {
switch_event_t *event;
/* Open the file */
fnode->fh.pre_buffer_datalen = SWITCH_DEFAULT_FILE_BUFFER_LEN;
if (switch_core_file_open(&fnode->fh,
- file, (uint8_t) 1, member->conference->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT,
+ file, (uint8_t) member->conference->channels, member->conference->rate, SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT,
pool) != SWITCH_STATUS_SUCCESS) {
switch_core_destroy_memory_pool(&pool);
status = SWITCH_STATUS_NOTFOUND;
if (!member->sh) {
memset(&member->lsh, 0, sizeof(member->lsh));
if (switch_core_speech_open(&member->lsh, conference->tts_engine, conference->tts_voice,
- conference->rate, conference->interval, &flags, switch_core_session_get_pool(member->session)) !=
+ conference->rate, conference->interval, conference->channels, &flags, switch_core_session_get_pool(member->session)) !=
SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_ERROR, "Invalid TTS module [%s]!\n", conference->tts_engine);
return SWITCH_STATUS_FALSE;
if (!conference->sh) {
memset(&conference->lsh, 0, sizeof(conference->lsh));
if (switch_core_speech_open(&conference->lsh, conference->tts_engine, conference->tts_voice,
- conference->rate, conference->interval, &flags, NULL) != SWITCH_STATUS_SUCCESS) {
+ conference->rate, conference->interval, conference->channels, &flags, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid TTS module [%s]!\n", conference->tts_engine);
return SWITCH_STATUS_FALSE;
}
if (switch_core_codec_init(&member->read_codec,
"L16",
NULL, read_impl.actual_samples_per_second, read_impl.microseconds_per_packet / 1000,
- 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, member->pool) == SWITCH_STATUS_SUCCESS) {
+ read_impl.number_of_channels,
+ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, member->pool) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG,
- "Raw Codec Activation Success L16@%uhz 1 channel %dms\n",
- read_impl.actual_samples_per_second, read_impl.microseconds_per_packet / 1000);
+ "Raw Codec Activation Success L16@%uhz %d channel %dms\n",
+ read_impl.actual_samples_per_second, read_impl.number_of_channels, read_impl.microseconds_per_packet / 1000);
} else {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed L16@%uhz 1 channel %dms\n",
- read_impl.actual_samples_per_second, read_impl.microseconds_per_packet / 1000);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed L16@%uhz %d channel %dms\n",
+ read_impl.actual_samples_per_second, read_impl.number_of_channels, read_impl.microseconds_per_packet / 1000);
goto done;
}
if (read_impl.actual_samples_per_second != conference->rate) {
if (switch_resample_create(&member->read_resampler,
read_impl.actual_samples_per_second,
- conference->rate, member->frame_size, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) {
+ conference->rate, member->frame_size, SWITCH_RESAMPLE_QUALITY, conference->channels) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_CRIT, "Unable to create resampler!\n");
goto done;
}
NULL,
conference->rate,
read_impl.microseconds_per_packet / 1000,
- 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, member->pool) == SWITCH_STATUS_SUCCESS) {
+ read_impl.number_of_channels,
+ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, member->pool) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG,
- "Raw Codec Activation Success L16@%uhz 1 channel %dms\n", conference->rate, read_impl.microseconds_per_packet / 1000);
+ "Raw Codec Activation Success L16@%uhz %d channel %dms\n",
+ conference->rate, conference->channels, read_impl.microseconds_per_packet / 1000);
} else {
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed L16@%uhz 1 channel %dms\n",
- conference->rate, read_impl.microseconds_per_packet / 1000);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Raw Codec Activation Failed L16@%uhz %d channel %dms\n",
+ conference->rate, conference->channels, read_impl.microseconds_per_packet / 1000);
goto codec_done2;
}
uint32_t announce_count = 0;
char *maxmember_sound = NULL;
uint32_t rate = 8000, interval = 20;
+ uint32_t channels = 1;
int broadcast_chat_messages = 0;
int comfort_noise_level = 0;
int pin_retries = 3;
switch_uuid_t uuid;
switch_codec_implementation_t read_impl = { 0 };
switch_channel_t *channel = NULL;
- const char *force_rate = NULL, *force_interval = NULL, *presence_id = NULL;
- uint32_t force_rate_i = 0, force_interval_i = 0;
+ const char *force_rate = NULL, *force_interval = NULL, *force_channels = NULL, *presence_id = NULL;
+ uint32_t force_rate_i = 0, force_interval_i = 0, force_channels_i = NULL;
/* Validate the conference name */
if (zstr(name)) {
}
}
+ if ((force_channels = switch_channel_get_variable(channel, "conference_force_channels"))) {
+ if (!strcasecmp(force_channels, "auto")) {
+ force_rate_i = read_impl.number_of_channels;
+ } else {
+ tmp = atoi(force_channels);
+
+ if (tmp == 1 || tmp == 2) {
+ force_channels_i = channels = tmp;
+ }
+ }
+ }
+
if ((force_interval = switch_channel_get_variable(channel, "conference_force_interval"))) {
if (!strcasecmp(force_interval, "auto")) {
force_interval_i = read_impl.microseconds_per_packet / 1000;
rate = tmp;
}
}
+ } else if (!force_channels_i && !strcasecmp(var, "channels") && !zstr(val)) {
+ uint32_t tmp = atoi(val);
+ if (session && tmp == 0) {
+ if (!strcasecmp(val, "auto")) {
+ channels = read_impl.number_of_channels;
+ }
+ } else {
+ if (tmp == 1 || tmp == 2) {
+ channels = tmp;
+ }
+ }
} else if (!strcasecmp(var, "domain") && !zstr(val)) {
domain = val;
} else if (!strcasecmp(var, "description") && !zstr(val)) {
conference->domain = "cluecon.com";
}
+ conference->channels = channels;
conference->rate = rate;
conference->interval = interval;
conference->ivr_dtmf_timeout = ivr_dtmf_timeout;
return rv;
}
-static switch_status_t cepstral_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, switch_speech_flag_t *flags)
+static switch_status_t cepstral_speech_open(switch_speech_handle_t *sh, const char *voice_name, int rate, int channels, switch_speech_flag_t *flags)
{
cepstral_t *cepstral = switch_core_alloc(sh->memory_pool, sizeof(*cepstral));
char srate[25];
if (!used && cepstral->done_gen) {
-
status = SWITCH_STATUS_BREAK;
break;
}
codec_settings->samplerate = atoi(arg);
codec_fmtp->actual_samples_per_second = codec_settings->samplerate;
}
+
+ if (!strcasecmp(data, "stereo")) {
+ codec_settings->stereo = atoi(arg);
+ codec_fmtp->stereo = codec_settings->stereo;
+ }
if (!strcasecmp(data, "maxaveragebitrate")) {
codec_settings->maxaveragebitrate = atoi(arg);
char buf[256] = "";
if (settings->useinbandfec) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "useinbandfec=1;");
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "useinbandfec=1; ");
}
if (settings->usedtx) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "usedtx=1;");
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "usedtx=1; ");
}
if (settings->maxaveragebitrate) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxaveragebitrate=%d;", settings->maxaveragebitrate);
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxaveragebitrate=%d; ", settings->maxaveragebitrate);
}
if (settings->ptime) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ptime=%d;", settings->ptime);
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ptime=%d; ", settings->ptime);
}
if (settings->minptime) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "minptime=%d;", settings->minptime);
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "minptime=%d; ", settings->minptime);
}
-
+
if (settings->maxptime) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxptime=%d;", settings->maxptime);
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "maxptime=%d; ", settings->maxptime);
}
if (settings->samplerate) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "samplerate=%d;", settings->samplerate);
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "samplerate=%d; ", settings->samplerate);
}
-
- if (end_of(buf) == ';') {
- end_of(buf) = '\0';
+
+ if (settings->stereo) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "stereo=%d; ", settings->stereo);
+ }
+
+ if (end_of(buf) == ' ') {
+ *(end_of_p(buf) - 1) = '\0';
}
return switch_core_strdup(pool, buf);
memset(&codec_fmtp, '\0', sizeof(struct switch_codec_fmtp));
codec_fmtp.private_info = &opus_codec_settings;
switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp);
-
codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool);
-
+
if (encoding) {
/* come up with a way to specify these */
int bitrate_bps = OPUS_AUTO;
context->encoder_object = opus_encoder_create(samplerate,
codec->implementation->number_of_channels,
- OPUS_APPLICATION_VOIP, &err);
+ codec->implementation->number_of_channels == 1 ? OPUS_APPLICATION_VOIP : OPUS_APPLICATION_AUDIO, &err);
if (err != OPUS_OK) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot create encoder: %s\n", opus_strerror(err));
if (!context) {
return SWITCH_STATUS_FALSE;
}
-
- if (len > 1275) len = 1275;
-
- bytes = opus_encode(context->encoder_object, (void *) decoded_data, decoded_data_len / 2, (unsigned char *) encoded_data, len);
-
+
+ if (len > 2880) len = 2880;
+
+ bytes = opus_encode(context->encoder_object, (void *) decoded_data,
+ decoded_data_len / 2 / codec->implementation->number_of_channels, (unsigned char *) encoded_data, len);
+
if (bytes > 0) {
*encoded_data_len = (uint32_t) bytes;
return SWITCH_STATUS_SUCCESS;
}
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder Error!\n");
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder Error: %s Decoded Datalen %u Codec NumberChans %u Len %u DecodedDate %p EncodedData %p ContextEncoderObject %p!\n", opus_strerror(bytes),decoded_data_len,codec->implementation->number_of_channels,len,(void *) decoded_data,(void *) encoded_data,(void *) context->encoder_object);
+
return SWITCH_STATUS_GENERR;
}
}
samples = opus_decode(context->decoder_object, (*flag & SFF_PLC) ? NULL : encoded_data, encoded_data_len, decoded_data, *decoded_data_len, 0);
-
+
if (samples < 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Decoder Error: %s!\n", opus_strerror(samples));
return SWITCH_STATUS_GENERR;
}
-
- *decoded_data_len = samples * 2;
+
+ *decoded_data_len = samples * 2 * codec->implementation->number_of_channels;
return SWITCH_STATUS_SUCCESS;
}
switch_opus_decode, /* function to decode encoded data into raw data */
switch_opus_destroy); /* deinitalize a codec handle using this implementation */
+ settings.stereo = 1;
+ dft_fmtp = gen_fmtp(&settings, pool);
+
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 116, /* the IANA code number */
+ "opus",/* the IANA code name */
+ dft_fmtp, /* default fmtp to send (can be overridden by the init function) */
+ rate, /* samples transferred per second */
+ rate, /* actual samples transferred per second */
+ bits, /* bits transferred per second */
+ mss, /* number of microseconds per frame */
+ samples, /* number of samples per frame */
+ bytes * 2, /* number of bytes per frame decompressed */
+ 0, /* number of bytes per frame compressed */
+ 2,/* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_opus_init, /* function to initialize a codec handle using this implementation */
+ switch_opus_encode, /* function to encode raw data into encoded data */
+ switch_opus_decode, /* function to decode encoded data into raw data */
+ switch_opus_destroy); /* deinitalize a codec handle using this implementation */
+
bytes *= 2;
samples *= 2;
mss *= 2;
}
}
- switch_buffer_write(audio_buffer, abuf, olen * 2);
+ switch_buffer_write(audio_buffer, abuf, olen * 2 * source->channels);
}
}
break;
}
- if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2)) {
- used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2);
+ if (!is_open || used >= source->prebuf || (source->total && used > source->samples * 2 * source->channels)) {
+ used = switch_buffer_read(audio_buffer, dist_buf, source->samples * 2 * source->channels);
if (source->total) {
uint32_t bused = 0;
switch_mutex_lock(source->mutex);
{
local_stream_context_t *context = handle->private_info;
switch_size_t bytes = 0;
- size_t need = *len * 2;
+ size_t need = *len * 2 * handle->real_channels;
if (!context->source->ready) {
*len = 0;
switch_mutex_lock(context->audio_mutex);
if ((bytes = switch_buffer_read(context->audio_buffer, data, need))) {
- *len = bytes / 2;
+ *len = bytes / 2 / handle->real_channels;
} else {
if (need > 2560) {
need = 2560;
}
memset(data, 255, need);
- *len = need / 2;
+ *len = need / 2 / handle->real_channels;
}
switch_mutex_unlock(context->audio_mutex);
handle->sample_count += *len;
return SWITCH_STATUS_FALSE;
}
+ handle->channels = 1;
+
context = switch_core_alloc(handle->memory_pool, sizeof(*context));
context->fds[0] = -1;
char *err = NULL;
const char *mpg123err = NULL;
int portno = 0;
+ long rate = 0;
+ int channels = 0;
+ int encoding = 0;
if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) {
return SWITCH_STATUS_MEMERR;
}
if (handle->handler) {
- if (mpg123_param(context->mh, MPG123_FLAGS, MPG123_SEEKBUFFER | MPG123_MONO_MIX, 0) != MPG123_OK) {
- MPGERROR();
- }
if (mpg123_open_feed(context->mh) != MPG123_OK) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening mpg feed\n");
mpg123err = mpg123_strerror(context->mh);
launch_read_stream_thread(context);
} else {
handle->seekable = 1;
- if (mpg123_param(context->mh, MPG123_FLAGS, MPG123_MONO_MIX, 0) != MPG123_OK) {
- MPGERROR();
- }
+
if (mpg123_open(context->mh, path) != MPG123_OK) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error opening %s\n", path);
mpg123err = mpg123_strerror(context->mh);
}
}
+
+
+ mpg123_getformat(context->mh, &rate, &channels, &encoding);
+ handle->channels = channels;
+ handle->samplerate = rate;
+
} else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) {
if (!(context->gfp = lame_init())) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate lame\n");
static switch_status_t shout_file_read(switch_file_handle_t *handle, void *data, size_t *len)
{
shout_context_t *context = handle->private_info;
- size_t rb = 0, bytes = *len * sizeof(int16_t), newbytes = 0;
+ size_t rb = 0, bytes = *len * sizeof(int16_t) * handle->channels, newbytes = 0;
*len = 0;
/* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "rb: %d, bytes: %d\n", (int) rb, (int) bytes); */
if (rb) {
- *len = rb / sizeof(int16_t);
+ *len = rb / sizeof(int16_t) / handle->channels;
} else {
/* no data, so insert 1 second of silence */
newbytes = 2 * handle->samplerate;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Padding mp3 stream with 1s of empty audio. (%s)\n", context->stream_url);
memset(data, 255, bytes);
- *len = bytes / sizeof(int16_t);
+ *len = bytes / sizeof(int16_t) / handle->channels;
}
handle->sample_count += *len;
}
}
+ handle->channels = 1;
handle->private_info = sh;
return SWITCH_STATUS_SUCCESS;
handle->samplerate = 8000;
}
+ handle->channels = 1;
+
teletone_init_session(&ts, 0, teletone_handler, audio_buffer);
ts.rate = handle->samplerate;
ts.channels = 1;
int samples;
int playing;
int samplerate;
+ int channels;
int err;
int pts;
libvlc_instance_t *inst_out;
switch_mutex_lock(context->audio_mutex);
if (context->audio_buffer) {
- if (!switch_buffer_write(context->audio_buffer, samples, count * 2)) {
+ if (!switch_buffer_write(context->audio_buffer, samples, count * 2 * context->channels)) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Buffer error\n");
}
}
context->samples = 0;
if ( samples ) {
- bytes = samples * 2;
+ bytes = samples * 2 * context->channels;
*output = malloc(bytes);
bytes = switch_buffer_read(context->audio_buffer, *output, bytes);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC imem samples: %d\n", samples);
context->mp = libvlc_media_player_new_from_media(context->m);
- if ( !handle->samplerate)
+ if (!handle->samplerate) {
handle->samplerate = 16000;
+ }
context->samplerate = handle->samplerate;
-
- libvlc_audio_set_format(context->mp, "S16N", context->samplerate, 1);
+ context->channels = handle->channels;
+
+ libvlc_audio_set_format(context->mp, "S16N", context->samplerate, handle->channels);
m_event_manager = libvlc_media_event_manager(context->m);
libvlc_event_attach(m_event_manager, libvlc_MediaStateChanged, vlc_media_state_callback, (void *) context);
opts[6] = "--rawaud-fourcc=s16l";
opts[7] = switch_mprintf("--rawaud-samplerate=%d", context->samplerate);
opts[8] = switch_mprintf("--imem-data=%ld", context);
- opts[9] = "--rawaud-channels=1";
+ //opts[9] = "--rawaud-channels=1";
/* Prepare to write to an output stream. */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for writing\n", path);
static switch_status_t vlc_file_read(switch_file_handle_t *handle, void *data, size_t *len)
{
vlc_file_context_t *context = handle->private_info;
- size_t bytes = *len * sizeof(int16_t), read;
+ size_t bytes = *len * sizeof(int16_t) * handle->channels, read;
libvlc_state_t status;
if (!context) {
read = switch_buffer_read(context->audio_buffer, data, bytes);
switch_mutex_unlock(context->audio_mutex);
- status = libvlc_media_get_state(context->m);
+ status = libvlc_media_get_state(context->m);
+
if (!read && (status == libvlc_Stopped || status == libvlc_Ended || status == libvlc_Error)) {
return SWITCH_STATUS_FALSE;
} else if (!read) {
memset(data, 0, read);
}
- if (read)
- *len = read/2;
+ if (read) {
+ *len = read / 2 / handle->channels;
+ }
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t vlc_file_write(switch_file_handle_t *handle, void *data, size_t *len)
{
vlc_file_context_t *context = handle->private_info;
- size_t bytes = *len * sizeof(int16_t);
+ size_t bytes = *len * sizeof(int16_t) * handle->channels;
switch_mutex_lock(context->audio_mutex);
context->samples += *len;
return SWITCH_STATUS_FALSE;
}
- if (switch_core_speech_open(&this->_speech->sh, engine, voice, rate, interval,
+ if (switch_core_speech_open(&this->_speech->sh, engine, voice, rate, interval, read_codec->implementation->number_of_channels,
&flags, switch_core_session_get_pool(this->_session)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid TTS module!\n");
switch_core_codec_destroy(&this->_speech->codec);
switch_set_flag(codec, SWITCH_CODEC_FLAG_READY);
return SWITCH_STATUS_SUCCESS;
} else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Codec %s Exists but not at the desired implementation. %dhz %dms\n", codec_name, rate,
- ms);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Codec %s Exists but not at the desired implementation. %dhz %dms %dch\n",
+ codec_name, rate, ms, channels);
+
}
UNPROTECT_INTERFACE(codec_interface);
}
if (codec->implementation->encoded_bytes_per_packet) {
- uint32_t frames = encoded_data_len / codec->implementation->encoded_bytes_per_packet;
+ uint32_t frames = encoded_data_len / codec->implementation->encoded_bytes_per_packet / codec->implementation->number_of_channels;
if (frames && codec->implementation->decoded_bytes_per_packet * frames > *decoded_data_len) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Buffer size sanity check failed! edl:%u ebpp:%u fr:%u ddl:%u\n",
switch_goto_status(status, fail);
}
+ fh->real_channels = fh->channels;
+
+ if (channels) {
+ fh->channels = channels;
+ }
if ((flags & SWITCH_FILE_FLAG_WRITE) && !is_stream && (status = switch_file_exists(file_path, fh->memory_pool)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "File [%s] not created!\n", file_path);
if (fh->pre_buffer_datalen) {
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Prebuffering %d bytes\n", (int)fh->pre_buffer_datalen);
- switch_buffer_create_dynamic(&fh->pre_buffer, fh->pre_buffer_datalen * fh->channels, fh->pre_buffer_datalen * fh->channels / 2, 0);
+ switch_buffer_create_dynamic(&fh->pre_buffer, fh->pre_buffer_datalen * fh->channels, fh->pre_buffer_datalen * fh->channels, 0);
fh->pre_buffer_data = switch_core_alloc(fh->memory_pool, fh->pre_buffer_datalen * fh->channels);
}
- if (fh->channels > 1 && (flags & SWITCH_FILE_FLAG_READ) && !(fh->flags & SWITCH_FILE_NOMUX)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File has %d channels, muxing to mono will occur.\n", fh->channels);
+
+ if (fh->real_channels != fh->channels && (flags & SWITCH_FILE_FLAG_READ) && !(fh->flags & SWITCH_FILE_NOMUX)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File has %d channels, muxing to %d channel%s will occur.\n", fh->real_channels, fh->channels, fh->channels == 1 ? "" : "s");
}
switch_set_flag(fh, SWITCH_FILE_OPEN);
return SWITCH_STATUS_FALSE;
}
- if (fh->buffer && switch_buffer_inuse(fh->buffer) >= *len * 2) {
- *len = switch_buffer_read(fh->buffer, data, orig_len * 2) / 2;
+ if (fh->buffer && switch_buffer_inuse(fh->buffer) >= *len * 2 * fh->channels) {
+ *len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels;
return *len == 0 ? SWITCH_STATUS_FALSE : SWITCH_STATUS_SUCCESS;
}
int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE);
if (!switch_test_flag(fh, SWITCH_FILE_BUFFER_DONE)) {
- rlen = asis ? fh->pre_buffer_datalen : fh->pre_buffer_datalen / 2;
+ rlen = asis ? fh->pre_buffer_datalen : fh->pre_buffer_datalen / 2 / fh->real_channels;
- if (switch_buffer_inuse(fh->pre_buffer) < rlen * 2) {
+ if (switch_buffer_inuse(fh->pre_buffer) < rlen * 2 * fh->channels) {
if ((status = fh->file_interface->file_read(fh, fh->pre_buffer_data, &rlen)) == SWITCH_STATUS_BREAK) {
return SWITCH_STATUS_BREAK;
}
switch_set_flag(fh, SWITCH_FILE_BUFFER_DONE);
} else {
fh->samples_in += rlen;
- if (fh->channels > 1 && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) {
- switch_mux_channels((int16_t *) fh->pre_buffer_data, rlen, fh->channels);
+ if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) {
+ switch_mux_channels((int16_t *) fh->pre_buffer_data, rlen, fh->real_channels, fh->channels);
}
- switch_buffer_write(fh->pre_buffer, fh->pre_buffer_data, asis ? rlen : rlen * 2);
+ switch_buffer_write(fh->pre_buffer, fh->pre_buffer_data, asis ? rlen : rlen * 2 * fh->channels);
}
}
}
- rlen = switch_buffer_read(fh->pre_buffer, data, asis ? *len : *len * 2);
- *len = asis ? rlen : rlen / 2;
+ rlen = switch_buffer_read(fh->pre_buffer, data, asis ? *len : *len * 2 * fh->channels);
+ *len = asis ? rlen : rlen / 2 / fh->channels;
if (*len == 0) {
switch_set_flag(fh, SWITCH_FILE_DONE);
fh->samples_in += *len;
- if (fh->channels > 1 && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) {
- switch_mux_channels((int16_t *) data, *len, fh->channels);
+ if (fh->real_channels != fh->channels && !switch_test_flag(fh, SWITCH_FILE_NOMUX)) {
+ switch_mux_channels((int16_t *) data, *len, fh->real_channels, fh->channels);
}
-
}
-
if (!switch_test_flag(fh, SWITCH_FILE_NATIVE) && fh->native_rate != fh->samplerate) {
if (!fh->resampler) {
if (switch_resample_create(&fh->resampler,
- fh->native_rate, fh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) {
+ fh->native_rate, fh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, fh->channels) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
return SWITCH_STATUS_GENERR;
}
}
- switch_resample_process(fh->resampler, data, (uint32_t) * len);
+ switch_resample_process(fh->resampler, data, (uint32_t) *len);
if (fh->resampler->to_len < want || fh->resampler->to_len > orig_len) {
if (!fh->buffer) {
switch_buffer_create_dynamic(&fh->buffer, factor, factor, 0);
switch_assert(fh->buffer);
}
- if (!fh->dbuf || fh->dbuflen < fh->resampler->to_len * 2) {
+ if (!fh->dbuf || fh->dbuflen < fh->resampler->to_len * 2 * fh->channels) {
void *mem;
- fh->dbuflen = fh->resampler->to_len * 2;
+ fh->dbuflen = fh->resampler->to_len * 2 * fh->channels;
mem = realloc(fh->dbuf, fh->dbuflen);
switch_assert(mem);
fh->dbuf = mem;
}
- switch_assert(fh->resampler->to_len * 2 <= fh->dbuflen);
- memcpy((int16_t *) fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2);
- switch_buffer_write(fh->buffer, fh->dbuf, fh->resampler->to_len * 2);
+ switch_assert(fh->resampler->to_len * 2 * fh->channels <= fh->dbuflen);
+ memcpy((int16_t *) fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
+ switch_buffer_write(fh->buffer, fh->dbuf, fh->resampler->to_len * 2 * fh->channels);
- if (switch_buffer_inuse(fh->buffer) < want * 2) {
+ if (switch_buffer_inuse(fh->buffer) < want * 2 * fh->channels) {
*len = want;
goto more;
}
- *len = switch_buffer_read(fh->buffer, data, orig_len * 2) / 2;
+ *len = switch_buffer_read(fh->buffer, data, orig_len * 2 * fh->channels) / 2 / fh->channels;
} else {
- memcpy(data, fh->resampler->to, fh->resampler->to_len * 2);
+ memcpy(data, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
*len = fh->resampler->to_len;
}
switch_assert(mem);
fh->dbuf = mem;
}
- switch_assert(fh->resampler->to_len * 2 <= fh->dbuflen);
+ switch_assert(fh->resampler->to_len * 2 *fh->channels <= fh->dbuflen);
memcpy(fh->dbuf, fh->resampler->to, fh->resampler->to_len * 2 * fh->channels);
data = fh->dbuf;
} else {
status = SWITCH_STATUS_RESAMPLE;
}
+ /* mux or demux to match */
+ if (session->read_impl.number_of_channels != read_frame->codec->implementation->number_of_channels) {
+ uint32_t rlen = session->raw_read_frame.datalen / 2 / read_frame->codec->implementation->number_of_channels;
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "%s MUX READ\n", switch_channel_get_name(session->channel));
+ switch_mux_channels((int16_t *) session->raw_read_frame.data, rlen,
+ read_frame->codec->implementation->number_of_channels, session->read_impl.number_of_channels);
+ session->raw_write_frame.datalen = rlen * 2 * session->read_impl.number_of_channels;
+ }
+
switch (status) {
case SWITCH_STATUS_RESAMPLE:
if (!session->read_resampler) {
status = switch_resample_create(&session->read_resampler,
read_frame->codec->implementation->actual_samples_per_second,
session->read_impl.actual_samples_per_second,
- session->read_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1);
+ session->read_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY,
+ session->read_impl.number_of_channels);
switch_mutex_unlock(session->resample_mutex);
if (session->read_resampler) {
short *data = read_frame->data;
switch_mutex_lock(session->resample_mutex);
- switch_resample_process(session->read_resampler, data, (int) read_frame->datalen / 2);
- memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2);
+ switch_resample_process(session->read_resampler, data, (int) read_frame->datalen / 2 / session->read_resampler->channels);
+ memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2 * session->read_resampler->channels);
read_frame->samples = session->read_resampler->to_len;
- read_frame->datalen = session->read_resampler->to_len * 2;
+ read_frame->datalen = session->read_resampler->to_len * 2 * session->read_resampler->channels;
read_frame->rate = session->read_resampler->to_rate;
switch_mutex_unlock(session->resample_mutex);
}
status = SWITCH_STATUS_RESAMPLE;
}
+ /* mux or demux to match */
+ if (session->write_impl.number_of_channels != frame->codec->implementation->number_of_channels) {
+ uint32_t rlen = session->raw_write_frame.datalen / 2 / frame->codec->implementation->number_of_channels;
+ switch_mux_channels((int16_t *) session->raw_write_frame.data, rlen,
+ frame->codec->implementation->number_of_channels, session->write_impl.number_of_channels);
+ session->raw_write_frame.datalen = rlen * 2 * session->write_impl.number_of_channels;
+ }
+
switch (status) {
case SWITCH_STATUS_RESAMPLE:
resample++;
status = switch_resample_create(&session->write_resampler,
frame->codec->implementation->actual_samples_per_second,
session->write_impl.actual_samples_per_second,
- session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1);
+ session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, session->write_impl.number_of_channels);
switch_mutex_unlock(session->resample_mutex);
switch_mutex_lock(session->resample_mutex);
if (session->write_resampler) {
- switch_resample_process(session->write_resampler, data, write_frame->datalen / 2);
+ switch_resample_process(session->write_resampler, data, write_frame->datalen / 2 / session->write_resampler->channels);
- memcpy(data, session->write_resampler->to, session->write_resampler->to_len * 2);
+ memcpy(data, session->write_resampler->to, session->write_resampler->to_len * 2 * session->write_resampler->channels);
write_frame->samples = session->write_resampler->to_len;
- write_frame->datalen = write_frame->samples * 2;
+ write_frame->datalen = write_frame->samples * 2 * session->write_resampler->channels;
write_frame->rate = session->write_resampler->to_rate;
status = switch_resample_create(&session->write_resampler,
frame->codec->implementation->actual_samples_per_second,
session->write_impl.actual_samples_per_second,
- session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY, 1);
+ session->write_impl.decoded_bytes_per_packet, SWITCH_RESAMPLE_QUALITY,
+ session->write_impl.number_of_channels);
}
switch_mutex_unlock(session->resample_mutex);
short *data = write_frame->data;
switch_mutex_lock(session->resample_mutex);
if (session->read_resampler) {
- switch_resample_process(session->read_resampler, data, write_frame->datalen / 2);
- memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2);
+ switch_resample_process(session->read_resampler, data, write_frame->datalen / 2 / session->read_resampler->channels);
+ memcpy(data, session->read_resampler->to, session->read_resampler->to_len * 2 * session->read_resampler->channels);
write_frame->samples = session->read_resampler->to_len;
- write_frame->datalen = session->read_resampler->to_len * 2;
+ write_frame->datalen = session->read_resampler->to_len * 2 * session->read_resampler->channels;
write_frame->rate = session->read_resampler->to_rate;
}
switch_mutex_unlock(session->resample_mutex);
SWITCH_DECLARE(switch_status_t) switch_core_speech_open(switch_speech_handle_t *sh,
const char *module_name,
const char *voice_name,
- unsigned int rate, unsigned int interval, switch_speech_flag_t *flags, switch_memory_pool_t *pool)
+ unsigned int rate, unsigned int interval, unsigned int channels,
+ switch_speech_flag_t *flags, switch_memory_pool_t *pool)
{
switch_status_t status;
char buf[256] = "";
sh->samples = switch_samples_per_packet(rate, interval);
sh->samplerate = rate;
sh->native_rate = rate;
+ sh->channels = channels;
+ sh->real_channels = 1;
- if ((status = sh->speech_interface->speech_open(sh, voice_name, rate, flags)) == SWITCH_STATUS_SUCCESS) {
+ if ((status = sh->speech_interface->speech_open(sh, voice_name, rate, channels, flags)) == SWITCH_STATUS_SUCCESS) {
switch_set_flag(sh, SWITCH_SPEECH_FLAG_OPEN);
} else {
UNPROTECT_INTERFACE(sh->speech_interface);
if (sh->buffer && (switch_buffer_inuse(sh->buffer) >= orig_len || switch_test_flag(sh, SWITCH_SPEECH_FLAG_DONE))) {
if ((*datalen = switch_buffer_read(sh->buffer, data, orig_len))) {
- return SWITCH_STATUS_SUCCESS;
+ status = SWITCH_STATUS_SUCCESS;
+ goto done;
}
}
more:
+ *datalen = orig_len / sh->channels;
+
if ((status = sh->speech_interface->speech_read_tts(sh, data, datalen, flags)) != SWITCH_STATUS_SUCCESS) {
switch_set_flag(sh, SWITCH_SPEECH_FLAG_DONE);
goto top;
}
-
if (sh->native_rate && sh->samplerate && sh->native_rate != sh->samplerate) {
if (!sh->resampler) {
if (switch_resample_create(&sh->resampler,
- sh->native_rate, sh->samplerate, (uint32_t) orig_len, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) {
+ sh->native_rate, sh->samplerate, (uint32_t) orig_len / sh->channels, SWITCH_RESAMPLE_QUALITY, 1) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unable to create resampler!\n");
return SWITCH_STATUS_GENERR;
}
}
}
+
+ done:
+
+ if (sh->channels != sh->real_channels) {
+ uint32_t rlen = *datalen / 2;
+ switch_mux_channels((int16_t *) data, rlen, 1, sh->channels);
+ *datalen = rlen * 2 * sh->channels;
+ }
+
return status;
}
st = switch_core_file_read(&dh->fh, buf, &len);
- for (x = 0; x < (uint32_t) len; x++) {
+ for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) {
int32_t mixed = fp[x] + buf[x];
switch_normalize_to_16bit(mixed);
fp[x] = (int16_t) mixed;
}
}
+ rframe->datalen = rframe->samples * 2 * dh->fh.channels;
+
+
if (st != SWITCH_STATUS_SUCCESS || len == 0) {
if (dh->loop) {
uint32_t pos = 0;
st = switch_core_file_read(&dh->fh, buf, &len);
- for (x = 0; x < (uint32_t) len; x++) {
+ for (x = 0; x < (uint32_t) len * dh->fh.channels; x++) {
int32_t mixed = fp[x] + buf[x];
switch_normalize_to_16bit(mixed);
fp[x] = (int16_t) mixed;
}
+
} else {
st = switch_core_file_read(&dh->fh, rframe->data, &len);
rframe->samples = (uint32_t) len;
- rframe->datalen = rframe->samples * 2;
}
+ rframe->datalen = rframe->samples * 2 * dh->fh.channels;
+
+
if (st != SWITCH_STATUS_SUCCESS || len == 0) {
if (dh->loop) {
uint32_t pos = 0;
if (!switch_test_flag(fh, SWITCH_FILE_PAUSE) && !switch_test_flag(read_frame, SFF_CNG)) {
int16_t *data = read_frame->data;
- len = (switch_size_t) asis ? read_frame->datalen : read_frame->datalen / 2;
+ len = (switch_size_t) asis ? read_frame->datalen : read_frame->datalen / 2 / fh->channels;
if (switch_core_file_write(fh, data, &len) != SWITCH_STATUS_SUCCESS) {
break;
}
} else if (switch_test_flag(read_frame, SFF_CNG) && fill_cng) {
- len = write_frame.datalen / 2;
+ len = write_frame.datalen / 2 / fh->channels;
if (switch_core_file_write(fh, write_frame.data, &len) != SWITCH_STATUS_SUCCESS) {
break;
}
codec_name,
NULL,
fh->samplerate,
- interval, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, pool) == SWITCH_STATUS_SUCCESS) {
+ interval, read_impl.number_of_channels,
+ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL, pool) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session),
- SWITCH_LOG_DEBUG, "Codec Activated %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval);
+ SWITCH_LOG_DEBUG, "Codec Activated %s@%uhz %u channels %dms\n",
+ codec_name, fh->samplerate, read_impl.number_of_channels, interval);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
- "Raw Codec Activation Failed %s@%uhz %u channels %dms\n", codec_name, fh->samplerate, fh->channels, interval);
+ "Raw Codec Activation Failed %s@%uhz %u channels %dms\n", codec_name,
+ fh->samplerate, read_impl.number_of_channels, interval);
switch_core_session_io_write_lock(session);
switch_channel_set_private(channel, "__fh", NULL);
switch_core_session_io_rwunlock(session);
uint32_t len;
len = samples * 2;
- if (switch_core_timer_init(&timer, timer_name, interval, samples, pool) != SWITCH_STATUS_SUCCESS) {
+ if (switch_core_timer_init(&timer, timer_name, interval, samples / codec.implementation->number_of_channels, pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Setup timer failed!\n");
switch_core_codec_destroy(&codec);
switch_core_session_io_write_lock(session);
continue;
}
switch_core_timer_sync(&timer); // Sync timer
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setup timer success %u bytes per %d ms!\n", len, interval);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
+ "Setup timer success %u bytes per %d ms! %d ch\n", len, interval, codec.implementation->number_of_channels);
}
write_frame.rate = fh->samplerate;
}
}
- buflen = FILE_STARTSAMPLES * sizeof(*abuf) * fh->cur_channels;
+ buflen = FILE_STARTSAMPLES * sizeof(*abuf) * fh->cur_channels ? fh->cur_channels : fh->channels;
if (buflen > write_frame.buflen) {
abuf = realloc(abuf, buflen);
olen /= 2;
}
switch_set_flag(fh, SWITCH_FILE_BREAK_ON_CHANGE);
+
if ((rstatus = switch_core_file_read(fh, abuf, &olen)) == SWITCH_STATUS_BREAK) {
continue;
}
-
+
if (rstatus != SWITCH_STATUS_SUCCESS) {
eof++;
continue;
last_native = test_native;
- switch_buffer_write(fh->audio_buffer, abuf, switch_test_flag(fh, SWITCH_FILE_NATIVE) ? olen : olen * 2);
+ switch_buffer_write(fh->audio_buffer, abuf, switch_test_flag(fh, SWITCH_FILE_NATIVE) ? olen : olen * 2 * fh->channels);
olen = switch_buffer_read(fh->audio_buffer, abuf, framelen);
fh->offset_pos += (uint32_t)(olen / 2);
switch_codec_t *codec, switch_timer_t *timer, char *text, switch_input_args_t *args)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
- short abuf[960];
+ short abuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
switch_dtmf_t dtmf = { 0 };
uint32_t len = 0;
switch_size_t ilen = 0;
switch_frame_t write_frame = { 0 };
- int x;
int done = 0;
- int lead_in_out = 10;
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_speech_flag_t flags = SWITCH_SPEECH_FLAG_NONE;
switch_size_t extra = 0;
write_frame.data = abuf;
write_frame.buflen = sizeof(abuf);
- len = sh->samples * 2;
+ len = sh->samples * 2 * sh->channels;
flags = 0;
text = NULL;
write_frame.rate = sh->rate;
-
memset(write_frame.data, 0, len);
write_frame.datalen = len;
write_frame.samples = len / 2;
switch_assert(codec->implementation != NULL);
- for (x = 0; !done && x < lead_in_out; x++) {
- switch_yield(codec->implementation->microseconds_per_packet);
- if (timer) {
- write_frame.timestamp = timer->samplecount;
- }
- if (switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
- done = 1;
- break;
- }
- }
-
switch_channel_audio_sync(channel);
- ilen = len;
+
for (;;) {
switch_event_t *event;
+ ilen = len;
+
if (!switch_channel_ready(channel)) {
status = SWITCH_STATUS_FALSE;
break;
continue;
}
+
flags = SWITCH_SPEECH_FLAG_BLOCKING;
status = switch_core_speech_read_tts(sh, abuf, &ilen, &flags);
if (status != SWITCH_STATUS_SUCCESS) {
- write_frame.datalen = (uint32_t) codec->implementation->decoded_bytes_per_packet;
- write_frame.samples = (uint32_t) (write_frame.datalen / 2);
- memset(write_frame.data, 0, write_frame.datalen);
- for (x = 0; !done && x < lead_in_out; x++) {
- switch_yield(codec->implementation->microseconds_per_packet);
- if (timer) {
- write_frame.timestamp = timer->samplecount;
- }
- if (switch_core_session_write_frame(session, &write_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
- done = 1;
- break;
- }
- }
if (status == SWITCH_STATUS_BREAK) {
status = SWITCH_STATUS_SUCCESS;
}
}
write_frame.datalen = (uint32_t) ilen;
- write_frame.samples = (uint32_t) (ilen / 2);
+ write_frame.samples = (uint32_t) (ilen / 2 / sh->channels);
if (timer) {
write_frame.timestamp = timer->samplecount;
}
switch_channel_t *channel = switch_core_session_get_channel(session);
uint32_t rate = 0;
int interval = 0;
+ uint32_t channels;
switch_frame_t write_frame = { 0 };
switch_timer_t ltimer, *timer;
switch_codec_t lcodec, *codec;
rate = read_impl.actual_samples_per_second;
interval = read_impl.microseconds_per_packet / 1000;
+ channels = read_impl.number_of_channels;
if (need_create) {
memset(sh, 0, sizeof(*sh));
- if ((status = switch_core_speech_open(sh, tts_name, voice_name, (uint32_t) rate, interval, &flags, NULL)) != SWITCH_STATUS_SUCCESS) {
+ if ((status = switch_core_speech_open(sh, tts_name, voice_name, (uint32_t) rate, interval, read_impl.number_of_channels, &flags, NULL)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Invalid TTS module!\n");
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
switch_ivr_clear_speech_cache(session);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "OPEN TTS %s\n", tts_name);
codec_name = "L16";
-
+
if (need_create) {
if (switch_core_codec_init(codec,
codec_name,
- NULL, (int) rate, interval, 1, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
+ NULL, (int) rate, interval, channels, SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE, NULL,
pool) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Raw Codec Activated\n");
} else {
switch_proxy_decode, /* function to decode encoded data into raw data */
switch_proxy_destroy); /* deinitalize a codec handle using this implementation */
+ SWITCH_ADD_CODEC(codec_interface, "PROXY PASS-THROUGH");
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 0, /* the IANA code number */
+ "PROXY", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 8000, /* samples transferred per second */
+ 8000, /* actual samples transferred per second */
+ 0, /* bits transferred per second */
+ 20000, /* number of microseconds per frame */
+ 160, /* number of samples per frame */
+ 320 * 2, /* number of bytes per frame decompressed */
+ 320 * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_proxy_init, /* function to initialize a codec handle using this implementation */
+ switch_proxy_encode, /* function to encode raw data into encoded data */
+ switch_proxy_decode, /* function to decode encoded data into raw data */
+ switch_proxy_destroy); /* deinitalize a codec handle using this implementation */
+
SWITCH_ADD_CODEC(codec_interface, "RAW Signed Linear (16 bit)");
for (counta = 1; counta <= 3; counta++) {
SWITCH_CODEC_TYPE_AUDIO, 70, "L16", NULL, rate, rate, bps,
mpf * countb, spf * countb, bpf * countb, ebpf * countb, 1, spf * countb,
switch_raw_init, switch_raw_encode, switch_raw_decode, switch_raw_destroy);
+
+ switch_core_codec_add_implementation(pool, codec_interface,
+ SWITCH_CODEC_TYPE_AUDIO, 70, "L16", NULL, rate, rate, bps,
+ mpf * countb, spf * countb, bpf * countb * 2, ebpf * countb, 2, spf * countb,
+ switch_raw_init, switch_raw_encode, switch_raw_decode, switch_raw_destroy);
}
rate = rate * 2;
bps = bps * 2;
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 12000, /* samples transferred per second */
+ 12000, /* actual samples transferred per second */
+ 192000 * 2, /* bits transferred per second */
+ ms_per_frame, /* number of microseconds per frame */
+ samples_per_frame, /* number of samples per frame */
+ bytes_per_frame * 2, /* number of bytes per frame decompressed */
+ bytes_per_frame * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
samples_per_frame += 240;
bytes_per_frame += 480;
ms_per_frame += 20000;
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 24000, /* samples transferred per second */
+ 24000, /* actual samples transferred per second */
+ 384000 * 2, /* bits transferred per second */
+ ms_per_frame, /* number of microseconds per frame */
+ samples_per_frame, /* number of samples per frame */
+ bytes_per_frame * 2, /* number of bytes per frame decompressed */
+ bytes_per_frame * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
samples_per_frame += 480;
bytes_per_frame += 960;
ms_per_frame += 20000;
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 48000, /* samples transferred per second */
+ 48000, /* actual samples transferred per second */
+ 768000 * 2, /* bits transferred per second */
+ ms_per_frame, /* number of microseconds per frame */
+ samples_per_frame * 2, /* number of samples per frame */
+ bytes_per_frame * 2, /* number of bytes per frame decompressed */
+ bytes_per_frame * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
samples_per_frame += 96;
bytes_per_frame += 192;
ms_per_frame += 2000;
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 8000, /* samples transferred per second */
+ 8000, /* actual samples transferred per second */
+ 128000 * 2, /* bits transferred per second */
+ ms_per_frame, /* number of microseconds per frame */
+ samples_per_frame, /* number of samples per frame */
+ bytes_per_frame * 2, /* number of bytes per frame decompressed */
+ bytes_per_frame * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
samples_per_frame += 16;
bytes_per_frame += 32;
ms_per_frame += 2000;
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 16000, /* samples transferred per second */
+ 16000, /* actual samples transferred per second */
+ 256000 * 2, /* bits transferred per second */
+ ms_per_frame, /* number of microseconds per frame */
+ samples_per_frame, /* number of samples per frame */
+ bytes_per_frame * 2, /* number of bytes per frame decompressed */
+ bytes_per_frame * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
samples_per_frame += 32;
bytes_per_frame += 64;
ms_per_frame += 2000;
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 32000, /* samples transferred per second */
+ 32000, /* actual samples transferred per second */
+ 512000 * 2, /* bits transferred per second */
+ ms_per_frame, /* number of microseconds per frame */
+ samples_per_frame, /* number of samples per frame */
+ bytes_per_frame * 2, /* number of bytes per frame decompressed */
+ bytes_per_frame * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
samples_per_frame += 64;
bytes_per_frame += 128;
ms_per_frame += 2000;
switch_raw_encode, /* function to encode raw data into encoded data */
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 48000, /* samples transferred per second */
+ 48000, /* actual samples transferred per second */
+ 768000 * 2, /* bits transferred per second */
+ ms_per_frame, /* number of microseconds per frame */
+ samples_per_frame * 2, /* number of samples per frame */
+ bytes_per_frame * 2, /* number of bytes per frame decompressed */
+ bytes_per_frame * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
samples_per_frame += 480;
bytes_per_frame += 960;
ms_per_frame += 10000;
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 22050, /* samples transferred per second */
+ 22050, /* actual samples transferred per second */
+ 352800 * 2, /* bits transferred per second */
+ 20000, /* number of microseconds per frame */
+ 441, /* number of samples per frame */
+ 882 * 2, /* number of bytes per frame decompressed */
+ 882 * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
70, /* the IANA code number */
"L16", /* the IANA code name */
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 11025, /* samples transferred per second */
+ 11025, /* actual samples transferred per second */
+ 176400 * 2, /* bits transferred per second */
+ 40000, /* number of microseconds per frame */
+ 441, /* number of samples per frame */
+ 882 * 2, /* number of bytes per frame decompressed */
+ 882 * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
+
switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
70, /* the IANA code number */
switch_raw_decode, /* function to decode encoded data into raw data */
switch_raw_destroy); /* deinitalize a codec handle using this implementation */
-
+ switch_core_codec_add_implementation(pool, codec_interface, SWITCH_CODEC_TYPE_AUDIO, /* enumeration defining the type of the codec */
+ 70, /* the IANA code number */
+ "L16", /* the IANA code name */
+ NULL, /* default fmtp to send (can be overridden by the init function) */
+ 11025, /* samples transferred per second */
+ 11025, /* actual samples transferred per second */
+ 176400 * 2, /* bits transferred per second */
+ 32000, /* number of microseconds per frame */
+ 256, /* number of samples per frame */
+ 512 * 2, /* number of bytes per frame decompressed */
+ 512 * 2, /* number of bytes per frame compressed */
+ 2, /* number of channels represented */
+ 1, /* number of frames per network packet */
+ switch_raw_init, /* function to initialize a codec handle using this implementation */
+ switch_raw_encode, /* function to encode raw data into encoded data */
+ switch_raw_decode, /* function to decode encoded data into raw data */
+ switch_raw_destroy); /* deinitalize a codec handle using this implementation */
/* indicate that the module should continue to be loaded */
resampler->factor = (lto_rate / lfrom_rate);
resampler->rfactor = (lfrom_rate / lto_rate);
resampler->to_size = resample_buffer(to_rate, from_rate, (uint32_t) to_size);
- resampler->to = malloc(resampler->to_size * sizeof(int16_t));
+ resampler->to = malloc(resampler->to_size * sizeof(int16_t) * channels);
+ resampler->channels = channels;
return SWITCH_STATUS_SUCCESS;
}
return x;
}
-SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t channels)
+SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, uint32_t orig_channels, uint32_t channels)
{
switch_size_t i = 0;
uint32_t j = 0;
- for (i = 0; i < samples; i++) {
- int32_t z = 0;
- for (j = 0; j < channels; j++) {
- z += data[i * channels + j];
- switch_normalize_to_16bit(z);
- data[i] = (int16_t) z;
+ switch_assert(channels < 11);
+
+ if (orig_channels > channels) {
+ for (i = 0; i < samples; i++) {
+ int32_t z = 0;
+ for (j = 0; j < orig_channels; j++) {
+ z += data[i * orig_channels + j];
+ switch_normalize_to_16bit(z);
+ data[i] = (int16_t) z;
+ }
+ }
+ } else if (orig_channels < channels) {
+
+ /* interesting problem... take a give buffer and double up every sample in the buffer without using any other buffer.....
+ This way beats the other i think bacause there is no malloc but I do have to copy the data twice */
+#if 1
+ uint32_t k = 0, len = samples * orig_channels;
+
+ for (i = 0; i < len; i++) {
+ data[i+len] = data[i];
+ }
+
+ for (i = 0; i < samples; i++) {
+ for (j = 0; j < channels; j++) {
+ data[k++] = data[i + samples];
+ }
}
+
+#else
+ uint32_t k = 0, len = samples * 2 * orig_channels;
+ int16_t *orig = NULL;
+
+ switch_zmalloc(orig, len);
+ memcpy(orig, data, len);
+
+ for (i = 0; i < samples; i++) {
+ for (j = 0; j < channels; j++) {
+ data[k++] = orig[i];
+ }
+ }
+
+ free(orig);
+#endif
+
}
}