OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
93 } | 93 } |
94 } // namespace | 94 } // namespace |
95 | 95 |
96 class AudioDecoderTest : public ::testing::Test { | 96 class AudioDecoderTest : public ::testing::Test { |
97 protected: | 97 protected: |
98 AudioDecoderTest() | 98 AudioDecoderTest() |
99 : input_audio_( | 99 : input_audio_( |
100 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), | 100 webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), |
101 32000), | 101 32000), |
102 codec_input_rate_hz_(32000), // Legacy default value. | 102 codec_input_rate_hz_(32000), // Legacy default value. |
103 encoded_(NULL), | |
104 frame_size_(0), | 103 frame_size_(0), |
105 data_length_(0), | 104 data_length_(0), |
106 encoded_bytes_(0), | 105 encoded_bytes_(0), |
107 channels_(1), | 106 channels_(1), |
108 payload_type_(17), | 107 payload_type_(17), |
109 decoder_(NULL) {} | 108 decoder_(NULL) {} |
110 | 109 |
111 virtual ~AudioDecoderTest() {} | 110 virtual ~AudioDecoderTest() {} |
112 | 111 |
113 virtual void SetUp() { | 112 virtual void SetUp() { |
114 if (audio_encoder_) | 113 if (audio_encoder_) |
115 codec_input_rate_hz_ = audio_encoder_->SampleRateHz(); | 114 codec_input_rate_hz_ = audio_encoder_->SampleRateHz(); |
116 // Create arrays. | 115 // Create arrays. |
117 ASSERT_GT(data_length_, 0u) << "The test must set data_length_ > 0"; | 116 ASSERT_GT(data_length_, 0u) << "The test must set data_length_ > 0"; |
118 // Longest encoded data is produced by PCM16b with 2 bytes per sample. | 117 // Make sure the encode buffer is empty at the start of each test. |
119 encoded_ = new uint8_t[data_length_ * 2]; | 118 encoded_.Clear(); |
kwiberg-webrtc
2016/02/25 00:29:04
Can you allocate a Buffer on the stack for each te
ossu
2016/02/25 10:39:51
Sure.
| |
120 // Logging to view input and output in Matlab. | 119 // Logging to view input and output in Matlab. |
121 // Use 'gyp -Denable_data_logging=1' to enable logging. | 120 // Use 'gyp -Denable_data_logging=1' to enable logging. |
122 DataLog::CreateLog(); | 121 DataLog::CreateLog(); |
123 DataLog::AddTable("CodecTest"); | 122 DataLog::AddTable("CodecTest"); |
124 DataLog::AddColumn("CodecTest", "input", 1); | 123 DataLog::AddColumn("CodecTest", "input", 1); |
125 DataLog::AddColumn("CodecTest", "output", 1); | 124 DataLog::AddColumn("CodecTest", "output", 1); |
126 } | 125 } |
127 | 126 |
128 virtual void TearDown() { | 127 virtual void TearDown() { |
129 delete decoder_; | 128 delete decoder_; |
130 decoder_ = NULL; | 129 decoder_ = NULL; |
131 // Delete arrays. | |
132 delete [] encoded_; | |
133 encoded_ = NULL; | |
134 // Close log. | 130 // Close log. |
135 DataLog::ReturnLog(); | 131 DataLog::ReturnLog(); |
136 } | 132 } |
137 | 133 |
138 virtual void InitEncoder() { } | 134 virtual void InitEncoder() { } |
139 | 135 |
140 // TODO(henrik.lundin) Change return type to size_t once most/all overriding | 136 // TODO(henrik.lundin) Change return type to size_t once most/all overriding |
141 // implementations are gone. | 137 // implementations are gone. |
142 virtual int EncodeFrame(const int16_t* input, | 138 virtual int EncodeFrame(const int16_t* input, |
143 size_t input_len_samples, | 139 size_t input_len_samples, |
144 uint8_t* output) { | 140 rtc::Buffer* output) { |
145 encoded_info_.encoded_bytes = 0; | 141 encoded_info_.encoded_bytes = 0; |
146 const size_t samples_per_10ms = audio_encoder_->SampleRateHz() / 100; | 142 const size_t samples_per_10ms = audio_encoder_->SampleRateHz() / 100; |
147 RTC_CHECK_EQ(samples_per_10ms * audio_encoder_->Num10MsFramesInNextPacket(), | 143 RTC_CHECK_EQ(samples_per_10ms * audio_encoder_->Num10MsFramesInNextPacket(), |
148 input_len_samples); | 144 input_len_samples); |
149 std::unique_ptr<int16_t[]> interleaved_input( | 145 std::unique_ptr<int16_t[]> interleaved_input( |
150 new int16_t[channels_ * samples_per_10ms]); | 146 new int16_t[channels_ * samples_per_10ms]); |
151 for (size_t i = 0; i < audio_encoder_->Num10MsFramesInNextPacket(); ++i) { | 147 for (size_t i = 0; i < audio_encoder_->Num10MsFramesInNextPacket(); ++i) { |
152 EXPECT_EQ(0u, encoded_info_.encoded_bytes); | 148 EXPECT_EQ(0u, encoded_info_.encoded_bytes); |
153 | 149 |
154 // Duplicate the mono input signal to however many channels the test | 150 // Duplicate the mono input signal to however many channels the test |
155 // wants. | 151 // wants. |
156 test::InputAudioFile::DuplicateInterleaved(input + i * samples_per_10ms, | 152 test::InputAudioFile::DuplicateInterleaved(input + i * samples_per_10ms, |
157 samples_per_10ms, channels_, | 153 samples_per_10ms, channels_, |
158 interleaved_input.get()); | 154 interleaved_input.get()); |
159 | 155 |
160 encoded_info_ = audio_encoder_->Encode( | 156 encoded_info_ = audio_encoder_->Encode( |
161 0, rtc::ArrayView<const int16_t>(interleaved_input.get(), | 157 0, rtc::ArrayView<const int16_t>(interleaved_input.get(), |
162 audio_encoder_->NumChannels() * | 158 audio_encoder_->NumChannels() * |
163 audio_encoder_->SampleRateHz() / | 159 audio_encoder_->SampleRateHz() / |
164 100), | 160 100), |
165 data_length_ * 2, output); | 161 output); |
166 } | 162 } |
167 EXPECT_EQ(payload_type_, encoded_info_.payload_type); | 163 EXPECT_EQ(payload_type_, encoded_info_.payload_type); |
168 return static_cast<int>(encoded_info_.encoded_bytes); | 164 return static_cast<int>(encoded_info_.encoded_bytes); |
169 } | 165 } |
170 | 166 |
171 // Encodes and decodes audio. The absolute difference between the input and | 167 // Encodes and decodes audio. The absolute difference between the input and |
172 // output is compared vs |tolerance|, and the mean-squared error is compared | 168 // output is compared vs |tolerance|, and the mean-squared error is compared |
173 // with |mse|. The encoded stream should contain |expected_bytes|. For stereo | 169 // with |mse|. The encoded stream should contain |expected_bytes|. For stereo |
174 // audio, the absolute difference between the two channels is compared vs | 170 // audio, the absolute difference between the two channels is compared vs |
175 // |channel_diff_tolerance|. | 171 // |channel_diff_tolerance|. |
176 void EncodeDecodeTest(size_t expected_bytes, int tolerance, double mse, | 172 void EncodeDecodeTest(size_t expected_bytes, int tolerance, double mse, |
177 int delay = 0, int channel_diff_tolerance = 0) { | 173 int delay = 0, int channel_diff_tolerance = 0) { |
178 ASSERT_GE(tolerance, 0) << "Test must define a tolerance >= 0"; | 174 ASSERT_GE(tolerance, 0) << "Test must define a tolerance >= 0"; |
179 ASSERT_GE(channel_diff_tolerance, 0) << | 175 ASSERT_GE(channel_diff_tolerance, 0) << |
180 "Test must define a channel_diff_tolerance >= 0"; | 176 "Test must define a channel_diff_tolerance >= 0"; |
181 size_t processed_samples = 0u; | 177 size_t processed_samples = 0u; |
178 encoded_.Clear(); | |
182 encoded_bytes_ = 0u; | 179 encoded_bytes_ = 0u; |
183 InitEncoder(); | 180 InitEncoder(); |
184 std::vector<int16_t> input; | 181 std::vector<int16_t> input; |
185 std::vector<int16_t> decoded; | 182 std::vector<int16_t> decoded; |
186 while (processed_samples + frame_size_ <= data_length_) { | 183 while (processed_samples + frame_size_ <= data_length_) { |
187 // Extend input vector with |frame_size_|. | 184 // Extend input vector with |frame_size_|. |
188 input.resize(input.size() + frame_size_, 0); | 185 input.resize(input.size() + frame_size_, 0); |
189 // Read from input file. | 186 // Read from input file. |
190 ASSERT_GE(input.size() - processed_samples, frame_size_); | 187 ASSERT_GE(input.size() - processed_samples, frame_size_); |
191 ASSERT_TRUE(input_audio_.Read( | 188 ASSERT_TRUE(input_audio_.Read( |
192 frame_size_, codec_input_rate_hz_, &input[processed_samples])); | 189 frame_size_, codec_input_rate_hz_, &input[processed_samples])); |
193 size_t enc_len = EncodeFrame( | 190 size_t enc_len = EncodeFrame( |
194 &input[processed_samples], frame_size_, &encoded_[encoded_bytes_]); | 191 &input[processed_samples], frame_size_, &encoded_); |
195 // Make sure that frame_size_ * channels_ samples are allocated and free. | 192 // Make sure that frame_size_ * channels_ samples are allocated and free. |
196 decoded.resize((processed_samples + frame_size_) * channels_, 0); | 193 decoded.resize((processed_samples + frame_size_) * channels_, 0); |
197 AudioDecoder::SpeechType speech_type; | 194 AudioDecoder::SpeechType speech_type; |
198 size_t dec_len = decoder_->Decode( | 195 size_t dec_len = decoder_->Decode( |
199 &encoded_[encoded_bytes_], enc_len, codec_input_rate_hz_, | 196 &encoded_.data()[encoded_bytes_], enc_len, codec_input_rate_hz_, |
200 frame_size_ * channels_ * sizeof(int16_t), | 197 frame_size_ * channels_ * sizeof(int16_t), |
201 &decoded[processed_samples * channels_], &speech_type); | 198 &decoded[processed_samples * channels_], &speech_type); |
202 EXPECT_EQ(frame_size_ * channels_, dec_len); | 199 EXPECT_EQ(frame_size_ * channels_, dec_len); |
203 encoded_bytes_ += enc_len; | 200 encoded_bytes_ += enc_len; |
204 processed_samples += frame_size_; | 201 processed_samples += frame_size_; |
205 } | 202 } |
206 // For some codecs it doesn't make sense to check expected number of bytes, | 203 // For some codecs it doesn't make sense to check expected number of bytes, |
207 // since the number can vary for different platforms. Opus and iSAC are | 204 // since the number can vary for different platforms. Opus and iSAC are |
208 // such codecs. In this case expected_bytes is set to 0. | 205 // such codecs. In this case expected_bytes is set to 0. |
209 if (expected_bytes) { | 206 if (expected_bytes) { |
210 EXPECT_EQ(expected_bytes, encoded_bytes_); | 207 EXPECT_EQ(expected_bytes, encoded_bytes_); |
211 } | 208 } |
212 CompareInputOutput( | 209 CompareInputOutput( |
213 input, decoded, processed_samples, channels_, tolerance, delay); | 210 input, decoded, processed_samples, channels_, tolerance, delay); |
214 if (channels_ == 2) | 211 if (channels_ == 2) |
215 CompareTwoChannels( | 212 CompareTwoChannels( |
216 decoded, processed_samples, channels_, channel_diff_tolerance); | 213 decoded, processed_samples, channels_, channel_diff_tolerance); |
217 EXPECT_LE( | 214 EXPECT_LE( |
218 MseInputOutput(input, decoded, processed_samples, channels_, delay), | 215 MseInputOutput(input, decoded, processed_samples, channels_, delay), |
219 mse); | 216 mse); |
220 } | 217 } |
221 | 218 |
222 // Encodes a payload and decodes it twice with decoder re-init before each | 219 // Encodes a payload and decodes it twice with decoder re-init before each |
223 // decode. Verifies that the decoded result is the same. | 220 // decode. Verifies that the decoded result is the same. |
224 void ReInitTest() { | 221 void ReInitTest() { |
225 InitEncoder(); | 222 InitEncoder(); |
226 std::unique_ptr<int16_t[]> input(new int16_t[frame_size_]); | 223 std::unique_ptr<int16_t[]> input(new int16_t[frame_size_]); |
227 ASSERT_TRUE( | 224 ASSERT_TRUE( |
228 input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get())); | 225 input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get())); |
229 size_t enc_len = EncodeFrame(input.get(), frame_size_, encoded_); | 226 encoded_.Clear(); |
227 size_t enc_len = EncodeFrame(input.get(), frame_size_, &encoded_); | |
230 size_t dec_len; | 228 size_t dec_len; |
231 AudioDecoder::SpeechType speech_type1, speech_type2; | 229 AudioDecoder::SpeechType speech_type1, speech_type2; |
232 decoder_->Reset(); | 230 decoder_->Reset(); |
233 std::unique_ptr<int16_t[]> output1(new int16_t[frame_size_ * channels_]); | 231 std::unique_ptr<int16_t[]> output1(new int16_t[frame_size_ * channels_]); |
234 dec_len = decoder_->Decode(encoded_, enc_len, codec_input_rate_hz_, | 232 dec_len = decoder_->Decode(encoded_.data(), enc_len, codec_input_rate_hz_, |
235 frame_size_ * channels_ * sizeof(int16_t), | 233 frame_size_ * channels_ * sizeof(int16_t), |
236 output1.get(), &speech_type1); | 234 output1.get(), &speech_type1); |
237 ASSERT_LE(dec_len, frame_size_ * channels_); | 235 ASSERT_LE(dec_len, frame_size_ * channels_); |
238 EXPECT_EQ(frame_size_ * channels_, dec_len); | 236 EXPECT_EQ(frame_size_ * channels_, dec_len); |
239 // Re-init decoder and decode again. | 237 // Re-init decoder and decode again. |
240 decoder_->Reset(); | 238 decoder_->Reset(); |
241 std::unique_ptr<int16_t[]> output2(new int16_t[frame_size_ * channels_]); | 239 std::unique_ptr<int16_t[]> output2(new int16_t[frame_size_ * channels_]); |
242 dec_len = decoder_->Decode(encoded_, enc_len, codec_input_rate_hz_, | 240 dec_len = decoder_->Decode(encoded_.data(), enc_len, codec_input_rate_hz_, |
243 frame_size_ * channels_ * sizeof(int16_t), | 241 frame_size_ * channels_ * sizeof(int16_t), |
244 output2.get(), &speech_type2); | 242 output2.get(), &speech_type2); |
245 ASSERT_LE(dec_len, frame_size_ * channels_); | 243 ASSERT_LE(dec_len, frame_size_ * channels_); |
246 EXPECT_EQ(frame_size_ * channels_, dec_len); | 244 EXPECT_EQ(frame_size_ * channels_, dec_len); |
247 for (unsigned int n = 0; n < frame_size_; ++n) { | 245 for (unsigned int n = 0; n < frame_size_; ++n) { |
248 ASSERT_EQ(output1[n], output2[n]) << "Exit test on first diff; n = " << n; | 246 ASSERT_EQ(output1[n], output2[n]) << "Exit test on first diff; n = " << n; |
249 } | 247 } |
250 EXPECT_EQ(speech_type1, speech_type2); | 248 EXPECT_EQ(speech_type1, speech_type2); |
251 } | 249 } |
252 | 250 |
253 // Call DecodePlc and verify that the correct number of samples is produced. | 251 // Call DecodePlc and verify that the correct number of samples is produced. |
254 void DecodePlcTest() { | 252 void DecodePlcTest() { |
255 InitEncoder(); | 253 InitEncoder(); |
256 std::unique_ptr<int16_t[]> input(new int16_t[frame_size_]); | 254 std::unique_ptr<int16_t[]> input(new int16_t[frame_size_]); |
257 ASSERT_TRUE( | 255 ASSERT_TRUE( |
258 input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get())); | 256 input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get())); |
259 size_t enc_len = EncodeFrame(input.get(), frame_size_, encoded_); | 257 encoded_.Clear(); |
258 size_t enc_len = EncodeFrame(input.get(), frame_size_, &encoded_); | |
260 AudioDecoder::SpeechType speech_type; | 259 AudioDecoder::SpeechType speech_type; |
261 decoder_->Reset(); | 260 decoder_->Reset(); |
262 std::unique_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]); | 261 std::unique_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]); |
263 size_t dec_len = decoder_->Decode(encoded_, enc_len, codec_input_rate_hz_, | 262 size_t dec_len = decoder_->Decode(encoded_.data(), enc_len, |
263 codec_input_rate_hz_, | |
264 frame_size_ * channels_ * sizeof(int16_t), | 264 frame_size_ * channels_ * sizeof(int16_t), |
265 output.get(), &speech_type); | 265 output.get(), &speech_type); |
266 EXPECT_EQ(frame_size_ * channels_, dec_len); | 266 EXPECT_EQ(frame_size_ * channels_, dec_len); |
267 // Call DecodePlc and verify that we get one frame of data. | 267 // Call DecodePlc and verify that we get one frame of data. |
268 // (Overwrite the output from the above Decode call, but that does not | 268 // (Overwrite the output from the above Decode call, but that does not |
269 // matter.) | 269 // matter.) |
270 dec_len = decoder_->DecodePlc(1, output.get()); | 270 dec_len = decoder_->DecodePlc(1, output.get()); |
271 EXPECT_EQ(frame_size_ * channels_, dec_len); | 271 EXPECT_EQ(frame_size_ * channels_, dec_len); |
272 } | 272 } |
273 | 273 |
274 test::ResampleInputAudioFile input_audio_; | 274 test::ResampleInputAudioFile input_audio_; |
275 int codec_input_rate_hz_; | 275 int codec_input_rate_hz_; |
276 uint8_t* encoded_; | 276 rtc::Buffer encoded_; |
277 size_t frame_size_; | 277 size_t frame_size_; |
278 size_t data_length_; | 278 size_t data_length_; |
279 size_t encoded_bytes_; | 279 size_t encoded_bytes_; |
280 size_t channels_; | 280 size_t channels_; |
281 const int payload_type_; | 281 const int payload_type_; |
282 AudioEncoder::EncodedInfo encoded_info_; | 282 AudioEncoder::EncodedInfo encoded_info_; |
283 AudioDecoder* decoder_; | 283 AudioDecoder* decoder_; |
284 std::unique_ptr<AudioEncoder> audio_encoder_; | 284 std::unique_ptr<AudioEncoder> audio_encoder_; |
285 }; | 285 }; |
286 | 286 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
341 audio_encoder_.reset(new AudioEncoderIlbc(config)); | 341 audio_encoder_.reset(new AudioEncoderIlbc(config)); |
342 } | 342 } |
343 | 343 |
344 // Overload the default test since iLBC's function WebRtcIlbcfix_NetEqPlc does | 344 // Overload the default test since iLBC's function WebRtcIlbcfix_NetEqPlc does |
345 // not return any data. It simply resets a few states and returns 0. | 345 // not return any data. It simply resets a few states and returns 0. |
346 void DecodePlcTest() { | 346 void DecodePlcTest() { |
347 InitEncoder(); | 347 InitEncoder(); |
348 std::unique_ptr<int16_t[]> input(new int16_t[frame_size_]); | 348 std::unique_ptr<int16_t[]> input(new int16_t[frame_size_]); |
349 ASSERT_TRUE( | 349 ASSERT_TRUE( |
350 input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get())); | 350 input_audio_.Read(frame_size_, codec_input_rate_hz_, input.get())); |
351 size_t enc_len = EncodeFrame(input.get(), frame_size_, encoded_); | 351 encoded_.Clear(); |
352 size_t enc_len = EncodeFrame(input.get(), frame_size_, &encoded_); | |
352 AudioDecoder::SpeechType speech_type; | 353 AudioDecoder::SpeechType speech_type; |
353 decoder_->Reset(); | 354 decoder_->Reset(); |
354 std::unique_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]); | 355 std::unique_ptr<int16_t[]> output(new int16_t[frame_size_ * channels_]); |
355 size_t dec_len = decoder_->Decode(encoded_, enc_len, codec_input_rate_hz_, | 356 size_t dec_len = decoder_->Decode(encoded_.data(), enc_len, |
357 codec_input_rate_hz_, | |
356 frame_size_ * channels_ * sizeof(int16_t), | 358 frame_size_ * channels_ * sizeof(int16_t), |
357 output.get(), &speech_type); | 359 output.get(), &speech_type); |
358 EXPECT_EQ(frame_size_, dec_len); | 360 EXPECT_EQ(frame_size_, dec_len); |
359 // Simply call DecodePlc and verify that we get 0 as return value. | 361 // Simply call DecodePlc and verify that we get 0 as return value. |
360 EXPECT_EQ(0U, decoder_->DecodePlc(1, output.get())); | 362 EXPECT_EQ(0U, decoder_->DecodePlc(1, output.get())); |
361 } | 363 } |
362 }; | 364 }; |
363 | 365 |
364 class AudioDecoderIsacFloatTest : public AudioDecoderTest { | 366 class AudioDecoderIsacFloatTest : public AudioDecoderTest { |
365 protected: | 367 protected: |
(...skipping 376 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
742 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderCNGnb)); | 744 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderCNGnb)); |
743 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderCNGwb)); | 745 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderCNGwb)); |
744 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderCNGswb32kHz)); | 746 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderCNGswb32kHz)); |
745 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderCNGswb48kHz)); | 747 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderCNGswb48kHz)); |
746 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderArbitrary)); | 748 EXPECT_TRUE(CodecSupported(NetEqDecoder::kDecoderArbitrary)); |
747 EXPECT_EQ(has_opus, CodecSupported(NetEqDecoder::kDecoderOpus)); | 749 EXPECT_EQ(has_opus, CodecSupported(NetEqDecoder::kDecoderOpus)); |
748 EXPECT_EQ(has_opus, CodecSupported(NetEqDecoder::kDecoderOpus_2ch)); | 750 EXPECT_EQ(has_opus, CodecSupported(NetEqDecoder::kDecoderOpus_2ch)); |
749 } | 751 } |
750 | 752 |
751 } // namespace webrtc | 753 } // namespace webrtc |
OLD | NEW |