liveMedia/VorbisAudioRTPSink.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-2013 Live Networks, Inc.  All rights reserved.
00018 // RTP sink for Vorbis audio
00019 // Implementation
00020 
00021 #include "VorbisAudioRTPSink.hh"
00022 #include "Base64.hh"
00023 
00024 VorbisAudioRTPSink::VorbisAudioRTPSink(UsageEnvironment& env, Groupsock* RTPgs,
00025                                        u_int8_t rtpPayloadFormat,
00026                                        u_int32_t rtpTimestampFrequency,
00027                                        unsigned numChannels,
00028                                        u_int8_t* identificationHeader, unsigned identificationHeaderSize,
00029                                        u_int8_t* commentHeader, unsigned commentHeaderSize,
00030                                        u_int8_t* setupHeader, unsigned setupHeaderSize,
00031                                        u_int32_t identField)
00032   : AudioRTPSink(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, "VORBIS", numChannels),
00033     fIdent(identField), fFmtpSDPLine(NULL) {
00034   // Create packed configuration headers, and encode this data into a "a=fmtp:" SDP line that we'll use to describe it:
00035   
00036   // First, count how many headers (<=3) are included, and how many bytes will be used to encode these headers' sizes:
00037   unsigned numHeaders = 0;
00038   unsigned sizeSize[2]; // The number of bytes used to encode the lengths of the first two headers (but not the length of the 3rd)
00039   sizeSize[0] = sizeSize[1] = 0;
00040   if (identificationHeaderSize > 0) {
00041     sizeSize[numHeaders++] = identificationHeaderSize < 128 ? 1 : identificationHeaderSize < 16384 ? 2 : 3;
00042   }
00043   if (commentHeaderSize > 0) {
00044     sizeSize[numHeaders++] = commentHeaderSize < 128 ? 1 : commentHeaderSize < 16384 ? 2 : 3;
00045   }
00046   if (setupHeaderSize > 0) {
00047     ++numHeaders;
00048   } else {
00049     sizeSize[1] = 0; // We have at most two headers, so the second one's length isn't encoded
00050   }
00051   if (numHeaders == 0) return; // With no headers, we can't set up a configuration
00052   if (numHeaders == 1) sizeSize[0] = 0; // With only one header, its length isn't encoded
00053 
00054   // Then figure out the size of the packed configuration headers, and allocate space for this:
00055   unsigned length = identificationHeaderSize + commentHeaderSize + setupHeaderSize; // The "length" field in the packed headers
00056   if (length > (unsigned)0xFFFF) return; // too big for a 16-bit field; we can't handle this
00057   unsigned packedHeadersSize
00058     = 4 // "Number of packed headers" field
00059     + 3 // "ident" field
00060     + 2 // "length" field
00061     + 1 // "n. of headers" field
00062     + sizeSize[0] + sizeSize[1] // "length1" and "length2" (if present) fields
00063     + length;
00064   u_int8_t* packedHeaders = new u_int8_t[packedHeadersSize];
00065   if (packedHeaders == NULL) return;
00066 
00067   // Fill in the 'packed headers':
00068   u_int8_t* p = packedHeaders;
00069   *p++ = 0; *p++ = 0; *p++ = 0; *p++ = 1; // "Number of packed headers": 1
00070   *p++ = fIdent>>16; *p++ = fIdent>>8; *p++ = fIdent; // "Ident" (24 bits)
00071   *p++ = length>>8; *p++ = length; // "length" (16 bits)
00072   *p++ = numHeaders-1; // "n. of headers"
00073   if (numHeaders > 1) {
00074     // Fill in the "length1" header:
00075     unsigned length1 = identificationHeaderSize > 0 ? identificationHeaderSize : commentHeaderSize;
00076     if (length1 >= 16384) {
00077       *p++ = 0x80; // flag, but no more, because we know length1 <= 32767
00078     }
00079     if (length1 >= 128) {
00080       *p++ = 0x80|((length1&0x3F80)>>7); // flag + the second 7 bits
00081     }
00082     *p++ = length1&0x7F; // the low 7 bits
00083 
00084     if (numHeaders > 2) { // numHeaders == 3
00085       // Fill in the "length2" header (for the 'Comment' header):
00086       unsigned length2 = commentHeaderSize;
00087       if (length2 >= 16384) {
00088         *p++ = 0x80; // flag, but no more, because we know length2 <= 32767
00089       }
00090       if (length2 >= 128) {
00091         *p++ = 0x80|((length2&0x3F80)>>7); // flag + the second 7 bits
00092       }
00093       *p++ = length2&0x7F; // the low 7 bits
00094     }
00095   }
00096   // Copy each header:
00097   if (identificationHeader != NULL) memmove(p, identificationHeader, identificationHeaderSize); p += identificationHeaderSize;
00098   if (commentHeader != NULL) memmove(p, commentHeader, commentHeaderSize); p += commentHeaderSize;
00099   if (setupHeader != NULL) memmove(p, setupHeader, setupHeaderSize);
00100   
00101   // Having set up the 'packed configuration headers', Base-64-encode this, and put it in our "a=fmtp:" SDP line:
00102   char* base64PackedHeaders = base64Encode((char const*)packedHeaders, packedHeadersSize);
00103   delete[] packedHeaders;
00104   
00105   unsigned fmtpSDPLineMaxSize = 50 + strlen(base64PackedHeaders); // 50 => more than enough space
00106   fFmtpSDPLine = new char[fmtpSDPLineMaxSize];
00107   sprintf(fFmtpSDPLine, "a=fmtp:%d configuration=%s\r\n", rtpPayloadType(), base64PackedHeaders);
00108   delete[] base64PackedHeaders;
00109 }
00110 
00111 VorbisAudioRTPSink::~VorbisAudioRTPSink() {
00112   delete[] fFmtpSDPLine;
00113 }
00114 
00115 VorbisAudioRTPSink*
00116 VorbisAudioRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs,
00117                               u_int8_t rtpPayloadFormat, u_int32_t rtpTimestampFrequency, unsigned numChannels,
00118                               u_int8_t* identificationHeader, unsigned identificationHeaderSize,
00119                               u_int8_t* commentHeader, unsigned commentHeaderSize,
00120                               u_int8_t* setupHeader, unsigned setupHeaderSize) {
00121   return new VorbisAudioRTPSink(env, RTPgs,
00122                                 rtpPayloadFormat, rtpTimestampFrequency, numChannels,
00123                                 identificationHeader, identificationHeaderSize,
00124                                 commentHeader, commentHeaderSize,
00125                                 setupHeader, setupHeaderSize);
00126 }
00127 
00128 #define ADVANCE(n) do { p += (n); rem -= (n); } while (0)
00129 #define GET_ENCODED_VAL(n) do { u_int8_t byte; n = 0; do { if (rem == 0) break; byte = *p; n = (n*128) + (byte&0x7F); ADVANCE(1); } while (byte&0x80); } while (0); if (rem == 0) break
00130 
00131 VorbisAudioRTPSink*
00132 VorbisAudioRTPSink::createNew(UsageEnvironment& env, Groupsock* RTPgs,
00133                               u_int8_t rtpPayloadFormat, u_int32_t rtpTimestampFrequency, unsigned numChannels,
00134                               char const* configStr) {
00135   u_int8_t* identificationHeader = NULL; unsigned identificationHeaderSize = 0;
00136   u_int8_t* commentHeader = NULL; unsigned commentHeaderSize = 0;
00137   u_int8_t* setupHeader = NULL; unsigned setupHeaderSize = 0;
00138   VorbisAudioRTPSink* resultSink = NULL;
00139 
00140   // Begin by Base64-decoding the configuration string:
00141   unsigned configDataSize;
00142   u_int8_t* configData = base64Decode(configStr, configDataSize);
00143   u_int8_t* p = configData;
00144   unsigned rem = configDataSize;
00145 
00146   do {
00147     if (rem < 4) break;
00148     u_int32_t numPackedHeaders = (p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]; ADVANCE(4);
00149 
00150     if (numPackedHeaders == 0) break;
00151     // Use the first 'packed header' only.
00152 
00153     if (rem < 3) break;
00154     u_int32_t ident = (p[0]<<16)|(p[1]<<8)|p[2]; ADVANCE(3);
00155 
00156     if (rem < 2) break;
00157     u_int16_t length = (p[0]<<8)|p[1]; ADVANCE(2);
00158 
00159     unsigned numHeaders;
00160     GET_ENCODED_VAL(numHeaders);
00161 
00162     Boolean success = False;
00163     for (unsigned i = 0; i < numHeaders+1 && i < 3; ++i) {
00164       success = False;
00165       unsigned headerSize;
00166       if (i < numHeaders) {
00167         // The header size is encoded:
00168         GET_ENCODED_VAL(headerSize);
00169         if (headerSize > length) break;
00170         length -= headerSize;
00171       } else {
00172         // The last header is implicit:
00173         headerSize = length;
00174       }
00175 
00176       // Allocate space for the header bytes; we'll fill it in later
00177       if (i == 0) {
00178         identificationHeaderSize = headerSize;
00179         identificationHeader = new u_int8_t[identificationHeaderSize];
00180       } else if (i == 1) {
00181         commentHeaderSize = headerSize;
00182         commentHeader = new u_int8_t[commentHeaderSize];
00183       } else { // i == 2
00184         setupHeaderSize = headerSize;
00185         setupHeader = new u_int8_t[setupHeaderSize];
00186       }
00187 
00188       success = True;
00189     }
00190     if (!success) break;
00191 
00192     // Copy the remaining config bytes into the appropriate 'header' buffers:
00193     if (identificationHeader != NULL) {
00194       memmove(identificationHeader, p, identificationHeaderSize); ADVANCE(identificationHeaderSize);
00195       if (commentHeader != NULL) {
00196         memmove(commentHeader, p, commentHeaderSize); ADVANCE(commentHeaderSize);
00197         if (setupHeader != NULL) {
00198           memmove(setupHeader, p, setupHeaderSize); ADVANCE(setupHeaderSize);
00199         }
00200       }
00201     }
00202 
00203     resultSink = new VorbisAudioRTPSink(env, RTPgs, rtpPayloadFormat, rtpTimestampFrequency, numChannels,
00204                                         identificationHeader, identificationHeaderSize,
00205                                         commentHeader, commentHeaderSize,
00206                                         setupHeader, setupHeaderSize,
00207                                         ident);
00208   } while (0);
00209 
00210   delete[] configData;
00211   delete[] identificationHeader; delete[] commentHeader; delete[] setupHeader;
00212   return resultSink;
00213 }
00214 
00215 char const* VorbisAudioRTPSink::auxSDPLine() {
00216   return fFmtpSDPLine;
00217 }
00218 
00219 void VorbisAudioRTPSink
00220 ::doSpecialFrameHandling(unsigned fragmentationOffset,
00221                          unsigned char* frameStart,
00222                          unsigned numBytesInFrame,
00223                          struct timeval framePresentationTime,
00224                          unsigned numRemainingBytes) {
00225   // Set the 4-byte "payload header", as defined in RFC 5215, section 2.2:
00226   u_int8_t header[4];
00227 
00228   // The three bytes of the header are our "Ident":
00229   header[0] = fIdent>>16; header[1] = fIdent>>8; header[2] = fIdent;
00230 
00231   // The final byte contains the "F", "VDT", and "numPkts" fields:
00232   u_int8_t F; // Fragment type
00233   if (numRemainingBytes > 0) {
00234     if (fragmentationOffset > 0) {
00235       F = 2<<6; // continuation fragment
00236     } else {
00237       F = 1<<6; // start fragment
00238     }
00239   } else {
00240     if (fragmentationOffset > 0) {
00241       F = 3<<6; // end fragment
00242     } else {
00243       F = 0<<6; // not fragmented
00244     }
00245   }
00246   u_int8_t const VDT = 0<<4; // Vorbis Data Type (always a "Raw Vorbis payload")
00247   u_int8_t numPkts = F == 0 ? (numFramesUsedSoFar() + 1): 0; // set to 0 when we're a fragment
00248   header[3] = F|VDT|numPkts;
00249 
00250   setSpecialHeaderBytes(header, sizeof header);
00251 
00252   // There's also a 2-byte 'frame-specific' header: The length of the Vorbis data:
00253   u_int8_t frameSpecificHeader[2];
00254   frameSpecificHeader[0] = numBytesInFrame>>8;
00255   frameSpecificHeader[1] = numBytesInFrame;
00256   setFrameSpecificHeaderBytes(frameSpecificHeader, 2);
00257 
00258   // Important: Also call our base class's doSpecialFrameHandling(),
00259   // to set the packet's timestamp:
00260   MultiFramedRTPSink::doSpecialFrameHandling(fragmentationOffset,
00261                                              frameStart, numBytesInFrame,
00262                                              framePresentationTime,
00263                                              numRemainingBytes);
00264 }
00265 
00266 Boolean VorbisAudioRTPSink::frameCanAppearAfterPacketStart(unsigned char const* /*frameStart*/,
00267                                                            unsigned /*numBytesInFrame*/) const {
00268   // We allow more than one frame to be packed into an outgoing RTP packet, but no more than 15:
00269   return numFramesUsedSoFar() <= 15;
00270 }
00271 
00272 unsigned VorbisAudioRTPSink::specialHeaderSize() const {
00273   return 4;
00274 }
00275 
00276 unsigned VorbisAudioRTPSink::frameSpecificHeaderSize() const {
00277   return 2;
00278 }

Generated on Mon Apr 29 13:28:03 2013 for live by  doxygen 1.5.2