OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
11 #include "webrtc/modules/audio_coding/acm2/initial_delay_manager.h" | |
12 | |
13 namespace webrtc { | |
14 | |
15 namespace acm2 { | |
16 | |
17 InitialDelayManager::InitialDelayManager(int initial_delay_ms, | |
18 int late_packet_threshold) | |
19 : last_packet_type_(kUndefinedPacket), | |
20 last_receive_timestamp_(0), | |
21 timestamp_step_(0), | |
22 audio_payload_type_(kInvalidPayloadType), | |
23 initial_delay_ms_(initial_delay_ms), | |
24 buffered_audio_ms_(0), | |
25 buffering_(true), | |
26 playout_timestamp_(0), | |
27 late_packet_threshold_(late_packet_threshold) { | |
28 last_packet_rtp_info_.header.payloadType = kInvalidPayloadType; | |
29 last_packet_rtp_info_.header.ssrc = 0; | |
30 last_packet_rtp_info_.header.sequenceNumber = 0; | |
31 last_packet_rtp_info_.header.timestamp = 0; | |
32 } | |
33 | |
34 void InitialDelayManager::UpdateLastReceivedPacket( | |
35 const WebRtcRTPHeader& rtp_info, | |
36 uint32_t receive_timestamp, | |
37 PacketType type, | |
38 bool new_codec, | |
39 int sample_rate_hz, | |
40 SyncStream* sync_stream) { | |
41 assert(sync_stream); | |
42 | |
43 // If payload of audio packets is changing |new_codec| has to be true. | |
44 assert(!(!new_codec && type == kAudioPacket && | |
45 rtp_info.header.payloadType != audio_payload_type_)); | |
46 | |
47 // Just shorthands. | |
48 const RTPHeader* current_header = &rtp_info.header; | |
49 RTPHeader* last_header = &last_packet_rtp_info_.header; | |
50 | |
51 // Don't do anything if getting DTMF. The chance of DTMF in applications where | |
52 // initial delay is required is very low (we don't know of any). This avoids a | |
53 // lot of corner cases. The effect of ignoring DTMF packet is minimal. Note | |
54 // that DTMFs are inserted into NetEq just not accounted here. | |
55 if (type == kAvtPacket || | |
56 (last_packet_type_ != kUndefinedPacket && | |
57 !IsNewerSequenceNumber(current_header->sequenceNumber, | |
58 last_header->sequenceNumber))) { | |
59 sync_stream->num_sync_packets = 0; | |
60 return; | |
61 } | |
62 | |
63 // Either if it is a new packet or the first packet record and set variables. | |
64 if (new_codec || | |
65 last_packet_rtp_info_.header.payloadType == kInvalidPayloadType) { | |
66 timestamp_step_ = 0; | |
67 if (type == kAudioPacket) | |
68 audio_payload_type_ = rtp_info.header.payloadType; | |
69 else | |
70 audio_payload_type_ = kInvalidPayloadType; // Invalid. | |
71 | |
72 RecordLastPacket(rtp_info, receive_timestamp, type); | |
73 sync_stream->num_sync_packets = 0; | |
74 buffered_audio_ms_ = 0; | |
75 buffering_ = true; | |
76 | |
77 // If |buffering_| is set then |playout_timestamp_| should have correct | |
78 // value. | |
79 UpdatePlayoutTimestamp(*current_header, sample_rate_hz); | |
80 return; | |
81 } | |
82 | |
83 uint32_t timestamp_increase = current_header->timestamp - | |
84 last_header->timestamp; | |
85 | |
86 // |timestamp_increase| is invalid if this is the first packet. The effect is | |
87 // that |buffered_audio_ms_| is not increased. | |
88 if (last_packet_type_ == kUndefinedPacket) { | |
89 timestamp_increase = 0; | |
90 } | |
91 | |
92 if (buffering_) { | |
93 buffered_audio_ms_ += timestamp_increase * 1000 / sample_rate_hz; | |
94 | |
95 // A timestamp that reflects the initial delay, while buffering. | |
96 UpdatePlayoutTimestamp(*current_header, sample_rate_hz); | |
97 | |
98 if (buffered_audio_ms_ >= initial_delay_ms_) | |
99 buffering_ = false; | |
100 } | |
101 | |
102 if (current_header->sequenceNumber == last_header->sequenceNumber + 1) { | |
103 // Two consecutive audio packets, the previous packet-type is audio, so we | |
104 // can update |timestamp_step_|. | |
105 if (last_packet_type_ == kAudioPacket) | |
106 timestamp_step_ = timestamp_increase; | |
107 RecordLastPacket(rtp_info, receive_timestamp, type); | |
108 sync_stream->num_sync_packets = 0; | |
109 return; | |
110 } | |
111 | |
112 uint16_t packet_gap = current_header->sequenceNumber - | |
113 last_header->sequenceNumber - 1; | |
114 | |
115 // For smooth transitions leave a gap between audio and sync packets. | |
116 sync_stream->num_sync_packets = last_packet_type_ == kSyncPacket ? | |
117 packet_gap - 1 : packet_gap - 2; | |
118 | |
119 // Do nothing if we haven't received any audio packet. | |
120 if (sync_stream->num_sync_packets > 0 && | |
121 audio_payload_type_ != kInvalidPayloadType) { | |
122 if (timestamp_step_ == 0) { | |
123 // Make an estimate for |timestamp_step_| if it is not updated, yet. | |
124 assert(packet_gap > 0); | |
125 timestamp_step_ = timestamp_increase / (packet_gap + 1); | |
126 } | |
127 sync_stream->timestamp_step = timestamp_step_; | |
128 | |
129 // Build the first sync-packet based on the current received packet. | |
130 memcpy(&sync_stream->rtp_info, &rtp_info, sizeof(rtp_info)); | |
131 sync_stream->rtp_info.header.payloadType = audio_payload_type_; | |
132 | |
133 uint16_t sequence_number_update = sync_stream->num_sync_packets + 1; | |
134 uint32_t timestamp_update = timestamp_step_ * sequence_number_update; | |
135 | |
136 // Rewind sequence number and timestamps. This will give a more accurate | |
137 // description of the missing packets. | |
138 // | |
139 // Note that we leave a gap between the last packet in sync-stream and the | |
140 // current received packet, so it should be compensated for in the following | |
141 // computation of timestamps and sequence number. | |
142 sync_stream->rtp_info.header.sequenceNumber -= sequence_number_update; | |
143 sync_stream->receive_timestamp = receive_timestamp - timestamp_update; | |
144 sync_stream->rtp_info.header.timestamp -= timestamp_update; | |
145 sync_stream->rtp_info.header.payloadType = audio_payload_type_; | |
146 } else { | |
147 sync_stream->num_sync_packets = 0; | |
148 } | |
149 | |
150 RecordLastPacket(rtp_info, receive_timestamp, type); | |
151 return; | |
152 } | |
153 | |
154 void InitialDelayManager::RecordLastPacket(const WebRtcRTPHeader& rtp_info, | |
155 uint32_t receive_timestamp, | |
156 PacketType type) { | |
157 last_packet_type_ = type; | |
158 last_receive_timestamp_ = receive_timestamp; | |
159 memcpy(&last_packet_rtp_info_, &rtp_info, sizeof(rtp_info)); | |
160 } | |
161 | |
162 void InitialDelayManager::LatePackets( | |
163 uint32_t timestamp_now, SyncStream* sync_stream) { | |
164 assert(sync_stream); | |
165 sync_stream->num_sync_packets = 0; | |
166 | |
167 // If there is no estimate of timestamp increment, |timestamp_step_|, then | |
168 // we cannot estimate the number of late packets. | |
169 // If the last packet has been CNG, estimating late packets is not meaningful, | |
170 // as a CNG packet is on unknown length. | |
171 // We can set a higher threshold if the last packet is CNG and continue | |
172 // execution, but this is how ACM1 code was written. | |
173 if (timestamp_step_ <= 0 || | |
174 last_packet_type_ == kCngPacket || | |
175 last_packet_type_ == kUndefinedPacket || | |
176 audio_payload_type_ == kInvalidPayloadType) // No audio packet received. | |
177 return; | |
178 | |
179 int num_late_packets = (timestamp_now - last_receive_timestamp_) / | |
180 timestamp_step_; | |
181 | |
182 if (num_late_packets < late_packet_threshold_) | |
183 return; | |
184 | |
185 int sync_offset = 1; // One gap at the end of the sync-stream. | |
186 if (last_packet_type_ != kSyncPacket) { | |
187 ++sync_offset; // One more gap at the beginning of the sync-stream. | |
188 --num_late_packets; | |
189 } | |
190 uint32_t timestamp_update = sync_offset * timestamp_step_; | |
191 | |
192 sync_stream->num_sync_packets = num_late_packets; | |
193 if (num_late_packets == 0) | |
194 return; | |
195 | |
196 // Build the first sync-packet in the sync-stream. | |
197 memcpy(&sync_stream->rtp_info, &last_packet_rtp_info_, | |
198 sizeof(last_packet_rtp_info_)); | |
199 | |
200 // Increase sequence number and timestamps. | |
201 sync_stream->rtp_info.header.sequenceNumber += sync_offset; | |
202 sync_stream->rtp_info.header.timestamp += timestamp_update; | |
203 sync_stream->receive_timestamp = last_receive_timestamp_ + timestamp_update; | |
204 sync_stream->timestamp_step = timestamp_step_; | |
205 | |
206 // Sync-packets have audio payload-type. | |
207 sync_stream->rtp_info.header.payloadType = audio_payload_type_; | |
208 | |
209 uint16_t sequence_number_update = num_late_packets + sync_offset - 1; | |
210 timestamp_update = sequence_number_update * timestamp_step_; | |
211 | |
212 // Fake the last RTP, assuming the caller will inject the whole sync-stream. | |
213 last_packet_rtp_info_.header.timestamp += timestamp_update; | |
214 last_packet_rtp_info_.header.sequenceNumber += sequence_number_update; | |
215 last_packet_rtp_info_.header.payloadType = audio_payload_type_; | |
216 last_receive_timestamp_ += timestamp_update; | |
217 | |
218 last_packet_type_ = kSyncPacket; | |
219 return; | |
220 } | |
221 | |
222 bool InitialDelayManager::GetPlayoutTimestamp(uint32_t* playout_timestamp) { | |
223 if (!buffering_) { | |
224 return false; | |
225 } | |
226 *playout_timestamp = playout_timestamp_; | |
227 return true; | |
228 } | |
229 | |
230 void InitialDelayManager::DisableBuffering() { | |
231 buffering_ = false; | |
232 } | |
233 | |
234 void InitialDelayManager::UpdatePlayoutTimestamp( | |
235 const RTPHeader& current_header, int sample_rate_hz) { | |
236 playout_timestamp_ = current_header.timestamp - static_cast<uint32_t>( | |
237 initial_delay_ms_ * sample_rate_hz / 1000); | |
238 } | |
239 | |
240 } // namespace acm2 | |
241 | |
242 } // namespace webrtc | |
OLD | NEW |