Skip to content

Commit

Permalink
Support recording transferred calls in Asterisk channels
Browse files Browse the repository at this point in the history
See #859
  • Loading branch information
matiasgarciaisaia committed Apr 7, 2020
1 parent 232ace0 commit ee6089f
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 28 deletions.
5 changes: 3 additions & 2 deletions broker/src/africas_talking/africas_talking_pbx.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-module(africas_talking_pbx).
-compile([{parse_transform, lager_transform}]).
-export([pid/1, answer/1, reject/1, hangup/1, can_play/2, play/2, capture/6, terminate/1, sound_path_for/2, sound_quality/1, dial/4, record/4]).
-export([pid/1, answer/1, reject/1, hangup/1, can_play/2, play/2, capture/6, terminate/1, sound_path_for/2, sound_quality/1, dial/6, record/4]).
-behaviour(pbx).

-export([start_link/1, find/1, new/1, resume/2, user_hangup/1]).
Expand Down Expand Up @@ -68,7 +68,8 @@ sound_path_for(Name, ?PBX(_)) ->
sound_quality(?PBX(_)) ->
"44100".

dial(_Channel, Number, CallerId, ?PBX(Pid)) ->
dial(_Channel, Number, CallerId, _LocalFilename, _AsteriskFilename, ?PBX(Pid)) ->
% FIXME: implement session recording
case gen_server:call(Pid, {dial, Number, CallerId}, timer:minutes(60)) of
hangup -> throw(hangup) ;
X -> X
Expand Down
10 changes: 9 additions & 1 deletion broker/src/asterisk/agi_session.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module(agi_session).
-export([start_link/1, close/1, get_variable/2, ringing/1, answer/1, hangup/1, stream_file/3, wait_for_digit/2, record_file/5, set_callerid/2, dial/2]).
-export([start_link/1, close/1, get_variable/2, ringing/1, answer/1, hangup/1, stream_file/3, wait_for_digit/2, record_file/5, set_callerid/2, dial/2, mix_monitor/2, stop_mix_monitor/1]).
-compile([{parse_transform, lager_transform}]).

-behaviour(gen_server).
Expand Down Expand Up @@ -75,6 +75,14 @@ dial(Pid, ArgList) ->
Args = string:join(ArgList, Separator),
gen_server:call(Pid, {execute, ["EXEC DIAL ", Args]}, infinity).

mix_monitor(Pid, [AsteriskFilename]) ->
lager:info("Monitoring the call in ~p ", [AsteriskFilename]),
gen_server:call(Pid, {execute, ["EXEC MIXMONITOR \"", AsteriskFilename, "\" b"]}).

stop_mix_monitor(Pid) ->
lager:info("Stop monitoring "),
gen_server:call(Pid, {execute, ["EXEC STOPMIXMONITOR"]}).

%% @private
init(Sock) ->
case read_params(Sock, []) of
Expand Down
21 changes: 17 additions & 4 deletions broker/src/asterisk/asterisk_pbx.erl
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
-module(asterisk_pbx).
-export([new/1, pid/1, answer/1, reject/1, hangup/1, can_play/2, play/2, capture/6, record/5, terminate/1, sound_path_for/2, sound_quality/1, dial/4]).
-export([new/1, pid/1, answer/1, reject/1, hangup/1, can_play/2, play/2, capture/6, record/5, terminate/1, sound_path_for/2, sound_quality/1, dial/6]).

-behaviour(pbx).

Expand Down Expand Up @@ -87,12 +87,25 @@ record(AsteriskFilename, FileName, StopKeys, Timeout, {?MODULE, Pid}) ->
file:delete(TempFile)
end.

dial(Channel, Address, undefined, {?MODULE, Pid}) ->
monitor_session(_Pid, undefined) ->
undefined;
monitor_session(Pid, AsteriskFilename) ->
agi_session:mix_monitor(Pid, [AsteriskFilename]).

stop_monitoring(_Pid, undefined, _LocalFilename) ->
undefined;
stop_monitoring(Pid, AsteriskFilename, LocalFilename) ->
agi_session:stop_mix_monitor(Pid),
file:rename(AsteriskFilename, LocalFilename).

dial(Channel, Address, undefined, LocalFilename, AsteriskFilename, {?MODULE, Pid}) ->
monitor_session(Pid, AsteriskFilename),
DialAddress = case asterisk_broker:dial_address(Channel, Address) of
AsBinary when is_binary(AsBinary) -> binary_to_list(AsBinary);
AsList -> AsList
end,
agi_session:dial(Pid, [DialAddress, "60", "mg"]),
stop_monitoring(Pid, AsteriskFilename, LocalFilename),
case agi_session:get_variable(Pid, "DIALSTATUS") of
hangup -> throw(hangup);
{ok, Value} -> case Value of
Expand All @@ -103,6 +116,6 @@ dial(Channel, Address, undefined, {?MODULE, Pid}) ->
_ -> failed
end
end;
dial(Channel, Address, CallerId, Pbx = {?MODULE, Pid}) ->
dial(Channel, Address, CallerId, LocalFilename, AsteriskFilename, Pbx = {?MODULE, Pid}) ->
agi_session:set_callerid(Pid, CallerId),
dial(Channel, Address, undefined, Pbx).
dial(Channel, Address, undefined, LocalFilename, AsteriskFilename, Pbx).
25 changes: 23 additions & 2 deletions broker/src/commands/dial.erl
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
-include("session.hrl").
-include("db.hrl").

run(Args, Session = #session{pbx = Pbx, channel = CurrentChannel, js_context = JS}) ->
run(Args, Session = #session{pbx = Pbx, channel = CurrentChannel, js_context = JS, call_log = CallLog, contact = Contact, project = Project}) ->
RawNumber = proplists:get_value(number, Args),
CallerId = proplists:get_value(caller_id, Args),
Number = util:interpolate_js(util:as_binary(RawNumber), JS),
Expand All @@ -28,12 +28,22 @@ run(Args, Session = #session{pbx = Pbx, channel = CurrentChannel, js_context = J
Expr -> util:parse_short_time(Expr)
end,

Key = util:to_string(proplists:get_value(key, Args)),
Description = proplists:get_value(description, Args),

[LocalFilename, AsteriskFilename] = case proplists:get_value(record_call, Args) of
true -> CallLogId = CallLog:id(),
recording_utils:asterisk_and_local_filenames(CallLogId, Key);
_ -> [undefined, undefined]
end,

poirot:log(info, "Dialing ~s through channel ~s", [Number, Channel#channel.name]),

DialStart = erlang:now(),

try
Result = Pbx:dial(Channel, Number, CallerId),
Result = Pbx:dial(Channel, Number, CallerId, LocalFilename, AsteriskFilename),
persist_recording(AsteriskFilename, [Contact, Project, CallLog:id(), Key, Description]),
ResultJS = erjs_context:set(dial_status, Result, JS),
NewJS = maybe_mark_session_successful(DialStart, SuccessAfterSeconds, ResultJS),

Expand All @@ -45,6 +55,17 @@ run(Args, Session = #session{pbx = Pbx, channel = CurrentChannel, js_context = J
throw({hangup, Session#session{js_context = UpdatedJS}})
end.

persist_recording(undefined, _) -> undefined;
persist_recording(_AsteriskFilename, [Contact, Project, CallLogId, Key, Description]) ->
RecordedAudio = #recorded_audio{
contact_id = Contact#contact.id,
project_id = Project#project.id,
call_log_id = CallLogId,
key = Key,
description = Description
},
RecordedAudio:save().

maybe_mark_session_successful(_DialStart, undefined, JS) ->
JS;
maybe_mark_session_successful(DialStart, SuccessAfterSeconds, JS) ->
Expand Down
17 changes: 1 addition & 16 deletions broker/src/commands/record.erl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ run(Args, Session = #session{pbx = Pbx, call_log = CallLog, contact = Contact, p
Timeout = proplists:get_value(timeout, Args, 10),

CallLogId = CallLog:id(),
LocalFilename = local_filename(CallLogId, Key),
AsteriskFilename = asterisk_filename(CallLogId, Key),
filelib:ensure_dir(LocalFilename),
[LocalFilename, AsteriskFilename] = recording_utils:asterisk_and_local_filenames(CallLogId, Key),

poirot:log(info, "Recording to filename: ~s, stop keys: ~s, timeout: ~B, as: ~s", [LocalFilename, StopKeys, Timeout, AsteriskFilename]),
case Pbx:record(AsteriskFilename, LocalFilename, StopKeys, Timeout) of
Expand All @@ -31,16 +29,3 @@ run(Args, Session = #session{pbx = Pbx, call_log = CallLog, contact = Contact, p
{error, Reason} ->
throw({error_recording, Reason})
end.

filename(RecordDir, CallLogId, Key) ->
filename:join([RecordDir, util:to_string(CallLogId), "results", Key ++ ".wav"]).

local_filename(CallLogId, Key) ->
RecordDir = verboice_config:record_dir(),
filename(RecordDir, CallLogId, Key).

asterisk_filename(CallLogId, Key) ->
case verboice_config:asterisk_record_dir() of
undefined -> local_filename(CallLogId, Key);
RecordDir -> filename(RecordDir, CallLogId, Key)
end.
21 changes: 21 additions & 0 deletions broker/src/commands/recording_utils.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-module(recording_utils).
-export([asterisk_and_local_filenames/2]).

local_filename(CallLogId, Key) ->
RecordDir = verboice_config:record_dir(),
filename(RecordDir, CallLogId, Key).

asterisk_filename(CallLogId, Key) ->
case verboice_config:asterisk_record_dir() of
undefined -> local_filename(CallLogId, Key);
RecordDir -> filename(RecordDir, CallLogId, Key)
end.

filename(RecordDir, CallLogId, Key) ->
filename:join([RecordDir, util:to_string(CallLogId), "results", Key ++ ".wav"]).

asterisk_and_local_filenames(CallLogId, Key) ->
LocalFilename = local_filename(CallLogId, Key),
AsteriskFilename = asterisk_filename(CallLogId, Key),
filelib:ensure_dir(LocalFilename),
[LocalFilename, AsteriskFilename].
2 changes: 1 addition & 1 deletion broker/src/pbx.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
-callback can_play(resource_kind(), pbx()) -> boolean().
-callback sound_path_for(string(), pbx()) -> string().
-callback sound_quality(pbx()) -> string().
-callback dial(#channel{}, string(), string(), pbx()) -> completed | busy | no_answer | failed.
-callback dial(#channel{}, string(), string(), string(), string(), pbx()) -> completed | busy | no_answer | failed.
-callback pid(pbx()) -> undefined | pid().

-export_type([pbx/0]).
5 changes: 3 additions & 2 deletions broker/src/twilio/twilio_pbx.erl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-module(twilio_pbx).
-compile([{parse_transform, lager_transform}]).
-export([pid/1, answer/1, reject/1, hangup/1, can_play/2, play/2, capture/6, terminate/1, sound_path_for/2, sound_quality/1, dial/4, record/4]).
-export([pid/1, answer/1, reject/1, hangup/1, can_play/2, play/2, capture/6, terminate/1, sound_path_for/2, sound_quality/1, dial/6, record/4]).
-behaviour(pbx).

-export([start_link/1, find/1, new/1, resume/2, user_hangup/1]).
Expand Down Expand Up @@ -68,7 +68,8 @@ sound_path_for(Name, ?PBX(_)) ->
sound_quality(?PBX(_)) ->
"44100".

dial(_Channel, Number, CallerId, ?PBX(Pid)) ->
dial(_Channel, Number, CallerId, _LocalFilename, _AsteriskFilename, ?PBX(Pid)) ->
% FIXME: implement session recording
case gen_server:call(Pid, {dial, Number, CallerId}, timer:minutes(60)) of
hangup -> throw(hangup) ;
X -> X
Expand Down

0 comments on commit ee6089f

Please sign in to comment.