Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc.
3 : *
4 : * This program is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * This program is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 : */
17 :
18 : #include <cppunit/TestAssert.h>
19 : #include <cppunit/TestFixture.h>
20 : #include <cppunit/extensions/HelperMacros.h>
21 :
22 : #include <condition_variable>
23 : #include <filesystem>
24 : #include <string>
25 :
26 : #include "../../test_runner.h"
27 : #include "account_const.h"
28 : #include "fileutils.h"
29 : #include "jami.h"
30 : #include "jamidht/jamiaccount.h"
31 : #include "manager.h"
32 : #include "media_const.h"
33 : #include "client/videomanager.h"
34 :
35 : #include "common.h"
36 :
37 : using namespace libjami::Account;
38 : using namespace std::literals::chrono_literals;
39 :
40 : namespace jami {
41 : namespace test {
42 :
43 : struct CallData
44 : {
45 : std::string callId {};
46 : std::string state {};
47 : std::string mediaStatus {};
48 : std::string device {};
49 : std::string hostState {};
50 : bool changeRequested = false;
51 :
52 5 : void reset()
53 : {
54 5 : callId = "";
55 5 : state = "";
56 5 : mediaStatus = "";
57 5 : device = "";
58 5 : hostState = "";
59 5 : }
60 : };
61 :
62 : class RecorderTest : public CppUnit::TestFixture
63 : {
64 : public:
65 5 : RecorderTest()
66 5 : {
67 : // Init daemon
68 5 : libjami::init(libjami::InitFlag(libjami::LIBJAMI_FLAG_DEBUG | libjami::LIBJAMI_FLAG_CONSOLE_LOG));
69 5 : if (not Manager::instance().initialized)
70 1 : CPPUNIT_ASSERT(libjami::start("jami-sample.yml"));
71 5 : }
72 10 : ~RecorderTest() { libjami::fini(); }
73 2 : static std::string name() { return "Recorder"; }
74 : void setUp();
75 : void tearDown();
76 :
77 : std::string aliceId {};
78 : std::string bobId {};
79 : std::string recordDir {};
80 : std::string recordedFile {};
81 : std::string playerId {};
82 : std::shared_ptr<MediaPlayer> player {};
83 : CallData bobCall {};
84 :
85 : std::mutex mtx;
86 : std::unique_lock<std::mutex> lk {mtx};
87 : std::condition_variable cv;
88 :
89 : std::string videoPath = "file://" + std::filesystem::absolute("media/test_video_file.mp4").string();
90 :
91 : private:
92 : void registerSignalHandlers();
93 : void testRecordCall();
94 : void testRecordAudioOnlyCall();
95 : void testRecordCallOnePersonRdv();
96 : void testStopCallWhileRecording();
97 : void testDaemonPreference();
98 :
99 2 : CPPUNIT_TEST_SUITE(RecorderTest);
100 1 : CPPUNIT_TEST(testRecordCall);
101 1 : CPPUNIT_TEST(testRecordAudioOnlyCall);
102 1 : CPPUNIT_TEST(testRecordCallOnePersonRdv);
103 1 : CPPUNIT_TEST(testStopCallWhileRecording);
104 1 : CPPUNIT_TEST(testDaemonPreference);
105 4 : CPPUNIT_TEST_SUITE_END();
106 : };
107 :
108 : CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(RecorderTest, RecorderTest::name());
109 :
110 : void
111 5 : RecorderTest::setUp()
112 : {
113 : // Generate a temporary directory with a file inside
114 5 : recordDir = "records";
115 5 : dhtnet::fileutils::recursive_mkdir(recordDir.c_str());
116 5 : CPPUNIT_ASSERT(std::filesystem::is_directory(recordDir));
117 :
118 10 : auto actors = load_actors_and_wait_for_announcement("actors/alice-bob.yml");
119 5 : aliceId = actors["alice"];
120 5 : bobId = actors["bob"];
121 5 : bobCall.reset();
122 5 : playerId = jami::createMediaPlayer(videoPath);
123 5 : player = jami::getMediaPlayer(playerId);
124 5 : player->setAutoRestart(true);
125 5 : player->pause(false);
126 :
127 5 : libjami::setRecordPath(recordDir);
128 5 : }
129 :
130 : void
131 5 : RecorderTest::tearDown()
132 : {
133 5 : player.reset();
134 5 : jami::closeMediaPlayer(playerId);
135 5 : libjami::setIsAlwaysRecording(false);
136 5 : dhtnet::fileutils::removeAll(recordDir);
137 :
138 15 : wait_for_removal_of({aliceId, bobId});
139 5 : }
140 :
141 : void
142 5 : RecorderTest::registerSignalHandlers()
143 : {
144 5 : auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
145 5 : auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
146 5 : auto bobUri = bobAccount->getUsername();
147 :
148 5 : std::map<std::string, std::shared_ptr<libjami::CallbackWrapperBase>> confHandlers;
149 : // Watch signals
150 5 : confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::IncomingCallWithMedia>(
151 5 : [=](const std::string& accountId,
152 : const std::string& callId,
153 : const std::string&,
154 : const std::vector<std::map<std::string, std::string>>&) {
155 5 : if (accountId == bobId) {
156 5 : bobCall.callId = callId;
157 : }
158 5 : cv.notify_one();
159 5 : }));
160 5 : confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::MediaChangeRequested>(
161 1 : [=](const std::string& accountId,
162 : const std::string& callId,
163 : const std::vector<std::map<std::string, std::string>>&) {
164 1 : if (accountId == bobId && bobCall.callId == callId) {
165 1 : bobCall.changeRequested = true;
166 : }
167 1 : }));
168 5 : confHandlers.insert(
169 10 : libjami::exportable_callback<libjami::CallSignal::StateChange>([=](const std::string& accountId,
170 : const std::string& callId,
171 : const std::string& state,
172 : signed) {
173 57 : if (accountId == aliceId) {
174 25 : auto details = libjami::getCallDetails(aliceId, callId);
175 25 : if (details["PEER_NUMBER"].find(bobUri) != std::string::npos)
176 25 : bobCall.hostState = state;
177 57 : } else if (bobCall.callId == callId)
178 17 : bobCall.state = state;
179 57 : cv.notify_one();
180 57 : }));
181 :
182 5 : confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::MediaNegotiationStatus>(
183 17 : [&](const std::string& callId,
184 : const std::string& event,
185 : const std::vector<std::map<std::string, std::string>>&) {
186 17 : if (callId == bobCall.callId)
187 9 : bobCall.mediaStatus = event;
188 17 : cv.notify_one();
189 17 : }));
190 5 : confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::RecordPlaybackStopped>(
191 9 : [&](const std::string& path) {
192 9 : recordedFile = path;
193 9 : cv.notify_one();
194 9 : }));
195 5 : libjami::registerSignalHandlers(confHandlers);
196 5 : }
197 :
198 : void
199 1 : RecorderTest::testRecordCall()
200 : {
201 1 : JAMI_INFO("Start testRecordCall");
202 1 : registerSignalHandlers();
203 1 : auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
204 1 : auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
205 1 : auto bobUri = bobAccount->getUsername();
206 :
207 1 : JAMI_INFO("Start call between Alice and Bob");
208 1 : std::vector<std::map<std::string, std::string>> mediaList;
209 : std::map<std::string, std::string> mediaAttributeA
210 : = {{libjami::Media::MediaAttributeKey::MEDIA_TYPE, libjami::Media::MediaAttributeValue::AUDIO},
211 : {libjami::Media::MediaAttributeKey::ENABLED, TRUE_STR},
212 : {libjami::Media::MediaAttributeKey::MUTED, FALSE_STR},
213 : {libjami::Media::MediaAttributeKey::LABEL, "audio_0"},
214 7 : {libjami::Media::MediaAttributeKey::SOURCE, ""}};
215 : std::map<std::string, std::string> mediaAttributeV
216 : = {{libjami::Media::MediaAttributeKey::MEDIA_TYPE, libjami::Media::MediaAttributeValue::VIDEO},
217 : {libjami::Media::MediaAttributeKey::ENABLED, TRUE_STR},
218 : {libjami::Media::MediaAttributeKey::MUTED, FALSE_STR},
219 : {libjami::Media::MediaAttributeKey::LABEL, "video_0"},
220 7 : {libjami::Media::MediaAttributeKey::SOURCE, videoPath}};
221 1 : mediaList.emplace_back(mediaAttributeA);
222 1 : auto callId = libjami::placeCallWithMedia(aliceId, bobUri, mediaList);
223 7 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !bobCall.callId.empty(); }));
224 1 : libjami::acceptWithMedia(bobId, bobCall.callId, mediaList);
225 4 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] {
226 : return bobCall.mediaStatus
227 : == libjami::Media::MediaNegotiationStatusEvents::NEGOTIATION_SUCCESS;
228 : }));
229 :
230 1 : std::this_thread::sleep_for(5s);
231 :
232 : // Start recorder
233 1 : recordedFile.clear();
234 1 : CPPUNIT_ASSERT(!libjami::getIsRecording(aliceId, callId));
235 1 : libjami::toggleRecording(aliceId, callId);
236 1 : std::this_thread::sleep_for(5s);
237 1 : CPPUNIT_ASSERT(libjami::getIsRecording(aliceId, callId));
238 :
239 2 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return recordedFile.empty(); }));
240 :
241 : // add local video
242 : {
243 1 : auto newMediaList = mediaList;
244 1 : newMediaList.emplace_back(mediaAttributeV);
245 :
246 : // Request Media Change
247 1 : libjami::requestMediaChange(aliceId, callId, newMediaList);
248 :
249 3 : CPPUNIT_ASSERT(cv.wait_for(lk, 10s, [&] { return bobCall.changeRequested; }));
250 :
251 : // Answer the change request
252 1 : bobCall.mediaStatus = "";
253 1 : libjami::answerMediaChangeRequest(bobId, bobCall.callId, newMediaList);
254 1 : bobCall.changeRequested = false;
255 3 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] {
256 : return bobCall.mediaStatus
257 : == libjami::Media::MediaNegotiationStatusEvents::NEGOTIATION_SUCCESS;
258 : }));
259 :
260 4 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !recordedFile.empty() && recordedFile.find(".ogg") != std::string::npos; }));
261 1 : recordedFile = "";
262 : // give time to start camera
263 1 : std::this_thread::sleep_for(10s);
264 :
265 2 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return recordedFile.empty(); }));
266 1 : }
267 :
268 : // mute local video
269 : {
270 1 : mediaAttributeV[libjami::Media::MediaAttributeKey::MUTED] = TRUE_STR;
271 1 : auto newMediaList = mediaList;
272 1 : newMediaList.emplace_back(mediaAttributeV);
273 :
274 : // Mute Bob video
275 1 : libjami::requestMediaChange(aliceId, callId, newMediaList);
276 1 : std::this_thread::sleep_for(5s);
277 1 : libjami::requestMediaChange(bobId, bobCall.callId, newMediaList);
278 :
279 4 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !recordedFile.empty() && recordedFile.find(".webm") != std::string::npos; }));
280 1 : recordedFile = "";
281 1 : std::this_thread::sleep_for(10s);
282 1 : }
283 :
284 : // Stop recorder after a few seconds
285 1 : libjami::toggleRecording(aliceId, callId);
286 1 : CPPUNIT_ASSERT(!libjami::getIsRecording(aliceId, callId));
287 :
288 2 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !recordedFile.empty() && recordedFile.find(".ogg") != std::string::npos; }));
289 :
290 1 : Manager::instance().hangupCall(aliceId, callId);
291 5 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER"; }));
292 1 : JAMI_INFO("End testRecordCall");
293 1 : }
294 :
295 : void
296 1 : RecorderTest::testRecordAudioOnlyCall()
297 : {
298 1 : JAMI_INFO("Start testRecordAudioOnlyCall");
299 1 : registerSignalHandlers();
300 1 : auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
301 1 : auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
302 1 : auto bobUri = bobAccount->getUsername();
303 :
304 1 : JAMI_INFO("Start call between Alice and Bob");
305 : // Audio only call
306 1 : std::vector<std::map<std::string, std::string>> mediaList;
307 : std::map<std::string, std::string> mediaAttribute
308 : = {{libjami::Media::MediaAttributeKey::MEDIA_TYPE, libjami::Media::MediaAttributeValue::AUDIO},
309 : {libjami::Media::MediaAttributeKey::ENABLED, TRUE_STR},
310 : {libjami::Media::MediaAttributeKey::MUTED, FALSE_STR},
311 : {libjami::Media::MediaAttributeKey::LABEL, "audio_0"},
312 7 : {libjami::Media::MediaAttributeKey::SOURCE, ""}};
313 1 : mediaList.emplace_back(mediaAttribute);
314 1 : auto callId = libjami::placeCallWithMedia(aliceId, bobUri, mediaList);
315 7 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !bobCall.callId.empty(); }));
316 1 : libjami::acceptWithMedia(bobId, bobCall.callId, mediaList);
317 4 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] {
318 : return bobCall.mediaStatus
319 : == libjami::Media::MediaNegotiationStatusEvents::NEGOTIATION_SUCCESS;
320 : }));
321 :
322 : // Start recorder
323 1 : recordedFile.clear();
324 1 : libjami::toggleRecording(aliceId, callId);
325 1 : std::this_thread::sleep_for(5s);
326 1 : CPPUNIT_ASSERT(libjami::getIsRecording(aliceId, callId));
327 :
328 : // Toggle recording
329 1 : libjami::toggleRecording(aliceId, callId);
330 1 : CPPUNIT_ASSERT(!libjami::getIsRecording(aliceId, callId));
331 :
332 2 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] {
333 : return !recordedFile.empty() && recordedFile.find(".ogg") != std::string::npos;
334 : }));
335 :
336 1 : Manager::instance().hangupCall(aliceId, callId);
337 2 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER"; }));
338 1 : JAMI_INFO("End testRecordAudioOnlyCall");
339 1 : }
340 :
341 : void
342 1 : RecorderTest::testRecordCallOnePersonRdv()
343 : {
344 1 : JAMI_INFO("Start testRecordCallOnePersonRdv");
345 1 : registerSignalHandlers();
346 1 : auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
347 1 : auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
348 1 : auto bobUri = bobAccount->getUsername();
349 :
350 : try {
351 1 : bobAccount->editConfig(
352 1 : [&](AccountConfig& config) { config.isRendezVous = true; });
353 0 : } catch (...) {}
354 :
355 1 : CPPUNIT_ASSERT(bobAccount->config().isRendezVous);
356 :
357 1 : recordedFile.clear();
358 :
359 1 : JAMI_INFO("Start call between Alice and Bob");
360 : // Audio only call
361 1 : std::vector<std::map<std::string, std::string>> mediaList;
362 : std::map<std::string, std::string> mediaAttributeA
363 : = {{libjami::Media::MediaAttributeKey::MEDIA_TYPE, libjami::Media::MediaAttributeValue::AUDIO},
364 : {libjami::Media::MediaAttributeKey::ENABLED, TRUE_STR},
365 : {libjami::Media::MediaAttributeKey::MUTED, FALSE_STR},
366 : {libjami::Media::MediaAttributeKey::LABEL, "audio_0"},
367 7 : {libjami::Media::MediaAttributeKey::SOURCE, ""}};
368 1 : mediaList.emplace_back(mediaAttributeA);
369 1 : auto callId = libjami::placeCallWithMedia(aliceId, bobUri, mediaList);
370 7 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !bobCall.callId.empty(); }));
371 6 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] {
372 : return bobCall.mediaStatus
373 : == libjami::Media::MediaNegotiationStatusEvents::NEGOTIATION_SUCCESS;
374 : }));
375 :
376 1 : CPPUNIT_ASSERT(!libjami::getIsRecording(aliceId, callId));
377 1 : libjami::toggleRecording(aliceId, callId);
378 1 : std::this_thread::sleep_for(5s);
379 :
380 1 : CPPUNIT_ASSERT(libjami::getIsRecording(aliceId, callId));
381 :
382 : // Stop recorder
383 1 : libjami::toggleRecording(aliceId, callId);
384 1 : CPPUNIT_ASSERT(!libjami::getIsRecording(aliceId, callId));
385 :
386 2 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !recordedFile.empty() && recordedFile.find(".ogg") != std::string::npos; }));
387 :
388 1 : Manager::instance().hangupCall(aliceId, callId);
389 5 : CPPUNIT_ASSERT(
390 : cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER"; }));
391 1 : JAMI_INFO("End testRecordCallOnePersonRdv");
392 1 : }
393 :
394 : void
395 1 : RecorderTest::testStopCallWhileRecording()
396 : {
397 1 : JAMI_INFO("Start testStopCallWhileRecording");
398 1 : registerSignalHandlers();
399 1 : auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
400 1 : auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
401 1 : auto bobUri = bobAccount->getUsername();
402 :
403 1 : JAMI_INFO("Start call between Alice and Bob");
404 1 : std::vector<std::map<std::string, std::string>> mediaList;
405 : std::map<std::string, std::string> mediaAttributeA
406 : = {{libjami::Media::MediaAttributeKey::MEDIA_TYPE, libjami::Media::MediaAttributeValue::AUDIO},
407 : {libjami::Media::MediaAttributeKey::ENABLED, TRUE_STR},
408 : {libjami::Media::MediaAttributeKey::MUTED, FALSE_STR},
409 : {libjami::Media::MediaAttributeKey::LABEL, "audio_0"},
410 7 : {libjami::Media::MediaAttributeKey::SOURCE, ""}};
411 : std::map<std::string, std::string> mediaAttributeV
412 : = {{libjami::Media::MediaAttributeKey::MEDIA_TYPE, libjami::Media::MediaAttributeValue::VIDEO},
413 : {libjami::Media::MediaAttributeKey::ENABLED, TRUE_STR},
414 : {libjami::Media::MediaAttributeKey::MUTED, FALSE_STR},
415 : {libjami::Media::MediaAttributeKey::LABEL, "video_0"},
416 7 : {libjami::Media::MediaAttributeKey::SOURCE, videoPath}};
417 1 : mediaList.emplace_back(mediaAttributeA);
418 1 : mediaList.emplace_back(mediaAttributeV);
419 1 : auto callId = libjami::placeCallWithMedia(aliceId, bobUri, mediaList);
420 7 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !bobCall.callId.empty(); }));
421 1 : libjami::acceptWithMedia(bobId, bobCall.callId, mediaList);
422 4 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] {
423 : return bobCall.mediaStatus
424 : == libjami::Media::MediaNegotiationStatusEvents::NEGOTIATION_SUCCESS;
425 : }));
426 :
427 : // give time to start camera
428 1 : std::this_thread::sleep_for(5s);
429 :
430 : // Start recorder
431 1 : recordedFile.clear();
432 1 : libjami::toggleRecording(aliceId, callId);
433 1 : std::this_thread::sleep_for(10s);
434 1 : CPPUNIT_ASSERT(libjami::getIsRecording(aliceId, callId));
435 :
436 : // Hangup call
437 1 : Manager::instance().hangupCall(aliceId, callId);
438 4 : CPPUNIT_ASSERT(
439 : cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER" && !recordedFile.empty() && recordedFile.find(".webm") != std::string::npos; }));
440 1 : JAMI_INFO("End testStopCallWhileRecording");
441 1 : }
442 :
443 : void
444 1 : RecorderTest::testDaemonPreference()
445 : {
446 1 : JAMI_INFO("Start testDaemonPreference");
447 1 : registerSignalHandlers();
448 1 : auto aliceAccount = Manager::instance().getAccount<JamiAccount>(aliceId);
449 1 : auto bobAccount = Manager::instance().getAccount<JamiAccount>(bobId);
450 1 : auto bobUri = bobAccount->getUsername();
451 :
452 1 : libjami::setIsAlwaysRecording(true);
453 1 : recordedFile.clear();
454 :
455 1 : JAMI_INFO("Start call between Alice and Bob");
456 1 : std::vector<std::map<std::string, std::string>> mediaList;
457 : std::map<std::string, std::string> mediaAttributeA
458 : = {{libjami::Media::MediaAttributeKey::MEDIA_TYPE, libjami::Media::MediaAttributeValue::AUDIO},
459 : {libjami::Media::MediaAttributeKey::ENABLED, TRUE_STR},
460 : {libjami::Media::MediaAttributeKey::MUTED, FALSE_STR},
461 : {libjami::Media::MediaAttributeKey::LABEL, "audio_0"},
462 7 : {libjami::Media::MediaAttributeKey::SOURCE, ""}};
463 : std::map<std::string, std::string> mediaAttributeV
464 : = {{libjami::Media::MediaAttributeKey::MEDIA_TYPE, libjami::Media::MediaAttributeValue::VIDEO},
465 : {libjami::Media::MediaAttributeKey::ENABLED, TRUE_STR},
466 : {libjami::Media::MediaAttributeKey::MUTED, FALSE_STR},
467 : {libjami::Media::MediaAttributeKey::LABEL, "video_0"},
468 7 : {libjami::Media::MediaAttributeKey::SOURCE, videoPath}};
469 1 : mediaList.emplace_back(mediaAttributeA);
470 1 : mediaList.emplace_back(mediaAttributeV);
471 1 : auto callId = libjami::placeCallWithMedia(aliceId, bobUri, mediaList);
472 7 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] { return !bobCall.callId.empty(); }));
473 1 : libjami::acceptWithMedia(bobId, bobCall.callId, mediaList);
474 5 : CPPUNIT_ASSERT(cv.wait_for(lk, 20s, [&] {
475 : return bobCall.mediaStatus
476 : == libjami::Media::MediaNegotiationStatusEvents::NEGOTIATION_SUCCESS;
477 : }));
478 :
479 : // Let record some seconds
480 1 : std::this_thread::sleep_for(5s);
481 1 : CPPUNIT_ASSERT(libjami::getIsRecording(aliceId, callId));
482 1 : std::this_thread::sleep_for(10s);
483 :
484 1 : Manager::instance().hangupCall(aliceId, callId);
485 6 : CPPUNIT_ASSERT(
486 : cv.wait_for(lk, 20s, [&] { return bobCall.state == "OVER" && !recordedFile.empty() && recordedFile.find(".webm") != std::string::npos; }));
487 1 : JAMI_INFO("End testDaemonPreference");
488 1 : }
489 :
490 : } // namespace test
491 : } // namespace jami
492 :
493 1 : RING_TEST_RUNNER(jami::test::RecorderTest::name())
|