Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/include/switch_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1888,6 +1888,8 @@ SMBF_THREAD_LOCK - Only let the same thread who created the bug remove it.
SMBF_PRUNE -
SMBF_NO_PAUSE -
SMBF_STEREO_SWAP - Record in stereo: Write Stream - left channel, Read Stream - right channel
SMBF_FIRST - Put the bug at the front of the list, before all other bugs
SMBF_LAST - Keep the bug at the end of the list: bugs added later are linked in front of it (only honored at add time; exclusive with SMBF_FIRST)
</pre>
*/
typedef enum {
Expand Down Expand Up @@ -1919,7 +1921,8 @@ typedef enum {
SMBF_READ_VIDEO_PATCH = (1 << 24),
SMBF_READ_TEXT_STREAM = (1 << 25),
SMBF_FIRST = (1 << 26),
SMBF_PAUSE = (1 << 27)
SMBF_PAUSE = (1 << 27),
SMBF_LAST = (1 << 28)
} switch_media_bug_flag_enum_t;
typedef uint32_t switch_media_bug_flag_t;

Expand Down
36 changes: 32 additions & 4 deletions src/switch_core_media_bug.c
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,30 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_push_spy_frame(switch_medi
return SWITCH_STATUS_FALSE;
}

/*
* Link a bug that is neither first nor the only one into the list: regular bugs go in front of the first SMBF_LAST bug (or at the end if
* there is none), SMBF_LAST bugs go to the end. That keeps SMBF_LAST bugs behind every other bug, so their stream and replace callbacks run after
* those of every other bug.
* The caller holds session->bug_rwlock for writing.
*/
static void switch_core_media_bug_insert(switch_core_session_t *session, switch_media_bug_t *bug)
{
switch_media_bug_t *bp = session->bugs, *prev = NULL;

while (bp && (switch_test_flag(bug, SMBF_LAST) || !switch_test_flag(bp, SMBF_LAST))) {
prev = bp;
bp = bp->next;
}

bug->next = bp;

if (prev) {
prev->next = bug;
} else {
session->bugs = bug;
}
}

#define MAX_BUG_BUFFER 1024 * 512
SWITCH_DECLARE(switch_status_t) switch_core_media_bug_add(switch_core_session_t *session,
const char *function,
Expand Down Expand Up @@ -866,6 +890,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_add(switch_core_session_t
}
#endif

if ((flags & SMBF_FIRST) && (flags & SMBF_LAST)) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "SMBF_FIRST and SMBF_LAST are mutually exclusive.\n");
return SWITCH_STATUS_GENERR;
}

if (!(bug = switch_core_session_alloc(session, sizeof(*bug)))) {
return SWITCH_STATUS_MEMERR;
}
Expand Down Expand Up @@ -991,11 +1020,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_bug_add(switch_core_session_t
if (bp->ready && !switch_test_flag(bp, SMBF_TAP_NATIVE_READ) && !switch_test_flag(bp, SMBF_TAP_NATIVE_WRITE)) {
tap_only = 0;
}
}

if (!added && !bp->next) {
bp->next = bug;
break;
}
if (!added) {
switch_core_media_bug_insert(session, bug);
}

switch_thread_rwlock_unlock(session->bug_rwlock);
Expand Down
43 changes: 43 additions & 0 deletions tests/unit/switch_ivr_async.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,18 @@ static switch_status_t partial_play_and_collect_input_callback(switch_core_sessi
return status;
}

static switch_bool_t noop_bug_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
return SWITCH_TRUE;
}

static switch_status_t add_ordering_bug(switch_core_session_t *session, const char *function, switch_media_bug_flag_t flags)
{
switch_media_bug_t *bug = NULL;

return switch_core_media_bug_add(session, function, NULL, noop_bug_callback, NULL, 0, SMBF_READ_PING | flags, &bug);
}

FST_CORE_BEGIN("./conf_async")
{
FST_SUITE_BEGIN(switch_ivr_play_async)
Expand Down Expand Up @@ -195,6 +207,37 @@ FST_CORE_BEGIN("./conf_async")
unlink(record_filename);
}
FST_SESSION_END()

FST_SESSION_BEGIN(media_bug_last_ordering)
{
const char *expected[] = { "first", "regular-1", "regular-2", "last-1", "last-2" };
switch_stream_handle_t stream = { 0 };
const char *pos;
int i;

fst_check(add_ordering_bug(fst_session, "last-1", SMBF_LAST) == SWITCH_STATUS_SUCCESS);
/* the only bug is SMBF_LAST: a regular bug must become the head */
fst_check(add_ordering_bug(fst_session, "regular-1", 0) == SWITCH_STATUS_SUCCESS);
fst_check(add_ordering_bug(fst_session, "first", SMBF_FIRST) == SWITCH_STATUS_SUCCESS);
fst_check(add_ordering_bug(fst_session, "last-2", SMBF_LAST) == SWITCH_STATUS_SUCCESS);
fst_check(add_ordering_bug(fst_session, "regular-2", 0) == SWITCH_STATUS_SUCCESS);
fst_check(add_ordering_bug(fst_session, "both", SMBF_FIRST | SMBF_LAST) == SWITCH_STATUS_GENERR);

SWITCH_STANDARD_STREAM(stream);
switch_core_media_bug_enumerate(fst_session, &stream);
pos = (const char *)stream.data;

for (i = 0; i < (int)(sizeof(expected) / sizeof(expected[0])); i++) {
const char *tag = switch_core_session_sprintf(fst_session, "<function>%s</function>", expected[i]);

pos = pos ? strstr(pos, tag) : NULL;
fst_xcheck(pos != NULL, "Expect media bugs in order first, regular-1, regular-2, last-1, last-2");
}

switch_safe_free(stream.data);
switch_core_media_bug_remove_all(fst_session);
}
FST_SESSION_END()
}
FST_SUITE_END()
}
Expand Down
Loading