switch_image_t *img,
void *encoded_data, uint32_t *encoded_data_len, unsigned int *flag);
+/*!
+ \brief send control data using a codec handle
+ \param codec the codec handle to use
+ \param cmd the command to send
+ \param ctype the type of the arguement
+ \param cmd_data a void pointer to the data matching the passed type
+ \param rtype the type of the response if any
+ \param ret_data a void pointer to a pointer of return data
+ \return SWITCH_STATUS_SUCCESS if the command was received
+*/
+SWITCH_DECLARE(switch_status_t) switch_core_codec_control(switch_codec_t *codec,
+ switch_codec_control_command_t cmd,
+ switch_codec_control_type_t ctype,
+ void *cmd_data,
+ switch_codec_control_type_t *rtype,
+ void **ret_data);
+
/*!
\brief Decode video data using a codec handle
\param codec the codec handle to use
SWITCH_DECLARE(int) switch_core_media_crypto_keylen(switch_rtp_crypto_key_type_t type);
SWITCH_DECLARE(char *) switch_core_media_filter_sdp(const char *sdp, const char *cmd, const char *arg);
SWITCH_DECLARE(char *) switch_core_media_process_sdp_filter(const char *sdp, const char *cmd_buf, switch_core_session_t *session);
+
+
+SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_session_t *session,
+ switch_media_type_t mtype,
+ switch_io_type_t iotype,
+ switch_codec_control_command_t cmd,
+ switch_codec_control_type_t ctype,
+ void *cmd_data,
+ switch_codec_control_type_t *rtype,
+ void **ret_data);
+
SWITCH_END_EXTERN_C
#endif
/* For Emacs:
///\}
static inline void switch_core_codec_add_video_implementation(switch_memory_pool_t *pool, switch_codec_interface_t *codec_interface,
- /*! the IANA code number */
- switch_payload_t ianacode,
- /*! the IANA code name */
- const char *iananame,
- /*! default fmtp to send (can be overridden by the init function) */
- char *fmtp,
- switch_core_codec_init_func_t init,
- /*! function to encode raw data into encoded data */
- switch_core_codec_video_encode_func_t encode,
- /*! function to decode encoded data into raw data */
- switch_core_codec_video_decode_func_t decode,
- /*! deinitalize a codec handle using this implementation */
- switch_core_codec_destroy_func_t destroy)
+ /*! the IANA code number */
+ switch_payload_t ianacode,
+ /*! the IANA code name */
+ const char *iananame,
+ /*! default fmtp to send (can be overridden by the init function) */
+ char *fmtp,
+ switch_core_codec_init_func_t init,
+ /*! function to encode raw data into encoded data */
+ switch_core_codec_video_encode_func_t encode,
+ /*! function to decode encoded data into raw data */
+ switch_core_codec_video_decode_func_t decode,
+ /*! function to send control messages to the codec */
+ switch_core_codec_control_func_t control,
+ /*! deinitalize a codec handle using this implementation */
+ switch_core_codec_destroy_func_t destroy)
{
switch_codec_implementation_t *impl = (switch_codec_implementation_t *) switch_core_alloc(pool, sizeof(*impl));
impl->init = init;
impl->encode_video = encode;
impl->decode_video = decode;
+ impl->codec_control = control;
impl->destroy = destroy;
impl->codec_id = codec_interface->codec_id;
impl->next = codec_interface->implementations;
switch_core_codec_video_encode_func_t encode_video;
/*! function to decode video encoded data into raw data */
switch_core_codec_video_decode_func_t decode_video;
+ /*! function to send control messages to the codec */
+ switch_core_codec_control_func_t codec_control;
/*! deinitalize a codec handle using this implementation */
switch_core_codec_destroy_func_t destroy;
uint32_t codec_id;
void *decoded_data, uint32_t *decoded_data_len, uint32_t *decoded_rate, unsigned int *flag);
typedef switch_status_t (*switch_core_codec_video_encode_func_t) (switch_codec_t *codec,
- switch_image_t *img,
- void *encoded_data, uint32_t *encoded_data_len, unsigned int *flag);
+ switch_image_t *img,
+ void *encoded_data, uint32_t *encoded_data_len, unsigned int *flag);
typedef switch_status_t (*switch_core_codec_video_decode_func_t) (switch_codec_t *codec,
- switch_frame_t *frame,
- switch_image_t **img, unsigned int *flag);
+ switch_frame_t *frame,
+ switch_image_t **img, unsigned int *flag);
+
+typedef enum {
+ SCC_VIDEO_REFRESH = 0
+} switch_codec_control_command_t;
+
+typedef enum {
+ SCCT_NONE = 0
+} switch_codec_control_type_t;
+
+typedef enum {
+ SWITCH_IO_READ,
+ SWITCH_IO_WRITE
+} switch_io_type_t;
+
+typedef switch_status_t (*switch_core_codec_control_func_t) (switch_codec_t *codec,
+ switch_codec_control_command_t cmd,
+ switch_codec_control_type_t ctype,
+ void *cmd_data,
+ switch_codec_control_type_t *rtype,
+ void **ret_data);
+
typedef switch_status_t (*switch_core_codec_init_func_t) (switch_codec_t *, switch_codec_flag_t, const switch_codec_settings_t *codec_settings);
typedef switch_status_t (*switch_core_codec_fmtp_parse_func_t) (const char *fmtp, switch_codec_fmtp_t *codec_fmtp);
return SWITCH_STATUS_SUCCESS;
}
+static switch_status_t switch_h264_control(switch_codec_t *codec,
+ switch_codec_control_command_t cmd,
+ switch_codec_control_type_t ctype,
+ void *cmd_data,
+ switch_codec_control_type_t *rtype,
+ void **ret_data) {
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
static switch_status_t switch_h264_destroy(switch_codec_t *codec)
{
h264_codec_context_t *context = (h264_codec_context_t *)codec->private_info;
SWITCH_ADD_CODEC(codec_interface, "H264 Video (with Cisco OpenH264)");
switch_core_codec_add_video_implementation(pool, codec_interface, 99, "H264", NULL,
- switch_h264_init, switch_h264_encode, switch_h264_decode, switch_h264_destroy);
+ switch_h264_init, switch_h264_encode, switch_h264_decode, switch_h264_control, switch_h264_destroy);
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
if (context->need_key_frame > 0) {
// force generate a key frame
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VPX KEYFRAME REQ\n");
vpx_flags |= VPX_EFLAG_FORCE_KF;
context->last_ts = switch_micro_time_now();
context->need_key_frame--;
return SWITCH_STATUS_FALSE;
}
+
+static switch_status_t switch_vpx_control(switch_codec_t *codec,
+ switch_codec_control_command_t cmd,
+ switch_codec_control_type_t ctype,
+ void *cmd_data,
+ switch_codec_control_type_t *rtype,
+ void **ret_data)
+{
+
+ vpx_context_t *context = (vpx_context_t *)codec->private_info;
+
+ switch(cmd) {
+ case SCC_VIDEO_REFRESH:
+ context->need_key_frame = 1;
+ break;
+ default:
+ break;
+ }
+
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
static switch_status_t switch_vpx_destroy(switch_codec_t *codec)
{
vpx_context_t *context = (vpx_context_t *)codec->private_info;
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_CODEC(codec_interface, "VP8 Video");
switch_core_codec_add_video_implementation(pool, codec_interface, 99, "VP8", NULL,
- switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_destroy);
+ switch_vpx_init, switch_vpx_encode, switch_vpx_decode, switch_vpx_control, switch_vpx_destroy);
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
SWITCH_ADD_CODEC(codec_interface, "YUV I420 Video (raw)");
switch_core_codec_add_video_implementation(pool, codec_interface, 99, "I420", NULL,
- switch_yuv_init, switch_yuv_encode, switch_yuv_decode, switch_yuv_destroy);
+ switch_yuv_init, switch_yuv_encode, switch_yuv_decode, NULL, switch_yuv_destroy);
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
return status;
}
+
+SWITCH_DECLARE(switch_status_t) switch_core_codec_control(switch_codec_t *codec,
+ switch_codec_control_command_t cmd,
+ switch_codec_control_type_t ctype,
+ void *cmd_data,
+ switch_codec_control_type_t *rtype,
+ void **ret_data)
+{
+
+ switch_status_t status = SWITCH_STATUS_FALSE;
+
+
+ switch_assert(codec != NULL);
+
+
+ if (!codec->implementation || !switch_core_codec_ready(codec)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Codec is not initialized!\n");
+ return SWITCH_STATUS_NOT_INITALIZED;
+ }
+
+
+ if (codec->mutex) switch_mutex_lock(codec->mutex);
+
+ if (codec->implementation->codec_control) {
+ status = codec->implementation->codec_control(codec, cmd, ctype, cmd_data, rtype, ret_data);
+ }
+
+ if (codec->mutex) switch_mutex_unlock(codec->mutex);
+
+
+ return status;
+}
+
SWITCH_DECLARE(switch_status_t) switch_core_codec_destroy(switch_codec_t *codec)
{
switch_mutex_t *mutex = codec->mutex;
uint8_t fir;
uint8_t pli;
+ uint8_t nack;
uint8_t no_crypto;
} switch_rtp_engine_t;
v_engine->fir++;
}
- //if (switch_stristr("pli", attr->a_value)) {
- // v_engine->pli++;
- //}
+ if (switch_stristr("pli", attr->a_value)) {
+ v_engine->pli++;
+ }
+
+ if (switch_stristr("nack", attr->a_value)) {
+ v_engine->nack++;
+ }
smh->mparams->rtcp_video_interval_msec = "10000";
}
switch_media_handle_t *smh;
ice_t *ice_out;
int vp8 = 0;
- int red = 0;
+ //int red = 0;
payload_map_t *pmap;
int is_outbound = switch_channel_direction(session->channel) == SWITCH_CALL_DIRECTION_OUTBOUND;
+ const char *vbw;
+ int bw = 256;
+ uint8_t fir = 0, nack = 0, pli = 0;
switch_assert(session);
vp8 = v_engine->cur_payload_map->pt;
}
- if (!strcasecmp(v_engine->cur_payload_map->rm_encoding, "red")) {
- red = v_engine->cur_payload_map->pt;
- }
+ //if (!strcasecmp(v_engine->cur_payload_map->rm_encoding, "red")) {
+ // red = v_engine->cur_payload_map->pt;
+ //}
rate = v_engine->cur_payload_map->rm_rate;
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%ld\n",
vp8 = ianacode;
}
- if (!strcasecmp(imp->iananame, "red")) {
- red = ianacode;
- }
+ //if (!strcasecmp(imp->iananame, "red")) {
+ // red = ianacode;
+ //}
if (channels > 1) {
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=rtpmap:%d %s/%d/%d\n", ianacode, imp->iananame,
}
- if (v_engine->fir || v_engine->pli) {
- switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf),
- "a=rtcp-fb:* %s%s\n", v_engine->fir ? "fir " : "", v_engine->pli ? "pli" : "");
+ if ((vbw = switch_channel_get_variable(smh->session->channel, "rtp_video_max_bandwidth"))) {
+ int v = atoi(vbw);
+ bw = v;
+ }
+
+ if (bw > 0) {
+ switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "b=AS:%d\n", bw);
+ }
+
+
+ if (sdp_type == SDP_TYPE_REQUEST) {
+ fir++;
+ pli++;
+ nack++;
+ }
+
+ if (vp8) {
+
+ if (v_engine->fir || fir) {
+ switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf),
+ "a=rtcp-fb:%d ccm fir\n", vp8);
+ }
+
+ if (v_engine->nack || nack) {
+ switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf),
+ "a=rtcp-fb:%d nack\n", vp8);
+ }
+
+ if (v_engine->pli || pli) {
+ switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf),
+ "a=rtcp-fb:%d nack pli\n", vp8);
+ }
}
+
//switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u\n", v_engine->ssrc);
if (v_engine->ice_out.cands[0][0].ready) {
uint32_t c2 = (2^24)*126 + (2^8)*65535 + (2^0)*(256 - 2);
uint32_t c3 = (2^24)*126 + (2^8)*65534 + (2^0)*(256 - 1);
uint32_t c4 = (2^24)*126 + (2^8)*65534 + (2^0)*(256 - 2);
- const char *vbw;
- int bw = 256;
+
tmp1[10] = '\0';
tmp2[10] = '\0';
switch_stun_random_string(tmp2, 10, "0123456789");
ice_out = &v_engine->ice_out;
-
-
- if ((vbw = switch_channel_get_variable(smh->session->channel, "rtp_video_max_bandwidth"))) {
- int v = atoi(vbw);
- bw = v;
- }
-
- if (bw > 0) {
- switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "b=AS:%d\n", bw);
- }
-
- if (vp8 && switch_channel_test_flag(session->channel, CF_WEBRTC)) {
- switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf),
- "a=rtcp-fb:%d ccm fir\n", vp8);
- }
-
- if (red) {
- switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf),
- "a=rtcp-fb:%d nack\n", vp8);
- }
-
+
+
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u cname:%s\n", v_engine->ssrc, smh->cname);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u msid:%s v0\n", v_engine->ssrc, smh->msid);
switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u mslabel:%s\n", v_engine->ssrc, smh->msid);
}
+
+SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_session_t *session,
+ switch_media_type_t mtype,
+ switch_io_type_t iotype,
+ switch_codec_control_command_t cmd,
+ switch_codec_control_type_t ctype,
+ void *cmd_data,
+ switch_codec_control_type_t *rtype,
+ void **ret_data)
+{
+ switch_rtp_engine_t *engine = NULL;
+ switch_media_handle_t *smh = NULL;
+ switch_codec_t *codec = NULL;
+
+ switch_assert(session);
+
+ if (!(smh = session->media_handle)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!(engine = &smh->engines[mtype])) {
+ return SWITCH_STATUS_NOTIMPL;
+ }
+
+ if (iotype == SWITCH_IO_READ) {
+ codec = &engine->read_codec;
+ } else {
+ codec = &engine->write_codec;
+ }
+
+ if (codec) {
+ return switch_core_codec_control(codec, cmd, ctype, cmd_data, rtype, ret_data);
+ }
+
+ return SWITCH_STATUS_FALSE;
+}
+
+
+
/* For Emacs:
* Local Variables:
* mode:c
if (rtcp_status == SWITCH_STATUS_SUCCESS) {
switch_rtp_reset_media_timer(rtp_session);
-
- if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_PASSTHRU] || rtp_session->rtcp_recv_msg_p->header.type == 206) {
+
+ if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && (rtp_session->rtcp_recv_msg_p->header.type == 205 || //RTPFB
+ rtp_session->rtcp_recv_msg_p->header.type == 206)) {//PSFB
+ rtcp_ext_msg_t *extp = (rtcp_ext_msg_t *) rtp_session->rtcp_recv_msg_p;
+
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG, "PICKED UP XRTCP type: %d fmt: %d\n",
+ rtp_session->rtcp_recv_msg_p->header.type, extp->header.fmt);
+
+ if ((extp->header.fmt == 4) || (extp->header.fmt == 1)) { /* FIR || PLI */
+
+ switch_core_media_codec_control(rtp_session->session,
+ SWITCH_MEDIA_TYPE_VIDEO,
+ SWITCH_IO_WRITE,
+ SCC_VIDEO_REFRESH,
+ SCCT_NONE,
+ NULL,
+ NULL,
+ NULL);
+ }
+ }
+
+ if (rtp_session->flags[SWITCH_RTP_FLAG_RTCP_PASSTHRU]) {
switch_channel_t *channel = switch_core_session_get_channel(rtp_session->session);
const char *uuid = switch_channel_get_partner_uuid(channel);
other_rtp_session->rtcp_sock_output &&
switch_rtp_test_flag(other_rtp_session, SWITCH_RTP_FLAG_ENABLE_RTCP)) {
other_rtp_session->rtcp_send_msg = rtp_session->rtcp_recv_msg;
-
- if (rtp_session->rtcp_recv_msg_p->header.type == 206) {
- rtcp_ext_msg_t *extp = (rtcp_ext_msg_t *) rtp_session->rtcp_recv_msg_p;
- extp->header.recv_ssrc = htonl(other_rtp_session->stats.rtcp.peer_ssrc);
- }
-
-
+
#ifdef ENABLE_SRTP
if (switch_rtp_test_flag(other_rtp_session, SWITCH_RTP_FLAG_SECURE_SEND)) {
int sbytes = (int) rtcp_bytes;