Commit ce567ebe authored by Ghislain MARY's avatar Ghislain MARY

Add VideoStream unit tests suite.

parent 4d6563b7
......@@ -14,6 +14,7 @@ mediastreamer2_tester_SOURCES= \
mediastreamer2_basic_audio_tester.c \
mediastreamer2_sound_card_tester.c \
mediastreamer2_audio_stream_tester.c \
mediastreamer2_video_stream_tester.c \
mediastreamer2_framework_tester.c
......
......@@ -74,51 +74,17 @@ static int tester_cleanup(void) {
#define RECORDED_8K_1S_FILE WRITE_FILE_PATH "recorded_hello8000-1s.wav"
#define RECORDED_16K_1S_FILE WRITE_FILE_PATH "recorded_hello16000-1s.wav"
typedef struct _stats_t {
rtp_stats_t rtp;
int number_of_EndOfFile;
} stats_t;
static void reset_stats(stats_t* s) {
memset(s,0,sizeof(stats_t));
}
bool_t wait_for_list(MSList* mss,int* counter,int value,int timeout_ms) {
int retry=0;
MSList* iterator;
while (*counter<value && retry++ <timeout_ms/100) {
for (iterator=mss;iterator!=NULL;iterator=iterator->next) {
MediaStream* stream = (MediaStream*)(iterator->data);
media_stream_iterate(stream);
if (retry%10==0) {
ms_message("stream [%p] bandwidth usage: [d=%.1f,u=%.1f] kbit/sec" , stream
, media_stream_get_down_bw(stream)/1000
, media_stream_get_up_bw(stream)/1000);
}
}
ms_usleep(100000);
}
if(*counter<value) return FALSE;
else return TRUE;
}
bool_t wait_for_until(MediaStream* ms_1, MediaStream* ms_2,int* counter,int value,int timeout) {
MSList* mss=NULL;
bool_t result;
if (ms_1)
mss=ms_list_append(mss,ms_1);
if (ms_2)
mss=ms_list_append(mss,ms_2);
result=wait_for_list(mss,counter,value,timeout);
ms_list_free(mss);
return result;
}
bool_t wait_for(MediaStream* ms_1, MediaStream* ms_2,int* counter,int value) {
return wait_for_until( ms_1, ms_2,counter,value,2000);
}
static void notify_cb(void *user_data, MSFilter *f, unsigned int event, void *eventdata) {
stats_t* stats = (stats_t*)user_data;
......
......@@ -114,6 +114,7 @@ void mediastreamer2_tester_init(void) {
add_test_suite(&basic_audio_test_suite);
add_test_suite(&sound_card_test_suite);
add_test_suite(&audio_stream_test_suite);
add_test_suite(&video_stream_test_suite);
add_test_suite(&framework_test_suite);
}
......
......@@ -48,6 +48,7 @@ extern "C" {
extern test_suite_t basic_audio_test_suite;
extern test_suite_t sound_card_test_suite;
extern test_suite_t audio_stream_test_suite;
extern test_suite_t video_stream_test_suite;
extern test_suite_t framework_test_suite;
......
......@@ -200,3 +200,71 @@ void ms_tester_tone_generation_and_detection_loop(void) {
}
}
bool_t wait_for_list(MSList *mss, int *counter, int value, int timeout_ms) {
return wait_for_list_with_parse_events(mss, counter, value, timeout_ms, NULL, NULL);
}
bool_t wait_for_list_with_parse_events(MSList *mss, int *counter, int value, int timeout_ms, MSList *cbs, MSList *ptrs) {
MSList *msi;
MSList *cbi;
MSList *ptri;
int retry = 0;
while ((*counter < value) && (retry++ < (timeout_ms / 100))) {
for (msi = mss, cbi = cbs, ptri = ptrs; msi != NULL; msi = msi->next) {
MediaStream *stream = (MediaStream *)msi->data;
ms_tester_iterate_cb cb = NULL;
media_stream_iterate(stream);
if ((retry % 10) == 0) {
ms_message("stream [%p] bandwidth usage: [d=%.1f,u=%.1f] kbit/sec",
stream,
media_stream_get_down_bw(stream) / 1000,
media_stream_get_up_bw(stream) / 1000);
}
if (cbi && ptri) {
cb = (ms_tester_iterate_cb)cbi->data;
cb(stream, ptri->data);
}
if (cbi) cbi = cbi->next;
if (ptri) ptri = ptri->next;
}
ms_usleep(100000);
}
if (*counter < value)
return FALSE;
return TRUE;
}
bool_t wait_for_until(MediaStream *ms_1, MediaStream *ms_2, int *counter, int value, int timeout_ms) {
return wait_for_until_with_parse_events(ms_1, ms_2, counter, value, timeout_ms, NULL, NULL, NULL, NULL);
}
bool_t wait_for_until_with_parse_events(MediaStream *ms1, MediaStream *ms2, int *counter, int value, int timeout_ms, ms_tester_iterate_cb cb1, void *ptr1, ms_tester_iterate_cb cb2, void *ptr2) {
MSList *mss = NULL;
MSList *cbs = NULL;
MSList *ptrs = NULL;
bool_t result;
if (ms1) {
mss = ms_list_append(mss, ms1);
if (cb1 && ptr1) {
cbs = ms_list_append(cbs, cb1);
ptrs = ms_list_append(ptrs, ptr1);
}
}
if (ms2) {
mss = ms_list_append(mss, ms2);
if (cb2 && ptr2) {
cbs = ms_list_append(cbs, cb2);
ptrs = ms_list_append(ptrs, ptr2);
}
}
result = wait_for_list_with_parse_events(mss, counter, value, timeout_ms, cbs, ptrs);
ms_list_free(mss);
return result;
}
bool_t wait_for(MediaStream* ms_1, MediaStream* ms_2, int *counter, int value) {
return wait_for_until(ms_1, ms_2, counter, value, 2000);
}
......@@ -21,6 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define _MEDIASTREAMER2_TESTER_PRIVATE_H
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/msticker.h"
......@@ -87,6 +88,13 @@ void ms_tester_tone_generation_loop(void);
void ms_tester_tone_detection_loop(void);
void ms_tester_tone_generation_and_detection_loop(void);
typedef void (*ms_tester_iterate_cb)(MediaStream *ms, void *user_pointer);
bool_t wait_for_list(MSList *mss, int *counter, int value, int timeout_ms);
bool_t wait_for_list_with_parse_events(MSList *mss, int *counter, int value, int timeout_ms, MSList *cbs, MSList *ptrs);
bool_t wait_for_until(MediaStream *ms1, MediaStream *ms2, int *counter, int value, int timeout_ms);
bool_t wait_for_until_with_parse_events(MediaStream *ms1, MediaStream *ms2, int *counter, int value, int timeout_ms, ms_tester_iterate_cb cb1, void *ptr1, ms_tester_iterate_cb cb2, void *ptr2);
bool_t wait_for(MediaStream* ms1, MediaStream* ms2, int *counter, int value);
#endif /* _MEDIASTREAMER2_TESTER_PRIVATE_H */
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006-2013 Belledonne Communications, Grenoble
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/mediastream.h"
#include "mediastreamer2/msrtp.h"
#include "private.h"
#include "mediastreamer2_tester.h"
#include "mediastreamer2_tester_private.h"
#include <stdio.h>
#include "CUnit/Basic.h"
#ifdef _MSC_VER
#define unlink _unlink
#endif
static RtpProfile rtp_profile;
#define VP8_PAYLOAD_TYPE 103
static int tester_init(void) {
ms_init();
ms_filter_enable_statistics(TRUE);
ortp_init();
rtp_profile_set_payload(&rtp_profile, VP8_PAYLOAD_TYPE, &payload_type_vp8);
return 0;
}
static int tester_cleanup(void) {
ms_exit();
rtp_profile_clear_all(&rtp_profile);
return 0;
}
#define MARIELLE_RTP_PORT 2564
#define MARIELLE_RTCP_PORT 2565
#define MARIELLE_IP "127.0.0.1"
#define MARGAUX_RTP_PORT 9864
#define MARGAUX_RTCP_PORT 9865
#define MARGAUX_IP "127.0.0.1"
typedef struct _video_stream_tester_stats_t {
OrtpEvQueue *q;
rtp_stats_t rtp;
int number_of_SR;
int number_of_RR;
int number_of_SDES;
int number_of_PLI;
int number_of_SLI;
int number_of_RPSI;
} video_stream_tester_stats_t;
typedef struct _video_stream_tester_t {
VideoStream *vs;
video_stream_tester_stats_t stats;
} video_stream_tester_t;
static void reset_stats(video_stream_tester_stats_t *s) {
memset(s, 0, sizeof(video_stream_tester_stats_t));
}
static void event_queue_cb(MediaStream *ms, void *user_pointer) {
video_stream_tester_stats_t *st = (video_stream_tester_stats_t *)user_pointer;
OrtpEvent *ev = NULL;
if (st->q != NULL) {
while ((ev = ortp_ev_queue_get(st->q)) != NULL) {
OrtpEventType evt = ortp_event_get_type(ev);
OrtpEventData *d = ortp_event_get_data(ev);
if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
do {
if (rtcp_is_RR(d->packet)) {
st->number_of_RR++;
} else if (rtcp_is_SR(d->packet)) {
st->number_of_SR++;
} else if (rtcp_is_SDES(d->packet)) {
st->number_of_SDES++;
} else if (rtcp_is_PSFB(d->packet)) {
switch (rtcp_PSFB_get_type(d->packet)) {
case RTCP_PSFB_PLI:
st->number_of_PLI++;
break;
case RTCP_PSFB_SLI:
st->number_of_SLI++;
break;
case RTCP_PSFB_RPSI:
st->number_of_RPSI++;
break;
default:
break;
}
}
} while (rtcp_next_packet(d->packet));
}
ortp_event_destroy(ev);
}
}
}
static void init_video_streams(video_stream_tester_t *marielle, video_stream_tester_t *margaux, bool_t avpf, OrtpNetworkSimulatorParams *params) {
PayloadType *pt;
MSWebCam *no_webcam = ms_web_cam_manager_get_cam(ms_web_cam_manager_get(), "StaticImage: Static picture");
MSWebCam *default_webcam = ms_web_cam_manager_get_default_cam(ms_web_cam_manager_get());
marielle->vs = video_stream_new(MARIELLE_RTP_PORT, MARIELLE_RTCP_PORT, FALSE);
margaux->vs = video_stream_new(MARGAUX_RTP_PORT, MARGAUX_RTCP_PORT, FALSE);
reset_stats(&marielle->stats);
reset_stats(&margaux->stats);
/* Enable/disable avpf. */
pt = rtp_profile_get_payload(&rtp_profile, VP8_PAYLOAD_TYPE);
CU_ASSERT_PTR_NOT_NULL_FATAL(pt);
if (avpf == TRUE) {
payload_type_set_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
} else {
payload_type_unset_flag(pt, PAYLOAD_TYPE_RTCP_FEEDBACK_ENABLED);
}
/* Configure network simulator. */
if ((params != NULL) && (params->enabled == TRUE)) {
rtp_session_enable_network_simulation(marielle->vs->ms.sessions.rtp_session, params);
rtp_session_enable_network_simulation(margaux->vs->ms.sessions.rtp_session, params);
}
marielle->stats.q = ortp_ev_queue_new();
rtp_session_register_event_queue(marielle->vs->ms.sessions.rtp_session, marielle->stats.q);
margaux->stats.q = ortp_ev_queue_new();
rtp_session_register_event_queue(margaux->vs->ms.sessions.rtp_session, margaux->stats.q);
CU_ASSERT_EQUAL(
video_stream_start(marielle->vs, &rtp_profile, MARGAUX_IP, MARGAUX_RTP_PORT, MARGAUX_IP, MARGAUX_RTCP_PORT, VP8_PAYLOAD_TYPE, 50, default_webcam),
0);
CU_ASSERT_EQUAL(
video_stream_start(margaux->vs, &rtp_profile, MARIELLE_IP, MARIELLE_RTP_PORT, MARIELLE_IP, MARIELLE_RTCP_PORT, VP8_PAYLOAD_TYPE, 50, no_webcam),
0);
}
static void uninit_video_streams(video_stream_tester_t *marielle, video_stream_tester_t *margaux) {
float rtcp_send_bandwidth;
PayloadType *pt;
pt = rtp_profile_get_payload(&rtp_profile, VP8_PAYLOAD_TYPE);
CU_ASSERT_PTR_NOT_NULL_FATAL(pt);
rtp_session_compute_send_bandwidth(marielle->vs->ms.sessions.rtp_session);
rtp_session_compute_send_bandwidth(margaux->vs->ms.sessions.rtp_session);
rtcp_send_bandwidth = rtp_session_get_rtcp_send_bandwidth(marielle->vs->ms.sessions.rtp_session);
CU_ASSERT_TRUE(rtcp_send_bandwidth <= (0.05 * payload_type_get_bitrate(pt)));
rtcp_send_bandwidth = rtp_session_get_rtcp_send_bandwidth(margaux->vs->ms.sessions.rtp_session);
CU_ASSERT_TRUE(rtcp_send_bandwidth <= (0.05 * payload_type_get_bitrate(pt)));
video_stream_stop(marielle->vs);
video_stream_stop(margaux->vs);
ortp_ev_queue_destroy(marielle->stats.q);
ortp_ev_queue_destroy(margaux->stats.q);
}
static void basic_video_stream(void) {
video_stream_tester_t marielle;
video_stream_tester_t margaux;
init_video_streams(&marielle, &margaux, FALSE, NULL);
CU_ASSERT_TRUE(wait_for_until_with_parse_events(&marielle.vs->ms, &margaux.vs->ms, &marielle.stats.number_of_SR, 2, 15000, event_queue_cb, &marielle.stats, event_queue_cb, &margaux.stats));
video_stream_get_local_rtp_stats(marielle.vs, &marielle.stats.rtp);
video_stream_get_local_rtp_stats(margaux.vs, &margaux.stats.rtp);
uninit_video_streams(&marielle, &margaux);
}
static void avpf_video_stream(void) {
video_stream_tester_t marielle;
video_stream_tester_t margaux;
OrtpNetworkSimulatorParams params = { 0 };
params.enabled = TRUE;
params.loss_rate = 5.;
init_video_streams(&marielle, &margaux, TRUE, &params);
CU_ASSERT_TRUE(wait_for_until_with_parse_events(&marielle.vs->ms, &margaux.vs->ms, &marielle.stats.number_of_SR, 2, 15000, event_queue_cb, &marielle.stats, event_queue_cb, &margaux.stats));
CU_ASSERT_TRUE(marielle.stats.number_of_PLI >= 0);
CU_ASSERT_TRUE(marielle.stats.number_of_SLI > 0);
CU_ASSERT_TRUE(marielle.stats.number_of_RPSI > 0);
uninit_video_streams(&marielle, &margaux);
}
static void avpf_high_loss_video_stream(void) {
video_stream_tester_t marielle;
video_stream_tester_t margaux;
OrtpNetworkSimulatorParams params = { 0 };
params.enabled = TRUE;
params.loss_rate = 25.;
init_video_streams(&marielle, &margaux, TRUE, &params);
CU_ASSERT_TRUE(wait_for_until_with_parse_events(&marielle.vs->ms, &margaux.vs->ms, &marielle.stats.number_of_SR, 2, 15000, event_queue_cb, &marielle.stats, event_queue_cb, &margaux.stats));
CU_ASSERT_TRUE(marielle.stats.number_of_PLI >= 0);
CU_ASSERT_TRUE(marielle.stats.number_of_SLI > 0);
CU_ASSERT_TRUE(marielle.stats.number_of_RPSI >= 0);
uninit_video_streams(&marielle, &margaux);
}
static test_t tests[] = {
{ "Basic video stream", basic_video_stream },
{ "AVPF video stream", avpf_video_stream },
{ "AVPF high-loss video stream", avpf_high_loss_video_stream }
};
test_suite_t video_stream_test_suite = {
"VideoStream",
tester_init,
tester_cleanup,
sizeof(tests) / sizeof(tests[0]),
tests
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment