blob: 93f2b9fa334cba9a0a99645fec535c3161f7370b [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(
Karl Wibergc62f6c72017-10-04 12:38:53 +020069 payloadName,
70 PayloadUnion(AudioPayload{
71 SdpAudioFormat(payloadName, frequency, channels), rate}));
pwestin@webrtc.orgf6bb77a2012-01-24 17:16:59 +000072 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000073}
74
Sergey Ulanovec4f0682016-07-28 15:19:10 -070075bool RTPSenderAudio::MarkerBit(FrameType frame_type, int8_t payload_type) {
76 rtc::CritScope cs(&send_audio_critsect_);
danilchap162abd32015-12-10 02:39:40 -080077 // for audio true for first packet in a speech burst
Sergey Ulanovec4f0682016-07-28 15:19:10 -070078 bool marker_bit = false;
79 if (last_payload_type_ != payload_type) {
80 if (payload_type != -1 && (cngnb_payload_type_ == payload_type ||
81 cngwb_payload_type_ == payload_type ||
82 cngswb_payload_type_ == payload_type ||
83 cngfb_payload_type_ == payload_type)) {
danilchap162abd32015-12-10 02:39:40 -080084 // Only set a marker bit when we change payload type to a non CNG
85 return false;
86 }
87
88 // payload_type differ
Sergey Ulanovec4f0682016-07-28 15:19:10 -070089 if (last_payload_type_ == -1) {
90 if (frame_type != kAudioFrameCN) {
danilchap162abd32015-12-10 02:39:40 -080091 // first packet and NOT CNG
92 return true;
93 } else {
94 // first packet and CNG
Sergey Ulanovec4f0682016-07-28 15:19:10 -070095 inband_vad_active_ = true;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +000096 return false;
97 }
niklase@google.com470e71d2011-07-07 08:21:25 +000098 }
99
danilchap162abd32015-12-10 02:39:40 -0800100 // not first packet AND
101 // not CNG AND
102 // payload_type changed
niklase@google.com470e71d2011-07-07 08:21:25 +0000103
danilchap162abd32015-12-10 02:39:40 -0800104 // set a marker bit when we change payload type
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700105 marker_bit = true;
danilchap162abd32015-12-10 02:39:40 -0800106 }
107
108 // For G.723 G.729, AMR etc we can have inband VAD
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700109 if (frame_type == kAudioFrameCN) {
110 inband_vad_active_ = true;
111 } else if (inband_vad_active_) {
112 inband_vad_active_ = false;
113 marker_bit = true;
danilchap162abd32015-12-10 02:39:40 -0800114 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700115 return marker_bit;
niklase@google.com470e71d2011-07-07 08:21:25 +0000116}
117
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700118bool RTPSenderAudio::SendAudio(FrameType frame_type,
danilchape5b41412016-08-22 03:39:23 -0700119 int8_t payload_type,
120 uint32_t rtp_timestamp,
121 const uint8_t* payload_data,
Niels Möller90397d92017-10-27 10:51:20 +0200122 size_t payload_size) {
ossu00bceb12016-12-02 02:40:02 -0800123 // From RFC 4733:
124 // A source has wide latitude as to how often it sends event updates. A
125 // natural interval is the spacing between non-event audio packets. [...]
126 // Alternatively, a source MAY decide to use a different spacing for event
127 // updates, with a value of 50 ms RECOMMENDED.
128 constexpr int kDtmfIntervalTimeMs = 50;
solenbergffbbcac2016-11-17 05:25:37 -0800129 uint8_t audio_level_dbov = 0;
solenbergffbbcac2016-11-17 05:25:37 -0800130 uint32_t dtmf_payload_freq = 0;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000131 {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700132 rtc::CritScope cs(&send_audio_critsect_);
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700133 audio_level_dbov = audio_level_dbov_;
solenbergffbbcac2016-11-17 05:25:37 -0800134 dtmf_payload_freq = dtmf_payload_freq_;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000135 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000136
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000137 // Check if we have pending DTMFs to send
solenbergffbbcac2016-11-17 05:25:37 -0800138 if (!dtmf_event_is_on_ && dtmf_queue_.PendingDtmf()) {
ossu00bceb12016-12-02 02:40:02 -0800139 if ((clock_->TimeInMilliseconds() - dtmf_time_last_sent_) >
140 kDtmfIntervalTimeMs) {
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000141 // New tone to play
danilchape5b41412016-08-22 03:39:23 -0700142 dtmf_timestamp_ = rtp_timestamp;
solenbergffbbcac2016-11-17 05:25:37 -0800143 if (dtmf_queue_.NextDtmf(&dtmf_current_event_)) {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700144 dtmf_event_first_packet_sent_ = false;
solenbergffbbcac2016-11-17 05:25:37 -0800145 dtmf_length_samples_ =
146 dtmf_current_event_.duration_ms * (dtmf_payload_freq / 1000);
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700147 dtmf_event_is_on_ = true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000148 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000149 }
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000150 }
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000151
152 // A source MAY send events and coded audio packets for the same time
153 // but we don't support it
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700154 if (dtmf_event_is_on_) {
155 if (frame_type == kEmptyFrame) {
pbos22993e12015-10-19 02:39:06 -0700156 // kEmptyFrame is used to drive the DTMF when in CN mode
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000157 // it can be triggered more frequently than we want to send the
158 // DTMF packets.
ossu00bceb12016-12-02 02:40:02 -0800159 const unsigned int dtmf_interval_time_rtp =
160 dtmf_payload_freq * kDtmfIntervalTimeMs / 1000;
161 if ((rtp_timestamp - dtmf_timestamp_last_sent_) <
162 dtmf_interval_time_rtp) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000163 // not time to send yet
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700164 return true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000165 }
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000166 }
danilchape5b41412016-08-22 03:39:23 -0700167 dtmf_timestamp_last_sent_ = rtp_timestamp;
168 uint32_t dtmf_duration_samples = rtp_timestamp - dtmf_timestamp_;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000169 bool ended = false;
170 bool send = true;
171
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700172 if (dtmf_length_samples_ > dtmf_duration_samples) {
173 if (dtmf_duration_samples <= 0) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000174 // Skip send packet at start, since we shouldn't use duration 0
175 send = false;
176 }
177 } else {
178 ended = true;
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700179 dtmf_event_is_on_ = false;
180 dtmf_time_last_sent_ = clock_->TimeInMilliseconds();
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000181 }
182 if (send) {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700183 if (dtmf_duration_samples > 0xffff) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000184 // RFC 4733 2.5.2.3 Long-Duration Events
solenbergffbbcac2016-11-17 05:25:37 -0800185 SendTelephoneEventPacket(ended, dtmf_timestamp_,
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000186 static_cast<uint16_t>(0xffff), false);
187
188 // set new timestap for this segment
danilchape5b41412016-08-22 03:39:23 -0700189 dtmf_timestamp_ = rtp_timestamp;
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700190 dtmf_duration_samples -= 0xffff;
191 dtmf_length_samples_ -= 0xffff;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000192
solenbergffbbcac2016-11-17 05:25:37 -0800193 return SendTelephoneEventPacket(ended, dtmf_timestamp_,
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700194 static_cast<uint16_t>(dtmf_duration_samples), false);
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000195 } else {
solenbergffbbcac2016-11-17 05:25:37 -0800196 if (!SendTelephoneEventPacket(ended, dtmf_timestamp_,
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700197 dtmf_duration_samples,
198 !dtmf_event_first_packet_sent_)) {
199 return false;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000200 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700201 dtmf_event_first_packet_sent_ = true;
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700202 return true;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000203 }
204 }
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700205 return true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000206 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700207 if (payload_size == 0 || payload_data == NULL) {
208 if (frame_type == kEmptyFrame) {
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000209 // we don't send empty audio RTP packets
210 // no error since we use it to drive DTMF when we use VAD
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700211 return true;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000212 }
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700213 return false;
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000214 }
solenbergffbbcac2016-11-17 05:25:37 -0800215
danilchap84c85282016-09-05 07:27:57 -0700216 std::unique_ptr<RtpPacketToSend> packet = rtp_sender_->AllocatePacket();
217 packet->SetMarker(MarkerBit(frame_type, payload_type));
218 packet->SetPayloadType(payload_type);
219 packet->SetTimestamp(rtp_timestamp);
220 packet->set_capture_time_ms(clock_->TimeInMilliseconds());
221 // Update audio level extension, if included.
222 packet->SetExtension<AudioLevel>(frame_type == kAudioFrameSpeech,
223 audio_level_dbov);
pwestin@webrtc.orgdf9bd9b2012-01-17 11:42:02 +0000224
Niels Möller90397d92017-10-27 10:51:20 +0200225 uint8_t* payload = packet->AllocatePayload(payload_size);
226 if (!payload) // Too large payload buffer.
227 return false;
228 memcpy(payload, payload_data, payload_size);
skvlad98bb6642016-04-07 15:36:45 -0700229
danilchap84c85282016-09-05 07:27:57 -0700230 if (!rtp_sender_->AssignSequenceNumber(packet.get()))
231 return false;
232
danilchap162abd32015-12-10 02:39:40 -0800233 {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700234 rtc::CritScope cs(&send_audio_critsect_);
235 last_payload_type_ = payload_type;
danilchap162abd32015-12-10 02:39:40 -0800236 }
danilchape5b41412016-08-22 03:39:23 -0700237 TRACE_EVENT_ASYNC_END2("webrtc", "Audio", rtp_timestamp, "timestamp",
danilchap84c85282016-09-05 07:27:57 -0700238 packet->Timestamp(), "seqnum",
239 packet->SequenceNumber());
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700240 bool send_result = rtp_sender_->SendToNetwork(
danilchap84c85282016-09-05 07:27:57 -0700241 std::move(packet), kAllowRetransmission, RtpPacketSender::kHighPriority);
skvlad98bb6642016-04-07 15:36:45 -0700242 if (first_packet_sent_()) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100243 RTC_LOG(LS_INFO) << "First audio RTP packet sent to pacer";
skvlad98bb6642016-04-07 15:36:45 -0700244 }
245 return send_result;
niklase@google.com470e71d2011-07-07 08:21:25 +0000246}
247
danilchap162abd32015-12-10 02:39:40 -0800248// Audio level magnitude and voice activity flag are set for each RTP packet
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700249int32_t RTPSenderAudio::SetAudioLevel(uint8_t level_dbov) {
250 if (level_dbov > 127) {
danilchap162abd32015-12-10 02:39:40 -0800251 return -1;
252 }
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700253 rtc::CritScope cs(&send_audio_critsect_);
254 audio_level_dbov_ = level_dbov;
danilchap162abd32015-12-10 02:39:40 -0800255 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000256}
257
niklase@google.com470e71d2011-07-07 08:21:25 +0000258// Send a TelephoneEvent tone using RFC 2833 (4733)
danilchap162abd32015-12-10 02:39:40 -0800259int32_t RTPSenderAudio::SendTelephoneEvent(uint8_t key,
260 uint16_t time_ms,
261 uint8_t level) {
solenbergffbbcac2016-11-17 05:25:37 -0800262 DtmfQueue::Event event;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000263 {
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700264 rtc::CritScope lock(&send_audio_critsect_);
265 if (dtmf_payload_type_ < 0) {
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000266 // TelephoneEvent payloadtype not configured
267 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000268 }
solenbergffbbcac2016-11-17 05:25:37 -0800269 event.payload_type = dtmf_payload_type_;
pbos@webrtc.org7c4d20f2015-02-12 12:20:08 +0000270 }
solenbergffbbcac2016-11-17 05:25:37 -0800271 event.key = key;
272 event.duration_ms = time_ms;
273 event.level = level;
274 return dtmf_queue_.AddDtmf(event) ? 0 : -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000275}
276
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700277bool RTPSenderAudio::SendTelephoneEventPacket(bool ended,
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700278 uint32_t dtmf_timestamp,
279 uint16_t duration,
280 bool marker_bit) {
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700281 uint8_t send_count = 1;
282 bool result = true;
niklase@google.com470e71d2011-07-07 08:21:25 +0000283
danilchap162abd32015-12-10 02:39:40 -0800284 if (ended) {
285 // resend last packet in an event 3 times
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700286 send_count = 3;
danilchap162abd32015-12-10 02:39:40 -0800287 }
288 do {
danilchap84c85282016-09-05 07:27:57 -0700289 // Send DTMF data.
290 constexpr RtpPacketToSend::ExtensionManager* kNoExtensions = nullptr;
291 constexpr size_t kDtmfSize = 4;
292 std::unique_ptr<RtpPacketToSend> packet(
293 new RtpPacketToSend(kNoExtensions, kRtpHeaderSize + kDtmfSize));
solenbergffbbcac2016-11-17 05:25:37 -0800294 packet->SetPayloadType(dtmf_current_event_.payload_type);
danilchap84c85282016-09-05 07:27:57 -0700295 packet->SetMarker(marker_bit);
296 packet->SetSsrc(rtp_sender_->SSRC());
297 packet->SetTimestamp(dtmf_timestamp);
298 packet->set_capture_time_ms(clock_->TimeInMilliseconds());
299 if (!rtp_sender_->AssignSequenceNumber(packet.get()))
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700300 return false;
niklase@google.com470e71d2011-07-07 08:21:25 +0000301
danilchap84c85282016-09-05 07:27:57 -0700302 // Create DTMF data.
303 uint8_t* dtmfbuffer = packet->AllocatePayload(kDtmfSize);
304 RTC_DCHECK(dtmfbuffer);
danilchap162abd32015-12-10 02:39:40 -0800305 /* From RFC 2833:
danilchap162abd32015-12-10 02:39:40 -0800306 0 1 2 3
307 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
308 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
309 | event |E|R| volume | duration |
310 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
311 */
312 // R bit always cleared
313 uint8_t R = 0x00;
solenbergffbbcac2016-11-17 05:25:37 -0800314 uint8_t volume = dtmf_current_event_.level;
niklase@google.com470e71d2011-07-07 08:21:25 +0000315
danilchap162abd32015-12-10 02:39:40 -0800316 // First packet un-ended
317 uint8_t E = ended ? 0x80 : 0x00;
niklase@google.com470e71d2011-07-07 08:21:25 +0000318
danilchap162abd32015-12-10 02:39:40 -0800319 // First byte is Event number, equals key number
solenbergffbbcac2016-11-17 05:25:37 -0800320 dtmfbuffer[0] = dtmf_current_event_.key;
danilchap84c85282016-09-05 07:27:57 -0700321 dtmfbuffer[1] = E | R | volume;
322 ByteWriter<uint16_t>::WriteBigEndian(dtmfbuffer + 2, duration);
niklase@google.com470e71d2011-07-07 08:21:25 +0000323
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700324 TRACE_EVENT_INSTANT2(
325 TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "Audio::SendTelephoneEvent",
danilchap84c85282016-09-05 07:27:57 -0700326 "timestamp", packet->Timestamp(), "seqnum", packet->SequenceNumber());
327 result = rtp_sender_->SendToNetwork(std::move(packet), kAllowRetransmission,
Sergey Ulanovec4f0682016-07-28 15:19:10 -0700328 RtpPacketSender::kHighPriority);
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700329 send_count--;
330 } while (send_count > 0 && result);
niklase@google.com470e71d2011-07-07 08:21:25 +0000331
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700332 return result;
niklase@google.com470e71d2011-07-07 08:21:25 +0000333}
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000334} // namespace webrtc