OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2010 Google Inc. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright notice, | |
9 * this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 * this list of conditions and the following disclaimer in the documentation | |
12 * and/or other materials provided with the distribution. | |
13 * 3. The name of the author may not be used to endorse or promote products | |
14 * derived from this software without specific prior written permission. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 #include <string> | |
29 | |
30 #include "talk/media/base/fakemediaengine.h" | |
31 #include "talk/media/base/rtpdump.h" | |
32 #include "talk/media/base/testutils.h" | |
33 #include "webrtc/p2p/base/fakesession.h" | |
34 #include "talk/session/media/channel.h" | |
35 #include "talk/session/media/mediarecorder.h" | |
36 #include "webrtc/base/bytebuffer.h" | |
37 #include "webrtc/base/fileutils.h" | |
38 #include "webrtc/base/gunit.h" | |
39 #include "webrtc/base/pathutils.h" | |
40 #include "webrtc/base/thread.h" | |
41 | |
42 namespace cricket { | |
43 | |
44 rtc::StreamInterface* Open(const std::string& path) { | |
45 return rtc::Filesystem::OpenFile( | |
46 rtc::Pathname(path), "wb"); | |
47 } | |
48 | |
49 ///////////////////////////////////////////////////////////////////////// | |
50 // Test RtpDumpSink | |
51 ///////////////////////////////////////////////////////////////////////// | |
52 class RtpDumpSinkTest : public testing::Test { | |
53 public: | |
54 virtual void SetUp() { | |
55 EXPECT_TRUE(rtc::Filesystem::GetTemporaryFolder(path_, true, NULL)); | |
56 path_.SetPathname(rtc::Filesystem::TempFilename(path_, "sink-test")); | |
57 sink_.reset(new RtpDumpSink(Open(path_.pathname()))); | |
58 | |
59 for (int i = 0; i < ARRAY_SIZE(rtp_buf_); ++i) { | |
60 RtpTestUtility::kTestRawRtpPackets[i].WriteToByteBuffer( | |
61 RtpTestUtility::kDefaultSsrc, &rtp_buf_[i]); | |
62 } | |
63 } | |
64 | |
65 virtual void TearDown() { | |
66 stream_.reset(); | |
67 EXPECT_TRUE(rtc::Filesystem::DeleteFile(path_)); | |
68 } | |
69 | |
70 protected: | |
71 void OnRtpPacket(const RawRtpPacket& raw) { | |
72 rtc::ByteBuffer buf; | |
73 raw.WriteToByteBuffer(RtpTestUtility::kDefaultSsrc, &buf); | |
74 sink_->OnPacket(buf.Data(), buf.Length(), false); | |
75 } | |
76 | |
77 rtc::StreamResult ReadPacket(RtpDumpPacket* packet) { | |
78 if (!stream_.get()) { | |
79 sink_.reset(); // This will close the file. So we can read it. | |
80 stream_.reset(rtc::Filesystem::OpenFile(path_, "rb")); | |
81 reader_.reset(new RtpDumpReader(stream_.get())); | |
82 } | |
83 return reader_->ReadPacket(packet); | |
84 } | |
85 | |
86 rtc::Pathname path_; | |
87 rtc::scoped_ptr<RtpDumpSink> sink_; | |
88 rtc::ByteBuffer rtp_buf_[3]; | |
89 rtc::scoped_ptr<rtc::StreamInterface> stream_; | |
90 rtc::scoped_ptr<RtpDumpReader> reader_; | |
91 }; | |
92 | |
93 TEST_F(RtpDumpSinkTest, TestRtpDumpSink) { | |
94 // By default, the sink is disabled. The 1st packet is not written. | |
95 EXPECT_FALSE(sink_->IsEnabled()); | |
96 sink_->set_packet_filter(PF_ALL); | |
97 OnRtpPacket(RtpTestUtility::kTestRawRtpPackets[0]); | |
98 | |
99 // Enable the sink. The 2nd packet is written. | |
100 EXPECT_TRUE(sink_->Enable(true)); | |
101 EXPECT_TRUE(sink_->IsEnabled()); | |
102 EXPECT_TRUE(rtc::Filesystem::IsFile(path_.pathname())); | |
103 OnRtpPacket(RtpTestUtility::kTestRawRtpPackets[1]); | |
104 | |
105 // Disable the sink. The 3rd packet is not written. | |
106 EXPECT_TRUE(sink_->Enable(false)); | |
107 EXPECT_FALSE(sink_->IsEnabled()); | |
108 OnRtpPacket(RtpTestUtility::kTestRawRtpPackets[2]); | |
109 | |
110 // Read the recorded file and verify it contains only the 2nd packet. | |
111 RtpDumpPacket packet; | |
112 EXPECT_EQ(rtc::SR_SUCCESS, ReadPacket(&packet)); | |
113 EXPECT_TRUE(RtpTestUtility::VerifyPacket( | |
114 &packet, &RtpTestUtility::kTestRawRtpPackets[1], false)); | |
115 EXPECT_EQ(rtc::SR_EOS, ReadPacket(&packet)); | |
116 } | |
117 | |
118 TEST_F(RtpDumpSinkTest, TestRtpDumpSinkMaxSize) { | |
119 EXPECT_TRUE(sink_->Enable(true)); | |
120 sink_->set_packet_filter(PF_ALL); | |
121 sink_->SetMaxSize(strlen(RtpDumpFileHeader::kFirstLine) + | |
122 RtpDumpFileHeader::kHeaderLength + | |
123 RtpDumpPacket::kHeaderLength + | |
124 RtpTestUtility::kTestRawRtpPackets[0].size()); | |
125 OnRtpPacket(RtpTestUtility::kTestRawRtpPackets[0]); | |
126 | |
127 // Exceed the limit size: the 2nd and 3rd packets are not written. | |
128 OnRtpPacket(RtpTestUtility::kTestRawRtpPackets[1]); | |
129 OnRtpPacket(RtpTestUtility::kTestRawRtpPackets[2]); | |
130 | |
131 // Read the recorded file and verify that it contains only the first packet. | |
132 RtpDumpPacket packet; | |
133 EXPECT_EQ(rtc::SR_SUCCESS, ReadPacket(&packet)); | |
134 EXPECT_TRUE(RtpTestUtility::VerifyPacket( | |
135 &packet, &RtpTestUtility::kTestRawRtpPackets[0], false)); | |
136 EXPECT_EQ(rtc::SR_EOS, ReadPacket(&packet)); | |
137 } | |
138 | |
139 TEST_F(RtpDumpSinkTest, TestRtpDumpSinkFilter) { | |
140 // The default filter is PF_NONE. | |
141 EXPECT_EQ(PF_NONE, sink_->packet_filter()); | |
142 | |
143 // Set to PF_RTPHEADER before enable. | |
144 sink_->set_packet_filter(PF_RTPHEADER); | |
145 EXPECT_EQ(PF_RTPHEADER, sink_->packet_filter()); | |
146 EXPECT_TRUE(sink_->Enable(true)); | |
147 // We dump only the header of the first packet. | |
148 OnRtpPacket(RtpTestUtility::kTestRawRtpPackets[0]); | |
149 | |
150 // Set the filter to PF_RTPPACKET. We dump all the second packet. | |
151 sink_->set_packet_filter(PF_RTPPACKET); | |
152 EXPECT_EQ(PF_RTPPACKET, sink_->packet_filter()); | |
153 OnRtpPacket(RtpTestUtility::kTestRawRtpPackets[1]); | |
154 | |
155 // Set the filter to PF_NONE. We do not dump the third packet. | |
156 sink_->set_packet_filter(PF_NONE); | |
157 EXPECT_EQ(PF_NONE, sink_->packet_filter()); | |
158 OnRtpPacket(RtpTestUtility::kTestRawRtpPackets[2]); | |
159 | |
160 // Read the recorded file and verify the header of the first packet and | |
161 // the whole packet for the second packet. | |
162 RtpDumpPacket packet; | |
163 EXPECT_EQ(rtc::SR_SUCCESS, ReadPacket(&packet)); | |
164 EXPECT_TRUE(RtpTestUtility::VerifyPacket( | |
165 &packet, &RtpTestUtility::kTestRawRtpPackets[0], true)); | |
166 EXPECT_EQ(rtc::SR_SUCCESS, ReadPacket(&packet)); | |
167 EXPECT_TRUE(RtpTestUtility::VerifyPacket( | |
168 &packet, &RtpTestUtility::kTestRawRtpPackets[1], false)); | |
169 EXPECT_EQ(rtc::SR_EOS, ReadPacket(&packet)); | |
170 } | |
171 | |
172 ///////////////////////////////////////////////////////////////////////// | |
173 // Test MediaRecorder | |
174 ///////////////////////////////////////////////////////////////////////// | |
175 void TestMediaRecorder(BaseChannel* channel, | |
176 FakeVideoMediaChannel* video_media_channel, | |
177 int filter) { | |
178 // Create media recorder. | |
179 rtc::scoped_ptr<MediaRecorder> recorder(new MediaRecorder); | |
180 // Fail to EnableChannel before AddChannel. | |
181 EXPECT_FALSE(recorder->EnableChannel(channel, true, true, SINK_PRE_CRYPTO)); | |
182 EXPECT_FALSE(channel->HasSendSinks(SINK_PRE_CRYPTO)); | |
183 EXPECT_FALSE(channel->HasRecvSinks(SINK_PRE_CRYPTO)); | |
184 EXPECT_FALSE(channel->HasSendSinks(SINK_POST_CRYPTO)); | |
185 EXPECT_FALSE(channel->HasRecvSinks(SINK_POST_CRYPTO)); | |
186 | |
187 // Add the channel to the recorder. | |
188 rtc::Pathname path; | |
189 EXPECT_TRUE(rtc::Filesystem::GetTemporaryFolder(path, true, NULL)); | |
190 std::string send_file = | |
191 rtc::Filesystem::TempFilename(path, "send"); | |
192 std::string recv_file = | |
193 rtc::Filesystem::TempFilename(path, "recv"); | |
194 if (video_media_channel) { | |
195 EXPECT_TRUE(recorder->AddChannel(static_cast<VideoChannel*>(channel), | |
196 Open(send_file), Open(recv_file), filter)); | |
197 } else { | |
198 EXPECT_TRUE(recorder->AddChannel(static_cast<VoiceChannel*>(channel), | |
199 Open(send_file), Open(recv_file), filter)); | |
200 } | |
201 | |
202 // Enable recording only the sent media. | |
203 EXPECT_TRUE(recorder->EnableChannel(channel, true, false, SINK_PRE_CRYPTO)); | |
204 EXPECT_TRUE(channel->HasSendSinks(SINK_PRE_CRYPTO)); | |
205 EXPECT_FALSE(channel->HasRecvSinks(SINK_POST_CRYPTO)); | |
206 EXPECT_FALSE(channel->HasSendSinks(SINK_POST_CRYPTO)); | |
207 EXPECT_FALSE(channel->HasRecvSinks(SINK_POST_CRYPTO)); | |
208 if (video_media_channel) { | |
209 EXPECT_TRUE_WAIT(video_media_channel->sent_intra_frame(), 100); | |
210 } | |
211 | |
212 // Enable recording only the received meida. | |
213 EXPECT_TRUE(recorder->EnableChannel(channel, false, true, SINK_PRE_CRYPTO)); | |
214 EXPECT_FALSE(channel->HasSendSinks(SINK_PRE_CRYPTO)); | |
215 EXPECT_TRUE(channel->HasRecvSinks(SINK_PRE_CRYPTO)); | |
216 if (video_media_channel) { | |
217 EXPECT_TRUE(video_media_channel->requested_intra_frame()); | |
218 } | |
219 | |
220 // Enable recording both the sent and the received video. | |
221 EXPECT_TRUE(recorder->EnableChannel(channel, true, true, SINK_PRE_CRYPTO)); | |
222 EXPECT_TRUE(channel->HasSendSinks(SINK_PRE_CRYPTO)); | |
223 EXPECT_TRUE(channel->HasRecvSinks(SINK_PRE_CRYPTO)); | |
224 | |
225 // Enable recording only headers. | |
226 if (video_media_channel) { | |
227 video_media_channel->set_sent_intra_frame(false); | |
228 video_media_channel->set_requested_intra_frame(false); | |
229 } | |
230 EXPECT_TRUE(recorder->EnableChannel(channel, true, true, SINK_PRE_CRYPTO)); | |
231 EXPECT_TRUE(channel->HasSendSinks(SINK_PRE_CRYPTO)); | |
232 EXPECT_TRUE(channel->HasRecvSinks(SINK_PRE_CRYPTO)); | |
233 if (video_media_channel) { | |
234 if ((filter & PF_RTPPACKET) == PF_RTPPACKET) { | |
235 // If record the whole RTP packet, trigers FIR. | |
236 EXPECT_TRUE(video_media_channel->requested_intra_frame()); | |
237 EXPECT_TRUE(video_media_channel->sent_intra_frame()); | |
238 } else { | |
239 // If record only the RTP header, does not triger FIR. | |
240 EXPECT_FALSE(video_media_channel->requested_intra_frame()); | |
241 EXPECT_FALSE(video_media_channel->sent_intra_frame()); | |
242 } | |
243 } | |
244 | |
245 // Remove the voice channel from the recorder. | |
246 recorder->RemoveChannel(channel, SINK_PRE_CRYPTO); | |
247 EXPECT_FALSE(channel->HasSendSinks(SINK_PRE_CRYPTO)); | |
248 EXPECT_FALSE(channel->HasRecvSinks(SINK_PRE_CRYPTO)); | |
249 | |
250 // Delete all files. | |
251 recorder.reset(); | |
252 EXPECT_TRUE(rtc::Filesystem::DeleteFile(send_file)); | |
253 EXPECT_TRUE(rtc::Filesystem::DeleteFile(recv_file)); | |
254 } | |
255 | |
256 // Fisrt start recording header and then start recording media. Verify that | |
257 // differnt files are created for header and media. | |
258 void TestRecordHeaderAndMedia(BaseChannel* channel, | |
259 FakeVideoMediaChannel* video_media_channel) { | |
260 // Create RTP header recorder. | |
261 rtc::scoped_ptr<MediaRecorder> header_recorder(new MediaRecorder); | |
262 | |
263 rtc::Pathname path; | |
264 EXPECT_TRUE(rtc::Filesystem::GetTemporaryFolder(path, true, NULL)); | |
265 std::string send_header_file = | |
266 rtc::Filesystem::TempFilename(path, "send-header"); | |
267 std::string recv_header_file = | |
268 rtc::Filesystem::TempFilename(path, "recv-header"); | |
269 if (video_media_channel) { | |
270 EXPECT_TRUE(header_recorder->AddChannel( | |
271 static_cast<VideoChannel*>(channel), | |
272 Open(send_header_file), Open(recv_header_file), PF_RTPHEADER)); | |
273 } else { | |
274 EXPECT_TRUE(header_recorder->AddChannel( | |
275 static_cast<VoiceChannel*>(channel), | |
276 Open(send_header_file), Open(recv_header_file), PF_RTPHEADER)); | |
277 } | |
278 | |
279 // Enable recording both sent and received. | |
280 EXPECT_TRUE( | |
281 header_recorder->EnableChannel(channel, true, true, SINK_POST_CRYPTO)); | |
282 EXPECT_TRUE(channel->HasSendSinks(SINK_POST_CRYPTO)); | |
283 EXPECT_TRUE(channel->HasRecvSinks(SINK_POST_CRYPTO)); | |
284 EXPECT_FALSE(channel->HasSendSinks(SINK_PRE_CRYPTO)); | |
285 EXPECT_FALSE(channel->HasRecvSinks(SINK_PRE_CRYPTO)); | |
286 if (video_media_channel) { | |
287 EXPECT_FALSE(video_media_channel->sent_intra_frame()); | |
288 EXPECT_FALSE(video_media_channel->requested_intra_frame()); | |
289 } | |
290 | |
291 // Verify that header files are created. | |
292 EXPECT_TRUE(rtc::Filesystem::IsFile(send_header_file)); | |
293 EXPECT_TRUE(rtc::Filesystem::IsFile(recv_header_file)); | |
294 | |
295 // Create RTP header recorder. | |
296 rtc::scoped_ptr<MediaRecorder> recorder(new MediaRecorder); | |
297 std::string send_file = | |
298 rtc::Filesystem::TempFilename(path, "send"); | |
299 std::string recv_file = | |
300 rtc::Filesystem::TempFilename(path, "recv"); | |
301 if (video_media_channel) { | |
302 EXPECT_TRUE(recorder->AddChannel( | |
303 static_cast<VideoChannel*>(channel), | |
304 Open(send_file), Open(recv_file), PF_RTPPACKET)); | |
305 } else { | |
306 EXPECT_TRUE(recorder->AddChannel( | |
307 static_cast<VoiceChannel*>(channel), | |
308 Open(send_file), Open(recv_file), PF_RTPPACKET)); | |
309 } | |
310 | |
311 // Enable recording both sent and received. | |
312 EXPECT_TRUE(recorder->EnableChannel(channel, true, true, SINK_PRE_CRYPTO)); | |
313 EXPECT_TRUE(channel->HasSendSinks(SINK_POST_CRYPTO)); | |
314 EXPECT_TRUE(channel->HasRecvSinks(SINK_POST_CRYPTO)); | |
315 EXPECT_TRUE(channel->HasSendSinks(SINK_PRE_CRYPTO)); | |
316 EXPECT_TRUE(channel->HasRecvSinks(SINK_PRE_CRYPTO)); | |
317 if (video_media_channel) { | |
318 EXPECT_TRUE_WAIT(video_media_channel->sent_intra_frame(), 100); | |
319 EXPECT_TRUE(video_media_channel->requested_intra_frame()); | |
320 } | |
321 | |
322 // Verify that media files are created. | |
323 EXPECT_TRUE(rtc::Filesystem::IsFile(send_file)); | |
324 EXPECT_TRUE(rtc::Filesystem::IsFile(recv_file)); | |
325 | |
326 // Delete all files. | |
327 header_recorder.reset(); | |
328 recorder.reset(); | |
329 EXPECT_TRUE(rtc::Filesystem::DeleteFile(send_header_file)); | |
330 EXPECT_TRUE(rtc::Filesystem::DeleteFile(recv_header_file)); | |
331 EXPECT_TRUE(rtc::Filesystem::DeleteFile(send_file)); | |
332 EXPECT_TRUE(rtc::Filesystem::DeleteFile(recv_file)); | |
333 } | |
334 | |
335 TEST(MediaRecorderTest, TestMediaRecorderVoiceChannel) { | |
336 // Create the voice channel. | |
337 FakeMediaEngine media_engine; | |
338 VoiceChannel channel(rtc::Thread::Current(), &media_engine, | |
339 new FakeVoiceMediaChannel(NULL), NULL, "", false); | |
340 TestMediaRecorder(&channel, NULL, PF_RTPPACKET); | |
341 TestMediaRecorder(&channel, NULL, PF_RTPHEADER); | |
342 TestRecordHeaderAndMedia(&channel, NULL); | |
343 } | |
344 | |
345 TEST(MediaRecorderTest, TestMediaRecorderVideoChannel) { | |
346 // Create the video channel. | |
347 FakeMediaEngine media_engine; | |
348 FakeVideoMediaChannel* media_channel = new FakeVideoMediaChannel(NULL); | |
349 VideoChannel channel(rtc::Thread::Current(), &media_engine, | |
350 media_channel, NULL, "", false); | |
351 TestMediaRecorder(&channel, media_channel, PF_RTPPACKET); | |
352 TestMediaRecorder(&channel, media_channel, PF_RTPHEADER); | |
353 TestRecordHeaderAndMedia(&channel, media_channel); | |
354 } | |
355 | |
356 } // namespace cricket | |
OLD | NEW |