Bug 966885 - Enable audio level RTP extension. r=jesup, r=ehugg

This commit is contained in:
Gustavo Garcia 2014-02-06 20:32:45 -05:00
parent 23c4f9b1c3
commit f79791737a
15 changed files with 347 additions and 0 deletions

View File

@ -76,6 +76,10 @@ WebrtcAudioConduit::~WebrtcAudioConduit()
delete mCurSendCodecConfig;
if (mPtrVoERTP_RTCP) {
mPtrVoERTP_RTCP->Release();
}
// The first one of a pair to be deleted shuts down media for both
if(mPtrVoEXmedia)
{
@ -285,6 +289,12 @@ MediaConduitErrorCode WebrtcAudioConduit::Init(WebrtcAudioConduit *other)
return kMediaConduitSessionNotInited;
}
if(!(mPtrVoERTP_RTCP = VoERTP_RTCP::GetInterface(mVoiceEngine)))
{
CSFLogError(logTag, "%s Unable to initialize VoERTP_RTCP", __FUNCTION__);
return kMediaConduitSessionNotInited;
}
if(!(mPtrVoEVideoSync = VoEVideoSync::GetInterface(mVoiceEngine)))
{
CSFLogError(logTag, "%s Unable to initialize VoEVideoSync", __FUNCTION__);
@ -563,6 +573,20 @@ WebrtcAudioConduit::ConfigureRecvMediaCodecs(
return kMediaConduitNoError;
}
MediaConduitErrorCode
WebrtcAudioConduit::EnableAudioLevelExtension(bool enabled)
{
CSFLogDebug(logTag, "%s %d ", __FUNCTION__, enabled);
if (mPtrVoERTP_RTCP->SetRTPAudioLevelIndicationStatus(mChannel, enabled, 1) == -1)
{
CSFLogError(logTag, "%s SetRTPAudioLevelIndicationStatus Failed", __FUNCTION__);
return kMediaConduitUnknownError;
}
return kMediaConduitNoError;
}
MediaConduitErrorCode
WebrtcAudioConduit::SendAudioFrame(const int16_t audio_data[],
int32_t lengthSamples,

View File

@ -31,6 +31,7 @@
using webrtc::VoEExternalMedia;
using webrtc::VoEAudioProcessing;
using webrtc::VoEVideoSync;
using webrtc::VoERTP_RTCP;
/** This file hosts several structures identifying different aspects
* of a RTP Session.
@ -87,6 +88,12 @@ public:
virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
const std::vector<AudioCodecConfig* >& codecConfigList);
/**
* Function to enable the audio level extension
* @param enabled: enable extension
*/
virtual MediaConduitErrorCode EnableAudioLevelExtension(bool enabled);
/**
* Register External Transport to this Conduit. RTP and RTCP frames from the VoiceEngine
* shall be passed to the registered transport for transporting externally.
@ -234,6 +241,7 @@ private:
webrtc::VoEExternalMedia* mPtrVoEXmedia;
webrtc::VoEAudioProcessing* mPtrVoEProcessing;
webrtc::VoEVideoSync* mPtrVoEVideoSync;
webrtc::VoERTP_RTCP* mPtrVoERTP_RTCP;
webrtc::VoERTP_RTCP* mPtrRTP;
//engine states of our interets

View File

@ -345,6 +345,13 @@ public:
virtual MediaConduitErrorCode ConfigureRecvMediaCodecs(
const std::vector<AudioCodecConfig* >& recvCodecConfigList) = 0;
/**
* Function to enable the audio level extension
* @param enabled: enable extension
* NOTE: See AudioConduit for more information
*/
virtual MediaConduitErrorCode EnableAudioLevelExtension(bool enabled) = 0;
};

View File

@ -2234,6 +2234,11 @@ static int vcmTxStartICE_m(cc_mcapid_t mcap_id,
if (!conduit || conduit->ConfigureSendMediaCodec(config))
return VCM_ERROR;
CSFLogError(logTag, "Created audio pipeline audio level %d", attrs->audio_level);
if (!conduit || conduit->EnableAudioLevelExtension(attrs->audio_level))
return VCM_ERROR;
pc.impl()->media()->AddConduit(level, false, conduit);
mozilla::RefPtr<mozilla::MediaPipeline> pipeline =

View File

@ -521,6 +521,7 @@ gsmsdp_init_media (fsmdef_media_t *media)
media->video = NULL;
media->candidate_ct = 0;
media->rtcp_mux = FALSE;
media->audio_level = TRUE;
/* ACTPASS is the value we put in every offer */
media->setup = SDP_SETUP_ACTPASS;
@ -1710,6 +1711,40 @@ gsmsdp_set_rtcp_fb_ack_attribute (uint16_t level,
}
}
/*
* gsmsdp_set_audio_level_attribute
*
* Description:
*
* Adds an audio level extension attributesto the specified SDP.
*
* Parameters:
*
* level - The media level of the SDP where the media attribute exists.
* sdp_p - Pointer to the SDP to set the attribute against.
*/
void
gsmsdp_set_extmap_attribute (uint16_t level,
void *sdp_p,
u16 id,
const char* uri)
{
uint16_t a_instance = 0;
sdp_result_e result;
result = sdp_add_new_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, &a_instance);
if (result != SDP_SUCCESS) {
GSM_ERR_MSG("Failed to add attribute");
return;
}
result = sdp_attr_set_extmap(sdp_p, level, id, uri, a_instance);
if (result != SDP_SUCCESS) {
GSM_ERR_MSG("Failed to set attribute");
}
}
/*
* gsmsdp_set_rtcp_fb_nack_attribute
*
@ -4633,6 +4668,57 @@ gsmsdp_negotiate_rtcp_fb (cc_sdp_t *cc_sdp_p,
return CC_CAUSE_OK;
}
/*
* gsmsdp_negotiate_extmap
*
* Description:
* Negotiates extmaps header extension to local SDP for supported audio codecs
*
* Parameters:
* cc_sdp_p - local and remote SDP
* media - The media structure for the current level to be negotiated
* offer - True if the remote SDP is an offer
*
* returns
* CC_CAUSE_OK - success
* any other code - failure
*/
cc_causes_t
gsmsdp_negotiate_extmap (cc_sdp_t *cc_sdp_p,
fsmdef_media_t *media,
boolean offer)
{
boolean audio_level = FALSE;
int level = media->level;
int i;
const char* uri;
/*
* Remove any previously negotiated extmap attributes from the
* local SDP
*/
sdp_result_e result = SDP_SUCCESS;
while (result == SDP_SUCCESS) {
result = sdp_delete_attr (cc_sdp_p->src_sdp, level, 0,
SDP_ATTR_EXTMAP, 1);
}
i = 1;
do {
uri = sdp_attr_get_extmap_uri(cc_sdp_p->dest_sdp, level, 0, i);
if (uri != NULL && strcmp(uri, SDP_EXTMAP_AUDIO_LEVEL) == 0) {
audio_level = TRUE;
}
i++;
} while (uri != NULL);
media->audio_level = audio_level;
return CC_CAUSE_OK;
}
/*
* gsmsdp_negotiate_media_lines
*
@ -4986,6 +5072,11 @@ gsmsdp_negotiate_media_lines (fsm_fcb_t *fcb_p, cc_sdp_t *sdp_p, boolean initial
gsmsdp_negotiate_rtcp_fb (dcb_p->sdp, media, offer);
}
/* Negotiate redundancy mechanisms */
if (media && media_type == SDP_MEDIA_AUDIO) {
gsmsdp_negotiate_extmap (dcb_p->sdp, media, offer);
}
/*
* Negotiate rtcp-mux
*/
@ -5598,6 +5689,12 @@ gsmsdp_add_media_line (fsmdef_dcb_t *dcb_p, const cc_media_cap_t *media_cap,
sdp_rtcp_fb_ccm_to_bitmap(SDP_RTCP_FB_CCM_FIR));
}
/* Add supported audio level rtp extension */
if (media_cap->type == SDP_MEDIA_AUDIO) {
gsmsdp_set_extmap_attribute(level, dcb_p->sdp->src_sdp, 1,
SDP_EXTMAP_AUDIO_LEVEL);
}
/* Add a=setup attribute */
gsmsdp_set_setup_attribute(level, dcb_p->sdp->src_sdp, media->setup);

View File

@ -207,6 +207,9 @@ typedef struct fsmdef_media_t_ {
*/
boolean rtcp_mux;
/* Flag to indicate if RTP Header extension for audio level is used */
boolean audio_level;
/*
* The value of the a=setup line
*/

View File

@ -1236,6 +1236,7 @@ lsm_tx_start (lsm_lcb_t *lcb, const char *fname, fsmdef_media_t *media)
attrs.mute = FALSE;
attrs.rtcp_mux = media->rtcp_mux;
attrs.audio_level = media->audio_level;
attrs.is_video = FALSE;
attrs.bundle_level = 0;

View File

@ -74,6 +74,8 @@
#define SDP_CONTEXT_RESET_MASTER_KEY(cw) ((cw) &= ~(SDP_SRTCP_KEY_MASK))
#define SDP_CONTEXT_RESET_MASTER_SALT(cw) ((cw) &= ~(SDP_SRTCP_SALT_MASK))
#define SDP_EXTMAP_AUDIO_LEVEL "urn:ietf:params:rtp-hdrext:ssrc-audio-level"
/* SDP Enum Types */
typedef enum {
@ -893,6 +895,18 @@ typedef struct sdp_media_profiles {
u16 payload_type[SDP_MAX_PROFILES][SDP_MAX_PAYLOAD_TYPES];
} sdp_media_profiles_t;
/*
* a=extmap:<value>["/"<direction>] <URI> <extensionattributes>
*
*/
typedef struct sdp_extmap {
u16 id;
sdp_direction_e media_direction;
char uri[SDP_MAX_STRING_LEN+1];
char extension_attributes[SDP_MAX_STRING_LEN+1];
} sdp_extmap_t;
/*
* sdp_srtp_crypto_context_t
@ -982,6 +996,7 @@ typedef struct sdp_attr {
sdp_fmtp_fb_t rtcp_fb;
sdp_setup_type_e setup;
sdp_connection_type_e connection;
sdp_extmap_t extmap;
} attr;
struct sdp_attr *next_p;
} sdp_attr_t;
@ -2104,4 +2119,10 @@ sdp_result_e
sdp_attr_set_rtcp_fb_ccm(void *sdp_ptr, u16 level, u16 payload_type, u16 inst,
sdp_rtcp_fb_ccm_type_e);
const char *
sdp_attr_get_extmap_uri(void *sdp_ptr, u16 level, u16 id, u16 inst);
sdp_result_e
sdp_attr_set_extmap(void *sdp_ptr, u16 level, u16 id, const char* uri, u16 inst);
#endif /* _SDP_H_ */

View File

@ -5148,3 +5148,77 @@ sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
return SDP_SUCCESS;
}
sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p,
sdp_attr_t *attr_p,
flex_string *fs)
{
flex_string_sprintf(fs, "a=extmap:%d %s\r\n",
attr_p->attr.extmap.id,
attr_p->attr.extmap.uri);
return SDP_SUCCESS;
}
sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p,
sdp_attr_t *attr_p,
const char *ptr)
{
sdp_result_e result;
attr_p->attr.extmap.id = 0;
attr_p->attr.extmap.media_direction = SDP_DIRECTION_SENDRECV;
attr_p->attr.extmap.uri[0] = '\0';
attr_p->attr.extmap.extension_attributes[0] = '\0';
/* Find the payload type number. */
attr_p->attr.extmap.id =
(u16)sdp_getnextnumtok(ptr, &ptr, "/ \t", &result);
if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p->peerconnection,
"%s Warning: Invalid extmap id specified for %s attribute.",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++;
return (SDP_INVALID_PARAMETER);
}
if (*ptr == '/') {
char direction[SDP_MAX_STRING_LEN+1];
/* Find the encoding name. */
ptr = sdp_getnextstrtok(ptr, direction,
sizeof(direction), " \t", &result);
if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p->peerconnection,
"%s Warning: No uri specified in %s attribute.",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++;
return (SDP_INVALID_PARAMETER);
}
}
ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.uri,
sizeof(attr_p->attr.extmap.uri), " \t", &result);
if (result != SDP_SUCCESS) {
sdp_parse_error(sdp_p->peerconnection,
"%s Warning: No uri specified in %s attribute.",
sdp_p->debug_str, sdp_get_attr_name(attr_p->type));
sdp_p->conf_p->num_invalid_param++;
return (SDP_INVALID_PARAMETER);
}
ptr = sdp_getnextstrtok(ptr, attr_p->attr.extmap.extension_attributes,
sizeof(attr_p->attr.extmap.extension_attributes), "\r\n", &result);
if (sdp_p->debug_flag[SDP_DEBUG_TRACE]) {
SDP_PRINT("%s Parsed a=%s, id %u, direction %s, "
"uri %s, extension %s", sdp_p->debug_str,
sdp_get_attr_name(attr_p->type),
attr_p->attr.extmap.id,
SDP_DIRECTION_PRINT(attr_p->attr.extmap.media_direction),
attr_p->attr.extmap.uri,
attr_p->attr.extmap.extension_attributes);
}
return (SDP_SUCCESS);
}

View File

@ -12484,3 +12484,76 @@ sdp_attr_set_rtcp_fb_ccm(void *sdp_ptr, u16 level, u16 payload_type, u16 inst,
attr_p->attr.rtcp_fb.extra[0] = '\0';
return (SDP_SUCCESS);
}
/* Function: sdp_attr_get_extmap_uri
* Description: Returns a pointer to the value of the encoding name
* parameter specified for the given attribute. Value is
* returned as a const ptr and so cannot be modified by the
* application. If the given attribute is not defined, NULL
* will be returned.
* Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
* level The level to check for the attribute.
* cap_num The capability number associated with the
* attribute if any. If none, should be zero.
* inst_num The attribute instance number to check.
* Returns: Codec value or SDP_CODEC_INVALID.
*/
const char *sdp_attr_get_extmap_uri(void *sdp_ptr, u16 level,
u16 id, u16 inst_num)
{
sdp_t *sdp_p = (sdp_t *)sdp_ptr;
sdp_attr_t *attr_p;
if (sdp_verify_sdp_ptr(sdp_p) == FALSE) {
return (NULL);
}
attr_p = sdp_find_attr(sdp_p, level, id, SDP_ATTR_EXTMAP, inst_num);
if (attr_p == NULL) {
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
CSFLogError(logTag, "%s extmap attribute, level %u instance %u "
"not found.", sdp_p->debug_str, level, inst_num);
}
sdp_p->conf_p->num_invalid_param++;
return (NULL);
} else {
return (attr_p->attr.extmap.uri);
}
}
/* Function: sdp_attr_set_extmap
* Description: Sets the value of an rtcp-fb:...ccm attribute
* Parameters: sdp_ptr The SDP handle returned by sdp_init_description.
* level The level to set the attribute.
* id The id to set the attribute.
* uri The uri to set the attribute.
* inst The attribute instance number to check.
* Returns: SDP_SUCCESS Attribute param was set successfully.
* SDP_INVALID_PARAMETER Specified attribute is not defined.
*/
sdp_result_e
sdp_attr_set_extmap(void *sdp_ptr, u16 level, u16 id, const char* uri, u16 inst)
{
sdp_t *sdp_p = (sdp_t *)sdp_ptr;
sdp_attr_t *attr_p;
if (!sdp_verify_sdp_ptr(sdp_p)) {
return (SDP_INVALID_SDP_PTR);
}
attr_p = sdp_find_attr(sdp_p, level, 0, SDP_ATTR_EXTMAP, inst);
if (!attr_p) {
if (sdp_p->debug_flag[SDP_DEBUG_ERRORS]) {
CSFLogError(logTag, "%s extmap attribute, level %u "
"instance %u not found.", sdp_p->debug_str, level,
inst);
}
sdp_p->conf_p->num_invalid_param++;
return (SDP_INVALID_PARAMETER);
}
attr_p->attr.extmap.id = id;
sstrncpy(attr_p->attr.extmap.uri, uri, SDP_MAX_STRING_LEN+1);
return (SDP_SUCCESS);
}

View File

@ -176,6 +176,8 @@ const sdp_attrarray_t sdp_attr[SDP_MAX_ATTR_TYPES] =
sdp_parse_attr_setup, sdp_build_attr_setup},
{"connection", sizeof("connection"),
sdp_parse_attr_connection, sdp_build_attr_connection},
{"extmap", sizeof("extmap"),
sdp_parse_attr_extmap, sdp_build_attr_extmap},
};
/* Note: These *must* be in the same order as the enum types. */

View File

@ -167,6 +167,12 @@ extern sdp_result_e sdp_parse_attr_connection(sdp_t *sdp_p,
extern sdp_result_e sdp_build_attr_connection(sdp_t *sdp_p,
sdp_attr_t *attr_p,
flex_string *fs);
extern sdp_result_e sdp_parse_attr_extmap(sdp_t *sdp_p,
sdp_attr_t *attr_p,
const char *ptr);
extern sdp_result_e sdp_build_attr_extmap(sdp_t *sdp_p,
sdp_attr_t *attr_p,
flex_string *fs);
extern sdp_result_e sdp_parse_attr_mptime(
sdp_t *sdp_p, sdp_attr_t *attr_p, const char *ptr);
extern sdp_result_e sdp_build_attr_mptime(

View File

@ -246,6 +246,7 @@ typedef enum {
SDP_ATTR_RTCP_FB, /* RFC 4585 */
SDP_ATTR_SETUP,
SDP_ATTR_CONNECTION,
SDP_ATTR_EXTMAP, /* RFC 5285 */
SDP_MAX_ATTR_TYPES,
SDP_ATTR_INVALID
} sdp_attr_e;

View File

@ -338,6 +338,7 @@ typedef struct vcm_attrs_t_ {
cc_boolean mute;
cc_boolean is_video;
cc_boolean rtcp_mux;
cc_boolean audio_level;
vcm_audioAttrs_t audio; /**< audio line attribs */
vcm_videoAttrs_t video; /**< Video Atrribs */
uint32_t bundle_level; /**< Where bundle transport info lives, if any */

View File

@ -192,6 +192,15 @@ class SdpTest : public ::testing::Test {
return inst_num;
}
u16 AddNewExtMap(int level, const char* uri) {
u16 inst_num = 0;
EXPECT_EQ(sdp_add_new_attr(sdp_ptr_, level, 0, SDP_ATTR_EXTMAP,
&inst_num), SDP_SUCCESS);
EXPECT_EQ(sdp_attr_set_extmap(sdp_ptr_, level, 0,
uri, inst_num), SDP_SUCCESS);
return inst_num;
}
u16 AddNewFmtpMaxFs(int level, u32 max_fs) {
u16 inst_num = 0;
EXPECT_EQ(sdp_add_new_attr(sdp_ptr_, level, 0, SDP_ATTR_FMTP,
@ -726,6 +735,21 @@ TEST_F(SdpTest, parseRtcpFbAllPayloads) {
}
}
TEST_F(SdpTest, addExtMap) {
InitLocalSdp();
int level = AddNewMedia(SDP_MEDIA_VIDEO);
AddNewExtMap(level, SDP_EXTMAP_AUDIO_LEVEL);
std::string body = SerializeSdp();
ASSERT_NE(body.find("a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n"), std::string::npos);
}
TEST_F(SdpTest, parseExtMap) {
ParseSdp(kVideoSdp +
"a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level\r\n");
ASSERT_STREQ(sdp_attr_get_extmap_uri(sdp_ptr_, 1, 0, 1),
SDP_EXTMAP_AUDIO_LEVEL);
}
TEST_F(SdpTest, parseFmtpMaxFs) {
u32 val = 0;
ParseSdp(kVideoSdp + "a=fmtp:120 max-fs=300;max-fr=30\r\n");