ari: Add events for playback and recording.
While there were events defined for playback and recording these were not actually sent. This change implements the to_json handlers which produces them. (closes issue ASTERISK-22710) Reported by: Jonathan Rose Review: https://reviewboard.asterisk.org/r/3026/ ........ Merged revisions 403119 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403120 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
parent
eda7126862
commit
14a7452934
|
@ -996,6 +996,15 @@ int ast_ari_validate_live_recording(struct ast_json *json)
|
||||||
int has_state = 0;
|
int has_state = 0;
|
||||||
|
|
||||||
for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
|
for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
|
||||||
|
if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
|
||||||
|
int prop_is_valid;
|
||||||
|
prop_is_valid = ast_ari_validate_string(
|
||||||
|
ast_json_object_iter_value(iter));
|
||||||
|
if (!prop_is_valid) {
|
||||||
|
ast_log(LOG_ERROR, "ARI LiveRecording field cause failed validation\n");
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
} else
|
||||||
if (strcmp("format", ast_json_object_iter_key(iter)) == 0) {
|
if (strcmp("format", ast_json_object_iter_key(iter)) == 0) {
|
||||||
int prop_is_valid;
|
int prop_is_valid;
|
||||||
has_format = 1;
|
has_format = 1;
|
||||||
|
@ -3292,20 +3301,9 @@ int ast_ari_validate_recording_failed(struct ast_json *json)
|
||||||
{
|
{
|
||||||
int res = 1;
|
int res = 1;
|
||||||
struct ast_json_iter *iter;
|
struct ast_json_iter *iter;
|
||||||
int has_cause = 0;
|
|
||||||
int has_recording = 0;
|
int has_recording = 0;
|
||||||
|
|
||||||
for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
|
for (iter = ast_json_object_iter(json); iter; iter = ast_json_object_iter_next(json, iter)) {
|
||||||
if (strcmp("cause", ast_json_object_iter_key(iter)) == 0) {
|
|
||||||
int prop_is_valid;
|
|
||||||
has_cause = 1;
|
|
||||||
prop_is_valid = ast_ari_validate_string(
|
|
||||||
ast_json_object_iter_value(iter));
|
|
||||||
if (!prop_is_valid) {
|
|
||||||
ast_log(LOG_ERROR, "ARI RecordingFailed field cause failed validation\n");
|
|
||||||
res = 0;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
if (strcmp("recording", ast_json_object_iter_key(iter)) == 0) {
|
if (strcmp("recording", ast_json_object_iter_key(iter)) == 0) {
|
||||||
int prop_is_valid;
|
int prop_is_valid;
|
||||||
has_recording = 1;
|
has_recording = 1;
|
||||||
|
@ -3324,11 +3322,6 @@ int ast_ari_validate_recording_failed(struct ast_json *json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_cause) {
|
|
||||||
ast_log(LOG_ERROR, "ARI RecordingFailed missing required field cause\n");
|
|
||||||
res = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!has_recording) {
|
if (!has_recording) {
|
||||||
ast_log(LOG_ERROR, "ARI RecordingFailed missing required field recording\n");
|
ast_log(LOG_ERROR, "ARI RecordingFailed missing required field recording\n");
|
||||||
res = 0;
|
res = 0;
|
||||||
|
|
|
@ -1032,6 +1032,7 @@ ari_validator ast_ari_validate_application_fn(void);
|
||||||
* - id: string (required)
|
* - id: string (required)
|
||||||
* - technology: string (required)
|
* - technology: string (required)
|
||||||
* LiveRecording
|
* LiveRecording
|
||||||
|
* - cause: string
|
||||||
* - format: string (required)
|
* - format: string (required)
|
||||||
* - name: string (required)
|
* - name: string (required)
|
||||||
* - state: string (required)
|
* - state: string (required)
|
||||||
|
@ -1167,7 +1168,6 @@ ari_validator ast_ari_validate_application_fn(void);
|
||||||
* - timestamp: Date
|
* - timestamp: Date
|
||||||
* - playback: Playback (required)
|
* - playback: Playback (required)
|
||||||
* RecordingFailed
|
* RecordingFailed
|
||||||
* - cause: string (required)
|
|
||||||
* - recording: LiveRecording (required)
|
* - recording: LiveRecording (required)
|
||||||
* RecordingFinished
|
* RecordingFinished
|
||||||
* - recording: LiveRecording (required)
|
* - recording: LiveRecording (required)
|
||||||
|
|
|
@ -57,8 +57,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
#define SOUND_URI_SCHEME "sound:"
|
#define SOUND_URI_SCHEME "sound:"
|
||||||
#define RECORDING_URI_SCHEME "recording:"
|
#define RECORDING_URI_SCHEME "recording:"
|
||||||
|
|
||||||
STASIS_MESSAGE_TYPE_DEFN(stasis_app_playback_snapshot_type);
|
|
||||||
|
|
||||||
/*! Container of all current playbacks */
|
/*! Container of all current playbacks */
|
||||||
static struct ao2_container *playbacks;
|
static struct ao2_container *playbacks;
|
||||||
|
|
||||||
|
@ -87,6 +85,32 @@ struct stasis_app_playback {
|
||||||
enum stasis_app_playback_state state;
|
enum stasis_app_playback_state state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct ast_json *playback_to_json(struct stasis_message *message,
|
||||||
|
const struct stasis_message_sanitizer *sanitize)
|
||||||
|
{
|
||||||
|
struct ast_channel_blob *channel_blob = stasis_message_data(message);
|
||||||
|
struct ast_json *blob = channel_blob->blob;
|
||||||
|
const char *state =
|
||||||
|
ast_json_string_get(ast_json_object_get(blob, "state"));
|
||||||
|
const char *type;
|
||||||
|
|
||||||
|
if (!strcmp(state, "playing")) {
|
||||||
|
type = "PlaybackStarted";
|
||||||
|
} else if (!strcmp(state, "done")) {
|
||||||
|
type = "PlaybackFinished";
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast_json_pack("{s: s, s: O}",
|
||||||
|
"type", type,
|
||||||
|
"playback", blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
STASIS_MESSAGE_TYPE_DEFN(stasis_app_playback_snapshot_type,
|
||||||
|
.to_json = playback_to_json,
|
||||||
|
);
|
||||||
|
|
||||||
static void playback_dtor(void *obj)
|
static void playback_dtor(void *obj)
|
||||||
{
|
{
|
||||||
struct stasis_app_playback *playback = obj;
|
struct stasis_app_playback *playback = obj;
|
||||||
|
|
|
@ -49,8 +49,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
|
||||||
/*! Recording check is unimplemented. le sigh */
|
/*! Recording check is unimplemented. le sigh */
|
||||||
#define RECORDING_CHECK 0
|
#define RECORDING_CHECK 0
|
||||||
|
|
||||||
STASIS_MESSAGE_TYPE_DEFN(stasis_app_recording_snapshot_type);
|
|
||||||
|
|
||||||
/*! Container of all current recordings */
|
/*! Container of all current recordings */
|
||||||
static struct ao2_container *recordings;
|
static struct ao2_container *recordings;
|
||||||
|
|
||||||
|
@ -61,13 +59,40 @@ struct stasis_app_recording {
|
||||||
char *absolute_name;
|
char *absolute_name;
|
||||||
/*! Control object for the channel we're recording */
|
/*! Control object for the channel we're recording */
|
||||||
struct stasis_app_control *control;
|
struct stasis_app_control *control;
|
||||||
|
|
||||||
/*! Current state of the recording. */
|
/*! Current state of the recording. */
|
||||||
enum stasis_app_recording_state state;
|
enum stasis_app_recording_state state;
|
||||||
/*! Indicates whether the recording is currently muted */
|
/*! Indicates whether the recording is currently muted */
|
||||||
int muted:1;
|
int muted:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct ast_json *recording_to_json(struct stasis_message *message,
|
||||||
|
const struct stasis_message_sanitizer *sanitize)
|
||||||
|
{
|
||||||
|
struct ast_channel_blob *channel_blob = stasis_message_data(message);
|
||||||
|
struct ast_json *blob = channel_blob->blob;
|
||||||
|
const char *state =
|
||||||
|
ast_json_string_get(ast_json_object_get(blob, "state"));
|
||||||
|
const char *type;
|
||||||
|
|
||||||
|
if (!strcmp(state, "recording")) {
|
||||||
|
type = "RecordingStarted";
|
||||||
|
} else if (!strcmp(state, "done") || !strcasecmp(state, "canceled")) {
|
||||||
|
type = "RecordingFinished";
|
||||||
|
} else if (!strcmp(state, "failed")) {
|
||||||
|
type = "RecordingFailed";
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ast_json_pack("{s: s, s: O}",
|
||||||
|
"type", type,
|
||||||
|
"recording", blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
STASIS_MESSAGE_TYPE_DEFN(stasis_app_recording_snapshot_type,
|
||||||
|
.to_json = recording_to_json,
|
||||||
|
);
|
||||||
|
|
||||||
static int recording_hash(const void *obj, int flags)
|
static int recording_hash(const void *obj, int flags)
|
||||||
{
|
{
|
||||||
const struct stasis_app_recording *recording = obj;
|
const struct stasis_app_recording *recording = obj;
|
||||||
|
@ -183,7 +208,7 @@ enum ast_record_if_exists stasis_app_recording_if_exists_parse(
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recording_publish(struct stasis_app_recording *recording)
|
static void recording_publish(struct stasis_app_recording *recording, const char *cause)
|
||||||
{
|
{
|
||||||
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
|
||||||
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
|
RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
|
||||||
|
@ -196,6 +221,19 @@ static void recording_publish(struct stasis_app_recording *recording)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ast_strlen_zero(cause)) {
|
||||||
|
struct ast_json *failure_cause = ast_json_string_create(cause);
|
||||||
|
|
||||||
|
if (!failure_cause) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ast_json_object_set(json, "cause", failure_cause)) {
|
||||||
|
ast_json_unref(failure_cause);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
message = ast_channel_blob_create_from_cache(
|
message = ast_channel_blob_create_from_cache(
|
||||||
stasis_app_control_get_channel_id(recording->control),
|
stasis_app_control_get_channel_id(recording->control),
|
||||||
stasis_app_recording_snapshot_type(), json);
|
stasis_app_recording_snapshot_type(), json);
|
||||||
|
@ -206,11 +244,11 @@ static void recording_publish(struct stasis_app_recording *recording)
|
||||||
stasis_app_control_publish(recording->control, message);
|
stasis_app_control_publish(recording->control, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recording_fail(struct stasis_app_recording *recording)
|
static void recording_fail(struct stasis_app_recording *recording, const char *cause)
|
||||||
{
|
{
|
||||||
SCOPED_AO2LOCK(lock, recording);
|
SCOPED_AO2LOCK(lock, recording);
|
||||||
recording->state = STASIS_APP_RECORDING_STATE_FAILED;
|
recording->state = STASIS_APP_RECORDING_STATE_FAILED;
|
||||||
recording_publish(recording);
|
recording_publish(recording, cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void recording_cleanup(struct stasis_app_recording *recording)
|
static void recording_cleanup(struct stasis_app_recording *recording)
|
||||||
|
@ -233,7 +271,7 @@ static void *record_file(struct stasis_app_control *control,
|
||||||
|
|
||||||
if (stasis_app_get_bridge(control)) {
|
if (stasis_app_get_bridge(control)) {
|
||||||
ast_log(LOG_ERROR, "Cannot record channel while in bridge\n");
|
ast_log(LOG_ERROR, "Cannot record channel while in bridge\n");
|
||||||
recording_fail(recording);
|
recording_fail(recording, "Cannot record channel while in bridge");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,13 +293,13 @@ static void *record_file(struct stasis_app_control *control,
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
ast_debug(3, "%s: Failed to answer\n",
|
ast_debug(3, "%s: Failed to answer\n",
|
||||||
ast_channel_uniqueid(chan));
|
ast_channel_uniqueid(chan));
|
||||||
recording_fail(recording);
|
recording_fail(recording, "Failed to answer channel");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ao2_lock(recording);
|
ao2_lock(recording);
|
||||||
recording->state = STASIS_APP_RECORDING_STATE_RECORDING;
|
recording->state = STASIS_APP_RECORDING_STATE_RECORDING;
|
||||||
recording_publish(recording);
|
recording_publish(recording, NULL);
|
||||||
ao2_unlock(recording);
|
ao2_unlock(recording);
|
||||||
|
|
||||||
ast_play_and_record_full(chan,
|
ast_play_and_record_full(chan,
|
||||||
|
@ -284,7 +322,7 @@ static void *record_file(struct stasis_app_control *control,
|
||||||
|
|
||||||
ao2_lock(recording);
|
ao2_lock(recording);
|
||||||
recording->state = STASIS_APP_RECORDING_STATE_COMPLETE;
|
recording->state = STASIS_APP_RECORDING_STATE_COMPLETE;
|
||||||
recording_publish(recording);
|
recording_publish(recording, NULL);
|
||||||
ao2_unlock(recording);
|
ao2_unlock(recording);
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -153,11 +153,6 @@
|
||||||
"type": "LiveRecording",
|
"type": "LiveRecording",
|
||||||
"description": "Recording control object",
|
"description": "Recording control object",
|
||||||
"required": true
|
"required": true
|
||||||
},
|
|
||||||
"cause": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "Cause for the recording failure",
|
|
||||||
"required": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -307,6 +307,11 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cause": {
|
||||||
|
"required": false,
|
||||||
|
"type": "string",
|
||||||
|
"description": "Cause for recording failure if failed"
|
||||||
|
},
|
||||||
"state": {
|
"state": {
|
||||||
"required": true,
|
"required": true,
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
|
Loading…
Reference in New Issue