liveMedia/AMRAudioRTPSink.cpp

Go to the documentation of this file.
00001 /**********
00002 This library is free software; you can redistribute it and/or modify it under
00003 the terms of the GNU Lesser General Public License as published by the
00004 Free Software Foundation; either version 2.1 of the License, or (at your
00005 option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
00006 
00007 This library is distributed in the hope that it will be useful, but WITHOUT
00008 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00009 FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
00010 more details.
00011 
00012 You should have received a copy of the GNU Lesser General Public License
00013 along with this library; if not, write to the Free Software Foundation, Inc.,
00014 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
00015 **********/
00016 // "liveMedia"
00017 // Copyright (c) 1996-2014 Live Networks, Inc.  All rights reserved.
00018 // RTP sink for AMR audio (RFC 4867)
00019 // Implementation
00020 
00021 // NOTE: At present, this is just a limited implementation, supporting:
00022 // octet-alignment only; no interleaving; no frame CRC; no robust-sorting.
00023 
00024 #include "AMRAudioRTPSink.hh"
00025 #include "AMRAudioSource.hh"
00026 
00027 AMRAudioRTPSink*
00028 AMRAudioRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs,
00029                            unsigned char rtpPayloadFormat,
00030                            Boolean sourceIsWideband,
00031                            unsigned numChannelsInSource) {
00032   return new AMRAudioRTPSink(env, RTPgs, rtpPayloadFormat,
00033                              sourceIsWideband, numChannelsInSource);
00034 }
00035 
00036 AMRAudioRTPSink
00037 ::AMRAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs,
00038                   unsigned char rtpPayloadFormat,
00039                   Boolean sourceIsWideband, unsigned numChannelsInSource)
00040   : AudioRTPSink(env, RTPgs, rtpPayloadFormat,
00041                  sourceIsWideband ? 16000 : 8000,
00042                  sourceIsWideband ? "AMR-WB": "AMR",
00043                  numChannelsInSource),
00044   fSourceIsWideband(sourceIsWideband), fFmtpSDPLine(NULL) {
00045 }
00046 
00047 AMRAudioRTPSink::~AMRAudioRTPSink() {
00048   delete[] fFmtpSDPLine;
00049 }
00050 
00051 Boolean AMRAudioRTPSink::sourceIsCompatibleWithUs(MediaSource& source) {
00052   // Our source must be an AMR audio source:
00053   if (!source.isAMRAudioSource()) return False;
00054 
00055   // Also, the source must be wideband iff we asked for this:
00056   AMRAudioSource& amrSource = (AMRAudioSource&)source;
00057   if ((amrSource.isWideband()^fSourceIsWideband) != 0) return False;
00058 
00059   // Also, the source must have the same number of channels that we
00060   // specified.  (It could, in principle, have more, but we don't
00061   // support that.)
00062   if (amrSource.numChannels() != numChannels()) return False;
00063 
00064   // Also, because in our current implementation we output only one
00065   // frame in each RTP packet, this means that for multi-channel audio,
00066   // each 'frame-block' will be split over multiple RTP packets, which
00067   // may violate the spec.  Warn about this:
00068   if (amrSource.numChannels() > 1) {
00069     envir() << "AMRAudioRTPSink: Warning: Input source has " << amrSource.numChannels()
00070             << " audio channels.  In the current implementation, the multi-frame frame-block will be split over multiple RTP packets\n";
00071   }
00072 
00073   return True;
00074 }
00075 
00076 void AMRAudioRTPSink::doSpecialFrameHandling(unsigned fragmentationOffset,
00077                                              unsigned char* frameStart,
00078                                              unsigned numBytesInFrame,
00079                                              struct timeval framePresentationTime,
00080                                              unsigned numRemainingBytes) {
00081   // If this is the 1st frame in the 1st packet, set the RTP 'M' (marker)
00082   // bit (because this is considered the start of a talk spurt):
00083   if (isFirstPacket() && isFirstFrameInPacket()) {
00084     setMarkerBit();
00085   }
00086 
00087   // If this is the first frame in the packet, set the 1-byte payload
00088   // header (using CMR 15)
00089   if (isFirstFrameInPacket()) {
00090     u_int8_t payloadHeader = 0xF0;
00091     setSpecialHeaderBytes(&payloadHeader, 1, 0);
00092   }
00093 
00094   // Set the TOC field for the current frame, based on the "FT" and "Q"
00095   // values from our source:
00096   AMRAudioSource* amrSource = (AMRAudioSource*)fSource;
00097   if (amrSource == NULL) return; // sanity check
00098 
00099   u_int8_t toc = amrSource->lastFrameHeader();
00100   // Clear the "F" bit, because we're the last frame in this packet: #####
00101   toc &=~ 0x80;
00102   setSpecialHeaderBytes(&toc, 1, 1+numFramesUsedSoFar());
00103 
00104   // Important: Also call our base class's doSpecialFrameHandling(),
00105   // to set the packet's timestamp:
00106   MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset,
00107                                              frameStart, numBytesInFrame,
00108                                              framePresentationTime,
00109                                              numRemainingBytes);
00110 }
00111 
00112 Boolean AMRAudioRTPSink
00113 ::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/,
00114                                  unsigned /*numBytesInFrame*/) const {
00115   // For now, pack only one AMR frame into each outgoing RTP packet: #####
00116   return False;
00117 }
00118 
00119 unsigned AMRAudioRTPSink::specialHeaderSize() const {
00120   // For now, because we're packing only one frame per packet,
00121   // there's just a 1-byte payload header, plus a 1-byte TOC #####
00122   return 2;
00123 }
00124 
00125 char const* AMRAudioRTPSink::auxSDPLine() {
00126   if (fFmtpSDPLine == NULL) {
00127     // Generate a "a=fmtp:" line with "octet-aligned=1"
00128     // (That is the only non-default parameter.)
00129     char buf[100];
00130     sprintf(buf, "a=fmtp:%d octet-align=1\r\n", rtpPayloadType());
00131     delete[] fFmtpSDPLine; fFmtpSDPLine = strDup(buf);
00132   }
00133   return fFmtpSDPLine;
00134 }

Generated on Tue Mar 25 14:35:34 2014 for live by  doxygen 1.5.2