Boolean RTPInterface::sendPacket(unsignedchar* packet, unsigned packetSize){ Boolean success = True; // we'll return False instead if any of the sends fail // Normal case: Send as a UDP packet: if (!fGS->output(envir(), packet, packetSize)) success = False;
// Also, send over each of our TCP sockets: tcpStreamRecord* nextStream; for (tcpStreamRecord* stream = fTCPStreams; stream != NULL; stream = nextStream) { nextStream = stream->fNext; // Set this now, in case the following deletes "stream": if (!sendRTPorRTCPPacketOverTCP(packet, packetSize, stream->fStreamSocketNum, stream->fStreamChannelId)) { success = False; } } return success; }
Boolean RTPInterface::sendRTPorRTCPPacketOverTCP(u_int8_t* packet, unsigned packetSize, int socketNum, unsignedchar streamChannelId){ #ifdef DEBUG_SEND fprintf(stderr, "sendRTPorRTCPPacketOverTCP: %d bytes over channel %d (socket %d)\n", packetSize, streamChannelId, socketNum); fflush(stderr); #endif // Send a RTP/RTCP packet over TCP, using the encoding defined in RFC 2326, section 10.12: // $<streamChannelId><packetSize><packet> // (If the initial "send()" of '$<streamChannelId><packetSize>' succeeds, then we force // the subsequent "send()" for the <packet> data to succeed, even if we have to do so with // a blocking "send()".) do { u_int8_t framingHeader[4]; framingHeader[0] = '$'; framingHeader[1] = streamChannelId; framingHeader[2] = (u_int8_t) ((packetSize&0xFF00)>>8); framingHeader[3] = (u_int8_t) (packetSize&0xFF); if (!sendDataOverTCP(socketNum, framingHeader, 4, False)) break; if (!sendDataOverTCP(socketNum, packet, packetSize, True)) break; #ifdef DEBUG_SEND fprintf(stderr, "sendRTPorRTCPPacketOverTCP: completed\n"); fflush(stderr); #endif return True; } while (0); #ifdef DEBUG_SEND fprintf(stderr, "sendRTPorRTCPPacketOverTCP: failed! (errno %d)\n", envir().getErrno()); fflush(stderr); #endif return False; }
Boolean RTPInterface::sendDataOverTCP(int socketNum, u_int8_tconst* data, unsigned dataSize, Boolean forceSendToSucceed){ int sendResult = send(socketNum, (charconst*)data, dataSize, 0/*flags*/); if (sendResult < (int)dataSize) { // The TCP send() failed - at least partially.
unsigned numBytesSentSoFar = sendResult < 0 ? 0 : (unsigned)sendResult; if (numBytesSentSoFar > 0 || (forceSendToSucceed && envir().getErrno() == EAGAIN)) { // The OS's TCP send buffer has filled up (because the stream's bitrate has exceeded // the capacity of the TCP connection!). // Force this data write to succeed, by blocking if necessary until it does: unsigned numBytesRemainingToSend = dataSize - numBytesSentSoFar; #ifdef DEBUG_SEND fprintf(stderr, "sendDataOverTCP: resending %d-byte send (blocking)\n", numBytesRemainingToSend); fflush(stderr); #endif makeSocketBlocking(socketNum, RTPINTERFACE_BLOCKING_WRITE_TIMEOUT_MS); sendResult = send(socketNum, (charconst*)(&data[numBytesSentSoFar]), numBytesRemainingToSend, 0/*flags*/); if ((unsigned)sendResult != numBytesRemainingToSend) { // The blocking "send()" failed, or timed out. In either case, we assume that the // TCP connection has failed (or is 'hanging' indefinitely), and we stop using it // (for both RTP and RTP). // (If we kept using the socket here, the RTP or RTCP packet write would be in an // incomplete, inconsistent state.) #ifdef DEBUG_SEND fprintf(stderr, "sendDataOverTCP: blocking send() failed (delivering %d bytes out of %d); closing socket %d\n", sendResult, numBytesRemainingToSend, socketNum); fflush(stderr); #endif removeStreamSocket(socketNum, 0xFF); return False; } makeSocketNonBlocking(socketNum);
return True; } elseif (sendResult < 0 && envir().getErrno() != EAGAIN) { // Because the "send()" call failed, assume that the socket is now unusable, so stop // using it (for both RTP and RTCP): removeStreamSocket(socketNum, 0xFF); }
Boolean RTPInterface::sendRTPorRTCPPacketOverTCP(u_int8_t* packet, unsigned packetSize, int socketNum, unsignedchar streamChannelId){ #ifdef DEBUG_SEND fprintf(stderr, "sendRTPorRTCPPacketOverTCP: %d bytes over channel %d (socket %d)\n", packetSize, streamChannelId, socketNum); fflush(stderr); #endif // Send a RTP/RTCP packet over TCP, using the encoding defined in RFC 2326, section 10.12: // $<streamChannelId><packetSize><packet> // (If the initial "send()" of '$<streamChannelId><packetSize>' succeeds, then we force // the subsequent "send()" for the <packet> data to succeed, even if we have to do so with // a blocking "send()".) do { u_int8_t framingHeader[4]; framingHeader[0] = '$'; framingHeader[1] = streamChannelId; framingHeader[2] = (u_int8_t) ((packetSize&0xFF00)>>8); framingHeader[3] = (u_int8_t) (packetSize&0xFF); #if USE_IOV structiovec iov[2]; iov[0].iov_base = framingHeader; iov[0].iov_len = 4; iov[1].iov_base = packet; iov[1].iov_len = packetSize; if (writev(socketNum, iov, 2) <= 0) break; #else if (!sendDataOverTCP(socketNum, framingHeader, 4, False)) break; if (!sendDataOverTCP(socketNum, packet, packetSize, True)) break; #endif #ifdef DEBUG_SEND fprintf(stderr, "sendRTPorRTCPPacketOverTCP: completed\n"); fflush(stderr); #endif
#ifndef RTP_PAYLOAD_MAX_SIZE #define RTP_PAYLOAD_MAX_SIZE 1456 // Default max packet size (1500, minus allowance for IP, UDP, UMTP headers) // (Also, make it a multiple of 4 bytes, just in case that matters.) #endif #ifndef RTP_PAYLOAD_PREFERRED_SIZE #define RTP_PAYLOAD_PREFERRED_SIZE ((RTP_PAYLOAD_MAX_SIZE) < 1000 ? (RTP_PAYLOAD_MAX_SIZE) : 1000) #endif