diff --git a/lib/rtp.cpp b/lib/rtp.cpp index 8d403850..eaf70001 100644 --- a/lib/rtp.cpp +++ b/lib/rtp.cpp @@ -155,13 +155,10 @@ namespace RTP { ((int *)rtcpData)[2] = htonl(2208988800UL + Util::epoch()); //epoch is in seconds ((int *)rtcpData)[3] = htonl((Util::getMS() % 1000) * 4294967.295); - if (metadata.tracks[tid].codec == "H264" || metadata.tracks[tid].codec == "MP3") { + if (metadata.tracks[tid].codec == "H264") { ((int *)rtcpData)[4] = htonl((ntpTime - 0) * 90000); //rtpts - } else if (metadata.tracks[tid].codec == "AAC" || metadata.tracks[tid].codec == "AC3") { - ((int *)rtcpData)[4] = htonl((ntpTime - 0) * metadata.tracks[tid].rate); //rtpts } else { - DEBUG_MSG(DLVL_FAIL, "Unsupported codec: %s", metadata.tracks[tid].codec.c_str()); - return; + ((int *)rtcpData)[4] = htonl((ntpTime - 0) * metadata.tracks[tid].rate); //rtpts } //it should be the time packet was sent maybe, after all? //*((int *)(rtcpData+16) ) = htonl(getTimeStamp());//rtpts diff --git a/src/output/output_rtsp.cpp b/src/output/output_rtsp.cpp index 35c296c0..0f078452 100644 --- a/src/output/output_rtsp.cpp +++ b/src/output/output_rtsp.cpp @@ -59,6 +59,7 @@ namespace Mist { capa["codecs"][0u][1u].append("AAC"); capa["codecs"][0u][1u].append("MP3"); capa["codecs"][0u][1u].append("AC3"); + capa["codecs"][0u][1u].append("ALAW"); capa["methods"][0u]["handler"] = "rtsp"; capa["methods"][0u]["type"] = "rtsp"; @@ -118,18 +119,6 @@ namespace Mist { callBack = sendTCP; } - if(myMeta.tracks[tid].codec == "MP3"){ - tracks[tid].pack.setTimestamp(timestamp * 90); - tracks[tid].pack.sendData(socket, callBack, dataPointer, dataLen, tracks[tid].channel, "MP3"); - return; - } - - if( myMeta.tracks[tid].codec == "AC3" || myMeta.tracks[tid].codec == "AAC"){ - tracks[tid].pack.setTimestamp(timestamp * ((double) myMeta.tracks[tid].rate / 1000.0)); - tracks[tid].pack.sendData(socket, callBack, dataPointer, dataLen, tracks[tid].channel,myMeta.tracks[tid].codec); - return; - } - if(myMeta.tracks[tid].codec == "H264"){ long long offset = thisPacket.getInt("offset"); tracks[tid].pack.setTimestamp(90 * (timestamp + offset)); @@ -141,6 +130,10 @@ namespace Mist { } return; } + + //Default packager + tracks[tid].pack.setTimestamp(timestamp * ((double) myMeta.tracks[tid].rate / 1000.0)); + tracks[tid].pack.sendData(socket, callBack, dataPointer, dataLen, tracks[tid].channel,myMeta.tracks[tid].codec); } @@ -580,8 +573,6 @@ namespace Mist { DTSC::Packet nextPack; nextPack.genericFill(newTs, offset, track, buffer, len, 0, isKey); tracks[track].packCount++; - nProxy.streamName = streamName; - continueNegotiate(track); bufferLivePacket(nextPack); } @@ -591,6 +582,13 @@ namespace Mist { if (!tracks[track].firstTime){ tracks[track].firstTime = pkt.getTimeStamp() + 1; } + if (myMeta.tracks[track].codec == "ALAW"){ + char * pl = pkt.getPayload(); + DTSC::Packet nextPack; + nextPack.genericFill((pkt.getTimeStamp() - tracks[track].firstTime + 1) / ((double)myMeta.tracks[track].rate / 1000.0), 0, track, pl, pkt.getPayloadSize(), 0, false); + bufferLivePacket(nextPack); + return; + } if (myMeta.tracks[track].codec == "AAC"){ //assume AAC packets are single AU units /// \todo Support other input than single AU units @@ -606,8 +604,6 @@ namespace Mist { nextPack.genericFill((pkt.getTimeStamp() + sampleOffset - tracks[track].firstTime + 1) / ((double)myMeta.tracks[track].rate / 1000.0), 0, track, pl+headLen+offset, std::min(auSize, pkt.getPayloadSize() - headLen - offset), 0, false); offset += auSize; sampleOffset += samples; - nProxy.streamName = streamName; - continueNegotiate(track); bufferLivePacket(nextPack); } return; @@ -784,6 +780,7 @@ namespace Mist { std::string to; uint64_t trackNo = 0; bool nope = true; //true if we have no valid track to fill + DTSC::Track * thisTrack = 0; while(std::getline(ss,to,'\n')){ if (!to.empty() && *to.rbegin() == '\r'){to.erase(to.size()-1, 1);} @@ -791,11 +788,12 @@ namespace Mist { if (to.substr(0,2) == "m="){ nope = true; ++trackNo; + thisTrack = &(myMeta.tracks[trackNo]); std::stringstream words(to.substr(2)); std::string item; if (getline(words, item, ' ') && (item == "audio" || item == "video")){ - myMeta.tracks[trackNo].type = item; - myMeta.tracks[trackNo].trackID = trackNo; + thisTrack->type = item; + thisTrack->trackID = trackNo; }else{ WARN_MSG("Media type not supported: %s", item.c_str()); continue; @@ -805,7 +803,29 @@ namespace Mist { WARN_MSG("Media transport not supported: %s", item.c_str()); continue; } - nope = false; + if (getline(words, item, ' ')){ + uint64_t avp_type = JSON::Value(item).asInt(); + switch (avp_type){ + case 8: //PCM A-law + INFO_MSG("PCM A-law payload type"); + nope = false; + thisTrack->codec = "ALAW"; + thisTrack->rate = 8000; + thisTrack->channels = 1; + INFO_MSG("Incoming track %s", thisTrack->getIdentifier().c_str()); + break; + default: + //dynamic type + if (avp_type >= 96 && avp_type <= 127){ + INFO_MSG("Dynamic payload type (%llu) detected", avp_type); + nope = false; + continue; + }else{ + FAIL_MSG("Payload type %llu not supported!", avp_type); + continue; + } + } + } continue; } if (nope){continue;}//ignore lines if we have no valid track @@ -813,25 +833,25 @@ namespace Mist { if (to.substr(0, 8) == "a=rtpmap"){ std::string mediaType = to.substr(to.find(' ', 8)+1); std::string trCodec = mediaType.substr(0, mediaType.find('/')); + //convert to fullcaps for(unsigned int i=0;i=97){trCodec[i]-=32;} } - if (trCodec == "H264"){ - myMeta.tracks[trackNo].codec = "H264"; - } - if (trCodec == "MPEG4-GENERIC"){ - myMeta.tracks[trackNo].codec = "AAC"; + if (thisTrack->type == "audio"){ std::string extraInfo = mediaType.substr(mediaType.find('/')+1); if (extraInfo.find('/') != std::string::npos){ size_t lastSlash = extraInfo.find('/'); - myMeta.tracks[trackNo].rate = atoll(extraInfo.substr(0, lastSlash).c_str()); - myMeta.tracks[trackNo].channels = atoll(extraInfo.substr(lastSlash+1).c_str()); + thisTrack->rate = atoll(extraInfo.substr(0, lastSlash).c_str()); + thisTrack->channels = atoll(extraInfo.substr(lastSlash+1).c_str()); }else{ - myMeta.tracks[trackNo].rate = atoll(extraInfo.c_str()); - myMeta.tracks[trackNo].channels = 1; + thisTrack->rate = atoll(extraInfo.c_str()); + thisTrack->channels = 1; } } - INFO_MSG("Incoming track %s", myMeta.tracks[trackNo].getIdentifier().c_str()); + if (trCodec == "H264"){thisTrack->codec = "H264";} + if (trCodec == "PCMA"){thisTrack->codec = "ALAW";} + if (trCodec == "MPEG4-GENERIC"){thisTrack->codec = "AAC";} + INFO_MSG("Incoming track %s", thisTrack->getIdentifier().c_str()); continue; } if (to.substr(0, 10) == "a=control:"){ @@ -840,7 +860,7 @@ namespace Mist { } if (to.substr(0, 7) == "a=fmtp:"){ tracks[trackNo].fmtp = to.substr(7); - if (myMeta.tracks[trackNo].codec == "AAC"){ + if (thisTrack->codec == "AAC"){ if (tracks[trackNo].getParamString("mode") != "AAC-hbr"){ //a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3; config=120856E500 FAIL_MSG("AAC transport mode not supported: %s", tracks[trackNo].getParamString("mode").c_str()); @@ -849,11 +869,11 @@ namespace Mist { tracks.erase(trackNo); continue; } - myMeta.tracks[trackNo].init = Encodings::Hex::decode(tracks[trackNo].getParamString("config")); + thisTrack->init = Encodings::Hex::decode(tracks[trackNo].getParamString("config")); //myMeta.tracks[trackNo].rate = aac::AudSpecConf::rate(myMeta.tracks[trackNo].init); } - if (myMeta.tracks[trackNo].codec == "H264"){ + if (thisTrack->codec == "H264"){ //a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z0LAHtkA2D3m//AUABqxAAADAAEAAAMAMg8WLkg=,aMuDyyA=; profile-level-id=42C01E std::string sprop = tracks[trackNo].getParamString("sprop-parameter-sets"); size_t comma = sprop.find(','); diff --git a/src/output/output_rtsp.h b/src/output/output_rtsp.h index 3c7495ff..acf79611 100644 --- a/src/output/output_rtsp.h +++ b/src/output/output_rtsp.h @@ -37,6 +37,7 @@ namespace Mist { cPort = 0; rtpSeq = 0; fpsTime = 0; + fpsMeta = 0; fps = 0; } std::string getParamString(const std::string & param) const{ @@ -87,6 +88,14 @@ namespace Mist { mediaDesc << "m=audio 0 RTP/AVP 100" << "\r\n" "a=rtpmap:100 AC3/" << trk.rate << "/" << trk.channels << "\r\n" "a=control:track" << trk.trackID << "\r\n"; + }else if ( trk.codec == "ALAW") { + if (trk.channels == 1 && trk.rate == 8000){ + mediaDesc << "m=audio 0 RTP/AVP 8" << "\r\n"; + }else{ + mediaDesc << "m=audio 0 RTP/AVP 101" << "\r\n"; + mediaDesc << "a=rtpmap:101 PCMA/" << trk.rate << "/" << trk.channels << "\r\n"; + } + mediaDesc << "a=control:track" << trk.trackID << "\r\n"; } return mediaDesc.str(); } @@ -100,11 +109,16 @@ namespace Mist { pack = RTP::Packet(100, 1, 0, SSrc); }else if(trk.codec == "MP3"){ pack = RTP::Packet(14, 1, 0, SSrc); + }else if(trk.codec == "ALAW"){ + if (trk.channels == 1 && trk.rate == 8000){ + pack = RTP::Packet(8, 1, 0, SSrc); + }else{ + pack = RTP::Packet(101, 1, 0, SSrc); + } }else{ ERROR_MSG("Unsupported codec %s for RTSP on track %u", trk.codec.c_str(), trk.trackID); return false; } - std::cerr << transport << std::endl; if (transport.find("TCP") != std::string::npos) { std::string chanE = transport.substr(transport.find("interleaved=") + 12, (transport.size() - transport.rfind('-') - 1)); //extract channel ID channel = atol(chanE.c_str()); @@ -136,10 +150,9 @@ namespace Mist { } std::string rtpInfo(const DTSC::Track & trk, const std::string & source, uint64_t currentTime){ unsigned int timeMultiplier = 1; + timeMultiplier = ((double)trk.rate / 1000.0); if (trk.codec == "H264") { timeMultiplier = 90; - } else if (trk.codec == "AAC" || trk.codec == "MP3" || trk.codec == "AC3") { - timeMultiplier = ((double)trk.rate / 1000.0); } std::stringstream rInfo; rInfo << "url=" << source << "/track" << trk.trackID << ";"; //get the current url, not localhost