2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-01-24 17:16:59 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-05-29 14:27:38 +00:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
#include <string.h>
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-04-07 15:36:45 -07:00
|
|
|
#include "webrtc/base/logging.h"
|
2015-10-20 23:00:48 -07:00
|
|
|
#include "webrtc/base/trace_event.h"
|
2015-11-04 08:31:52 +01:00
|
|
|
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
|
2015-03-17 16:42:49 +00:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
|
2015-12-07 10:26:18 +01:00
|
|
|
#include "webrtc/system_wrappers/include/tick_util.h"
|
2013-04-09 19:54:10 +00:00
|
|
|
|
2011-07-07 08:21:25 +00:00
|
|
|
namespace webrtc {
|
2015-02-12 12:20:08 +00:00
|
|
|
|
|
|
|
|
static const int kDtmfFrequencyHz = 8000;
|
|
|
|
|
|
2016-03-15 11:41:53 -07:00
|
|
|
RTPSenderAudio::RTPSenderAudio(Clock* clock, RTPSender* rtpSender)
|
2015-09-17 23:03:57 +02:00
|
|
|
: _clock(clock),
|
|
|
|
|
_rtpSender(rtpSender),
|
|
|
|
|
_packetSizeSamples(160),
|
|
|
|
|
_dtmfEventIsOn(false),
|
|
|
|
|
_dtmfEventFirstPacketSent(false),
|
|
|
|
|
_dtmfPayloadType(-1),
|
|
|
|
|
_dtmfTimestamp(0),
|
|
|
|
|
_dtmfKey(0),
|
|
|
|
|
_dtmfLengthSamples(0),
|
|
|
|
|
_dtmfLevel(0),
|
|
|
|
|
_dtmfTimeLastSent(0),
|
|
|
|
|
_dtmfTimestampLastSent(0),
|
|
|
|
|
_REDPayloadType(-1),
|
|
|
|
|
_inbandVADactive(false),
|
|
|
|
|
_cngNBPayloadType(-1),
|
|
|
|
|
_cngWBPayloadType(-1),
|
|
|
|
|
_cngSWBPayloadType(-1),
|
|
|
|
|
_cngFBPayloadType(-1),
|
|
|
|
|
_lastPayloadType(-1),
|
|
|
|
|
_audioLevel_dBov(0) {}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
RTPSenderAudio::~RTPSenderAudio() {}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-02-12 12:20:08 +00:00
|
|
|
int RTPSenderAudio::AudioFrequency() const {
|
|
|
|
|
return kDtmfFrequencyHz;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-02-12 12:20:08 +00:00
|
|
|
// set audio packet size, used to determine when it's time to send a DTMF packet
|
|
|
|
|
// in silence (CNG)
|
2015-12-10 02:39:40 -08:00
|
|
|
int32_t RTPSenderAudio::SetAudioPacketSize(uint16_t packetSizeSamples) {
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&_sendAudioCritsect);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
_packetSizeSamples = packetSizeSamples;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
int32_t RTPSenderAudio::RegisterAudioPayload(
|
2012-01-24 17:16:59 +00:00
|
|
|
const char payloadName[RTP_PAYLOAD_NAME_SIZE],
|
2013-04-08 11:08:41 +00:00
|
|
|
const int8_t payloadType,
|
|
|
|
|
const uint32_t frequency,
|
Convert channel counts to size_t.
IIRC, this was originally requested by ajm during review of the other size_t conversions I did over the past year, and I agreed it made sense, but wanted to do it separately since those changes were already gargantuan.
BUG=chromium:81439
TEST=none
R=henrik.lundin@webrtc.org, henrika@webrtc.org, kjellander@webrtc.org, minyue@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1316523002 .
Cr-Commit-Position: refs/heads/master@{#11229}
2016-01-12 16:26:35 -08:00
|
|
|
const size_t channels,
|
2013-04-08 11:08:41 +00:00
|
|
|
const uint32_t rate,
|
2015-12-15 02:54:47 -08:00
|
|
|
RtpUtility::Payload** payload) {
|
2014-07-08 12:10:51 +00:00
|
|
|
if (RtpUtility::StringCompare(payloadName, "cn", 2)) {
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&_sendAudioCritsect);
|
2012-01-24 17:16:59 +00:00
|
|
|
// we can have multiple CNG payload types
|
2015-02-12 12:20:08 +00:00
|
|
|
switch (frequency) {
|
|
|
|
|
case 8000:
|
|
|
|
|
_cngNBPayloadType = payloadType;
|
|
|
|
|
break;
|
|
|
|
|
case 16000:
|
|
|
|
|
_cngWBPayloadType = payloadType;
|
|
|
|
|
break;
|
|
|
|
|
case 32000:
|
|
|
|
|
_cngSWBPayloadType = payloadType;
|
|
|
|
|
break;
|
|
|
|
|
case 48000:
|
|
|
|
|
_cngFBPayloadType = payloadType;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2015-02-12 12:20:08 +00:00
|
|
|
} else if (RtpUtility::StringCompare(payloadName, "telephone-event", 15)) {
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&_sendAudioCritsect);
|
2012-01-24 17:16:59 +00:00
|
|
|
// Don't add it to the list
|
|
|
|
|
// we dont want to allow send with a DTMF payloadtype
|
|
|
|
|
_dtmfPayloadType = payloadType;
|
2011-07-07 08:21:25 +00:00
|
|
|
return 0;
|
2012-01-24 17:16:59 +00:00
|
|
|
// The default timestamp rate is 8000 Hz, but other rates may be defined.
|
|
|
|
|
}
|
2015-12-15 02:54:47 -08:00
|
|
|
*payload = new RtpUtility::Payload;
|
|
|
|
|
(*payload)->typeSpecific.Audio.frequency = frequency;
|
|
|
|
|
(*payload)->typeSpecific.Audio.channels = channels;
|
|
|
|
|
(*payload)->typeSpecific.Audio.rate = rate;
|
|
|
|
|
(*payload)->audio = true;
|
|
|
|
|
(*payload)->name[RTP_PAYLOAD_NAME_SIZE - 1] = '\0';
|
|
|
|
|
strncpy((*payload)->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
|
2012-01-24 17:16:59 +00:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
bool RTPSenderAudio::MarkerBit(FrameType frameType, int8_t payload_type) {
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&_sendAudioCritsect);
|
2015-12-10 02:39:40 -08:00
|
|
|
// for audio true for first packet in a speech burst
|
|
|
|
|
bool markerBit = false;
|
|
|
|
|
if (_lastPayloadType != payload_type) {
|
|
|
|
|
if (payload_type != -1 && (_cngNBPayloadType == payload_type ||
|
|
|
|
|
_cngWBPayloadType == payload_type ||
|
|
|
|
|
_cngSWBPayloadType == payload_type ||
|
|
|
|
|
_cngFBPayloadType == payload_type)) {
|
|
|
|
|
// Only set a marker bit when we change payload type to a non CNG
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2015-02-12 12:20:08 +00:00
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
// payload_type differ
|
|
|
|
|
if (_lastPayloadType == -1) {
|
|
|
|
|
if (frameType != kAudioFrameCN) {
|
|
|
|
|
// first packet and NOT CNG
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
// first packet and CNG
|
|
|
|
|
_inbandVADactive = true;
|
|
|
|
|
return false;
|
2015-02-12 12:20:08 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
// not first packet AND
|
|
|
|
|
// not CNG AND
|
|
|
|
|
// payload_type changed
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
// set a marker bit when we change payload type
|
|
|
|
|
markerBit = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// For G.723 G.729, AMR etc we can have inband VAD
|
|
|
|
|
if (frameType == kAudioFrameCN) {
|
|
|
|
|
_inbandVADactive = true;
|
|
|
|
|
} else if (_inbandVADactive) {
|
|
|
|
|
_inbandVADactive = false;
|
|
|
|
|
markerBit = true;
|
|
|
|
|
}
|
|
|
|
|
return markerBit;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
int32_t RTPSenderAudio::SendAudio(FrameType frameType,
|
|
|
|
|
int8_t payloadType,
|
|
|
|
|
uint32_t captureTimeStamp,
|
|
|
|
|
const uint8_t* payloadData,
|
|
|
|
|
size_t dataSize,
|
|
|
|
|
const RTPFragmentationHeader* fragmentation) {
|
2012-01-17 11:42:02 +00:00
|
|
|
// TODO(pwestin) Breakup function in smaller functions.
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
size_t payloadSize = dataSize;
|
|
|
|
|
size_t maxPayloadLength = _rtpSender->MaxPayloadLength();
|
2013-04-08 11:08:41 +00:00
|
|
|
uint16_t dtmfLengthMS = 0;
|
|
|
|
|
uint8_t key = 0;
|
2015-02-12 12:20:08 +00:00
|
|
|
int red_payload_type;
|
|
|
|
|
uint8_t audio_level_dbov;
|
|
|
|
|
int8_t dtmf_payload_type;
|
|
|
|
|
uint16_t packet_size_samples;
|
|
|
|
|
{
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&_sendAudioCritsect);
|
2015-02-12 12:20:08 +00:00
|
|
|
red_payload_type = _REDPayloadType;
|
|
|
|
|
audio_level_dbov = _audioLevel_dBov;
|
|
|
|
|
dtmf_payload_type = _dtmfPayloadType;
|
|
|
|
|
packet_size_samples = _packetSizeSamples;
|
|
|
|
|
}
|
2012-01-17 11:42:02 +00:00
|
|
|
|
|
|
|
|
// Check if we have pending DTMFs to send
|
|
|
|
|
if (!_dtmfEventIsOn && PendingDTMF()) {
|
2015-12-10 02:39:40 -08:00
|
|
|
int64_t delaySinceLastDTMF =
|
|
|
|
|
_clock->TimeInMilliseconds() - _dtmfTimeLastSent;
|
2012-01-17 11:42:02 +00:00
|
|
|
|
|
|
|
|
if (delaySinceLastDTMF > 100) {
|
|
|
|
|
// New tone to play
|
|
|
|
|
_dtmfTimestamp = captureTimeStamp;
|
|
|
|
|
if (NextDTMF(&key, &dtmfLengthMS, &_dtmfLevel) >= 0) {
|
|
|
|
|
_dtmfEventFirstPacketSent = false;
|
|
|
|
|
_dtmfKey = key;
|
2015-02-12 12:20:08 +00:00
|
|
|
_dtmfLengthSamples = (kDtmfFrequencyHz / 1000) * dtmfLengthMS;
|
2012-01-17 11:42:02 +00:00
|
|
|
_dtmfEventIsOn = true;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-01-17 11:42:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// A source MAY send events and coded audio packets for the same time
|
|
|
|
|
// but we don't support it
|
2015-02-12 12:20:08 +00:00
|
|
|
if (_dtmfEventIsOn) {
|
2015-10-19 02:39:06 -07:00
|
|
|
if (frameType == kEmptyFrame) {
|
|
|
|
|
// kEmptyFrame is used to drive the DTMF when in CN mode
|
2015-02-12 12:20:08 +00:00
|
|
|
// it can be triggered more frequently than we want to send the
|
|
|
|
|
// DTMF packets.
|
|
|
|
|
if (packet_size_samples > (captureTimeStamp - _dtmfTimestampLastSent)) {
|
|
|
|
|
// not time to send yet
|
|
|
|
|
return 0;
|
2012-01-17 11:42:02 +00:00
|
|
|
}
|
2015-02-12 12:20:08 +00:00
|
|
|
}
|
|
|
|
|
_dtmfTimestampLastSent = captureTimeStamp;
|
|
|
|
|
uint32_t dtmfDurationSamples = captureTimeStamp - _dtmfTimestamp;
|
|
|
|
|
bool ended = false;
|
|
|
|
|
bool send = true;
|
|
|
|
|
|
|
|
|
|
if (_dtmfLengthSamples > dtmfDurationSamples) {
|
|
|
|
|
if (dtmfDurationSamples <= 0) {
|
|
|
|
|
// Skip send packet at start, since we shouldn't use duration 0
|
|
|
|
|
send = false;
|
2012-01-17 11:42:02 +00:00
|
|
|
}
|
2015-02-12 12:20:08 +00:00
|
|
|
} else {
|
|
|
|
|
ended = true;
|
|
|
|
|
_dtmfEventIsOn = false;
|
|
|
|
|
_dtmfTimeLastSent = _clock->TimeInMilliseconds();
|
|
|
|
|
}
|
|
|
|
|
if (send) {
|
|
|
|
|
if (dtmfDurationSamples > 0xffff) {
|
|
|
|
|
// RFC 4733 2.5.2.3 Long-Duration Events
|
|
|
|
|
SendTelephoneEventPacket(ended, dtmf_payload_type, _dtmfTimestamp,
|
|
|
|
|
static_cast<uint16_t>(0xffff), false);
|
|
|
|
|
|
|
|
|
|
// set new timestap for this segment
|
|
|
|
|
_dtmfTimestamp = captureTimeStamp;
|
|
|
|
|
dtmfDurationSamples -= 0xffff;
|
|
|
|
|
_dtmfLengthSamples -= 0xffff;
|
|
|
|
|
|
|
|
|
|
return SendTelephoneEventPacket(
|
|
|
|
|
ended, dtmf_payload_type, _dtmfTimestamp,
|
|
|
|
|
static_cast<uint16_t>(dtmfDurationSamples), false);
|
|
|
|
|
} else {
|
|
|
|
|
if (SendTelephoneEventPacket(ended, dtmf_payload_type, _dtmfTimestamp,
|
|
|
|
|
static_cast<uint16_t>(dtmfDurationSamples),
|
|
|
|
|
!_dtmfEventFirstPacketSent) != 0) {
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2015-02-12 12:20:08 +00:00
|
|
|
_dtmfEventFirstPacketSent = true;
|
|
|
|
|
return 0;
|
2012-01-17 11:42:02 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2015-02-12 12:20:08 +00:00
|
|
|
return 0;
|
2012-01-17 11:42:02 +00:00
|
|
|
}
|
|
|
|
|
if (payloadSize == 0 || payloadData == NULL) {
|
2015-10-19 02:39:06 -07:00
|
|
|
if (frameType == kEmptyFrame) {
|
2012-01-17 11:42:02 +00:00
|
|
|
// we don't send empty audio RTP packets
|
|
|
|
|
// no error since we use it to drive DTMF when we use VAD
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2013-04-08 11:08:41 +00:00
|
|
|
uint8_t dataBuffer[IP_PACKET_SIZE];
|
2012-01-17 11:42:02 +00:00
|
|
|
bool markerBit = MarkerBit(frameType, payloadType);
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
int32_t rtpHeaderLength = 0;
|
|
|
|
|
uint16_t timestampOffset = 0;
|
2012-01-17 11:42:02 +00:00
|
|
|
|
2015-02-12 12:20:08 +00:00
|
|
|
if (red_payload_type >= 0 && fragmentation && !markerBit &&
|
2012-01-17 11:42:02 +00:00
|
|
|
fragmentation->fragmentationVectorSize > 1) {
|
|
|
|
|
// have we configured RED? use its payload type
|
|
|
|
|
// we need to get the current timestamp to calc the diff
|
2013-04-08 11:08:41 +00:00
|
|
|
uint32_t oldTimeStamp = _rtpSender->Timestamp();
|
2015-02-12 12:20:08 +00:00
|
|
|
rtpHeaderLength = _rtpSender->BuildRTPheader(dataBuffer, red_payload_type,
|
2013-06-19 14:13:42 +00:00
|
|
|
markerBit, captureTimeStamp,
|
|
|
|
|
_clock->TimeInMilliseconds());
|
2012-01-17 11:42:02 +00:00
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
timestampOffset = uint16_t(_rtpSender->Timestamp() - oldTimeStamp);
|
2012-01-17 11:42:02 +00:00
|
|
|
} else {
|
|
|
|
|
rtpHeaderLength = _rtpSender->BuildRTPheader(dataBuffer, payloadType,
|
2013-06-19 14:13:42 +00:00
|
|
|
markerBit, captureTimeStamp,
|
|
|
|
|
_clock->TimeInMilliseconds());
|
2012-01-17 11:42:02 +00:00
|
|
|
}
|
|
|
|
|
if (rtpHeaderLength <= 0) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2014-03-06 23:49:08 +00:00
|
|
|
if (maxPayloadLength < (rtpHeaderLength + payloadSize)) {
|
|
|
|
|
// Too large payload buffer.
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2015-12-10 02:39:40 -08:00
|
|
|
if (red_payload_type >= 0 && // Have we configured RED?
|
|
|
|
|
fragmentation && fragmentation->fragmentationVectorSize > 1 &&
|
|
|
|
|
!markerBit) {
|
|
|
|
|
if (timestampOffset <= 0x3fff) {
|
|
|
|
|
if (fragmentation->fragmentationVectorSize != 2) {
|
|
|
|
|
// we only support 2 codecs when using RED
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
// only 0x80 if we have multiple blocks
|
|
|
|
|
dataBuffer[rtpHeaderLength++] =
|
|
|
|
|
0x80 + fragmentation->fragmentationPlType[1];
|
|
|
|
|
size_t blockLength = fragmentation->fragmentationLength[1];
|
2012-01-17 11:42:02 +00:00
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
// sanity blockLength
|
|
|
|
|
if (blockLength > 0x3ff) { // block length 10 bits 1023 bytes
|
|
|
|
|
return -1;
|
2012-01-17 11:42:02 +00:00
|
|
|
}
|
2015-12-10 02:39:40 -08:00
|
|
|
uint32_t REDheader = (timestampOffset << 10) + blockLength;
|
|
|
|
|
ByteWriter<uint32_t>::WriteBigEndian(dataBuffer + rtpHeaderLength,
|
|
|
|
|
REDheader);
|
|
|
|
|
rtpHeaderLength += 3;
|
|
|
|
|
|
|
|
|
|
dataBuffer[rtpHeaderLength++] = fragmentation->fragmentationPlType[0];
|
|
|
|
|
// copy the RED data
|
|
|
|
|
memcpy(dataBuffer + rtpHeaderLength,
|
|
|
|
|
payloadData + fragmentation->fragmentationOffset[1],
|
|
|
|
|
fragmentation->fragmentationLength[1]);
|
|
|
|
|
|
|
|
|
|
// copy the normal data
|
|
|
|
|
memcpy(
|
|
|
|
|
dataBuffer + rtpHeaderLength + fragmentation->fragmentationLength[1],
|
|
|
|
|
payloadData + fragmentation->fragmentationOffset[0],
|
|
|
|
|
fragmentation->fragmentationLength[0]);
|
|
|
|
|
|
|
|
|
|
payloadSize = fragmentation->fragmentationLength[0] +
|
|
|
|
|
fragmentation->fragmentationLength[1];
|
2012-01-17 11:42:02 +00:00
|
|
|
} else {
|
2015-12-10 02:39:40 -08:00
|
|
|
// silence for too long send only new data
|
|
|
|
|
dataBuffer[rtpHeaderLength++] = fragmentation->fragmentationPlType[0];
|
|
|
|
|
memcpy(dataBuffer + rtpHeaderLength,
|
|
|
|
|
payloadData + fragmentation->fragmentationOffset[0],
|
|
|
|
|
fragmentation->fragmentationLength[0]);
|
|
|
|
|
|
|
|
|
|
payloadSize = fragmentation->fragmentationLength[0];
|
2012-01-17 11:42:02 +00:00
|
|
|
}
|
2015-12-10 02:39:40 -08:00
|
|
|
} else {
|
|
|
|
|
if (fragmentation && fragmentation->fragmentationVectorSize > 0) {
|
|
|
|
|
// use the fragment info if we have one
|
|
|
|
|
dataBuffer[rtpHeaderLength++] = fragmentation->fragmentationPlType[0];
|
|
|
|
|
memcpy(dataBuffer + rtpHeaderLength,
|
|
|
|
|
payloadData + fragmentation->fragmentationOffset[0],
|
|
|
|
|
fragmentation->fragmentationLength[0]);
|
|
|
|
|
|
|
|
|
|
payloadSize = fragmentation->fragmentationLength[0];
|
|
|
|
|
} else {
|
|
|
|
|
memcpy(dataBuffer + rtpHeaderLength, payloadData, payloadSize);
|
2014-03-06 23:49:08 +00:00
|
|
|
}
|
2015-02-12 12:20:08 +00:00
|
|
|
}
|
2016-04-07 15:36:45 -07:00
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
{
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&_sendAudioCritsect);
|
2015-12-10 02:39:40 -08:00
|
|
|
_lastPayloadType = payloadType;
|
|
|
|
|
}
|
|
|
|
|
// Update audio level extension, if included.
|
|
|
|
|
size_t packetSize = payloadSize + rtpHeaderLength;
|
|
|
|
|
RtpUtility::RtpHeaderParser rtp_parser(dataBuffer, packetSize);
|
|
|
|
|
RTPHeader rtp_header;
|
2015-12-28 10:18:46 -08:00
|
|
|
rtp_parser.Parse(&rtp_header);
|
2015-12-10 02:39:40 -08:00
|
|
|
_rtpSender->UpdateAudioLevel(dataBuffer, packetSize, rtp_header,
|
|
|
|
|
(frameType == kAudioFrameSpeech),
|
|
|
|
|
audio_level_dbov);
|
|
|
|
|
TRACE_EVENT_ASYNC_END2("webrtc", "Audio", captureTimeStamp, "timestamp",
|
|
|
|
|
_rtpSender->Timestamp(), "seqnum",
|
|
|
|
|
_rtpSender->SequenceNumber());
|
2016-04-07 15:36:45 -07:00
|
|
|
int32_t send_result = _rtpSender->SendToNetwork(
|
|
|
|
|
dataBuffer, payloadSize, rtpHeaderLength,
|
|
|
|
|
TickTime::MillisecondTimestamp(), kAllowRetransmission,
|
|
|
|
|
RtpPacketSender::kHighPriority);
|
|
|
|
|
if (first_packet_sent_()) {
|
|
|
|
|
LOG(LS_INFO) << "First audio RTP packet sent to pacer";
|
|
|
|
|
}
|
|
|
|
|
return send_result;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
// Audio level magnitude and voice activity flag are set for each RTP packet
|
|
|
|
|
int32_t RTPSenderAudio::SetAudioLevel(uint8_t level_dBov) {
|
|
|
|
|
if (level_dBov > 127) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&_sendAudioCritsect);
|
2015-12-10 02:39:40 -08:00
|
|
|
_audioLevel_dBov = level_dBov;
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
// Set payload type for Redundant Audio Data RFC 2198
|
|
|
|
|
int32_t RTPSenderAudio::SetRED(int8_t payloadType) {
|
|
|
|
|
if (payloadType < -1) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&_sendAudioCritsect);
|
2015-12-10 02:39:40 -08:00
|
|
|
_REDPayloadType = payloadType;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get payload type for Redundant Audio Data RFC 2198
|
2015-12-15 02:54:47 -08:00
|
|
|
int32_t RTPSenderAudio::RED(int8_t* payloadType) const {
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&_sendAudioCritsect);
|
2015-12-10 02:39:40 -08:00
|
|
|
if (_REDPayloadType == -1) {
|
|
|
|
|
// not configured
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2015-12-15 02:54:47 -08:00
|
|
|
*payloadType = _REDPayloadType;
|
2015-12-10 02:39:40 -08:00
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Send a TelephoneEvent tone using RFC 2833 (4733)
|
2015-12-10 02:39:40 -08:00
|
|
|
int32_t RTPSenderAudio::SendTelephoneEvent(uint8_t key,
|
|
|
|
|
uint16_t time_ms,
|
|
|
|
|
uint8_t level) {
|
2015-02-12 12:20:08 +00:00
|
|
|
{
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope lock(&_sendAudioCritsect);
|
2015-02-12 12:20:08 +00:00
|
|
|
if (_dtmfPayloadType < 0) {
|
|
|
|
|
// TelephoneEvent payloadtype not configured
|
|
|
|
|
return -1;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2015-02-12 12:20:08 +00:00
|
|
|
}
|
|
|
|
|
return AddDTMF(key, time_ms, level);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-10 02:39:40 -08:00
|
|
|
int32_t RTPSenderAudio::SendTelephoneEventPacket(bool ended,
|
|
|
|
|
int8_t dtmf_payload_type,
|
|
|
|
|
uint32_t dtmfTimeStamp,
|
|
|
|
|
uint16_t duration,
|
|
|
|
|
bool markerBit) {
|
|
|
|
|
uint8_t dtmfbuffer[IP_PACKET_SIZE];
|
|
|
|
|
uint8_t sendCount = 1;
|
|
|
|
|
int32_t retVal = 0;
|
|
|
|
|
|
|
|
|
|
if (ended) {
|
|
|
|
|
// resend last packet in an event 3 times
|
|
|
|
|
sendCount = 3;
|
|
|
|
|
}
|
|
|
|
|
do {
|
|
|
|
|
// Send DTMF data
|
|
|
|
|
_rtpSender->BuildRTPheader(dtmfbuffer, dtmf_payload_type, markerBit,
|
|
|
|
|
dtmfTimeStamp, _clock->TimeInMilliseconds());
|
|
|
|
|
|
|
|
|
|
// reset CSRC and X bit
|
|
|
|
|
dtmfbuffer[0] &= 0xe0;
|
|
|
|
|
|
|
|
|
|
// Create DTMF data
|
|
|
|
|
/* From RFC 2833:
|
|
|
|
|
|
|
|
|
|
0 1 2 3
|
|
|
|
|
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
|
| event |E|R| volume | duration |
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
|
*/
|
|
|
|
|
// R bit always cleared
|
|
|
|
|
uint8_t R = 0x00;
|
|
|
|
|
uint8_t volume = _dtmfLevel;
|
|
|
|
|
|
|
|
|
|
// First packet un-ended
|
|
|
|
|
uint8_t E = ended ? 0x80 : 0x00;
|
|
|
|
|
|
|
|
|
|
// First byte is Event number, equals key number
|
|
|
|
|
dtmfbuffer[12] = _dtmfKey;
|
|
|
|
|
dtmfbuffer[13] = E | R | volume;
|
|
|
|
|
ByteWriter<uint16_t>::WriteBigEndian(dtmfbuffer + 14, duration);
|
|
|
|
|
|
|
|
|
|
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
|
|
|
|
|
"Audio::SendTelephoneEvent", "timestamp",
|
|
|
|
|
dtmfTimeStamp, "seqnum", _rtpSender->SequenceNumber());
|
|
|
|
|
retVal = _rtpSender->SendToNetwork(
|
|
|
|
|
dtmfbuffer, 4, 12, TickTime::MillisecondTimestamp(),
|
|
|
|
|
kAllowRetransmission, RtpPacketSender::kHighPriority);
|
|
|
|
|
sendCount--;
|
|
|
|
|
} while (sendCount > 0 && retVal == 0);
|
|
|
|
|
|
|
|
|
|
return retVal;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2013-07-03 15:12:26 +00:00
|
|
|
} // namespace webrtc
|