blob: dadf30b53293cb0d0304a2a2c04fffe06e82175f [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 }
Karl Wiberg83d3ec12017-09-28 19:54:38 +020068 *payload = new RtpUtility::Payload(
69 payloadName, PayloadUnion(AudioPayload{frequency, channels, rate}));
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +000070 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000071}
72
Sergey Ulanovec4f0682016-07-28 15:19:10 -070073bool RTPSenderAudio::MarkerBit(FrameType frame_type, int8_t payload_type) {
74 rtc::CritScope cs(&send_audio_critsect_);
danilchap162abd32015-12-10 02:39:40 -080075 // for audio true for first packet in a speech burst
Sergey Ulanovec4f0682016-07-28 15:19:10 -070076 bool marker_bit = false;
77 if (last_payload_type_ != payload_type) {
78 if (payload_type != -1 && (cngnb_payload_type_ == payload_type ||
79 cngwb_payload_type_ == payload_type ||
80 cngswb_payload_type_ == payload_type ||
81 cngfb_payload_type_ == payload_type)) {
danilchap162abd32015-12-10 02:39:40 -080082 // Only set a marker bit when we change payload type to a non CNG
83 return false;
84 }
85
86 // payload_type differ
Sergey Ulanovec4f0682016-07-28 15:19:10 -070087 if (last_payload_type_ == -1) {
88 if (frame_type != kAudioFrameCN) {
danilchap162abd32015-12-10 02:39:40 -080089 // first packet and NOT CNG
90 return true;
91 } else {
92 // first packet and CNG
Sergey Ulanovec4f0682016-07-28 15:19:10 -070093 inband_vad_active_ = true;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000094 return false;
95 }
niklase@google.com470e71d2011-07-07 08:21:25 +000096 }
97
danilchap162abd32015-12-10 02:39:40 -080098 // not first packet AND
99 // not CNG AND
100 // payload_type changed
niklase@google.com470e71d2011-07-07 08:21:25 +0000101
danilchap162abd32015-12-10 02:39:40 -0800102 // set a marker bit when we change payload type
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700103 marker_bit = true;
danilchap162abd32015-12-10 02:39:40 -0800104 }
105
106 // For G.723 G.729, AMR etc we can have inband VAD
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700107 if (frame_type == kAudioFrameCN) {
108 inband_vad_active_ = true;
109 } else if (inband_vad_active_) {
110 inband_vad_active_ = false;
111 marker_bit = true;
danilchap162abd32015-12-10 02:39:40 -0800112 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700113 return marker_bit;
niklase@google.com470e71d2011-07-07 08:21:25 +0000114}
115
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700116bool RTPSenderAudio::SendAudio(FrameType frame_type,
danilchape5b41412016-08-22 03:39:23 -0700117 int8_t payload_type,
118 uint32_t rtp_timestamp,
119 const uint8_t* payload_data,
danilchap84c85282016-09-05 07:27:57 -0700120 size_t payload_size,
danilchape5b41412016-08-22 03:39:23 -0700121 const RTPFragmentationHeader* fragmentation) {
ossu00bceb12016-12-02 02:40:02 -0800122 // From RFC 4733:
123 // A source has wide latitude as to how often it sends event updates. A
124 // natural interval is the spacing between non-event audio packets. [...]
125 // Alternatively, a source MAY decide to use a different spacing for event
126 // updates, with a value of 50 ms RECOMMENDED.
127 constexpr int kDtmfIntervalTimeMs = 50;
solenbergffbbcac2016-11-17 05:25:37 -0800128 uint8_t audio_level_dbov = 0;
solenbergffbbcac2016-11-17 05:25:37 -0800129 uint32_t dtmf_payload_freq = 0;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000130 {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700131 rtc::CritScope cs(&send_audio_critsect_);
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700132 audio_level_dbov = audio_level_dbov_;
solenbergffbbcac2016-11-17 05:25:37 -0800133 dtmf_payload_freq = dtmf_payload_freq_;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000134 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000135
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000136 // Check if we have pending DTMFs to send
solenbergffbbcac2016-11-17 05:25:37 -0800137 if (!dtmf_event_is_on_ && dtmf_queue_.PendingDtmf()) {
ossu00bceb12016-12-02 02:40:02 -0800138 if ((clock_->TimeInMilliseconds() - dtmf_time_last_sent_) >
139 kDtmfIntervalTimeMs) {
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000140 // New tone to play
danilchape5b41412016-08-22 03:39:23 -0700141 dtmf_timestamp_ = rtp_timestamp;
solenbergffbbcac2016-11-17 05:25:37 -0800142 if (dtmf_queue_.NextDtmf(&dtmf_current_event_)) {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700143 dtmf_event_first_packet_sent_ = false;
solenbergffbbcac2016-11-17 05:25:37 -0800144 dtmf_length_samples_ =
145 dtmf_current_event_.duration_ms * (dtmf_payload_freq / 1000);
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700146 dtmf_event_is_on_ = true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000147 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000148 }
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000149 }
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000150
151 // A source MAY send events and coded audio packets for the same time
152 // but we don't support it
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700153 if (dtmf_event_is_on_) {
154 if (frame_type == kEmptyFrame) {
pbos22993e12015-10-19 02:39:06 -0700155 // kEmptyFrame is used to drive the DTMF when in CN mode
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000156 // it can be triggered more frequently than we want to send the
157 // DTMF packets.
ossu00bceb12016-12-02 02:40:02 -0800158 const unsigned int dtmf_interval_time_rtp =
159 dtmf_payload_freq * kDtmfIntervalTimeMs / 1000;
160 if ((rtp_timestamp - dtmf_timestamp_last_sent_) <
161 dtmf_interval_time_rtp) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000162 // not time to send yet
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700163 return true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000164 }
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000165 }
danilchape5b41412016-08-22 03:39:23 -0700166 dtmf_timestamp_last_sent_ = rtp_timestamp;
167 uint32_t dtmf_duration_samples = rtp_timestamp - dtmf_timestamp_;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000168 bool ended = false;
169 bool send = true;
170
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700171 if (dtmf_length_samples_ > dtmf_duration_samples) {
172 if (dtmf_duration_samples <= 0) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000173 // Skip send packet at start, since we shouldn't use duration 0
174 send = false;
175 }
176 } else {
177 ended = true;
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700178 dtmf_event_is_on_ = false;
179 dtmf_time_last_sent_ = clock_->TimeInMilliseconds();
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000180 }
181 if (send) {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700182 if (dtmf_duration_samples > 0xffff) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000183 // RFC 4733 2.5.2.3 Long-Duration Events
solenbergffbbcac2016-11-17 05:25:37 -0800184 SendTelephoneEventPacket(ended, dtmf_timestamp_,
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000185 static_cast<uint16_t>(0xffff), false);
186
187 // set new timestap for this segment
danilchape5b41412016-08-22 03:39:23 -0700188 dtmf_timestamp_ = rtp_timestamp;
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700189 dtmf_duration_samples -= 0xffff;
190 dtmf_length_samples_ -= 0xffff;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000191
solenbergffbbcac2016-11-17 05:25:37 -0800192 return SendTelephoneEventPacket(ended, dtmf_timestamp_,
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700193 static_cast<uint16_t>(dtmf_duration_samples), false);
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000194 } else {
solenbergffbbcac2016-11-17 05:25:37 -0800195 if (!SendTelephoneEventPacket(ended, dtmf_timestamp_,
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700196 dtmf_duration_samples,
197 !dtmf_event_first_packet_sent_)) {
198 return false;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000199 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700200 dtmf_event_first_packet_sent_ = true;
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700201 return true;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000202 }
203 }
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700204 return true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000205 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700206 if (payload_size == 0 || payload_data == NULL) {
207 if (frame_type == kEmptyFrame) {
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000208 // we don't send empty audio RTP packets
209 // no error since we use it to drive DTMF when we use VAD
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700210 return true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000211 }
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700212 return false;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000213 }
solenbergffbbcac2016-11-17 05:25:37 -0800214
danilchap84c85282016-09-05 07:27:57 -0700215 std::unique_ptr<RtpPacketToSend> packet = rtp_sender_->AllocatePacket();
216 packet->SetMarker(MarkerBit(frame_type, payload_type));
217 packet->SetPayloadType(payload_type);
218 packet->SetTimestamp(rtp_timestamp);
219 packet->set_capture_time_ms(clock_->TimeInMilliseconds());
220 // Update audio level extension, if included.
221 packet->SetExtension<AudioLevel>(frame_type == kAudioFrameSpeech,
222 audio_level_dbov);
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000223
kwiberg963be232016-08-15 07:08:29 -0700224 if (fragmentation && fragmentation->fragmentationVectorSize > 0) {
danilchap84c85282016-09-05 07:27:57 -0700225 // Use the fragment info if we have one.
226 uint8_t* payload =
227 packet->AllocatePayload(1 + fragmentation->fragmentationLength[0]);
228 if (!payload) // Too large payload buffer.
229 return false;
230 payload[0] = fragmentation->fragmentationPlType[0];
231 memcpy(payload + 1, payload_data + fragmentation->fragmentationOffset[0],
kwiberg963be232016-08-15 07:08:29 -0700232 fragmentation->fragmentationLength[0]);
danilchap162abd32015-12-10 02:39:40 -0800233 } else {
danilchap84c85282016-09-05 07:27:57 -0700234 uint8_t* payload = packet->AllocatePayload(payload_size);
235 if (!payload) // Too large payload buffer.
236 return false;
237 memcpy(payload, payload_data, payload_size);
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000238 }
skvlad98bb6642016-04-07 15:36:45 -0700239
danilchap84c85282016-09-05 07:27:57 -0700240 if (!rtp_sender_->AssignSequenceNumber(packet.get()))
241 return false;
242
danilchap162abd32015-12-10 02:39:40 -0800243 {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700244 rtc::CritScope cs(&send_audio_critsect_);
245 last_payload_type_ = payload_type;
danilchap162abd32015-12-10 02:39:40 -0800246 }
danilchape5b41412016-08-22 03:39:23 -0700247 TRACE_EVENT_ASYNC_END2("webrtc", "Audio", rtp_timestamp, "timestamp",
danilchap84c85282016-09-05 07:27:57 -0700248 packet->Timestamp(), "seqnum",
249 packet->SequenceNumber());
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700250 bool send_result = rtp_sender_->SendToNetwork(
danilchap84c85282016-09-05 07:27:57 -0700251 std::move(packet), kAllowRetransmission, RtpPacketSender::kHighPriority);
skvlad98bb6642016-04-07 15:36:45 -0700252 if (first_packet_sent_()) {
253 LOG(LS_INFO) << "First audio RTP packet sent to pacer";
254 }
255 return send_result;
niklase@google.com470e71d2011-07-07 08:21:25 +0000256}
257
danilchap162abd32015-12-10 02:39:40 -0800258// Audio level magnitude and voice activity flag are set for each RTP packet
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700259int32_t RTPSenderAudio::SetAudioLevel(uint8_t level_dbov) {
260 if (level_dbov > 127) {
danilchap162abd32015-12-10 02:39:40 -0800261 return -1;
262 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700263 rtc::CritScope cs(&send_audio_critsect_);
264 audio_level_dbov_ = level_dbov;
danilchap162abd32015-12-10 02:39:40 -0800265 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000266}
267
niklase@google.com470e71d2011-07-07 08:21:25 +0000268// Send a TelephoneEvent tone using RFC 2833 (4733)
danilchap162abd32015-12-10 02:39:40 -0800269int32_t RTPSenderAudio::SendTelephoneEvent(uint8_t key,
270 uint16_t time_ms,
271 uint8_t level) {
solenbergffbbcac2016-11-17 05:25:37 -0800272 DtmfQueue::Event event;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000273 {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700274 rtc::CritScope lock(&send_audio_critsect_);
275 if (dtmf_payload_type_ < 0) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000276 // TelephoneEvent payloadtype not configured
277 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000278 }
solenbergffbbcac2016-11-17 05:25:37 -0800279 event.payload_type = dtmf_payload_type_;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000280 }
solenbergffbbcac2016-11-17 05:25:37 -0800281 event.key = key;
282 event.duration_ms = time_ms;
283 event.level = level;
284 return dtmf_queue_.AddDtmf(event) ? 0 : -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000285}
286
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700287bool RTPSenderAudio::SendTelephoneEventPacket(bool ended,
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700288 uint32_t dtmf_timestamp,
289 uint16_t duration,
290 bool marker_bit) {
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700291 uint8_t send_count = 1;
292 bool result = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000293
danilchap162abd32015-12-10 02:39:40 -0800294 if (ended) {
295 // resend last packet in an event 3 times
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700296 send_count = 3;
danilchap162abd32015-12-10 02:39:40 -0800297 }
298 do {
danilchap84c85282016-09-05 07:27:57 -0700299 // Send DTMF data.
300 constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
301 constexpr size_t kDtmfSize = 4;
302 std::unique_ptr<RtpPacketToSend> packet(
303 new RtpPacketToSend(kNoExtensions, kRtpHeaderSize + kDtmfSize));
solenbergffbbcac2016-11-17 05:25:37 -0800304 packet->SetPayloadType(dtmf_current_event_.payload_type);
danilchap84c85282016-09-05 07:27:57 -0700305 packet->SetMarker(marker_bit);
306 packet->SetSsrc(rtp_sender_->SSRC());
307 packet->SetTimestamp(dtmf_timestamp);
308 packet->set_capture_time_ms(clock_->TimeInMilliseconds());
309 if (!rtp_sender_->AssignSequenceNumber(packet.get()))
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700310 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000311
danilchap84c85282016-09-05 07:27:57 -0700312 // Create DTMF data.
313 uint8_t* dtmfbuffer = packet->AllocatePayload(kDtmfSize);
314 RTC_DCHECK(dtmfbuffer);
danilchap162abd32015-12-10 02:39:40 -0800315 /* From RFC 2833:
danilchap162abd32015-12-10 02:39:40 -0800316 0 1 2 3
317 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
318 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
319 | event |E|R| volume | duration |
320 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
321 */
322 // R bit always cleared
323 uint8_t R = 0x00;
solenbergffbbcac2016-11-17 05:25:37 -0800324 uint8_t volume = dtmf_current_event_.level;
niklase@google.com470e71d2011-07-07 08:21:25 +0000325
danilchap162abd32015-12-10 02:39:40 -0800326 // First packet un-ended
327 uint8_t E = ended ? 0x80 : 0x00;
niklase@google.com470e71d2011-07-07 08:21:25 +0000328
danilchap162abd32015-12-10 02:39:40 -0800329 // First byte is Event number, equals key number
solenbergffbbcac2016-11-17 05:25:37 -0800330 dtmfbuffer[0] = dtmf_current_event_.key;
danilchap84c85282016-09-05 07:27:57 -0700331 dtmfbuffer[1] = E | R | volume;
332 ByteWriter<uint16_t>::WriteBigEndian(dtmfbuffer + 2, duration);
niklase@google.com470e71d2011-07-07 08:21:25 +0000333
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700334 TRACE_EVENT_INSTANT2(
335 TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "Audio::SendTelephoneEvent",
danilchap84c85282016-09-05 07:27:57 -0700336 "timestamp", packet->Timestamp(), "seqnum", packet->SequenceNumber());
337 result = rtp_sender_->SendToNetwork(std::move(packet), kAllowRetransmission,
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700338 RtpPacketSender::kHighPriority);
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700339 send_count--;
340 } while (send_count > 0 && result);
niklase@google.com470e71d2011-07-07 08:21:25 +0000341
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700342 return result;
niklase@google.com470e71d2011-07-07 08:21:25 +0000343}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000344} // namespace webrtc