RtpTransmitter.cxx
上传用户:sy_wanhua
上传日期:2013-07-25
资源大小:3048k
文件大小:13k
- /* ====================================================================
- * The Vovida Software License, Version 1.0
- *
- * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. The names "VOCAL", "Vovida Open Communication Application Library",
- * and "Vovida Open Communication Application Library (VOCAL)" must
- * not be used to endorse or promote products derived from this
- * software without prior written permission. For written
- * permission, please contact vocal@vovida.org.
- *
- * 4. Products derived from this software may not be called "VOCAL", nor
- * may "VOCAL" appear in their name, without prior written
- * permission of Vovida Networks, Inc.
- *
- * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
- * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
- * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
- * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
- * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * ====================================================================
- *
- * This software consists of voluntary contributions made by Vovida
- * Networks, Inc. and many individuals on behalf of Vovida Networks,
- * Inc. For more information on Vovida Networks, Inc., please see
- * <http://www.vovida.org/>.
- *
- */
- static const char* const RtpTransmitter_cxx_Version =
- "$Id: RtpTransmitter.cxx,v 1.14 2001/05/07 19:12:50 kle Exp $";
- #include <iostream>
- #include <stdlib.h>
- #include <stdio.h>
- #include <assert.h>
- #include <time.h>
- #include <sys/types.h>
- #include "vtypes.h"
- #include <unistd.h>
- #include <string.h>
- // network socket
- //#include <netinet/in.h> // struct socketaddr_in
- //#include <sys/socket.h>
- //#include <netdb.h>
- #include "cpLog.h"
- #include "vsock.hxx"
- #include "NetworkAddress.h"
- #include "NtpTime.hxx"
- #include "rtpTypes.h"
- #include "rtpTools.hxx"
- #include "Rtp.hxx"
- #include "rtpCodec.h"
- /* ----------------------------------------------------------------- */
- /* --- RtpTransmitter Constructor ---------------------------------- */
- /* ----------------------------------------------------------------- */
- RtpTransmitter::RtpTransmitter (const char* remoteHost,
- int remoteMinPort, int remoteMaxPort,
- RtpPayloadType newApiFormat,
- RtpPayloadType newNetworkFormat,
- RtpReceiver* receiver)
- {
- NetworkAddress netAddress;
- if( remoteHost )
- {
- netAddress.setHostName(remoteHost);
- netAddress.setPort(remoteMinPort);
- }
- if( receiver )
- {
- myStack = receiver->getUdpStack();
- myStack->setDestination(&netAddress);
- remoteAddr = netAddress;
- // assume that RTP will always use send instead of sendto
- // so that it can only receive from/send to the same remote port
- // myStack->connectPorts();
- freeStack = false;
- }
- else
- {
- myStack = new UdpStack (&netAddress, remoteMinPort,
- remoteMaxPort, sendonly) ;
- remoteAddr = netAddress;
- // myStack->connectPorts();
- freeStack = true;
- }
- constructRtpTransmitter (newApiFormat, newNetworkFormat);
- }
- RtpTransmitter::RtpTransmitter (const char* remoteHost, int remotePort,
- RtpPayloadType newApiFormat,
- RtpPayloadType newNetworkFormat,
- RtpReceiver* receiver)
- {
- NetworkAddress netAddress;
- if( remoteHost )
- {
- netAddress.setHostName(remoteHost);
- netAddress.setPort(remotePort);
- }
- if( receiver )
- {
- myStack = receiver->getUdpStack();
- myStack->setDestination(&netAddress);
- remoteAddr = netAddress;
- // myStack->connectPorts();
- freeStack = false;
- }
- else
- {
- myStack = new UdpStack (&netAddress, remotePort,
- remotePort, sendonly) ;
- remoteAddr = netAddress;
- // myStack->connectPorts();
- freeStack = true;
- }
- constructRtpTransmitter (newApiFormat, newNetworkFormat);
- }
- void RtpTransmitter::constructRtpTransmitter (RtpPayloadType newApiFormat,
- RtpPayloadType newNetworkFormat)
- {
- outPos = 0;
- recPos = 0;
- memset (outBuff, 0, OUT_BUFFER_SIZE);
- // set format and baseSampleRate
- setApiFormat(newApiFormat, 160, 0, NULL, false);
- setNetworkFormat(newNetworkFormat, 160, 0, NULL, false);
- // set private variables
- ssrc = generateSRC();
- seedNtpTime = getNtpTime();
- seedRtpTime = generate32();
- prevNtpTime = seedNtpTime;
- prevRtpTime = seedRtpTime;
- prevSequence = generate32();
- // set counters
- packetSent = 0;
- payloadSent = 0;
- cpLog(LOG_DEBUG_STACK, "Constructed ssrc = %d", ssrc);
- }
- RtpTransmitter::~RtpTransmitter ()
- {
- if( freeStack)
- {
- delete myStack;
- myStack = NULL;
- }
- cpLog(LOG_DEBUG_STACK, "Closed ssrc = %d", ssrc);
- }
- void
- RtpTransmitter::setRemoteAddr (const NetworkAddress& theAddr)
- {
- remoteAddr = theAddr;
- }
- /* --- send packet functions --------------------------------------- */
- RtpPacket* RtpTransmitter::createPacket (int npadSize, int csrc_count)
- {
- // create packet
- RtpPacket* packet = new RtpPacket (apiFormat_payloadSize, npadSize, csrc_count);
- assert (packet);
- // load packet
- packet->setSSRC (ssrc);
- packet->setPayloadType (apiFormat);
- return packet;
- }
- // takes api RTP packet and send to network
- // assumes payload size is already set
- int RtpTransmitter::transmit(RtpPacket* packet, bool eventFlag )
- {
- if( !packet )
- {
- cpLog(LOG_ERR,"Attempting to transmit a NULL rtp packet");
- return -1;
- }
- RtpPacket* p = packet;
- // convert codec
- if( p->getPayloadType() != networkFormat && !eventFlag )
- {
- #ifndef __sparc
- // replace p with a new packet
- p = convertRtpPacketCodec (networkFormat, packet);
- assert (packet->getSequence() == p->getSequence());
- #endif
- }
- rtp_htonl(p);
- // finish packet
- if( p->getPayloadUsage() != networkFormat_payloadSize && !eventFlag )
- {
- cpLog(LOG_DEBUG_STACK,"Sending mismatched packetSize(%d) to networkFormatSize(%d)",
- p->getPayloadUsage(), networkFormat_payloadSize);
- }
- if( !p->timestampSet )
- p->setRtpTime( prevRtpTime + network_pktSampleSize );
- if( !p->sequenceSet )
- p->setSequence( prevSequence + 1 );
- if( p->getPayloadUsage() < 0 || p->getPayloadUsage() > 1012 )
- {
- cpLog(LOG_DEBUG_STACK,"Invalid data packet size %d", p->getPayloadUsage());
- return -1;
- }
- //set marker once
- if( markerOnce )
- {
- cpLog( LOG_DEBUG_STACK,"Setting marker bit once");
- p->setMarkerFlag(1);
- markerOnce = false;
- }
- // for packet reuse
- p->timestampSet = false;
- p->sequenceSet = false;
- // transmit packet
- try
- {
- myStack->transmitTo( (char*)p->getHeader(), p->getTotalUsage(), &remoteAddr );
- }
- catch( UdpStackExceptionConectionRefused& e )
- {
- cpLog (LOG_ERR,"Connection refused");
- return -1;
- }
- // update counters
- packetSent++;
- prevSequence = p->getSequence();
- if( !eventFlag )
- {
- payloadSent += p->getPayloadUsage();
- prevNtpTime = getNtpTime();
- prevRtpTime = p->getRtpTime();
- }
- // set up return value
- int result = p->getPayloadUsage();
- // delete newly created packet
- if( ( p != packet ) && p )
- {
- delete p; p = NULL;
- }
- // exit with success
- return result;
- }
- // takes rawdata, buffers it, and send network packets
- int RtpTransmitter::transmitRaw (char* data, int len)
- {
- int len1;
- // convert codec
- if( apiFormat != networkFormat)
- {
- char* buffer = new char[1012];
- len = convertCodec(apiFormat, networkFormat, data, buffer, len);
- data = buffer;
- }
- // write packet to output buffer
- if( (outPos + len) < OUT_BUFFER_SIZE)
- {
- memcpy (outBuff + outPos, data, len);
- outPos += len;
- }
- else
- {
- // circular memory copy
- len1 = OUT_BUFFER_SIZE - outPos;
- memcpy (outBuff + outPos, data, len1);
- memcpy (outBuff, data + len1, len - len1);
- outPos = len - len1;
- }
- // check if enough data to send out packet
- int packetSize = networkFormat_payloadSize;
- if( (outPos == 0) && (recPos == 0) )
- {
- cpLog (LOG_DEBUG_STACK, "Buffer is empty");
- return 0;
- }
- if( ((outPos + OUT_BUFFER_SIZE - recPos) % OUT_BUFFER_SIZE) < packetSize )
- {
- cpLog (LOG_DEBUG_STACK, "Not enough data for a network packet. Need %d",
- packetSize);
- return 0;
- }
- // send out packets from buffer
- int result = 0;
- // create packet
- RtpPacket* p = new RtpPacket (networkFormat_payloadSize);
- assert (p);
- p->setSSRC (ssrc);
- p->setPayloadType (networkFormat);
- p->setPayloadUsage (packetSize);
- //fill packets
- while ( ((outPos + OUT_BUFFER_SIZE - recPos) % OUT_BUFFER_SIZE) >= packetSize )
- {
- if( (recPos + packetSize) < OUT_BUFFER_SIZE)
- {
- memcpy (p->getPayloadLoc(), outBuff + recPos, packetSize);
- recPos += packetSize;
- }
- else
- {
- // circular memory write
- len1 = OUT_BUFFER_SIZE - recPos;
- memcpy (p->getPayloadLoc(), outBuff + recPos, len1);
- memcpy (p->getPayloadLoc() + len1, outBuff, packetSize - len1);
- recPos = packetSize - len1;
- }
- // finish packet
- result += transmit(p);
- }
- if( p) delete p;
- p = NULL;
- // exit with success
- return result;
- }
- void RtpTransmitter::setNetworkFormat (RtpPayloadType newtype, int no_samples, int packetSize,
- RtpPacket* p, bool print)
- {
- networkFormat = newtype;
- network_pktSampleSize = no_samples;
- networkFormat_perSampleSize = 1;
- switch (newtype)
- {
- case rtpPayloadPCMU:
- case rtpPayloadPCMA:
- if( print) cpLog(LOG_DEBUG, "Setting network format to: PCMU %d", no_samples);
- networkFormat_clockRate = 8000;
- break;
- case rtpPayloadL16_mono:
- if( print) cpLog(LOG_DEBUG, "Setting network format to: L16 %d", no_samples);
- networkFormat_clockRate = 44100;
- networkFormat_perSampleSize = 2;
- break;
- case rtpPayloadG729:
- if( print) cpLog(LOG_DEBUG, "Setting network format to: G729 %d", no_samples);
- networkFormat_clockRate = 8000;
- break;
- default:
- cpLog(LOG_ERR, "Unknown networkFormat: codec(%d) samples(%d) packetSize(%d)",
- (int)networkFormat, no_samples, packetSize);
- networkFormat_clockRate = 8000;
- }
- if( p )
- networkFormat_payloadSize = p->getPayloadUsage();
- else
- networkFormat_payloadSize = network_pktSampleSize * networkFormat_perSampleSize;
- if( packetSize != 0 )
- networkFormat_payloadSize = packetSize;
- }
- void RtpTransmitter::setApiFormat (RtpPayloadType newtype, int no_samples, int packetSize,
- RtpPacket* p, bool print)
- {
- apiFormat = newtype;
- api_pktSampleSize = no_samples;
- apiFormat_perSampleSize = 1;
- switch( newtype )
- {
- case rtpPayloadPCMU:
- case rtpPayloadPCMA:
- if( print ) cpLog(LOG_DEBUG, "Setting api format to: PCMU %d", no_samples);
- apiFormat_clockRate = 8000;
- break;
- case rtpPayloadL16_mono:
- if( print ) cpLog(LOG_DEBUG, "Setting api format to: L16 %d", no_samples);
- apiFormat_clockRate = 44100;
- apiFormat_perSampleSize = 2;
- break;
- case rtpPayloadG729:
- if( print ) cpLog(LOG_DEBUG, "Setting api format to: G729 %d", no_samples);
- apiFormat_clockRate = 8000;
- break;
- default:
- cpLog(LOG_ERR, "Unknown apiFormat: codec(%d) samples(%d) packetSize(%d)",
- (int)apiFormat, no_samples, packetSize);
- apiFormat_clockRate = 8000;
- }
- if( p )
- apiFormat_payloadSize = p->getPayloadUsage();
- else
- apiFormat_payloadSize = api_pktSampleSize * apiFormat_perSampleSize;
- if( packetSize != 0 )
- apiFormat_payloadSize = packetSize;
- }