I know eavesdrop is an application, not an API, so you have to use it differently. I have an operator dialing in on extension 5000 being bridged to a client, and I'm getting those lovely little echoes that confirm the call is bridged (both operator and client softphones are sharing my one headset and mic.) In the dialplan, I parse out the extension when someone dials in to 665000 (last 4 digits are the extension to monitor), look up the appropriate operator UUID in my mnesia/Erlang tables, receive the "call" callback from Freeswitch, and build a proplists replacement with the execute-app-name set to "eavesdrop" and execute-app-arg set to the operator UUID. I issue a sendmsg() command to Freeswitch, and it returns ok. However, what happens to the extension that tried to eavesdrop is it gets two events: CHANNEL_PARK and SEND_MESSAGE. The person making the eavesdrop call can't actually hear anything. I've attached the Erlang callback module that the dialplan executes. The dialplan fragment is as follows: <extension name=\"eavesdrop\"> <condition field=\"destination_number\" expression=\"^66(\\d\\d\\d\\d)$\"> <action application=\"answer\"/> <action application=\"set\" data=\"eavesdrop_extension=$1\" /> <action application=\"erlang\" data=\"pbx_eavesdrop pursuit@testsrv\" /> </condition> </extension> Unfortunately I can't think of any way to look up the UUID other than using the mnesia tables from the application. When I tried the sample dialplans from Freeswitch, the eavesdrop module itself _did_ work. I'm just having trouble cobbling together the "glue" for Erlang. P.S. This is the last Freeswitch feature I have to code for this release, other than niggling cleanups like adding a few more voice prompts, which is easy enough as I've already sample code on how to do it. With a little luck we'll make our April 1st ready-for-testing deadline! We wouldn't have made it without Andrew's hints, tips, and tricks for using Erlang with Freeswitch. Thanks a lot! :D -- Mark Sobkow Senior Developer MarkeTel Multi-Line Dialing Systems LTD. 428 Victoria Ave Regina, SK S4N-0P6 Toll-Free: 800-289-8616-X533 Local: 306-359-6893-X533 Fax: 306-359-6879 Email: m.sobkow@marketelsystems.com Web: http://www.marketelsystems.com %% Author: mark %% %% Created: Mar 8, 2010 %% %% Description: %% This callback is executed when someone dials in to an eavesdrop %% -module(pbx_eavesdrop). %% %% Exported Functions %% -export([start/0, run/0, launch/1]). %% %% Include files %% -include_lib("figure/include/gut.hrl"). -include_lib("pbx/include/pbx_mnesia.hrl"). start() -> Pid = spawn( ?MODULE, run, [] ), register( ?MODULE, Pid ), syslog:debug( "pbx_eavesdrop:start() Started eavesdrop thread ~p~n", [Pid] ), { ok, Pid }. run() -> receive { call, Data } -> { event, [UUID | Rest]} = Data, EavesdropExtension = proplists:get_value( "variable_eavesdrop_extension", Rest ), %% syslog:debug( "pbx_eavesdrop:run() Rest=~p~n", [Rest] ), syslog:debug( "pbx_eavesdrop:run() New eavesdrop received for extension=~p~n", [EavesdropExtension] ), case pbx_mnesia:lookupOperatorByExtension( EavesdropExtension ) of { ok, ExtensionRegistry } -> case proplists:is_defined( "execute-app-name", Rest ) of true -> PropsNoAppName = proplists:delete( "execute-app-name", Rest ); _ -> PropsNoAppName = Rest end, case proplists:is_defined( "execute-app-arg", PropsNoAppName ) of true -> PropsNoAppArg = proplists:delete( "execute-app-arg", PropsNoAppName ); _ -> PropsNoAppArg = PropsNoAppName end, PropsWithAppName = PropsNoAppArg ++ [ proplists:property( "execute-app-name", "eavesdrop" ) ], PropsWithAppArg = PropsWithAppName ++ [ proplists:property( "execute-app-arg", ExtensionRegistry#pbx_operator_registry.operator_uuid ) ], %% syslog:debug( "pbx_eavesdrop:run() sendmsg( ~p, ~p )~n", [ UUID, PropsWithAppArg ] ), EavesdropResult = pbx:sendmsg( UUID, PropsWithAppArg ), syslog:debug( "pbx_eavesdrop:run() EavesdropResult = ~p~n", [EavesdropResult] ); Error -> %% Operator not logged in to extension syslog:info( "pbx_eavesdrop:run() Could not locate extension ~s, Error ~p~n", [ EavesdropExtension, Error ] ), _BgapiResult = pbx:bgapi( uuid_broadcast, UUID ++ " " ++ "/opt/freeswitch/sounds/en/us/callie/misc/8000/sorry.wav both" ), _ResultHangup = pbx:bgapi( sched_hangup, "+3 " ++ UUID ) end, run(); {call_event, Data} -> { event, [UUID | Rest]} = Data, EventName = proplists:get_value( "Event-Name", Rest ), syslog:debug( "pbx_eavesdrop:run() call_event UUID=~p, EventName=~p~n", [UUID, EventName] ), run(); {get_pid, _UUID, Ref, Pid} -> NewPid = spawn( ?MODULE, run, [] ), syslog:debug( "pbx_eavesdrop:run() Request to spawn new handler process, returning PID ~p~n", [NewPid] ), Pid ! { Ref, NewPid }, run() end. launch( Ref ) -> NewPid = spawn( ?MODULE, run, [] ), syslog:debug( "pbx_eavesdrop:launch() Returning new PID ~p~n", [NewPid] ), {Ref, NewPid}.
I do it like this: freeswitch:bgapi(Fnode, originate, "user/agentname" ++ " &eavesdrop(" ++ UUID ++ ")") But user/agentname can be any FS dialstring (SIP/... or whatever). It dials the endpoint and then the b leg is the eavesdrop() call. Andrew
Ok, so that new originate command will give me another UUID, and I'll have to bridge it to the original call's UUID, correct? i.e. Someone dials the 66xxxx extension, it calls back to Erlang and parks. Erlang issues the originate command, returns a UUID for the new call, and I do a uuid_bridge so the caller can hear the eavesdrop. The only thing I'm a little puzzled by is the user/agentname string. The caller is already on the phone, so how can Freeswitch call them? Alternatively maybe I could set the operator UUID into a variable and establish the call through a dialplan extension, but I think that ends up with the same problem of the caller being busy. I do have one other option -- we have a softphone built into our front-end application, so I could have a button press/menu selection on that application issue a command to Erlang, which would mean it could call the softphone because it's not busy trying to dial a special 66xxxx extension. That actually might be the best solution, because then there is no "secret" extension in the dialplan that unauthorized users might learn about. I just need to have one of our other developers provide an API to retrieve the configured extension/registration information for the softphone so it can pass along the extension to Erlang for building a dial string. The only "downside" to that approach is that it _requires_ our client application to work, but I think our user community will be ok with that because managers need that application for a whole host of features, not just the softphone. Andrew Thompson wrote:
I do it like this:
freeswitch:bgapi(Fnode, originate, "user/agentname" ++ " &eavesdrop(" ++ UUID ++ ")")
But user/agentname can be any FS dialstring (SIP/... or whatever). It dials the endpoint and then the b leg is the eavesdrop() call.
Andrew
_______________________________________________ FreeSWITCH-users mailing list FreeSWITCH-users@lists.freeswitch.org http://lists.freeswitch.org/mailman/listinfo/freeswitch-users UNSUBSCRIBE:http://lists.freeswitch.org/mailman/options/freeswitch-users http://www.freeswitch.org
-- Mark Sobkow Senior Developer MarkeTel Multi-Line Dialing Systems LTD. 428 Victoria Ave Regina, SK S4N-0P6 Toll-Free: 800-289-8616-X533 Local: 306-359-6893-X533 Fax: 306-359-6879 Email: m.sobkow@marketelsystems.com Web: http://www.marketelsystems.com
On Thu, Mar 18, 2010 at 03:36:53PM -0600, Mark Sobkow wrote:
Ok, so that new originate command will give me another UUID, and I'll have to bridge it to the original call's UUID, correct? i.e. Someone dials the 66xxxx extension, it calls back to Erlang and parks. Erlang issues the originate command, returns a UUID for the new call, and I do a uuid_bridge so the caller can hear the eavesdrop.
The only thing I'm a little puzzled by is the user/agentname string. The caller is already on the phone, so how can Freeswitch call them?
Alternatively maybe I could set the operator UUID into a variable and establish the call through a dialplan extension, but I think that ends up with the same problem of the caller being busy.
I do have one other option -- we have a softphone built into our front-end application, so I could have a button press/menu selection on that application issue a command to Erlang, which would mean it could call the softphone because it's not busy trying to dial a special 66xxxx extension. That actually might be the best solution, because then there is no "secret" extension in the dialplan that unauthorized users might learn about. I just need to have one of our other developers provide an API to retrieve the configured extension/registration information for the softphone so it can pass along the extension to Erlang for building a dial string. The only "downside" to that approach is that it _requires_ our client application to work, but I think our user community will be ok with that because managers need that application for a whole host of features, not just the softphone.
Oh, I see what you wanted. Why not just bridge the call to an inline dialplan that calls eavesdrop() then? That way you don't have to serve up an extension or anything annoying. something like uuid_transfer CallerUUID 'eavesdrop:EavesdropUUID' inline ? Andrew
%% Author: mark %% %% Created: Mar 18, 2010 %% %% Description: %% This server function allows the client to have Freeswitch initiate %% an eavesdrop call to the manager's extension. It is assumed %% that the manager isn't on the phone or logged in as an operator %% when they initiate the eavesdrop session. %% -module(pbx_eavesdrop). %% %% Exported Functions %% -export([callManager/2]). -export([functions/0, variables/0]). -export([fsfuns/0, fsvars/0, fsnodes/0]). %% %% Include files %% -include_lib("figure/include/gut.hrl"). callManager( _Data, [[SessionCookie, #str{s=ManagerExtension}, #str{s=OperatorUUID} ]] ) -> case storage:isSessionManagerUser( SessionCookie ) of true -> { ok, DialerLocalPrefix } = mnesia_sofia:getSofiaConfigValue( dialerLocalPrefix ), { ok, DialerLocalSuffix } = mnesia_sofia:getSofiaConfigValue( dialerLocalSuffix ), OriginateCmd = DialerLocalPrefix ++ ManagerExtension ++ DialerLocalSuffix ++ " '&eavesdrop( " ++ OperatorUUID ++ " )'", syslog:debug( "pbx_eavesdrop:callManager() OriginateCmd is \"~s\"~n", [OriginateCmd] ), case pbx:api( originate, OriginateCmd ) of { ok, ResultStrA } -> LenA = string:len( ResultStrA ), UuidA = string:substr( ResultStrA, 5, LenA - 5 ), syslog:debug( "pbx_eavesdrop:callManager() UUID A is \"~s\"~n", [ UuidA ] ), [ ok, UuidA ]; Error -> syslog:error( "pbx_eavesdrop:callManager() Error trying to originate eavesdrop -- ~p~n", [Error] ), [ error, eavesdrop_failed ] end; _ -> syslog:error( "pbx_eavesdrop:callManager() Permission denied~n" ), [ error, permission_denied ] end. functions() -> [func(callManager)]. variables() -> []. fsfuns() -> [func(callManager)]. fsvars() -> []. fsnodes() -> nd(str("PBX Eavesdrop"), [{program, nd(str("PBXEavesdrop"), [{function, nd(str("PBX Eavesdrop Functions"), fsfuns())}, {variable, nd(str("PBX Eavesdrop Variables"), fsvars())}])} ]).
participants (2)
-
Andrew Thompson
-
Mark Sobkow