Browse Source

TT#79601 support media/DTMF playback to all parties

Change-Id: I534ba39c800e0b075c1502808a56b887baf3e323
changes/79/39279/3
Richard Fuchs 6 years ago
parent
commit
c1d29a41a7
3 changed files with 84 additions and 51 deletions
  1. +5
    -3
      README.md
  2. +77
    -47
      daemon/call_interfaces.c
  3. +2
    -1
      utils/rtpengine-ng-client

+ 5
- 3
README.md View File

@ -1571,7 +1571,8 @@ and stopped independently of each other.
Only available if compiled with transcoding support. The message must contain the key `call-id` and one
of the participant selection keys described under the `block DTMF` message (such as `from-tag`,
`address`, or `label`).
`address`, or `label`). Alternatively, the `all` flag can be set to play the media to all involved
call parties.
Starts playback of a provided media file to the selected call participant. The format of the media file
can be anything that is supported by *ffmpeg*, for example a `.wav` or `.mp3` file. It will automatically
@ -1611,8 +1612,9 @@ The same participant selection keys as for the `play media` message can and must
-------------------
Instructs *rtpengine* to inject a DTMF tone or event into a running audio stream. A call participant must
be selected in the same way as described under the `block DTMF` message above. The selected call participant
is the one generating the DTMF event, not the one receiving it.
be selected in the same way as described under the `play media` message above (including the possibility
of using the `all` flag). The selected call participant is the one generating the DTMF event, not the
one receiving it.
The dictionary key `code` must be present in the message, indicating the DTMF event to be generated. It can
be either an integer with values 0-15, or a string containing a single character


+ 77
- 47
daemon/call_interfaces.c View File

@ -1603,6 +1603,9 @@ static const char *media_block_match(struct call **call, struct call_monologue *
return "Unknown call-id";
// directional?
if (flags->all) // explicitly non-directional, so skip the rest
return NULL;
if (flags->label.s) {
*monologue = g_hash_table_lookup((*call)->labels, &flags->label);
if (!*monologue)
@ -1848,14 +1851,23 @@ out:
#ifdef WITH_TRANSCODING
static const char *play_media_select_party(struct call **call, struct call_monologue **monologue,
static const char *play_media_select_party(struct call **call, GQueue *monologues,
bencode_item_t *input)
{
const char *err = media_block_match(call, monologue, NULL, input);
struct call_monologue *monologue;
struct sdp_ng_flags flags;
g_queue_init(monologues);
const char *err = media_block_match(call, &monologue, &flags, input);
if (err)
return err;
if (!*monologue)
if (flags.all)
g_queue_append(monologues, &(*call)->monologues);
else if (!monologue)
return "No participant party specified";
else
g_queue_push_tail(monologues, monologue);
return NULL;
}
#endif
@ -1865,42 +1877,47 @@ const char *call_play_media_ng(bencode_item_t *input, bencode_item_t *output) {
#ifdef WITH_TRANSCODING
str str;
struct call *call;
struct call_monologue *monologue;
GQueue monologues;
const char *err = NULL;
long long db_id;
err = play_media_select_party(&call, &monologue, input);
err = play_media_select_party(&call, &monologues, input);
if (err)
goto out;
if (!monologue->player)
monologue->player = media_player_new(monologue);
for (GList *l = monologues.head; l; l = l->next) {
struct call_monologue *monologue = l->data;
err = "No media file specified";
if (bencode_dictionary_get_str(input, "file", &str)) {
err = "Failed to start media playback from file";
if (media_player_play_file(monologue->player, &str))
goto out;
}
else if (bencode_dictionary_get_str(input, "blob", &str)) {
err = "Failed to start media playback from blob";
if (media_player_play_blob(monologue->player, &str))
goto out;
}
else if ((db_id = bencode_dictionary_get_int_str(input, "db-id", 0)) > 0) {
err = "Failed to start media playback from database";
if (media_player_play_db(monologue->player, db_id))
if (!monologue->player)
monologue->player = media_player_new(monologue);
err = "No media file specified";
if (bencode_dictionary_get_str(input, "file", &str)) {
err = "Failed to start media playback from file";
if (media_player_play_file(monologue->player, &str))
goto out;
}
else if (bencode_dictionary_get_str(input, "blob", &str)) {
err = "Failed to start media playback from blob";
if (media_player_play_blob(monologue->player, &str))
goto out;
}
else if ((db_id = bencode_dictionary_get_int_str(input, "db-id", 0)) > 0) {
err = "Failed to start media playback from database";
if (media_player_play_db(monologue->player, db_id))
goto out;
}
else
goto out;
}
else
goto out;
if (monologue->player->duration)
bencode_dictionary_add_integer(output, "duration", monologue->player->duration);
if (l == monologues.head && monologue->player->duration)
bencode_dictionary_add_integer(output, "duration", monologue->player->duration);
}
err = NULL;
out:
g_queue_clear(&monologues);
if (call) {
rwlock_unlock_w(&call->master_lock);
obj_put(call);
@ -1915,21 +1932,27 @@ out:
const char *call_stop_media_ng(bencode_item_t *input, bencode_item_t *output) {
#ifdef WITH_TRANSCODING
struct call *call;
struct call_monologue *monologue;
GQueue monologues;
const char *err = NULL;
err = play_media_select_party(&call, &monologue, input);
err = play_media_select_party(&call, &monologues, input);
if (err)
goto out;
if (!monologue->player)
return "Not currently playing media";
for (GList *l = monologues.head; l; l = l->next) {
struct call_monologue *monologue = l->data;
media_player_stop(monologue->player);
err = "Not currently playing media";
if (!monologue->player)
goto out;
media_player_stop(monologue->player);
}
err = NULL;
out:
g_queue_clear(&monologues);
if (call) {
rwlock_unlock_w(&call->master_lock);
obj_put(call);
@ -1944,11 +1967,11 @@ out:
const char *call_play_dtmf_ng(bencode_item_t *input, bencode_item_t *output) {
#ifdef WITH_TRANSCODING
struct call *call;
struct call_monologue *monologue;
GQueue monologues;
str str;
const char *err = NULL;
err = play_media_select_party(&call, &monologue, input);
err = play_media_select_party(&call, &monologues, input);
if (err)
goto out;
@ -1998,25 +2021,32 @@ const char *call_play_dtmf_ng(bencode_item_t *input, bencode_item_t *output) {
if (volume > 0)
volume *= -1;
// find a usable output media
struct call_media *media;
for (GList *l = monologue->medias.head; l; l = l->next) {
media = l->data;
if (media->type_id != MT_AUDIO)
continue;
if (!media->dtmf_injector)
continue;
goto found;
}
for (GList *l = monologues.head; l; l = l->next) {
struct call_monologue *monologue = l->data;
err = "Monologue has no media capable of DTMF injection";
// XXX fall back to generating a secondary stream
goto out;
// find a usable output media
struct call_media *media;
for (GList *l = monologue->medias.head; l; l = l->next) {
media = l->data;
if (media->type_id != MT_AUDIO)
continue;
if (!media->dtmf_injector)
continue;
goto found;
}
err = "Monologue has no media capable of DTMF injection";
// XXX fall back to generating a secondary stream
goto out;
found:;
err = dtmf_inject(media, code, volume, duration, pause);
err = dtmf_inject(media, code, volume, duration, pause);
if (err)
break;
}
out:
g_queue_clear(&monologues);
if (call) {
rwlock_unlock_w(&call->master_lock);
obj_put(call);


+ 2
- 1
utils/rtpengine-ng-client View File

@ -72,13 +72,14 @@ GetOptions(
'blob-file=s' => \$options{'blob-file'},
'db-id=i' => \$options{'db-id'},
'T38=s@' => \$options{'T.38'},
'code=s' => \$options{'code'},
) or die;
my $cmd = shift(@ARGV) or die;
my %packet = (command => $cmd);
for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family,DTLS,via-branch,media address,ptime,xmlrpc-callback,metadata,address,file,db-id')) {
for my $x (split(/,/, 'from-tag,to-tag,call-id,transport protocol,media address,ICE,address family,DTLS,via-branch,media address,ptime,xmlrpc-callback,metadata,address,file,db-id,code')) {
defined($options{$x}) and $packet{$x} = \$options{$x};
}
for my $x (split(/,/, 'TOS,delete-delay')) {


Loading…
Cancel
Save