blob: 346ac5faeb983c42e97217514968e919aab76e90 [file] [log] [blame]
Niels Möller2e47f7c2018-10-16 10:41:42 +02001/*
2 * Copyright 2018 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
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "api/test/loopback_media_transport.h"
12
Niels Möllerd5696fb2018-11-28 15:34:37 +010013#include <algorithm>
Bjorn Mellem273d0292018-11-01 16:42:44 -070014#include <memory>
Niels Möller2e47f7c2018-10-16 10:41:42 +020015#include <vector>
16
Niels Möller2e47f7c2018-10-16 10:41:42 +020017#include "test/gmock.h"
18
19namespace webrtc {
20
21namespace {
22
23class MockMediaTransportAudioSinkInterface
24 : public MediaTransportAudioSinkInterface {
25 public:
26 MOCK_METHOD2(OnData, void(uint64_t, MediaTransportEncodedAudioFrame));
27};
28
Niels Möllerd5696fb2018-11-28 15:34:37 +010029class MockMediaTransportVideoSinkInterface
30 : public MediaTransportVideoSinkInterface {
31 public:
32 MOCK_METHOD2(OnData, void(uint64_t, MediaTransportEncodedVideoFrame));
Niels Möller1c7f5f62018-12-10 11:06:02 +010033};
34
35class MockMediaTransportKeyFrameRequestCallback
36 : public MediaTransportKeyFrameRequestCallback {
37 public:
Niels Möllerd5696fb2018-11-28 15:34:37 +010038 MOCK_METHOD1(OnKeyFrameRequested, void(uint64_t));
39};
40
Bjorn Mellem273d0292018-11-01 16:42:44 -070041class MockDataChannelSink : public DataChannelSink {
42 public:
43 MOCK_METHOD3(OnDataReceived,
44 void(int, DataMessageType, const rtc::CopyOnWriteBuffer&));
45 MOCK_METHOD1(OnChannelClosing, void(int));
46 MOCK_METHOD1(OnChannelClosed, void(int));
Bjorn A Mellemb689af42019-08-21 10:44:59 -070047 MOCK_METHOD0(OnReadyToSend, void());
Bjorn Mellem273d0292018-11-01 16:42:44 -070048};
49
Bjorn Mellem175aa2e2018-11-08 11:23:22 -080050class MockStateCallback : public MediaTransportStateCallback {
51 public:
52 MOCK_METHOD1(OnStateChanged, void(MediaTransportState));
53};
54
Niels Möller2e47f7c2018-10-16 10:41:42 +020055// Test only uses the sequence number.
56MediaTransportEncodedAudioFrame CreateAudioFrame(int sequence_number) {
57 static constexpr int kSamplingRateHz = 48000;
58 static constexpr int kStartingSampleIndex = 0;
59 static constexpr int kSamplesPerChannel = 480;
Niels Möllerd8a1b7a2018-12-06 13:00:27 +010060 static constexpr int kPayloadType = 17;
Niels Möller2e47f7c2018-10-16 10:41:42 +020061
62 return MediaTransportEncodedAudioFrame(
63 kSamplingRateHz, kStartingSampleIndex, kSamplesPerChannel,
64 sequence_number, MediaTransportEncodedAudioFrame::FrameType::kSpeech,
65 kPayloadType, std::vector<uint8_t>(kSamplesPerChannel));
66}
67
Niels Möllerd5696fb2018-11-28 15:34:37 +010068MediaTransportEncodedVideoFrame CreateVideoFrame(
69 int frame_id,
70 const webrtc::EncodedImage& encoded_image) {
Niels Möllerd8a1b7a2018-12-06 13:00:27 +010071 static constexpr int kPayloadType = 18;
Niels Möllerd5696fb2018-11-28 15:34:37 +010072 return MediaTransportEncodedVideoFrame(frame_id, /*referenced_frame_ids=*/{},
Niels Möllerd8a1b7a2018-12-06 13:00:27 +010073 kPayloadType, encoded_image);
Niels Möllerd5696fb2018-11-28 15:34:37 +010074}
75
Niels Möller2e47f7c2018-10-16 10:41:42 +020076} // namespace
77
78TEST(LoopbackMediaTransport, AudioWithNoSinkSilentlyIgnored) {
Bjorn Mellem273d0292018-11-01 16:42:44 -070079 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
80 thread->Start();
81 MediaTransportPair transport_pair(thread.get());
Niels Möller2e47f7c2018-10-16 10:41:42 +020082 transport_pair.first()->SendAudioFrame(1, CreateAudioFrame(0));
83 transport_pair.second()->SendAudioFrame(2, CreateAudioFrame(0));
Bjorn Mellem273d0292018-11-01 16:42:44 -070084 transport_pair.FlushAsyncInvokes();
Niels Möller2e47f7c2018-10-16 10:41:42 +020085}
86
87TEST(LoopbackMediaTransport, AudioDeliveredToSink) {
Bjorn Mellem273d0292018-11-01 16:42:44 -070088 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
89 thread->Start();
90 MediaTransportPair transport_pair(thread.get());
Mirko Bonadei6a489f22019-04-09 15:11:12 +020091 ::testing::StrictMock<MockMediaTransportAudioSinkInterface> sink;
Niels Möller2e47f7c2018-10-16 10:41:42 +020092 EXPECT_CALL(sink,
Mirko Bonadei6a489f22019-04-09 15:11:12 +020093 OnData(1, ::testing::Property(
Niels Möller2e47f7c2018-10-16 10:41:42 +020094 &MediaTransportEncodedAudioFrame::sequence_number,
Mirko Bonadei6a489f22019-04-09 15:11:12 +020095 ::testing::Eq(10))));
Niels Möller2e47f7c2018-10-16 10:41:42 +020096 transport_pair.second()->SetReceiveAudioSink(&sink);
97 transport_pair.first()->SendAudioFrame(1, CreateAudioFrame(10));
98
Bjorn Mellem273d0292018-11-01 16:42:44 -070099 transport_pair.FlushAsyncInvokes();
Niels Möller2e47f7c2018-10-16 10:41:42 +0200100 transport_pair.second()->SetReceiveAudioSink(nullptr);
101}
102
Niels Möllerd5696fb2018-11-28 15:34:37 +0100103TEST(LoopbackMediaTransport, VideoDeliveredToSink) {
104 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
105 thread->Start();
106 MediaTransportPair transport_pair(thread.get());
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200107 ::testing::StrictMock<MockMediaTransportVideoSinkInterface> sink;
Niels Möller663844d2019-02-14 16:15:54 +0100108 constexpr uint8_t encoded_data[] = {1, 2, 3};
Niels Möllerd5696fb2018-11-28 15:34:37 +0100109 EncodedImage encoded_image;
Niels Möller4d504c72019-06-18 15:56:56 +0200110 encoded_image.SetEncodedData(
111 EncodedImageBuffer::Create(encoded_data, sizeof(encoded_data)));
Niels Möllerd5696fb2018-11-28 15:34:37 +0100112
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200113 EXPECT_CALL(sink, OnData(1, ::testing::Property(
Niels Möllerd5696fb2018-11-28 15:34:37 +0100114 &MediaTransportEncodedVideoFrame::frame_id,
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200115 ::testing::Eq(10))))
116 .WillOnce(::testing::Invoke(
Niels Möllerd5696fb2018-11-28 15:34:37 +0100117 [&encoded_image](int frame_id,
118 const MediaTransportEncodedVideoFrame& frame) {
Niels Möller4d504c72019-06-18 15:56:56 +0200119 EXPECT_EQ(frame.encoded_image().data(), encoded_image.data());
Niels Möller77536a22019-01-15 08:50:01 +0100120 EXPECT_EQ(frame.encoded_image().size(), encoded_image.size());
Niels Möllerd5696fb2018-11-28 15:34:37 +0100121 }));
122
123 transport_pair.second()->SetReceiveVideoSink(&sink);
124 transport_pair.first()->SendVideoFrame(1,
125 CreateVideoFrame(10, encoded_image));
126
127 transport_pair.FlushAsyncInvokes();
128 transport_pair.second()->SetReceiveVideoSink(nullptr);
129}
130
Niels Möller1c7f5f62018-12-10 11:06:02 +0100131TEST(LoopbackMediaTransport, VideoKeyFrameRequestDeliveredToCallback) {
132 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
133 thread->Start();
134 MediaTransportPair transport_pair(thread.get());
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200135 ::testing::StrictMock<MockMediaTransportKeyFrameRequestCallback> callback1;
136 ::testing::StrictMock<MockMediaTransportKeyFrameRequestCallback> callback2;
Niels Möller1c7f5f62018-12-10 11:06:02 +0100137 const uint64_t kFirstChannelId = 1111;
138 const uint64_t kSecondChannelId = 2222;
139
140 EXPECT_CALL(callback1, OnKeyFrameRequested(kSecondChannelId));
141 EXPECT_CALL(callback2, OnKeyFrameRequested(kFirstChannelId));
142 transport_pair.first()->SetKeyFrameRequestCallback(&callback1);
143 transport_pair.second()->SetKeyFrameRequestCallback(&callback2);
144
145 transport_pair.first()->RequestKeyFrame(kFirstChannelId);
146 transport_pair.second()->RequestKeyFrame(kSecondChannelId);
147
148 transport_pair.FlushAsyncInvokes();
149}
150
Bjorn Mellem273d0292018-11-01 16:42:44 -0700151TEST(LoopbackMediaTransport, DataDeliveredToSink) {
152 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
153 thread->Start();
154 MediaTransportPair transport_pair(thread.get());
155
156 MockDataChannelSink sink;
157 transport_pair.first()->SetDataSink(&sink);
158
159 const int channel_id = 1;
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200160 EXPECT_CALL(
161 sink, OnDataReceived(
162 channel_id, DataMessageType::kText,
163 ::testing::Property<rtc::CopyOnWriteBuffer, const char*>(
164 &rtc::CopyOnWriteBuffer::cdata, ::testing::StrEq("foo"))));
Bjorn Mellem273d0292018-11-01 16:42:44 -0700165
166 SendDataParams params;
167 params.type = DataMessageType::kText;
168 rtc::CopyOnWriteBuffer buffer("foo");
169 transport_pair.second()->SendData(channel_id, params, buffer);
170
171 transport_pair.FlushAsyncInvokes();
172 transport_pair.first()->SetDataSink(nullptr);
173}
174
175TEST(LoopbackMediaTransport, CloseDeliveredToSink) {
176 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
177 thread->Start();
178 MediaTransportPair transport_pair(thread.get());
179
180 MockDataChannelSink first_sink;
181 transport_pair.first()->SetDataSink(&first_sink);
182
183 MockDataChannelSink second_sink;
184 transport_pair.second()->SetDataSink(&second_sink);
185
186 const int channel_id = 1;
187 {
Mirko Bonadei6a489f22019-04-09 15:11:12 +0200188 ::testing::InSequence s;
Bjorn Mellem273d0292018-11-01 16:42:44 -0700189 EXPECT_CALL(second_sink, OnChannelClosing(channel_id));
190 EXPECT_CALL(second_sink, OnChannelClosed(channel_id));
191 EXPECT_CALL(first_sink, OnChannelClosed(channel_id));
192 }
193
194 transport_pair.first()->CloseChannel(channel_id);
195
196 transport_pair.FlushAsyncInvokes();
197 transport_pair.first()->SetDataSink(nullptr);
198 transport_pair.second()->SetDataSink(nullptr);
199}
200
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800201TEST(LoopbackMediaTransport, InitialStateDeliveredWhenCallbackSet) {
202 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
203 thread->Start();
204 MediaTransportPair transport_pair(thread.get());
205
206 MockStateCallback state_callback;
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800207 EXPECT_CALL(state_callback, OnStateChanged(MediaTransportState::kPending));
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700208
Bjorn Mellem175aa2e2018-11-08 11:23:22 -0800209 transport_pair.first()->SetMediaTransportStateCallback(&state_callback);
210 transport_pair.FlushAsyncInvokes();
211}
212
213TEST(LoopbackMediaTransport, ChangedStateDeliveredWhenCallbackSet) {
214 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
215 thread->Start();
216 MediaTransportPair transport_pair(thread.get());
217
218 transport_pair.SetState(MediaTransportState::kWritable);
219 transport_pair.FlushAsyncInvokes();
220
221 MockStateCallback state_callback;
222
223 EXPECT_CALL(state_callback, OnStateChanged(MediaTransportState::kWritable));
224 transport_pair.first()->SetMediaTransportStateCallback(&state_callback);
225 transport_pair.FlushAsyncInvokes();
226}
227
228TEST(LoopbackMediaTransport, StateChangeDeliveredToCallback) {
229 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
230 thread->Start();
231 MediaTransportPair transport_pair(thread.get());
232
233 MockStateCallback state_callback;
234
235 EXPECT_CALL(state_callback, OnStateChanged(MediaTransportState::kPending));
236 EXPECT_CALL(state_callback, OnStateChanged(MediaTransportState::kWritable));
237 transport_pair.first()->SetMediaTransportStateCallback(&state_callback);
238 transport_pair.SetState(MediaTransportState::kWritable);
239 transport_pair.FlushAsyncInvokes();
240}
241
Bjorn A Mellemb689af42019-08-21 10:44:59 -0700242TEST(LoopbackMediaTransport, NotReadyToSendWhenDataSinkSet) {
243 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
244 thread->Start();
245 MediaTransportPair transport_pair(thread.get());
246
247 MockDataChannelSink data_channel_sink;
248 EXPECT_CALL(data_channel_sink, OnReadyToSend()).Times(0);
249
250 transport_pair.first()->SetDataSink(&data_channel_sink);
251 transport_pair.FlushAsyncInvokes();
252 transport_pair.first()->SetDataSink(nullptr);
253}
254
255TEST(LoopbackMediaTransport, ReadyToSendWhenDataSinkSet) {
256 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
257 thread->Start();
258 MediaTransportPair transport_pair(thread.get());
259
260 transport_pair.SetState(MediaTransportState::kWritable);
261 transport_pair.FlushAsyncInvokes();
262
263 MockDataChannelSink data_channel_sink;
264 EXPECT_CALL(data_channel_sink, OnReadyToSend());
265
266 transport_pair.first()->SetDataSink(&data_channel_sink);
267 transport_pair.FlushAsyncInvokes();
268 transport_pair.first()->SetDataSink(nullptr);
269}
270
271TEST(LoopbackMediaTransport, StateChangeDeliveredToDataSink) {
272 std::unique_ptr<rtc::Thread> thread = rtc::Thread::Create();
273 thread->Start();
274 MediaTransportPair transport_pair(thread.get());
275
276 MockDataChannelSink data_channel_sink;
277 EXPECT_CALL(data_channel_sink, OnReadyToSend());
278
279 transport_pair.first()->SetDataSink(&data_channel_sink);
280 transport_pair.SetState(MediaTransportState::kWritable);
281 transport_pair.FlushAsyncInvokes();
282 transport_pair.first()->SetDataSink(nullptr);
283}
284
Niels Möller2e47f7c2018-10-16 10:41:42 +0200285} // namespace webrtc