~morphis/aethercast/audio-streaming

« back to all changes in this revision

Viewing changes to tests/mcs/streaming/rtpsender_tests.cpp

Rework part of the streaming framework and add further unit tests

This reworks the streaming framework to be better testable which wasn't the case before
for all parts. Most critical parts are covered with tests now.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2016 Canonical, Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU General Public License version 3, as published
 
6
 * by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful, but
 
9
 * WITHOUT ANY WARRANTY; without even the implied warranties of
 
10
 * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
 
11
 * PURPOSE.  See the GNU General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU General Public License along
 
14
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 */
 
17
 
 
18
#include <gmock/gmock.h>
 
19
 
 
20
#include "mcs/network/stream.h"
 
21
 
 
22
#include "mcs/streaming/rtpsender.h"
 
23
 
 
24
using namespace ::testing;
 
25
 
 
26
namespace {
 
27
static constexpr unsigned int kRTPHeaderSize{12};
 
28
static constexpr unsigned int kStreamMaxUnitSize = 1472;
 
29
static constexpr unsigned int kMPEGTSPacketSize{188};
 
30
static constexpr unsigned int kSourceID = 0xdeadbeef;
 
31
// See http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml
 
32
static constexpr unsigned int kRTPPayloadTypeMP2T = 33;
 
33
 
 
34
class MockNetworkStream : public mcs::network::Stream {
 
35
public:
 
36
    MOCK_METHOD2(Connect, bool(const std::string &address, const mcs::network::Port &port));
 
37
    MOCK_METHOD0(WaitUntilReady, bool());
 
38
    MOCK_METHOD2(Write, mcs::network::Stream::Error(const uint8_t*, unsigned int));
 
39
    MOCK_CONST_METHOD0(LocalPort, mcs::network::Port());
 
40
    MOCK_CONST_METHOD0(MaxUnitSize, std::uint32_t());
 
41
};
 
42
 
 
43
class MockSenderReport : public mcs::video::SenderReport {
 
44
public:
 
45
    MOCK_METHOD2(SentPacket, void(const mcs::TimestampUs&, const size_t&));
 
46
};
 
47
}
 
48
 
 
49
TEST(RTPSender, ForwardsCorrectPort) {
 
50
    auto mock_stream = std::make_shared<MockNetworkStream>();
 
51
    auto mock_report = std::make_shared<MockSenderReport>();
 
52
 
 
53
    EXPECT_CALL(*mock_stream, MaxUnitSize())
 
54
            .WillRepeatedly(Return(kStreamMaxUnitSize));
 
55
 
 
56
    mcs::network::Port local_port = 1234;
 
57
 
 
58
    EXPECT_CALL(*mock_stream, LocalPort())
 
59
            .Times(1)
 
60
            .WillOnce(Return(local_port));
 
61
 
 
62
    auto sender = std::make_shared<mcs::streaming::RTPSender>(mock_stream, mock_report);
 
63
 
 
64
    EXPECT_EQ(local_port, sender->LocalPort());
 
65
}
 
66
 
 
67
TEST(RTPSender, SpecifiesExecutableName) {
 
68
    auto mock_stream = std::make_shared<MockNetworkStream>();
 
69
    auto mock_report = std::make_shared<MockSenderReport>();
 
70
 
 
71
    EXPECT_CALL(*mock_stream, MaxUnitSize())
 
72
            .WillRepeatedly(Return(kStreamMaxUnitSize));
 
73
 
 
74
    auto sender = std::make_shared<mcs::streaming::RTPSender>(mock_stream, mock_report);
 
75
    EXPECT_NE(0, sender->Name().length());
 
76
}
 
77
 
 
78
TEST(RTPSender, StartAndStopDoesNotFail) {
 
79
    auto mock_stream = std::make_shared<MockNetworkStream>();
 
80
    auto mock_report = std::make_shared<MockSenderReport>();
 
81
 
 
82
    EXPECT_CALL(*mock_stream, MaxUnitSize())
 
83
            .WillRepeatedly(Return(kStreamMaxUnitSize));
 
84
 
 
85
    auto sender = std::make_shared<mcs::streaming::RTPSender>(mock_stream, mock_report);
 
86
 
 
87
    EXPECT_TRUE(sender->Start());
 
88
    EXPECT_TRUE(sender->Stop());
 
89
}
 
90
 
 
91
TEST(RTPSender, DoeNotAcceptIncorrectPacketSizes) {
 
92
    auto mock_stream = std::make_shared<MockNetworkStream>();
 
93
    auto mock_report = std::make_shared<MockSenderReport>();
 
94
 
 
95
    EXPECT_CALL(*mock_stream, MaxUnitSize())
 
96
            .WillRepeatedly(Return(kStreamMaxUnitSize));
 
97
 
 
98
    auto sender = std::make_shared<mcs::streaming::RTPSender>(mock_stream, mock_report);
 
99
 
 
100
    auto packets = mcs::video::Buffer::Create(kMPEGTSPacketSize + 1);
 
101
    EXPECT_FALSE(sender->Queue(packets));
 
102
 
 
103
    packets = mcs::video::Buffer::Create(kMPEGTSPacketSize - 1);
 
104
    EXPECT_FALSE(sender->Queue(packets));
 
105
}
 
106
 
 
107
TEST(RTPSender, ExecutesWithEmptyQueue) {
 
108
    auto mock_stream = std::make_shared<MockNetworkStream>();
 
109
    auto mock_report = std::make_shared<MockSenderReport>();
 
110
 
 
111
    EXPECT_CALL(*mock_stream, MaxUnitSize())
 
112
            .WillRepeatedly(Return(kStreamMaxUnitSize));
 
113
 
 
114
    auto sender = std::make_shared<mcs::streaming::RTPSender>(mock_stream, mock_report);
 
115
 
 
116
    EXPECT_TRUE(sender->Execute());
 
117
}
 
118
 
 
119
TEST(RTPSender, ExecuteDoesNotFailWhenStreamIsNotReady) {
 
120
    auto mock_stream = std::make_shared<MockNetworkStream>();
 
121
    auto mock_report = std::make_shared<MockSenderReport>();
 
122
 
 
123
    EXPECT_CALL(*mock_stream, MaxUnitSize())
 
124
            .WillRepeatedly(Return(kStreamMaxUnitSize));
 
125
 
 
126
    EXPECT_CALL(*mock_stream, WaitUntilReady())
 
127
            .Times(1)
 
128
            .WillOnce(Return(false));
 
129
 
 
130
    auto sender = std::make_shared<mcs::streaming::RTPSender>(mock_stream, mock_report);
 
131
 
 
132
    auto packets = mcs::video::Buffer::Create(kMPEGTSPacketSize);
 
133
 
 
134
    EXPECT_TRUE(sender->Queue(packets));
 
135
    EXPECT_TRUE(sender->Execute());
 
136
}
 
137
 
 
138
TEST(RTPSender, QueuesUpPackagesAndSendsAll) {
 
139
    auto mock_stream = std::make_shared<MockNetworkStream>();
 
140
    auto mock_report = std::make_shared<MockSenderReport>();
 
141
 
 
142
    auto now = mcs::Utils::GetNowUs();
 
143
 
 
144
    EXPECT_CALL(*mock_report, SentPacket(now, _))
 
145
            .Times(3);
 
146
 
 
147
    EXPECT_CALL(*mock_stream, MaxUnitSize())
 
148
            .WillRepeatedly(Return(kStreamMaxUnitSize));
 
149
 
 
150
    EXPECT_CALL(*mock_stream, WaitUntilReady())
 
151
            .Times(1)
 
152
            .WillOnce(Return(true));
 
153
 
 
154
    EXPECT_CALL(*mock_stream, Write(_, _))
 
155
            .Times(3)
 
156
            .WillRepeatedly(Return(mcs::network::Stream::Error::kNone));
 
157
 
 
158
    auto sender = std::make_shared<mcs::streaming::RTPSender>(mock_stream, mock_report);
 
159
 
 
160
    auto packets = mcs::video::Buffer::Create(kMPEGTSPacketSize * 15);
 
161
    packets->SetTimestamp(now);
 
162
 
 
163
    EXPECT_TRUE(sender->Queue(packets));
 
164
    EXPECT_TRUE(sender->Execute());
 
165
}
 
166
 
 
167
TEST(RTPSender, WritePackageFails) {
 
168
    auto mock_stream = std::make_shared<MockNetworkStream>();
 
169
    auto mock_report = std::make_shared<MockSenderReport>();
 
170
 
 
171
    EXPECT_CALL(*mock_stream, MaxUnitSize())
 
172
            .WillRepeatedly(Return(kStreamMaxUnitSize));
 
173
 
 
174
    EXPECT_CALL(*mock_stream, WaitUntilReady())
 
175
            .Times(1)
 
176
            .WillOnce(Return(true));
 
177
 
 
178
    EXPECT_CALL(*mock_stream, Write(_, _))
 
179
            .Times(1)
 
180
            .WillOnce(Return(mcs::network::Stream::Error::kRemoteClosedConnection));
 
181
 
 
182
    auto sender = std::make_shared<mcs::streaming::RTPSender>(mock_stream, mock_report);
 
183
 
 
184
    auto packets = mcs::video::Buffer::Create(kMPEGTSPacketSize);
 
185
 
 
186
    EXPECT_TRUE(sender->Queue(packets));
 
187
    EXPECT_FALSE(sender->Execute());
 
188
}
 
189
 
 
190
TEST(RTPSender, ConstructsCorrectRTPHeader) {
 
191
    auto mock_stream = std::make_shared<MockNetworkStream>();
 
192
    auto mock_report = std::make_shared<MockSenderReport>();
 
193
 
 
194
    auto packet_timestamp = mcs::Utils::GetNowUs();
 
195
 
 
196
    uint32_t expected_output_size = kMPEGTSPacketSize + kRTPHeaderSize;
 
197
 
 
198
    EXPECT_CALL(*mock_report, SentPacket(packet_timestamp, expected_output_size))
 
199
            .Times(1);
 
200
 
 
201
    EXPECT_CALL(*mock_stream, MaxUnitSize())
 
202
            .WillRepeatedly(Return(kStreamMaxUnitSize));
 
203
 
 
204
    EXPECT_CALL(*mock_stream, WaitUntilReady())
 
205
            .WillOnce(Return(true));
 
206
 
 
207
    std::uint8_t *output_data = nullptr;
 
208
 
 
209
    EXPECT_CALL(*mock_stream, Write(_, expected_output_size))
 
210
            .WillOnce(DoAll(Invoke([&](const uint8_t *data, unsigned int size) {
 
211
                                // Need to copy the data here as otherwise its freed
 
212
                                // as soon as the write call comes back.
 
213
                                output_data = new std::uint8_t[size];
 
214
                                ::memcpy(output_data, data, size);
 
215
                            }),
 
216
                            Return(mcs::network::Stream::Error::kNone)));
 
217
 
 
218
    auto sender = std::make_shared<mcs::streaming::RTPSender>(mock_stream, mock_report);
 
219
 
 
220
    auto packets = mcs::video::Buffer::Create(kMPEGTSPacketSize);
 
221
    packets->SetTimestamp(packet_timestamp);
 
222
 
 
223
    EXPECT_TRUE(sender->Queue(packets));
 
224
    EXPECT_TRUE(sender->Execute());
 
225
 
 
226
    EXPECT_NE(nullptr, output_data);
 
227
 
 
228
    EXPECT_EQ(0x80, output_data[0]);
 
229
    EXPECT_EQ(kRTPPayloadTypeMP2T, output_data[1]);
 
230
 
 
231
    // Sequence should start at 0
 
232
    EXPECT_EQ(0x00, output_data[2]);
 
233
    EXPECT_EQ(0x00, output_data[3]);
 
234
 
 
235
    // We can't compare the actual RTP time here but we can make sure
 
236
    // its between our start time and now.
 
237
    std::uint32_t rtp_time = 0;
 
238
    rtp_time |= (output_data[4] << 24);
 
239
    rtp_time |= (output_data[5] << 16);
 
240
    rtp_time |= (output_data[6] << 8);
 
241
    rtp_time |= (output_data[7] << 0);
 
242
 
 
243
    // Convert back from a 90 kHz clock
 
244
    rtp_time *= 100ll;
 
245
    rtp_time /= 9;
 
246
 
 
247
    auto packet_timestamp_ms = packet_timestamp / 1000ll;
 
248
    EXPECT_LE(packet_timestamp_ms, rtp_time);
 
249
    EXPECT_GE(mcs::Utils::GetNowUs(), rtp_time);
 
250
 
 
251
    std::uint32_t source_id = 0;
 
252
    source_id |= (output_data[8] << 24);
 
253
    source_id |= (output_data[9] << 16);
 
254
    source_id |= (output_data[10] << 8);
 
255
    source_id |= (output_data[11] << 0);
 
256
 
 
257
    EXPECT_EQ(kSourceID, source_id);
 
258
 
 
259
    if (output_data)
 
260
        delete output_data;
 
261
}