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

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