blob: f75452fde91dd90195fa3c8f92cfd96ccaa5625d [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/source/rtp_sender_audio.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
danilchap162abd32015-12-10 02:39:40 -080013#include <string.h>
niklase@google.com470e71d2011-07-07 08:21:25 +000014
danilchap84c85282016-09-05 07:27:57 -070015#include <memory>
16#include <utility>
17
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "modules/rtp_rtcp/include/rtp_rtcp_defines.h"
19#include "modules/rtp_rtcp/source/byte_io.h"
20#include "modules/rtp_rtcp/source/rtp_header_extensions.h"
21#include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
22#include "rtc_base/logging.h"
23#include "rtc_base/timeutils.h"
24#include "rtc_base/trace_event.h"
hclam@chromium.org806dc3b2013-04-09 19:54:10 +000025
niklase@google.com470e71d2011-07-07 08:21:25 +000026namespace webrtc {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000027
Sergey Ulanovec4f0682016-07-28 15:19:10 -070028RTPSenderAudio::RTPSenderAudio(Clock* clock, RTPSender* rtp_sender)
29 : clock_(clock),
solenbergffbbcac2016-11-17 05:25:37 -080030 rtp_sender_(rtp_sender) {}
niklase@google.com470e71d2011-07-07 08:21:25 +000031
danilchap162abd32015-12-10 02:39:40 -080032RTPSenderAudio::~RTPSenderAudio() {}
niklase@google.com470e71d2011-07-07 08:21:25 +000033
pbos@webrtc.org2f446732013-04-08 11:08:41 +000034int32_t RTPSenderAudio::RegisterAudioPayload(
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +000035 const char payloadName[RTP_PAYLOAD_NAME_SIZE],
Sergey Ulanovec4f0682016-07-28 15:19:10 -070036 const int8_t payload_type,
pbos@webrtc.org2f446732013-04-08 11:08:41 +000037 const uint32_t frequency,
Peter Kasting69558702016-01-12 16:26:35 -080038 const size_t channels,
pbos@webrtc.org2f446732013-04-08 11:08:41 +000039 const uint32_t rate,
danilchap6db6cdc2015-12-15 02:54:47 -080040 RtpUtility::Payload** payload) {
pbos@webrtc.org62bafae2014-07-08 12:10:51 +000041 if (RtpUtility::StringCompare(payloadName, "cn", 2)) {
Sergey Ulanovec4f0682016-07-28 15:19:10 -070042 rtc::CritScope cs(&send_audio_critsect_);
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +000043 // we can have multiple CNG payload types
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000044 switch (frequency) {
45 case 8000:
Sergey Ulanovec4f0682016-07-28 15:19:10 -070046 cngnb_payload_type_ = payload_type;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000047 break;
48 case 16000:
Sergey Ulanovec4f0682016-07-28 15:19:10 -070049 cngwb_payload_type_ = payload_type;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000050 break;
51 case 32000:
Sergey Ulanovec4f0682016-07-28 15:19:10 -070052 cngswb_payload_type_ = payload_type;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000053 break;
54 case 48000:
Sergey Ulanovec4f0682016-07-28 15:19:10 -070055 cngfb_payload_type_ = payload_type;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000056 break;
57 default:
58 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +000059 }
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000060 } else if (RtpUtility::StringCompare(payloadName, "telephone-event", 15)) {
Sergey Ulanovec4f0682016-07-28 15:19:10 -070061 rtc::CritScope cs(&send_audio_critsect_);
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +000062 // Don't add it to the list
63 // we dont want to allow send with a DTMF payloadtype
Sergey Ulanovec4f0682016-07-28 15:19:10 -070064 dtmf_payload_type_ = payload_type;
solenbergffbbcac2016-11-17 05:25:37 -080065 dtmf_payload_freq_ = frequency;
niklase@google.com470e71d2011-07-07 08:21:25 +000066 return 0;
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +000067 }
danilchap6db6cdc2015-12-15 02:54:47 -080068 *payload = new RtpUtility::Payload;
69 (*payload)->typeSpecific.Audio.frequency = frequency;
70 (*payload)->typeSpecific.Audio.channels = channels;
71 (*payload)->typeSpecific.Audio.rate = rate;
72 (*payload)->audio = true;
73 (*payload)->name[RTP_PAYLOAD_NAME_SIZE - 1] = '\0';
74 strncpy((*payload)->name, payloadName, RTP_PAYLOAD_NAME_SIZE - 1);
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +000075 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000076}
77
Sergey Ulanovec4f0682016-07-28 15:19:10 -070078bool RTPSenderAudio::MarkerBit(FrameType frame_type, int8_t payload_type) {
79 rtc::CritScope cs(&send_audio_critsect_);
danilchap162abd32015-12-10 02:39:40 -080080 // for audio true for first packet in a speech burst
Sergey Ulanovec4f0682016-07-28 15:19:10 -070081 bool marker_bit = false;
82 if (last_payload_type_ != payload_type) {
83 if (payload_type != -1 && (cngnb_payload_type_ == payload_type ||
84 cngwb_payload_type_ == payload_type ||
85 cngswb_payload_type_ == payload_type ||
86 cngfb_payload_type_ == payload_type)) {
danilchap162abd32015-12-10 02:39:40 -080087 // Only set a marker bit when we change payload type to a non CNG
88 return false;
89 }
90
91 // payload_type differ
Sergey Ulanovec4f0682016-07-28 15:19:10 -070092 if (last_payload_type_ == -1) {
93 if (frame_type != kAudioFrameCN) {
danilchap162abd32015-12-10 02:39:40 -080094 // first packet and NOT CNG
95 return true;
96 } else {
97 // first packet and CNG
Sergey Ulanovec4f0682016-07-28 15:19:10 -070098 inband_vad_active_ = true;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000099 return false;
100 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000101 }
102
danilchap162abd32015-12-10 02:39:40 -0800103 // not first packet AND
104 // not CNG AND
105 // payload_type changed
niklase@google.com470e71d2011-07-07 08:21:25 +0000106
danilchap162abd32015-12-10 02:39:40 -0800107 // set a marker bit when we change payload type
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700108 marker_bit = true;
danilchap162abd32015-12-10 02:39:40 -0800109 }
110
111 // For G.723 G.729, AMR etc we can have inband VAD
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700112 if (frame_type == kAudioFrameCN) {
113 inband_vad_active_ = true;
114 } else if (inband_vad_active_) {
115 inband_vad_active_ = false;
116 marker_bit = true;
danilchap162abd32015-12-10 02:39:40 -0800117 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700118 return marker_bit;
niklase@google.com470e71d2011-07-07 08:21:25 +0000119}
120
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700121bool RTPSenderAudio::SendAudio(FrameType frame_type,
danilchape5b41412016-08-22 03:39:23 -0700122 int8_t payload_type,
123 uint32_t rtp_timestamp,
124 const uint8_t* payload_data,
danilchap84c85282016-09-05 07:27:57 -0700125 size_t payload_size,
danilchape5b41412016-08-22 03:39:23 -0700126 const RTPFragmentationHeader* fragmentation) {
ossu00bceb12016-12-02 02:40:02 -0800127 // From RFC 4733:
128 // A source has wide latitude as to how often it sends event updates. A
129 // natural interval is the spacing between non-event audio packets. [...]
130 // Alternatively, a source MAY decide to use a different spacing for event
131 // updates, with a value of 50 ms RECOMMENDED.
132 constexpr int kDtmfIntervalTimeMs = 50;
solenbergffbbcac2016-11-17 05:25:37 -0800133 uint8_t audio_level_dbov = 0;
solenbergffbbcac2016-11-17 05:25:37 -0800134 uint32_t dtmf_payload_freq = 0;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000135 {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700136 rtc::CritScope cs(&send_audio_critsect_);
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700137 audio_level_dbov = audio_level_dbov_;
solenbergffbbcac2016-11-17 05:25:37 -0800138 dtmf_payload_freq = dtmf_payload_freq_;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000139 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000140
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000141 // Check if we have pending DTMFs to send
solenbergffbbcac2016-11-17 05:25:37 -0800142 if (!dtmf_event_is_on_ && dtmf_queue_.PendingDtmf()) {
ossu00bceb12016-12-02 02:40:02 -0800143 if ((clock_->TimeInMilliseconds() - dtmf_time_last_sent_) >
144 kDtmfIntervalTimeMs) {
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000145 // New tone to play
danilchape5b41412016-08-22 03:39:23 -0700146 dtmf_timestamp_ = rtp_timestamp;
solenbergffbbcac2016-11-17 05:25:37 -0800147 if (dtmf_queue_.NextDtmf(&dtmf_current_event_)) {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700148 dtmf_event_first_packet_sent_ = false;
solenbergffbbcac2016-11-17 05:25:37 -0800149 dtmf_length_samples_ =
150 dtmf_current_event_.duration_ms * (dtmf_payload_freq / 1000);
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700151 dtmf_event_is_on_ = true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000152 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000153 }
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000154 }
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000155
156 // A source MAY send events and coded audio packets for the same time
157 // but we don't support it
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700158 if (dtmf_event_is_on_) {
159 if (frame_type == kEmptyFrame) {
pbos22993e12015-10-19 02:39:06 -0700160 // kEmptyFrame is used to drive the DTMF when in CN mode
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000161 // it can be triggered more frequently than we want to send the
162 // DTMF packets.
ossu00bceb12016-12-02 02:40:02 -0800163 const unsigned int dtmf_interval_time_rtp =
164 dtmf_payload_freq * kDtmfIntervalTimeMs / 1000;
165 if ((rtp_timestamp - dtmf_timestamp_last_sent_) <
166 dtmf_interval_time_rtp) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000167 // not time to send yet
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700168 return true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000169 }
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000170 }
danilchape5b41412016-08-22 03:39:23 -0700171 dtmf_timestamp_last_sent_ = rtp_timestamp;
172 uint32_t dtmf_duration_samples = rtp_timestamp - dtmf_timestamp_;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000173 bool ended = false;
174 bool send = true;
175
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700176 if (dtmf_length_samples_ > dtmf_duration_samples) {
177 if (dtmf_duration_samples <= 0) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000178 // Skip send packet at start, since we shouldn't use duration 0
179 send = false;
180 }
181 } else {
182 ended = true;
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700183 dtmf_event_is_on_ = false;
184 dtmf_time_last_sent_ = clock_->TimeInMilliseconds();
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000185 }
186 if (send) {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700187 if (dtmf_duration_samples > 0xffff) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000188 // RFC 4733 2.5.2.3 Long-Duration Events
solenbergffbbcac2016-11-17 05:25:37 -0800189 SendTelephoneEventPacket(ended, dtmf_timestamp_,
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000190 static_cast<uint16_t>(0xffff), false);
191
192 // set new timestap for this segment
danilchape5b41412016-08-22 03:39:23 -0700193 dtmf_timestamp_ = rtp_timestamp;
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700194 dtmf_duration_samples -= 0xffff;
195 dtmf_length_samples_ -= 0xffff;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000196
solenbergffbbcac2016-11-17 05:25:37 -0800197 return SendTelephoneEventPacket(ended, dtmf_timestamp_,
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700198 static_cast<uint16_t>(dtmf_duration_samples), false);
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000199 } else {
solenbergffbbcac2016-11-17 05:25:37 -0800200 if (!SendTelephoneEventPacket(ended, dtmf_timestamp_,
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700201 dtmf_duration_samples,
202 !dtmf_event_first_packet_sent_)) {
203 return false;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000204 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700205 dtmf_event_first_packet_sent_ = true;
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700206 return true;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000207 }
208 }
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700209 return true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000210 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700211 if (payload_size == 0 || payload_data == NULL) {
212 if (frame_type == kEmptyFrame) {
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000213 // we don't send empty audio RTP packets
214 // no error since we use it to drive DTMF when we use VAD
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700215 return true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000216 }
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700217 return false;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000218 }
solenbergffbbcac2016-11-17 05:25:37 -0800219
danilchap84c85282016-09-05 07:27:57 -0700220 std::unique_ptr<RtpPacketToSend> packet = rtp_sender_->AllocatePacket();
221 packet->SetMarker(MarkerBit(frame_type, payload_type));
222 packet->SetPayloadType(payload_type);
223 packet->SetTimestamp(rtp_timestamp);
224 packet->set_capture_time_ms(clock_->TimeInMilliseconds());
225 // Update audio level extension, if included.
226 packet->SetExtension<AudioLevel>(frame_type == kAudioFrameSpeech,
227 audio_level_dbov);
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000228
kwiberg963be232016-08-15 07:08:29 -0700229 if (fragmentation && fragmentation->fragmentationVectorSize > 0) {
danilchap84c85282016-09-05 07:27:57 -0700230 // Use the fragment info if we have one.
231 uint8_t* payload =
232 packet->AllocatePayload(1 + fragmentation->fragmentationLength[0]);
233 if (!payload) // Too large payload buffer.
234 return false;
235 payload[0] = fragmentation->fragmentationPlType[0];
236 memcpy(payload + 1, payload_data + fragmentation->fragmentationOffset[0],
kwiberg963be232016-08-15 07:08:29 -0700237 fragmentation->fragmentationLength[0]);
danilchap162abd32015-12-10 02:39:40 -0800238 } else {
danilchap84c85282016-09-05 07:27:57 -0700239 uint8_t* payload = packet->AllocatePayload(payload_size);
240 if (!payload) // Too large payload buffer.
241 return false;
242 memcpy(payload, payload_data, payload_size);
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000243 }
skvlad98bb6642016-04-07 15:36:45 -0700244
danilchap84c85282016-09-05 07:27:57 -0700245 if (!rtp_sender_->AssignSequenceNumber(packet.get()))
246 return false;
247
danilchap162abd32015-12-10 02:39:40 -0800248 {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700249 rtc::CritScope cs(&send_audio_critsect_);
250 last_payload_type_ = payload_type;
danilchap162abd32015-12-10 02:39:40 -0800251 }
danilchape5b41412016-08-22 03:39:23 -0700252 TRACE_EVENT_ASYNC_END2("webrtc", "Audio", rtp_timestamp, "timestamp",
danilchap84c85282016-09-05 07:27:57 -0700253 packet->Timestamp(), "seqnum",
254 packet->SequenceNumber());
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700255 bool send_result = rtp_sender_->SendToNetwork(
danilchap84c85282016-09-05 07:27:57 -0700256 std::move(packet), kAllowRetransmission, RtpPacketSender::kHighPriority);
skvlad98bb6642016-04-07 15:36:45 -0700257 if (first_packet_sent_()) {
258 LOG(LS_INFO) << "First audio RTP packet sent to pacer";
259 }
260 return send_result;
niklase@google.com470e71d2011-07-07 08:21:25 +0000261}
262
danilchap162abd32015-12-10 02:39:40 -0800263// Audio level magnitude and voice activity flag are set for each RTP packet
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700264int32_t RTPSenderAudio::SetAudioLevel(uint8_t level_dbov) {
265 if (level_dbov > 127) {
danilchap162abd32015-12-10 02:39:40 -0800266 return -1;
267 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700268 rtc::CritScope cs(&send_audio_critsect_);
269 audio_level_dbov_ = level_dbov;
danilchap162abd32015-12-10 02:39:40 -0800270 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000271}
272
niklase@google.com470e71d2011-07-07 08:21:25 +0000273// Send a TelephoneEvent tone using RFC 2833 (4733)
danilchap162abd32015-12-10 02:39:40 -0800274int32_t RTPSenderAudio::SendTelephoneEvent(uint8_t key,
275 uint16_t time_ms,
276 uint8_t level) {
solenbergffbbcac2016-11-17 05:25:37 -0800277 DtmfQueue::Event event;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000278 {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700279 rtc::CritScope lock(&send_audio_critsect_);
280 if (dtmf_payload_type_ < 0) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000281 // TelephoneEvent payloadtype not configured
282 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000283 }
solenbergffbbcac2016-11-17 05:25:37 -0800284 event.payload_type = dtmf_payload_type_;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000285 }
solenbergffbbcac2016-11-17 05:25:37 -0800286 event.key = key;
287 event.duration_ms = time_ms;
288 event.level = level;
289 return dtmf_queue_.AddDtmf(event) ? 0 : -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000290}
291
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700292bool RTPSenderAudio::SendTelephoneEventPacket(bool ended,
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700293 uint32_t dtmf_timestamp,
294 uint16_t duration,
295 bool marker_bit) {
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700296 uint8_t send_count = 1;
297 bool result = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000298
danilchap162abd32015-12-10 02:39:40 -0800299 if (ended) {
300 // resend last packet in an event 3 times
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700301 send_count = 3;
danilchap162abd32015-12-10 02:39:40 -0800302 }
303 do {
danilchap84c85282016-09-05 07:27:57 -0700304 // Send DTMF data.
305 constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
306 constexpr size_t kDtmfSize = 4;
307 std::unique_ptr<RtpPacketToSend> packet(
308 new RtpPacketToSend(kNoExtensions, kRtpHeaderSize + kDtmfSize));
solenbergffbbcac2016-11-17 05:25:37 -0800309 packet->SetPayloadType(dtmf_current_event_.payload_type);
danilchap84c85282016-09-05 07:27:57 -0700310 packet->SetMarker(marker_bit);
311 packet->SetSsrc(rtp_sender_->SSRC());
312 packet->SetTimestamp(dtmf_timestamp);
313 packet->set_capture_time_ms(clock_->TimeInMilliseconds());
314 if (!rtp_sender_->AssignSequenceNumber(packet.get()))
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700315 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000316
danilchap84c85282016-09-05 07:27:57 -0700317 // Create DTMF data.
318 uint8_t* dtmfbuffer = packet->AllocatePayload(kDtmfSize);
319 RTC_DCHECK(dtmfbuffer);
danilchap162abd32015-12-10 02:39:40 -0800320 /* From RFC 2833:
danilchap162abd32015-12-10 02:39:40 -0800321 0 1 2 3
322 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
323 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324 | event |E|R| volume | duration |
325 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326 */
327 // R bit always cleared
328 uint8_t R = 0x00;
solenbergffbbcac2016-11-17 05:25:37 -0800329 uint8_t volume = dtmf_current_event_.level;
niklase@google.com470e71d2011-07-07 08:21:25 +0000330
danilchap162abd32015-12-10 02:39:40 -0800331 // First packet un-ended
332 uint8_t E = ended ? 0x80 : 0x00;
niklase@google.com470e71d2011-07-07 08:21:25 +0000333
danilchap162abd32015-12-10 02:39:40 -0800334 // First byte is Event number, equals key number
solenbergffbbcac2016-11-17 05:25:37 -0800335 dtmfbuffer[0] = dtmf_current_event_.key;
danilchap84c85282016-09-05 07:27:57 -0700336 dtmfbuffer[1] = E | R | volume;
337 ByteWriter<uint16_t>::WriteBigEndian(dtmfbuffer + 2, duration);
niklase@google.com470e71d2011-07-07 08:21:25 +0000338
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700339 TRACE_EVENT_INSTANT2(
340 TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "Audio::SendTelephoneEvent",
danilchap84c85282016-09-05 07:27:57 -0700341 "timestamp", packet->Timestamp(), "seqnum", packet->SequenceNumber());
342 result = rtp_sender_->SendToNetwork(std::move(packet), kAllowRetransmission,
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700343 RtpPacketSender::kHighPriority);
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700344 send_count--;
345 } while (send_count > 0 && result);
niklase@google.com470e71d2011-07-07 08:21:25 +0000346
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700347 return result;
niklase@google.com470e71d2011-07-07 08:21:25 +0000348}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000349} // namespace webrtc