AGI play file after pickup (python)

I wrote a script that generates a sound file, dials a number and should play it after picking up the phone. But instead, it just connects and I can talk to the recipient.
Through freepbx, I have set up a call to number 777 through custom distances.
Accordingly, I dial 777 from my phone.
I call the script like this:

[autodial]
exten => s,1,AGI(/var/lib/asterisk/agi-bin/Autodial.agi)

It works out, generates a sound file. The file format is correct, the rights are asterisk:asterisk

The connection is established, the recipient picks up the phone and I can talk to him, instead of playing the file and processing further script logic.

Tell me, please, what is my mistake?
(I’ve attached the part I’m having trouble with here)

with open(file_path, 'r') as file:
    for line in file:
        surname, lastname, name, phone_number = line.strip().split(',')
        phone_number = int(phone_number)
             
        replaced_text = f"Hello, {name} {lastname}!"

        command_gen = f" '{replaced_text}' --output {temp_audio_path} && sox {temp_audio_path} -r 8000 {audio_path}"
        os.system(command_gen)
...

        command = 'SIP/Ed/{}'.format(phone_number)
        timeout = '30'
        timeout = int(timeout)
        result = agi.exec_command('Dial', command, timeout)

        agi.verbose('Dial result: {}'.format(result))
        if agi.env['agi_channel_state'] == '6':
            agi.verbose('Success')

            agi.stream_file(f'/home/asterisk/sounds/{audio_path}')
            agi.stream_file('/home/asterisk/sounds/autodial_message_body.wav')

...

I also tried this option - the situation is similar. I dial an extension number, the called subscriber picks up the phone and can talk to me instead of playing the file

audio_path = "/var/lib/asterisk/sounds/en/intro.wav"

with open(file_path, 'r') as file:
    for line in file:
        surname, name, lastname, phone_number = line.strip().split(',')
        phone_number = int(phone_number)

       ...

        dial_command = (
            'SIP/Ed/{},n,1,Answer(),Playback({}),WaitExten(5)'.format(
                phone_number, audio_path
            )
        )
        agi.exec_command('Dial', dial_command)

First of all, we usually do not support FreePBX installations here.

That being said, the Dial application normally does not return control to your AGI script, or the dialplan, until the call is hung up. What you want, is instead to add the parameter to Dial, that plays an audio file to either caller or callee, depending on who should hear it, I don’t remember the parameter on the top of my head, but you can find it in the Asterisk documentation for Dial.

What I would do, unless you want the script to perform tasks on hangup, is to set a channel variable with the filename to be played, and put the call to Dial in your Dialplan instead of the AGI.

Then have another AGI script run when the call is done, to clean up the generated audio files, or perhaps use a call to System() if you like to live dangerously.

But your best bet would probably be the FreePBX forums, they would also know, if a method to archive whatever you’re trying to do, already exists in FreePBX, saving you the trouble of doing it yourself.

Thank you. Freepbx is just listed here as an example of calling the script itself, I tried to do this by means of the asterisk itself by calling just an extension.

I thought that it might be important, that’s why I wrote that I called it like this :sweat_smile:

In the future, I plan to record the person’s response after the message has been played to him, then translate the record into text and give the decryption to the CRM. Therefore, I wanted to do everything within the framework of one script.

Thank you again, I will think further and try to use your recommendations

I came across this and can’t figure out how to process it further:
I created a script that generates a request and a phone number from a file as variables for the dialplan:

...
with open(file_path, 'r') as file:
    for line in file:
        surname, name, lastname, phone_number = line.strip().split(',')
        phone_number = int(phone_number)

        agi.set_variable('PHONE_NUMBER', phone_number)
        agi.set_variable('AUTODIAL_HEADER', audio_path)
        agi.set_variable('CURRENT_INDEX', str(i))
    agi.exec_dial("Local/autodial,s,1")
....

The dialplan must be called several times and I added the call to the script.
But then it turns out that I again call the dialplan from the script in which I call the script - this will be a loop.

I can’t figure out how to avoid this?

[autodial]
exten => s,1,Answer()
exten => s,2,AGI(Autodial_Generate.py)
exten => s,3,Dial(SIP/Ed/${PHONE_NUMBER},30)
exten => s,4,Playback(${AUTODIAL_HEADER})
exten => s,5,Playback(/home/asterisk/sounds/autodial_message_body.wav)
exten => s,6,WaitExten(5) 
exten => s,7,NoOp(DTMF Received: ${EXTEN})
;NO DTMF
exten => s,8,GotoIf($["${EXTEN}" = ""]?9:11) ; 9 no DTMF, else 11
exten => s,9,Playback(/home/asterisk/sounds/autodial_thank_you.wav)
exten => s,10,Hangup()
; DTMF
exten => s,11,Record(/home/asterisk/sounds/voice_${CURRENT_INDEX}.wav,3,10)
exten => s,12,AGI(Autodial_Finalize.py,/home/asterisk/sounds/voice.wav)
exten => s,13,Playback(/home/asterisk/sounds/autodial_thank_you.wav) 
exten => s,14,Hangup()

If I add it to the script and then check it in the dialplan like this
agi.set_variable('DIALFROMSCRIPT', '1')

Will this work as expected and not slow down with every request?

[autodial]
exten => s,1,Answer()
**exten => s,2,GotoIf($["${ENV(DIALFROMSCRIPT)}" = "1"]?4:3)**
exten => s,3,AGI(Autodial_Generate.py)
exten => s,4,Dial(SIP/Ed/${PHONE_NUMBER},30)
exten => s,5,Playback(${AUTODIAL_HEADER})
exten => s,6,Playback(/home/asterisk/sounds/autodial_message_body.wav)
exten => s,7,WaitExten(5) 
exten => s,8,NoOp(DTMF Received: ${EXTEN})
;NO DTMF
exten => s,9,GotoIf($["${EXTEN}" = ""]?10:12) ; 10 no DTMF, else 11
exten => s,10,Playback(/home/asterisk/sounds/autodial_thank_you.wav)
exten => s,11,Hangup()
; DTMF
exten => s,12,Record(/home/asterisk/sounds/voice_${CURRENT_INDEX}.wav,3,10)
exten => s,13,AGI(Autodial_Finalize.py,/home/asterisk/sounds/voice.wav)
exten => s,14,Playback(/home/asterisk/sounds/autodial_thank_you.wav) 
exten => s,15,Hangup()

When you call dial, through AGI, you use the same context and extension, your AGI script is executed in, this will cause a loop.

If I understand it correctly, you’re making some sort of call center/telemarketing autodialer, that just calls a list of numbers.

I assume you start the process by calling an extension on your own phone, and expect the call to be bridged to you, when it’s established.

A high level overview would be something like this.

  1. Call 1234 to start the process
  2. Call the AGI script, that does the following:
    a. Get the list of numbers
    b. Dial numbers one by one
    c. On answer play a pre-recorded message
    d. Bridge the call to you
    e. Upon hangup, call the next number in the list
    f. Repeat steps c-e for every number in the list.
    g. Clean up whatever mess the AGI script made
  3. Do some post AGI stuff in the dialplan.

You would NOT like to jump back and forth from dialplan to AGI script all the time. Ideally you would only do in AGI what you can’t do in the dialplan, and your AGI scripts would be short, and have simple functions, with whatever business logic you might need. Eg. entering customer number, to present customer information to the agent, once the call is connected.

What you want it to add a parameter to the Dial command, that will play the file to either the caller or callee, and/or run some dialplan before connecting the call. The U and u options to Dial would most likely be what you’re after. This dialplan snippet, would handle playback and recording as desired, you can even run additional AGI scripts here, if needed.

If you want to avoid a loop in your AGI, you could make a channel variable representing the last dialed number, in some form, then skip directly to the next number after that, on each run, you would not avoid the loop, but the loop will be broken whenever an outbound call is created. You would need to consider how to handle changes to the file containing the number list, between executions.

Almost everything works for me.
I run a script that connects to the dialplan through AMI and works further.
On the test, everything passes if I use this construction:

originate_command = ("Action: Originate\r\n"
                         "Channel: SIP/Ed/123456789\r\n"
                         "Context: autodial\r\n"
                         "Exten: s\r\n"
                         "Priority: 1\r\n"
                         "CallerID: AutoDial <123321>\r\n"
                         "Timeout: 30000\r\n\r\n")
    ami_socket.send(originate_command.encode())

It calls 123456789 and when I pick up the phone the message plays. Finally! :star_struck:

How can I make a call without giving the end number? There is a script in the dialpan that takes a phone number from a file, I would like the number to be taken from there.

In other words - how to call just a context through ami?

I have read about callfiles but don’t want to use them

[autodial]
exten => s,1,Answer()
exten => s,2,GotoIf($["${ENV(DIALFROMSCRIPT)}" = "1"]?4:3) ; 4 from script, else 3
exten => s,3,AGI(Autodial_Generate.py)
exten => s,4,Dial(SIP/Ed/${PHONE_NUMBER},30)
exten => s,5,Background(${AUTODIAL_HEADER})
exten => s,6,Background(/var/lib/asterisk/sounds/en/custom/autodial_message_body,m)
.....

Why wouldn’t you just let the script running the originate command, handle picking the number? Having the number being picked in the dialplan seems like the wrong solution.

There’s also no real different between having a script connect to Asterisk fire off an Originate request, then disconnecting, compared to using a callfile, especially if you run the script on the same machine Asterisk is running on. The AMI approach is actually quite a bit slower if you run both on the same machine.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.