bool SipccSdpAttributeList::LoadMsidSemantics(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { auto msidSemantics = MakeUnique<SdpMsidSemanticAttributeList>(); for (uint16_t i = 1; i < UINT16_MAX; ++i) { sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_MSID_SEMANTIC, i); if (!attr) { break; } sdp_msid_semantic_t* msid_semantic = &(attr->attr.msid_semantic); std::vector<std::string> msids; for (size_t i = 0; i < SDP_MAX_MEDIA_STREAMS; ++i) { if (!msid_semantic->msids[i]) { break; } msids.push_back(msid_semantic->msids[i]); } msidSemantics->PushEntry(msid_semantic->semantic, msids); } if (!msidSemantics->mMsidSemantics.empty()) { SetAttribute(msidSemantics.release()); } return true; }
void SipccSdpAttributeList::LoadMsids(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { uint16_t attrCount = 0; if (sdp_attr_num_instances(sdp, level, 0, SDP_ATTR_MSID, &attrCount) != SDP_SUCCESS) { MOZ_ASSERT(false, "Unable to get count of msid attributes"); errorHolder.AddParseError(0, "Unable to get count of msid attributes"); return; } auto msids = MakeUnique<SdpMsidAttributeList>(); for (uint16_t i = 1; i <= attrCount; ++i) { uint32_t lineNumber = sdp_attr_line_number(sdp, SDP_ATTR_MSID, level, 0, i); const char* identifier = sdp_attr_get_msid_identifier(sdp, level, 0, i); if (!identifier) { errorHolder.AddParseError(lineNumber, "msid attribute with bad identity"); continue; } const char* appdata = sdp_attr_get_msid_appdata(sdp, level, 0, i); if (!appdata) { errorHolder.AddParseError(lineNumber, "msid attribute with bad appdata"); continue; } msids->PushEntry(identifier, appdata); } if (!msids->mMsids.empty()) { SetAttribute(msids.release()); } }
bool SipccSdpAttributeList::LoadSctpmap(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { auto sctpmap = MakeUnique<SdpSctpmapAttributeList>(); for (uint16_t i = 0; i < UINT16_MAX; ++i) { sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_SCTPMAP, i + 1); if (!attr) { break; } // Yeah, this is a little weird, but for now we'll just store this as a // payload type. uint16_t payloadType = attr->attr.sctpmap.port; uint16_t streams = attr->attr.sctpmap.streams; const char* name = attr->attr.sctpmap.protocol; std::ostringstream osPayloadType; osPayloadType << payloadType; sctpmap->PushEntry(osPayloadType.str(), name, streams); } if (!sctpmap->mSctpmaps.empty()) { SetAttribute(sctpmap.release()); } return true; }
bool SipccSdpAttributeList::LoadRtpmap(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { auto rtpmap = MakeUnique<SdpRtpmapAttributeList>(); uint16_t count; sdp_result_e result = sdp_attr_num_instances(sdp, level, 0, SDP_ATTR_RTPMAP, &count); if (result != SDP_SUCCESS) { MOZ_ASSERT(false, "Unable to get rtpmap size"); errorHolder.AddParseError(sdp_get_media_line_number(sdp, level), "Unable to get rtpmap size"); return false; } for (uint16_t i = 0; i < count; ++i) { uint16_t pt = sdp_attr_get_rtpmap_payload_type(sdp, level, 0, i + 1); const char* ccName = sdp_attr_get_rtpmap_encname(sdp, level, 0, i + 1); if (!ccName) { // Probably no rtpmap attribute for a pt in an m-line errorHolder.AddParseError(sdp_get_media_line_number(sdp, level), "No rtpmap attribute for payload type"); continue; } std::string name(ccName); SdpRtpmapAttributeList::CodecType codec = GetCodecType(sdp_get_known_payload_type(sdp, level, pt)); uint32_t clock = sdp_attr_get_rtpmap_clockrate(sdp, level, 0, i + 1); uint16_t channels = 0; // sipcc gives us a channels value of "1" for video if (sdp_get_media_type(sdp, level) == SDP_MEDIA_AUDIO) { channels = sdp_attr_get_rtpmap_num_chan(sdp, level, 0, i + 1); } std::ostringstream osPayloadType; osPayloadType << pt; rtpmap->PushEntry(osPayloadType.str(), codec, name, clock, channels); } if (!rtpmap->mRtpmaps.empty()) { SetAttribute(rtpmap.release()); } return true; }
void SipccSdpAttributeList::LoadSsrc(sdp_t* sdp, uint16_t level) { auto ssrcs = MakeUnique<SdpSsrcAttributeList>(); for (uint16_t i = 1; i < UINT16_MAX; ++i) { sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_SSRC, i); if (!attr) { break; } sdp_ssrc_t* ssrc = &(attr->attr.ssrc); ssrcs->PushEntry(ssrc->ssrc, ssrc->attribute); } if (!ssrcs->mSsrcs.empty()) { SetAttribute(ssrcs.release()); } }
void SipccSdpAttributeList::LoadExtmap(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { auto extmaps = MakeUnique<SdpExtmapAttributeList>(); for (uint16_t i = 1; i < UINT16_MAX; ++i) { sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_EXTMAP, i); if (!attr) { break; } sdp_extmap_t* extmap = &(attr->attr.extmap); SdpDirectionAttribute::Direction dir = SdpDirectionAttribute::kSendrecv; if (extmap->media_direction_specified) { ConvertDirection(extmap->media_direction, &dir); } extmaps->PushEntry(extmap->id, dir, extmap->media_direction_specified, extmap->uri, extmap->extension_attributes); } if (!extmaps->mExtmaps.empty()) { if (!AtSessionLevel() && mSessionLevel->HasAttribute(SdpAttribute::kExtmapAttribute)) { uint32_t lineNumber = sdp_attr_line_number(sdp, SDP_ATTR_EXTMAP, level, 0, 1); errorHolder.AddParseError( lineNumber, "extmap attributes in both session and media level"); } SetAttribute(extmaps.release()); } }
void SipccSdpAttributeList::LoadRtcpFb(sdp_t* sdp, uint16_t level, SdpErrorHolder& errorHolder) { auto rtcpfbs = MakeUnique<SdpRtcpFbAttributeList>(); for (uint16_t i = 1; i < UINT16_MAX; ++i) { sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_RTCP_FB, i); if (!attr) { break; } sdp_fmtp_fb_t* rtcpfb = &attr->attr.rtcp_fb; SdpRtcpFbAttributeList::Type type; std::string parameter; // Set type and parameter switch (rtcpfb->feedback_type) { case SDP_RTCP_FB_ACK: type = SdpRtcpFbAttributeList::kAck; switch (rtcpfb->param.ack) { // TODO: sipcc doesn't seem to support ack with no following token. // Issue 189. case SDP_RTCP_FB_ACK_RPSI: parameter = SdpRtcpFbAttributeList::rpsi; break; case SDP_RTCP_FB_ACK_APP: parameter = SdpRtcpFbAttributeList::app; break; default: // Type we don't care about, ignore. continue; } break; case SDP_RTCP_FB_CCM: type = SdpRtcpFbAttributeList::kCcm; switch (rtcpfb->param.ccm) { case SDP_RTCP_FB_CCM_FIR: parameter = SdpRtcpFbAttributeList::fir; break; case SDP_RTCP_FB_CCM_TMMBR: parameter = SdpRtcpFbAttributeList::tmmbr; break; case SDP_RTCP_FB_CCM_TSTR: parameter = SdpRtcpFbAttributeList::tstr; break; case SDP_RTCP_FB_CCM_VBCM: parameter = SdpRtcpFbAttributeList::vbcm; break; default: // Type we don't care about, ignore. continue; } break; case SDP_RTCP_FB_NACK: type = SdpRtcpFbAttributeList::kNack; switch (rtcpfb->param.nack) { case SDP_RTCP_FB_NACK_BASIC: break; case SDP_RTCP_FB_NACK_SLI: parameter = SdpRtcpFbAttributeList::sli; break; case SDP_RTCP_FB_NACK_PLI: parameter = SdpRtcpFbAttributeList::pli; break; case SDP_RTCP_FB_NACK_RPSI: parameter = SdpRtcpFbAttributeList::rpsi; break; case SDP_RTCP_FB_NACK_APP: parameter = SdpRtcpFbAttributeList::app; break; default: // Type we don't care about, ignore. continue; } break; case SDP_RTCP_FB_TRR_INT: { type = SdpRtcpFbAttributeList::kTrrInt; std::ostringstream os; os << rtcpfb->param.trr_int; parameter = os.str(); } break; case SDP_RTCP_FB_REMB: { type = SdpRtcpFbAttributeList::kRemb; } break; default: // Type we don't care about, ignore. continue; } std::stringstream osPayloadType; if (rtcpfb->payload_num == UINT16_MAX) { osPayloadType << "*"; } else { osPayloadType << rtcpfb->payload_num; } std::string pt(osPayloadType.str()); std::string extra(rtcpfb->extra); rtcpfbs->PushEntry(pt, type, parameter, extra); } if (!rtcpfbs->mFeedbacks.empty()) { SetAttribute(rtcpfbs.release()); } }
void SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level) { auto fmtps = MakeUnique<SdpFmtpAttributeList>(); for (uint16_t i = 1; i < UINT16_MAX; ++i) { sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_FMTP, i); if (!attr) { break; } sdp_fmtp_t* fmtp = &(attr->attr.fmtp); // Get the payload type std::stringstream osPayloadType; // payload_num is the number in the fmtp attribute, verbatim osPayloadType << fmtp->payload_num; // Get parsed form of parameters, if supported UniquePtr<SdpFmtpAttributeList::Parameters> parameters; rtp_ptype codec = sdp_get_known_payload_type(sdp, level, fmtp->payload_num); switch (codec) { case RTP_H264_P0: case RTP_H264_P1: { SdpFmtpAttributeList::H264Parameters* h264Parameters( new SdpFmtpAttributeList::H264Parameters); sstrncpy(h264Parameters->sprop_parameter_sets, fmtp->parameter_sets, sizeof(h264Parameters->sprop_parameter_sets)); h264Parameters->level_asymmetry_allowed = !!(fmtp->level_asymmetry_allowed); h264Parameters->packetization_mode = fmtp->packetization_mode; sscanf(fmtp->profile_level_id, "%x", &h264Parameters->profile_level_id); h264Parameters->max_mbps = fmtp->max_mbps; h264Parameters->max_fs = fmtp->max_fs; h264Parameters->max_cpb = fmtp->max_cpb; h264Parameters->max_dpb = fmtp->max_dpb; h264Parameters->max_br = fmtp->max_br; parameters.reset(h264Parameters); } break; case RTP_VP9: { SdpFmtpAttributeList::VP8Parameters* vp9Parameters( new SdpFmtpAttributeList::VP8Parameters( SdpRtpmapAttributeList::kVP9)); vp9Parameters->max_fs = fmtp->max_fs; vp9Parameters->max_fr = fmtp->max_fr; parameters.reset(vp9Parameters); } break; case RTP_VP8: { SdpFmtpAttributeList::VP8Parameters* vp8Parameters( new SdpFmtpAttributeList::VP8Parameters( SdpRtpmapAttributeList::kVP8)); vp8Parameters->max_fs = fmtp->max_fs; vp8Parameters->max_fr = fmtp->max_fr; parameters.reset(vp8Parameters); } break; case RTP_RED: { SdpFmtpAttributeList::RedParameters* redParameters( new SdpFmtpAttributeList::RedParameters); for (int i = 0; i < SDP_FMTP_MAX_REDUNDANT_ENCODINGS && fmtp->redundant_encodings[i]; ++i) { redParameters->encodings.push_back(fmtp->redundant_encodings[i]); } parameters.reset(redParameters); } break; case RTP_OPUS: { SdpFmtpAttributeList::OpusParameters* opusParameters( new SdpFmtpAttributeList::OpusParameters); opusParameters->maxplaybackrate = fmtp->maxplaybackrate; opusParameters->stereo = fmtp->stereo; opusParameters->useInBandFec = fmtp->useinbandfec; parameters.reset(opusParameters); } break; default: { } } fmtps->PushEntry(osPayloadType.str(), Move(parameters)); } if (!fmtps->mFmtps.empty()) { SetAttribute(fmtps.release()); } }
void SipccSdpAttributeList::LoadFmtp(sdp_t* sdp, uint16_t level) { auto fmtps = MakeUnique<SdpFmtpAttributeList>(); for (uint16_t i = 1; i < UINT16_MAX; ++i) { sdp_attr_t* attr = sdp_find_attr(sdp, level, 0, SDP_ATTR_FMTP, i); if (!attr) { break; } sdp_fmtp_t* fmtp = &(attr->attr.fmtp); // Get the payload type std::stringstream osPayloadType; // payload_num is the number in the fmtp attribute, verbatim osPayloadType << fmtp->payload_num; // Get the serialized form of the parameters flex_string fs; flex_string_init(&fs); // Very lame, but we need direct access so we can get the serialized form sdp_result_e sdpres = sdp_build_attr_fmtp_params(sdp, fmtp, &fs); if (sdpres != SDP_SUCCESS) { flex_string_free(&fs); continue; } std::string paramsString(fs.buffer); flex_string_free(&fs); // Get parsed form of parameters, if supported UniquePtr<SdpFmtpAttributeList::Parameters> parameters; rtp_ptype codec = sdp_get_known_payload_type(sdp, level, fmtp->payload_num); switch (codec) { case RTP_H264_P0: case RTP_H264_P1: { SdpFmtpAttributeList::H264Parameters* h264Parameters( new SdpFmtpAttributeList::H264Parameters); sstrncpy(h264Parameters->sprop_parameter_sets, fmtp->parameter_sets, sizeof(h264Parameters->sprop_parameter_sets)); h264Parameters->level_asymmetry_allowed = !!(fmtp->level_asymmetry_allowed); h264Parameters->packetization_mode = fmtp->packetization_mode; // Copied from VcmSIPCCBinding #ifdef _WIN32 sscanf_s(fmtp->profile_level_id, "%x", &h264Parameters->profile_level_id, sizeof(unsigned*)); #else sscanf(fmtp->profile_level_id, "%xu", &h264Parameters->profile_level_id); #endif h264Parameters->max_mbps = fmtp->max_mbps; h264Parameters->max_fs = fmtp->max_fs; h264Parameters->max_cpb = fmtp->max_cpb; h264Parameters->max_dpb = fmtp->max_dpb; h264Parameters->max_br = fmtp->max_br; parameters.reset(h264Parameters); } break; case RTP_VP9: { SdpFmtpAttributeList::VP8Parameters* vp9Parameters( new SdpFmtpAttributeList::VP8Parameters( SdpRtpmapAttributeList::kVP9)); vp9Parameters->max_fs = fmtp->max_fs; vp9Parameters->max_fr = fmtp->max_fr; parameters.reset(vp9Parameters); } break; case RTP_VP8: { SdpFmtpAttributeList::VP8Parameters* vp8Parameters( new SdpFmtpAttributeList::VP8Parameters( SdpRtpmapAttributeList::kVP8)); vp8Parameters->max_fs = fmtp->max_fs; vp8Parameters->max_fr = fmtp->max_fr; parameters.reset(vp8Parameters); } break; default: { } } fmtps->PushEntry(osPayloadType.str(), paramsString, Move(parameters)); } if (!fmtps->mFmtps.empty()) { SetAttribute(fmtps.release()); } }