liveMedia/WAVAudioFileServerMediaSubsession.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-2012 Live Networks, Inc.  All rights reserved.
00018 // A 'ServerMediaSubsession' object that creates new, unicast, "RTPSink"s
00019 // on demand, from an WAV audio file.
00020 // Implementation
00021 
00022 #include "WAVAudioFileServerMediaSubsession.hh"
00023 #include "WAVAudioFileSource.hh"
00024 #include "uLawAudioFilter.hh"
00025 #include "SimpleRTPSink.hh"
00026 
00027 WAVAudioFileServerMediaSubsession* WAVAudioFileServerMediaSubsession
00028 ::createNew(UsageEnvironment& env, char const* fileName, Boolean reuseFirstSource,
00029             Boolean convertToULaw) {
00030   return new WAVAudioFileServerMediaSubsession(env, fileName,
00031                                                reuseFirstSource, convertToULaw);
00032 }
00033 
00034 WAVAudioFileServerMediaSubsession
00035 ::WAVAudioFileServerMediaSubsession(UsageEnvironment& env, char const* fileName,
00036                                     Boolean reuseFirstSource, Boolean convertToULaw)
00037   : FileServerMediaSubsession(env, fileName, reuseFirstSource),
00038     fConvertToULaw(convertToULaw) {
00039 }
00040 
00041 WAVAudioFileServerMediaSubsession
00042 ::~WAVAudioFileServerMediaSubsession() {
00043 }
00044 
00045 void WAVAudioFileServerMediaSubsession
00046 ::seekStreamSource(FramedSource* inputSource, double& seekNPT, double streamDuration, u_int64_t& numBytes) {
00047   WAVAudioFileSource* wavSource;
00048   if (fBitsPerSample == 16) {
00049     // "inputSource" is a filter; its input source is the original WAV file source:
00050     wavSource = (WAVAudioFileSource*)(((FramedFilter*)inputSource)->inputSource());
00051   } else {
00052     // "inputSource" is the original WAV file source:
00053     wavSource = (WAVAudioFileSource*)inputSource;
00054   }
00055 
00056   unsigned seekSampleNumber = (unsigned)(seekNPT*fSamplingFrequency);
00057   unsigned seekByteNumber = (seekSampleNumber*fNumChannels*fBitsPerSample)/8;
00058 
00059   unsigned numDurationSamples = (unsigned)(streamDuration*fSamplingFrequency);
00060   unsigned numDurationBytes = (numDurationSamples*fNumChannels*fBitsPerSample)/8;
00061   numBytes = (u_int64_t)numDurationBytes;
00062 
00063   wavSource->seekToPCMByte(seekByteNumber, numDurationBytes);
00064 }
00065 
00066 void WAVAudioFileServerMediaSubsession
00067 ::setStreamSourceScale(FramedSource* inputSource, float scale) {
00068   int iScale = (int)scale;
00069   WAVAudioFileSource* wavSource;
00070   if (fBitsPerSample == 16) {
00071     // "inputSource" is a filter; its input source is the original WAV file source:
00072     wavSource = (WAVAudioFileSource*)(((FramedFilter*)inputSource)->inputSource());
00073   } else {
00074     // "inputSource" is the original WAV file source:
00075     wavSource = (WAVAudioFileSource*)inputSource;
00076   }
00077 
00078   wavSource->setScaleFactor(iScale);
00079 }
00080 
00081 FramedSource* WAVAudioFileServerMediaSubsession
00082 ::createNewStreamSource(unsigned /*clientSessionId*/, unsigned& estBitrate) {
00083   FramedSource* resultSource = NULL;
00084   do {
00085     WAVAudioFileSource* wavSource
00086       = WAVAudioFileSource::createNew(envir(), fFileName);
00087     if (wavSource == NULL) break;
00088 
00089     // Get attributes of the audio source:
00090 
00091     fAudioFormat = wavSource->getAudioFormat();
00092     fBitsPerSample = wavSource->bitsPerSample();
00093     if (!(fBitsPerSample == 4 || fBitsPerSample == 8 || fBitsPerSample == 16)) {
00094       envir() << "The input file contains " << fBitsPerSample << " bit-per-sample audio, which we don't handle\n";
00095       break;
00096     }
00097     fSamplingFrequency = wavSource->samplingFrequency();
00098     fNumChannels = wavSource->numChannels();
00099     unsigned bitsPerSecond
00100       = fSamplingFrequency*fBitsPerSample*fNumChannels;
00101 
00102     fFileDuration = (float)((8.0*wavSource->numPCMBytes())
00103       /(fSamplingFrequency*fNumChannels*fBitsPerSample));
00104 
00105     // Add in any filter necessary to transform the data prior to streaming:
00106     if (fBitsPerSample == 16) {
00107       // Note that samples in the WAV audio file are in little-endian order.
00108       if (fConvertToULaw) {
00109         // Add a filter that converts from raw 16-bit PCM audio
00110         // to 8-bit u-law audio:
00111         resultSource
00112           = uLawFromPCMAudioSource::createNew(envir(), wavSource, 1/*little-endian*/);
00113         bitsPerSecond /= 2;
00114       } else {
00115         // Add a filter that converts from little-endian to network (big-endian) order:
00116         resultSource = EndianSwap16::createNew(envir(), wavSource);
00117       }
00118     } else { // fBitsPerSample == 8
00119       // Don't do any transformation; send the 8-bit PCM data 'as is':
00120       resultSource = wavSource;
00121     }
00122 
00123     estBitrate = (bitsPerSecond+500)/1000; // kbps
00124     return resultSource;
00125   } while (0);
00126 
00127   // An error occurred:
00128   Medium::close(resultSource);
00129   return NULL;
00130 }
00131 
00132 RTPSink* WAVAudioFileServerMediaSubsession
00133 ::createNewRTPSink(Groupsock* rtpGroupsock,
00134                    unsigned char rtpPayloadTypeIfDynamic,
00135                    FramedSource* /*inputSource*/) {
00136   do {
00137     char const* mimeType;
00138     unsigned char payloadFormatCode;
00139     if (fAudioFormat == WA_PCM) {
00140       if (fBitsPerSample == 16) {
00141         if (fConvertToULaw) {
00142           mimeType = "PCMU";
00143           if (fSamplingFrequency == 8000 && fNumChannels == 1) {
00144             payloadFormatCode = 0; // a static RTP payload type
00145           } else {
00146             payloadFormatCode = rtpPayloadTypeIfDynamic;
00147           }
00148         } else {
00149           mimeType = "L16";
00150           if (fSamplingFrequency == 44100 && fNumChannels == 2) {
00151             payloadFormatCode = 10; // a static RTP payload type
00152           } else if (fSamplingFrequency == 44100 && fNumChannels == 1) {
00153             payloadFormatCode = 11; // a static RTP payload type
00154           } else {
00155             payloadFormatCode = rtpPayloadTypeIfDynamic;
00156           }
00157         }
00158       } else { // fBitsPerSample == 8
00159         mimeType = "L8";
00160         payloadFormatCode = rtpPayloadTypeIfDynamic;
00161       }
00162     } else if (fAudioFormat == WA_PCMU) {
00163       mimeType = "PCMU";
00164       if (fSamplingFrequency == 8000 && fNumChannels == 1) {
00165         payloadFormatCode = 0; // a static RTP payload type
00166       } else {
00167         payloadFormatCode = rtpPayloadTypeIfDynamic;
00168       }
00169     } else if (fAudioFormat == WA_PCMA) {
00170       mimeType = "PCMA";
00171       if (fSamplingFrequency == 8000 && fNumChannels == 1) {
00172         payloadFormatCode = 8; // a static RTP payload type
00173       } else {
00174         payloadFormatCode = rtpPayloadTypeIfDynamic;
00175       }
00176     } else if (fAudioFormat == WA_IMA_ADPCM) {
00177       mimeType = "DVI4";
00178       payloadFormatCode = rtpPayloadTypeIfDynamic; // by default; could be changed below:
00179       // Use a static payload type, if one is defined:
00180       if (fNumChannels == 1) {
00181         if (fSamplingFrequency == 8000) {
00182           payloadFormatCode = 5; // a static RTP payload type
00183         } else if (fSamplingFrequency == 16000) {
00184           payloadFormatCode = 6; // a static RTP payload type
00185         } else if (fSamplingFrequency == 11025) {
00186           payloadFormatCode = 16; // a static RTP payload type
00187         } else if (fSamplingFrequency == 22050) {
00188           payloadFormatCode = 17; // a static RTP payload type
00189         }
00190       }
00191     } else { //unknown format
00192                 break;
00193         }
00194 
00195     return SimpleRTPSink::createNew(envir(), rtpGroupsock,
00196                                     payloadFormatCode, fSamplingFrequency,
00197                                     "audio", mimeType, fNumChannels);
00198   } while (0);
00199 
00200   // An error occurred:
00201   return NULL;
00202 }
00203 
00204 void WAVAudioFileServerMediaSubsession::testScaleFactor(float& scale) {
00205   if (fFileDuration <= 0.0) {
00206     // The file is non-seekable, so is probably a live input source.
00207     // We don't support scale factors other than 1
00208     scale = 1;
00209   } else {
00210     // We support any integral scale, other than 0
00211     int iScale = scale < 0.0 ? (int)(scale - 0.5) : (int)(scale + 0.5); // round
00212     if (iScale == 0) iScale = 1;
00213     scale = (float)iScale;
00214   }
00215 }
00216 
00217 float WAVAudioFileServerMediaSubsession::duration() const {
00218   return fFileDuration;
00219 }

Generated on Thu May 17 07:11:47 2012 for live by  doxygen 1.5.2