switch_sdp_type_t sdp_type,
uint32_t pt,
uint32_t rate,
- uint32_t ptime,
+ uint32_t ptime,
+ uint32_t channels,
uint8_t negotiated);
uint32_t samples;
/*! the rate of the frame */
uint32_t rate;
+ /*! the number of channels in the frame */
+ uint32_t channels;
/*! the payload of the frame */
switch_payload_t payload;
/*! the timestamp of the frame */
*/
SWITCH_DECLARE(switch_codec_interface_t *) switch_loadable_module_get_codec_interface(const char *name);
-SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit);
+SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit, uint32_t *channels);
/*!
\brief Retrieve the dialplan interface by it's registered name
switch_opus_fmtp_parse(codec->fmtp_in, &codec_fmtp);
codec->fmtp_out = gen_fmtp(&opus_codec_settings, codec->memory_pool);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "OPUS init %d %d\n", codec->implementation->actual_samples_per_second, codec->implementation->number_of_channels);
+
if (encoding) {
/* come up with a way to specify these */
int bitrate_bps = OPUS_AUTO;
settings.maxptime = settings.ptime;
settings.minptime = settings.ptime;
settings.samplerate = rate;
+ settings.stereo = 0;
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 */
switch_opus_destroy); /* deinitalize a codec handle using this implementation */
settings.stereo = 1;
+ if (x < 2) {
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 */
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;
if ((var = switch_channel_get_variable(channel, "loopback_initial_codec"))) {
char *dup = switch_core_session_strdup(session, var);
- uint32_t bit;
- iananame = switch_parse_codec_buf(dup, &interval, &rate, &bit);
+ uint32_t bit, channels;
+ iananame = switch_parse_codec_buf(dup, &interval, &rate, &bit, &channels);
}
}
verto_set_media_options(tech_pvt, jsock->profile);
- switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
+
switch_channel_set_variable(tech_pvt->channel, "verto_profile_name", jsock->profile->name);
if (!switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) {
+ switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_TRUE);
+
if ((status = switch_core_media_choose_ports(tech_pvt->session, SWITCH_TRUE, SWITCH_TRUE)) != SWITCH_STATUS_SUCCESS) {
//if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) {
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
tmp_frame.codec = (*frame)->codec;
tmp_frame.datalen = (*frame)->codec->implementation->encoded_bytes_per_packet;
tmp_frame.samples = (*frame)->codec->implementation->samples_per_packet;
+ tmp_frame.channels = (*frame)->codec->implementation->number_of_channels;
tmp_frame.data = data;
switch_core_gen_encoded_silence(data, (*frame)->codec->implementation, tmp_frame.datalen);
session->raw_read_frame.timestamp = 0;
session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet;
- session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
+ session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t) / session->read_impl.number_of_channels;
+ session->raw_read_frame.channels = read_frame->codec->implementation->number_of_channels;
read_frame = &session->raw_read_frame;
status = SWITCH_STATUS_SUCCESS;
} else {
if (switch_test_flag(read_frame, SFF_PLC)) {
session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet;
- session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
+ session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t) / session->read_impl.number_of_channels;
+ session->raw_read_frame.channels = session->read_impl.number_of_channels;
memset(session->raw_read_frame.data, 255, session->raw_read_frame.datalen);
status = SWITCH_STATUS_SUCCESS;
} else {
}
}
case SWITCH_STATUS_SUCCESS:
- session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
+ session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t) / session->read_impl.number_of_channels;
+ session->raw_read_frame.channels = session->read_impl.number_of_channels;
session->raw_read_frame.rate = read_frame->rate;
if (read_frame->codec->implementation->samples_per_packet != session->read_impl.samples_per_packet) {
session->raw_read_frame.timestamp = 0;
case SWITCH_STATUS_BREAK:
memset(session->raw_read_frame.data, 255, read_frame->codec->implementation->decoded_bytes_per_packet);
session->raw_read_frame.datalen = read_frame->codec->implementation->decoded_bytes_per_packet;
- session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t);
+ session->raw_read_frame.samples = session->raw_read_frame.datalen / sizeof(int16_t) / session->read_impl.number_of_channels;
+ session->raw_read_frame.channels = session->read_impl.number_of_channels;
session->raw_read_frame.timestamp = read_frame->timestamp;
session->raw_read_frame.rate = read_frame->rate;
session->raw_read_frame.ssrc = read_frame->ssrc;
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->channels = session->read_resampler->channels;
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);
case SWITCH_STATUS_RESAMPLE:
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Fixme 1\n");
case SWITCH_STATUS_SUCCESS:
- session->enc_read_frame.samples = session->read_impl.decoded_bytes_per_packet / sizeof(int16_t);
+ session->enc_read_frame.samples = session->read_impl.decoded_bytes_per_packet / sizeof(int16_t) / session->read_impl.number_of_channels;
+ session->enc_read_frame.channels = session->read_impl.number_of_channels;
if (perfect) {
if (enc_frame->codec->implementation->samples_per_packet != session->read_impl.samples_per_packet) {
session->enc_read_frame.timestamp = 0;
break;
case SWITCH_STATUS_NOOP:
session->raw_read_frame.samples = enc_frame->codec->implementation->samples_per_packet;
+ session->raw_read_frame.channels = enc_frame->codec->implementation->number_of_channels;
session->raw_read_frame.timestamp = read_frame->timestamp;
session->raw_read_frame.payload = enc_frame->codec->implementation->ianacode;
session->raw_read_frame.m = read_frame->m;
}
break;
case SWITCH_STATUS_SUCCESS:
- session->raw_write_frame.samples = session->raw_write_frame.datalen / sizeof(int16_t);
+ session->raw_write_frame.samples = session->raw_write_frame.datalen / sizeof(int16_t) / session->write_impl.number_of_channels;
+ session->raw_write_frame.channels = session->write_impl.number_of_channels;
session->raw_write_frame.timestamp = frame->timestamp;
session->raw_write_frame.rate = frame->rate;
session->raw_write_frame.m = frame->m;
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->channels = session->write_resampler->channels;
write_frame->datalen = write_frame->samples * 2 * session->write_resampler->channels;
write_frame->rate = session->write_resampler->to_rate;
/* switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Fixme 2\n"); */
case SWITCH_STATUS_SUCCESS:
session->enc_write_frame.codec = session->write_codec;
- session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
+ session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t) / session->write_impl.number_of_channels;
+ session->enc_write_frame.channels = session->write_impl.number_of_channels;
if (frame->codec->implementation->samples_per_packet != session->write_impl.samples_per_packet) {
session->enc_write_frame.timestamp = 0;
} else {
break;
case SWITCH_STATUS_NOOP:
enc_frame->codec = session->write_codec;
- enc_frame->samples = enc_frame->datalen / sizeof(int16_t);
+ enc_frame->samples = enc_frame->datalen / sizeof(int16_t) / session->write_impl.number_of_channels;
+ enc_frame->channels = session->write_impl.number_of_channels;
enc_frame->timestamp = frame->timestamp;
enc_frame->m = frame->m;
enc_frame->seq = frame->seq;
case SWITCH_STATUS_RESAMPLE:
resample++;
session->enc_write_frame.codec = session->write_codec;
- session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
+ session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t) / session->write_impl.number_of_channels;
+ session->enc_write_frame.channels = session->write_impl.number_of_channels;
session->enc_write_frame.m = frame->m;
session->enc_write_frame.ssrc = frame->ssrc;
session->enc_write_frame.payload = session->write_impl.ianacode;
break;
case SWITCH_STATUS_SUCCESS:
session->enc_write_frame.codec = session->write_codec;
- session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t);
+ session->enc_write_frame.samples = enc_frame->datalen / sizeof(int16_t) / session->write_impl.number_of_channels;
+ session->enc_write_frame.channels = session->write_impl.number_of_channels;
session->enc_write_frame.m = frame->m;
session->enc_write_frame.ssrc = frame->ssrc;
session->enc_write_frame.payload = session->write_impl.ianacode;
}
enc_frame->codec = session->write_codec;
- enc_frame->samples = enc_frame->datalen / sizeof(int16_t);
+ enc_frame->samples = enc_frame->datalen / sizeof(int16_t) / session->read_impl.number_of_channels;
+ enc_frame->channels = session->read_impl.number_of_channels;
enc_frame->m = frame->m;
enc_frame->ssrc = frame->ssrc;
enc_frame->payload = enc_frame->codec->implementation->ianacode;
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->channels = session->read_resampler->channels;
write_frame->datalen = session->read_resampler->to_len * 2 * session->read_resampler->channels;
write_frame->rate = session->read_resampler->to_rate;
}
switch_sdp_type_t sdp_type,
uint32_t pt,
uint32_t rate,
- uint32_t ptime,
+ uint32_t ptime,
+ uint32_t channels,
uint8_t negotiated)
{
payload_map_t *pmap;
pmap->iananame = switch_core_strdup(session->pool, name);
pmap->rm_encoding = pmap->iananame;
pmap->hash = switch_ci_hashfunc_default(pmap->iananame, &hlen);
+ pmap->channels = 1;
}
pmap->sdp_type = sdp_type;
pmap->rate = rate;
}
+ if (channels) {
+ pmap->channels = channels;
+ }
+
if (!zstr(fmtp) && (zstr(pmap->rm_fmtp) || strcmp(pmap->rm_fmtp, fmtp))) {
pmap->rm_fmtp = switch_core_strdup(session->pool, fmtp);
}
switch_channel_set_variable(session->channel, "rtp_use_codec_fmtp", a_engine->cur_payload_map->rm_fmtp);
switch_channel_set_variable_printf(session->channel, "rtp_use_codec_rate", "%d", a_engine->cur_payload_map->rm_rate);
switch_channel_set_variable_printf(session->channel, "rtp_use_codec_ptime", "%d", a_engine->cur_payload_map->codec_ms);
- switch_channel_set_variable_printf(session->channel, "rtp_last_audio_codec_string", "%s@%dh@%di",
- a_engine->cur_payload_map->iananame, a_engine->cur_payload_map->rm_rate, a_engine->cur_payload_map->codec_ms);
+ switch_channel_set_variable_printf(session->channel, "rtp_use_codec_channels", "%d", a_engine->cur_payload_map->channels);
+ switch_channel_set_variable_printf(session->channel, "rtp_last_audio_codec_string", "%s@%dh@%di@%dc",
+ a_engine->cur_payload_map->iananame, a_engine->cur_payload_map->rm_rate, a_engine->cur_payload_map->codec_ms, a_engine->cur_payload_map->channels);
switch_assert(a_engine->read_codec.implementation);
switch_assert(a_engine->write_codec.implementation);
a_engine->cur_payload_map->codec_ms,
a_engine->read_impl.samples_per_packet, a_engine->read_impl.bits_per_second);
a_engine->read_frame.codec = &a_engine->read_codec;
-
+ a_engine->read_frame.channels = a_engine->read_impl.number_of_channels;
a_engine->write_codec.agreed_pt = a_engine->cur_payload_map->agreed_pt;
a_engine->read_codec.agreed_pt = a_engine->cur_payload_map->agreed_pt;
reneg = 0;
}
+ if (switch_channel_test_flag(session->channel, CF_RECOVERING)) {
+ reneg = 0;
+ }
+
if (!reneg && smh->num_negotiated_codecs) {
codec_array = smh->negotiated_codecs;
total_codecs = smh->num_negotiated_codecs;
matches[j].map->rm_pt,
matches[j].imp->samples_per_second,
matches[j].imp->microseconds_per_packet / 1000,
+ matches[j].imp->number_of_channels,
SWITCH_TRUE);
mimp = matches[j].imp;
mmap = matches[j].map;
matches[j].map->rm_pt,
matches[j].imp->samples_per_second,
matches[j].imp->microseconds_per_packet / 1000,
+ matches[j].imp->number_of_channels,
SWITCH_TRUE);
if (j == 0) {
v_engine->cur_payload_map = pmap;
smh->ianacodes[i] = (switch_payload_t)smh->payload_space++;
}
}
-
switch_core_media_add_payload_map(session,
imp->codec_type == SWITCH_CODEC_TYPE_AUDIO ? SWITCH_MEDIA_TYPE_AUDIO : SWITCH_MEDIA_TYPE_VIDEO,
smh->ianacodes[i],
imp->samples_per_second,
imp->microseconds_per_packet / 1000,
+ imp->number_of_channels,
SWITCH_FALSE);
}
static void add_audio_codec(sdp_rtpmap_t *map, int ptime, char *buf, switch_size_t buflen)
{
int codec_ms = ptime;
- uint32_t map_bit_rate = 0;
+ uint32_t map_bit_rate = 0, map_channels = 1;
char ptstr[20] = "";
char ratestr[20] = "";
char bitstr[20] = "";
codec_ms = switch_default_ptime(map->rm_encoding, map->rm_pt);
}
+ map_channels = map->rm_params ? atoi(map->rm_params) : 1;
map_bit_rate = switch_known_bitrate((switch_payload_t)map->rm_pt);
if (!ptime && !strcasecmp(map->rm_encoding, "g723")) {
switch_snprintf(bitstr, sizeof(bitstr), "@%db", map_bit_rate);
}
+ if (map_channels > 1) {
+ switch_snprintf(bitstr, sizeof(bitstr), "@%dc", map_channels);
+ }
+
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), ",%s%s%s%s", map->rm_encoding, ratestr, ptstr, bitstr);
}
map->rm_pt,
map->rm_rate,
ptime,
+ map->rm_params ? atoi(map->rm_params) : 1,
SWITCH_FALSE);
}
}
}
for (i = 0; i < num_codecs; i++) {
const switch_codec_implementation_t *imp = codecs[i];
+ int channels;
if (imp->codec_type != SWITCH_CODEC_TYPE_VIDEO || imp->ianacode > 127 || already_did[imp->ianacode]) {
continue;
}
if (match) {
+ channels = map->rm_params ? atoi(map->rm_params) : 1;
if (ptime > 0) {
- switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di", imp->iananame, (unsigned int) map->rm_rate,
- ptime);
+ switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%di@%dc", imp->iananame, (unsigned int) map->rm_rate,
+ ptime, channels);
} else {
- switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh", imp->iananame, (unsigned int) map->rm_rate);
+ switch_snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ",%s@%uh@%dc", imp->iananame, (unsigned int) map->rm_rate, channels);
}
already_did[imp->ianacode] = 1;
break;
a_engine->cur_payload_map->codec_ms = atoi(tmp);
}
+ if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_codec_channels"))) {
+ a_engine->cur_payload_map->channels = atoi(tmp);
+ }
+
if ((tmp = switch_channel_get_variable(session->channel, "rtp_use_pt"))) {
a_engine->cur_payload_map->pt = a_engine->cur_payload_map->agreed_pt = (switch_payload_t)atoi(tmp);
}
if ((tmp = switch_channel_get_variable(session->channel, "rtp_audio_recv_pt"))) {
a_engine->cur_payload_map->recv_pt = (switch_payload_t)atoi(tmp);
}
-
- switch_core_media_set_codec(session, 1, smh->mparams->codec_flags);
+
+ switch_core_media_set_codec(session, 0, smh->mparams->codec_flags);
a_engine->adv_sdp_ip = smh->mparams->extrtpip = (char *) ip;
a_engine->adv_sdp_port = a_engine->local_sdp_port = (switch_port_t)atoi(port);
len = rframe->samples;
if (dh->mux) {
- int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE / 2];
+ int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
int16_t *fp = rframe->data;
uint32_t x;
} else {
st = switch_core_file_read(&dh->fh, rframe->data, &len);
if (len < rframe->samples) {
- memset((char *)rframe->data + len * 2, 0, rframe->datalen - len * 2);
+ memset((char *)rframe->data + len * 2 * dh->fh.channels, 0, (rframe->datalen - len) * 2 * dh->fh.channels);
}
}
rframe->datalen = rframe->samples * 2 * dh->fh.channels;
-
if (st != SWITCH_STATUS_SUCCESS || len == 0) {
if (dh->loop) {
uint32_t pos = 0;
len = rframe->samples;
if (dh->mux) {
- int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE / 2];
+ int16_t buf[SWITCH_RECOMMENDED_BUFFER_SIZE];
int16_t *fp = rframe->data;
uint32_t x;
}
-SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit)
+SWITCH_DECLARE(char *) switch_parse_codec_buf(char *buf, uint32_t *interval, uint32_t *rate, uint32_t *bit, uint32_t *channels)
{
char *cur, *next = NULL, *name, *p;
name = next = cur = buf;
+ *channels = 1;
+
for (;;) {
if (!next) {
break;
*rate = atoi(cur);
} else if (strchr(cur, 'b')) {
*bit = atoi(cur);
+ } else if (strchr(cur, 'c')) {
+ *channels = atoi(cur);
} else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad syntax for codec string. Missing qualifier [h|k|i|b] for part [%s]!\n", cur);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Bad syntax for codec string. Missing qualifier [h|k|i|b|c] for part [%s]!\n", cur);
}
}
cur = next;
for (x = 0; x < preflen; x++) {
char *name, buf[256], jbuf[256];
- uint32_t interval = 0, rate = 0, bit = 0;
+ uint32_t interval = 0, rate = 0, bit = 0, channels = 1;
switch_copy_string(buf, prefs[x], sizeof(buf));
- name = switch_parse_codec_buf(buf, &interval, &rate, &bit);
+ name = switch_parse_codec_buf(buf, &interval, &rate, &bit, &channels);
for(j = 0; j < x; j++) {
char *jname;
- uint32_t jinterval = 0, jrate = 0, jbit = 0;
- uint32_t ointerval = interval, orate = rate;
+ uint32_t jinterval = 0, jrate = 0, jbit = 0, jchannels = 1;
+ uint32_t ointerval = interval, orate = rate, ochannels = channels;
if (ointerval == 0) {
ointerval = switch_default_ptime(name, 0);
orate = switch_default_rate(name, 0);
}
+ if (ochannels == 0) {
+ ochannels = 1;
+ }
+
switch_copy_string(jbuf, prefs[j], sizeof(jbuf));
- jname = switch_parse_codec_buf(jbuf, &jinterval, &jrate, &jbit);
+ jname = switch_parse_codec_buf(jbuf, &jinterval, &jrate, &jbit, &jchannels);
if (jinterval == 0) {
jinterval = switch_default_ptime(jname, 0);
jrate = switch_default_rate(jname, 0);
}
- if (!strcasecmp(name, jname) && ointerval == jinterval && orate == jrate) {
+ if (jchannels == 0) {
+ jchannels = 1;
+ }
+
+ if (!strcasecmp(name, jname) && ointerval == jinterval && orate == jrate && ochannels == jchannels) {
goto next_x;
}
}
(interval && (uint32_t) (imp->microseconds_per_packet / 1000) != interval)) {
continue;
}
-
+
if (((!rate && crate != default_rate) || (rate && (uint32_t) imp->actual_samples_per_second != rate))) {
continue;
}
continue;
}
+ if (channels && imp->number_of_channels != channels) {
+ continue;
+ }
}
if (bit && (uint32_t) imp->bits_per_second != bit) {
continue;
}
-
+
+ if (channels && imp->number_of_channels != channels) {
+ continue;
+ }
}
array[i++] = imp;