return NULL;
}
-static struct ast_channel *prepare_bridge_media_channel(const char *type)
+static struct ast_channel *prepare_bridge_media_channel(const char *type,
+ struct ast_format *channel_format)
{
RAII_VAR(struct ast_format_cap *, cap, NULL, ao2_cleanup);
struct ast_channel *chan;
return NULL;
}
- ast_format_cap_append(cap, ast_format_slin, 0);
+ /* This bumps the format's refcount */
+ ast_format_cap_append(cap, channel_format, 0);
chan = ast_request(type, cap, NULL, NULL, "ARI", NULL);
if (!chan) {
static void ari_bridges_play_new(const char **args_media,
size_t args_media_count,
+ const char *args_format,
const char *args_lang,
int args_offset_ms,
int args_skipms,
struct stasis_topic *bridge_topic;
struct bridge_channel_control_thread_data *thread_data;
pthread_t threadid;
+ struct ast_format *channel_format = NULL;
struct ast_frame prog = {
.frametype = AST_FRAME_CONTROL,
.subclass.integer = AST_CONTROL_PROGRESS,
};
+ /*
+ * Determine the format for the playback channel.
+ * If a format was specified, use that if it's valid.
+ * Otherwise, if the bridge is empty, use slin.
+ * If the bridge has one channel, use that channel's raw write format.
+ * If the bridge has multiple channels, use the slin format that
+ * will handle the highest sample rate of the raw write format of all the channels.
+ */
+ if (!ast_strlen_zero(args_format)) {
+ channel_format = ast_format_cache_get(args_format);
+ if (!channel_format) {
+ ast_ari_response_error(
+ response, 422, "Unprocessable Entity",
+ "specified announcer_format is unknown on this system");
+ return;
+ }
+ /*
+ * ast_format_cache_get() bumps the refcount but the other calls
+ * to retrieve formats don't so we'll drop this reference.
+ * It'll be bumped again in the prepare_bridge_media_channel() call below.
+ */
+ ao2_ref(channel_format, -1);
+ } else {
+ ast_bridge_lock(bridge);
+ if (bridge->num_channels == 0) {
+ channel_format = ast_format_slin;
+ } else if (bridge->num_channels == 1) {
+ struct ast_bridge_channel *bc = NULL;
+ bc = AST_LIST_FIRST(&bridge->channels);
+ if (bc) {
+ channel_format = ast_channel_rawwriteformat(bc->chan);
+ }
+ } else {
+ struct ast_bridge_channel *bc = NULL;
+ unsigned int max_sample_rate = 0;
+ AST_LIST_TRAVERSE(&bridge->channels, bc, entry) {
+ struct ast_format *fmt = ast_channel_rawwriteformat(bc->chan);
+ max_sample_rate = MAX(ast_format_get_sample_rate(fmt), max_sample_rate);
+ }
+ channel_format = ast_format_cache_get_slin_by_rate(max_sample_rate);
+ }
+ ast_bridge_unlock(bridge);
+ }
+
+ if (!channel_format) {
+ channel_format = ast_format_slin;
+ }
- if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
+ play_channel = prepare_bridge_media_channel("Announcer", channel_format);
+ ao2_cleanup(channel_format);
+ if (!play_channel) {
ast_ari_response_error(
response, 500, "Internal Error", "Could not create playback channel");
return;
const char *args_bridge_id,
const char **args_media,
size_t args_media_count,
+ const char *args_format,
const char *args_lang,
int args_offset_ms,
int args_skipms,
return;
}
- ari_bridges_play_new(args_media, args_media_count, args_lang, args_offset_ms,
+ ari_bridges_play_new(args_media, args_media_count, args_format, args_lang, args_offset_ms,
args_skipms, args_playback_id, response, bridge);
}
ari_bridges_handle_play(args->bridge_id,
args->media,
args->media_count,
+ args->announcer_format,
args->lang,
args->offsetms,
args->skipms,
ari_bridges_handle_play(args->bridge_id,
args->media,
args->media_count,
+ args->announcer_format,
args->lang,
args->offsetms,
args->skipms,
size_t uri_name_maxlen;
struct bridge_channel_control_thread_data *thread_data;
pthread_t threadid;
+ struct ast_format *file_format = NULL;
+ struct ast_format *channel_format = NULL;
ast_assert(response != NULL);
return;
}
- if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
+ file_format = ast_get_format_for_file_ext(args->format);
+ if (!file_format) {
+ ast_ari_response_error(
+ response, 422, "Unprocessable Entity",
+ "specified format is unknown on this system");
+ return;
+ }
+
+ if (!ast_strlen_zero(args->recorder_format)) {
+ channel_format = ast_format_cache_get(args->recorder_format);
+ if (!channel_format) {
+ ast_ari_response_error(
+ response, 422, "Unprocessable Entity",
+ "specified recorder_format is unknown on this system");
+ return;
+ }
+ /*
+ * ast_format_cache_get() bumps the refcount but the other calls
+ * to retrieve formats don't so we'll drop this reference.
+ * It'll be bumped again in the prepare_bridge_media_channel() call below.
+ */
+ ao2_ref(channel_format, -1);
+
+ } else {
+ channel_format = file_format;
+ }
+
+ if (!(record_channel = prepare_bridge_media_channel("Recorder", channel_format))) {
ast_ari_response_error(
response, 500, "Internal Server Error", "Failed to create recording channel");
return;
return;
}
- if (!ast_get_format_for_file_ext(options->format)) {
- ast_ari_response_error(
- response, 422, "Unprocessable Entity",
- "specified format is unknown on this system");
- return;
- }
-
recording = stasis_app_control_record(control, options);
if (recording == NULL) {
switch(errno) {
args->media[0] = ast_json_string_get(field);
}
}
+ field = ast_json_object_get(body, "announcer_format");
+ if (field) {
+ args->announcer_format = ast_json_string_get(field);
+ }
field = ast_json_object_get(body, "lang");
if (field) {
args->lang = ast_json_string_get(field);
args.media[j] = (vals[j]);
}
} else
+ if (strcmp(i->name, "announcer_format") == 0) {
+ args.announcer_format = (i->value);
+ } else
if (strcmp(i->name, "lang") == 0) {
args.lang = (i->value);
} else
case 501: /* Not Implemented */
case 404: /* Bridge not found */
case 409: /* Bridge not in a Stasis application */
+ case 422: /* The format specified is unknown on this system */
is_valid = 1;
break;
default:
args->media[0] = ast_json_string_get(field);
}
}
+ field = ast_json_object_get(body, "announcer_format");
+ if (field) {
+ args->announcer_format = ast_json_string_get(field);
+ }
field = ast_json_object_get(body, "lang");
if (field) {
args->lang = ast_json_string_get(field);
args.media[j] = (vals[j]);
}
} else
+ if (strcmp(i->name, "announcer_format") == 0) {
+ args.announcer_format = (i->value);
+ } else
if (strcmp(i->name, "lang") == 0) {
args.lang = (i->value);
} else
case 501: /* Not Implemented */
case 404: /* Bridge not found */
case 409: /* Bridge not in a Stasis application */
+ case 422: /* The format specified is unknown on this system */
is_valid = 1;
break;
default:
if (field) {
args->format = ast_json_string_get(field);
}
+ field = ast_json_object_get(body, "recorder_format");
+ if (field) {
+ args->recorder_format = ast_json_string_get(field);
+ }
field = ast_json_object_get(body, "maxDurationSeconds");
if (field) {
args->max_duration_seconds = ast_json_integer_get(field);
if (strcmp(i->name, "format") == 0) {
args.format = (i->value);
} else
+ if (strcmp(i->name, "recorder_format") == 0) {
+ args.recorder_format = (i->value);
+ } else
if (strcmp(i->name, "maxDurationSeconds") == 0) {
args.max_duration_seconds = atoi(i->value);
} else
"allowMultiple": true,
"dataType": "string"
},
+ {
+ "name": "announcer_format",
+ "description": "Format of the 'Anouncer' channel attached to the bridge. Defaults to the format of the channel in the bridge with the highest sampe rate.",
+ "paramType": "query",
+ "required": false,
+ "allowMultiple": false,
+ "dataType": "string"
+ },
{
"name": "lang",
"description": "For sounds, selects language for sound.",
"valueType": "RANGE",
"min": 0
}
-
},
{
"name": "skipms",
{
"code": 409,
"reason": "Bridge not in a Stasis application"
+ },
+ {
+ "code": 422,
+ "reason": "The format specified is unknown on this system"
}
]
}
"allowMultiple": true,
"dataType": "string"
},
+ {
+ "name": "announcer_format",
+ "description": "Format of the 'Anouncer' channel attached to the bridge. Defaults to the format of the channel in the bridge with the highest sampe rate.",
+ "paramType": "query",
+ "required": false,
+ "allowMultiple": false,
+ "dataType": "string"
+ },
{
"name": "lang",
"description": "For sounds, selects language for sound.",
{
"code": 409,
"reason": "Bridge not in a Stasis application"
+ },
+ {
+ "code": 422,
+ "reason": "The format specified is unknown on this system"
}
]
"allowMultiple": false,
"dataType": "string"
},
+ {
+ "name": "recorder_format",
+ "description": "Format of the 'Recorder' channel attached to the bridge. Defaults to the same format as the 'format' parameter.",
+ "paramType": "query",
+ "required": false,
+ "allowMultiple": false,
+ "dataType": "string"
+ },
{
"name": "maxDurationSeconds",
"description": "Maximum duration of the recording, in seconds. 0 for no limit.",