How to play background music in Asterisk AGI while some process is Going on in background to remove the silence during execution

I am using python 2 in asterisk 2 there is a section where code listen to callers audio and process the audio. During the process there is a silence of 15 sec before the audio is played. I want to add a music during the processing of audio. Is there a way to do this. the extension.config is like this

[autoattendant2]
exten => 5555,1,same=>n,Answer() 
same=> n, AGI(/root/code_base/Queue/code2.py)
same=>n,hangup()
   

Below is the python code

#!/usr/bin/env python2
import sys

import json
from datetime import datetime
#!/usr/bin/env python2
import sys
import re
import time
import random
import subprocess
import requests
import json
from datetime import datetime

    
    env = {}
    tests = 0;
    while 1:
       line = sys.stdin.readline().strip()
       if line == '':
          break
       key,data = line.split(':')
       if key[:4] <> 'agi_':
          #skip input that doesn't begin with agi_
          sys.stderr.write("Did not work!\n");
          sys.stderr.flush()
          continue
       key = key.strip()
       data = data.strip()
       if key <> '':
          env[key] = data
    
    sys.stderr.write("AGI Environment Dump:\n");
    sys.stderr.flush()
    for key in env.keys():
       sys.stderr.write(" -- %s = %s\n" % (key, env[key]))
       sys.stderr.flush()
    
    def checkresult (params):
       params = params.rstrip()
       if re.search('^200',params):
          result = re.search('result=(\d+)',params)
          if (not result):
             sys.stderr.write("FAIL ('%s')\n" % params)
             sys.stderr.flush()
             return -1
          else:
             result = result.group(1)
             #debug("Result:%s Params:%s" % (result, params))
             sys.stderr.write("PASS (%s)\n" % result)
             sys.stderr.flush()
             return result
       else:
          sys.stderr.write("FAIL (unexpected result '%s')\n" % params)
          sys.stderr.flush()
          return -2
    
    def change_file(path, cid):
    # one of the process example  
       filename = 'complain{0}'.format(cid)
       #filename = 
       input_file = path + '/' + filename + '.gsm'
       output_file = path + '/' + filename + '.wav'
       #command = "sox {} -r 8000 -c 1 {}".format(input_file, output_file)
       command = "sox {} -b 16 -r 44100 -c 1  {} trim 0 7 vol 2".format(input_file, output_file)
       subprocess.call(command, shell=True)
       pbcheck = requests.get("http://127.0.0.1:8000/STT_complaint/", params = {"address" : output_file, "lang" : language, "cid":cid, "phone":callerid, "start_time":now})
       res = pbcheck.content
       res2 = res.replace('"', "")  
         
       return res2
    def run_cmd(cmd):
    #This runs the general command 
       sys.stderr.write(cmd)
       sys.stderr.flush()
       sys.stdout.write(cmd)
       sys.stdout.flush()
       result = sys.stdin.readline().strip()
       checkresult(result)
    
    
    #language = "ben"
# asking problem recorded audio
    cmd_streaming = "STREAM FILE /root/code_base/recorded_voices/{0}/plz_tell_problem \"\"\n".format(language, language)
    run_cmd(cmd_streaming)
# listening to caller / recording caller voice    
    cmd_record = "RECORD FILE {0}/complain{1} gsm 1234 {2} s=3 \"\"\n".format(fixed_path, cid, 15)
    run_cmd(cmd_record)
  #processing audio
    processed_output = change_file(path , cid) # while this is executing ad giving output i want to play wait_music and then stop to run 
    # while processing play this 
    cmd_streaming = "STREAM FILE /root/code_base/recorded_voices/wait_music  \"\"\n".format(language, language)
    run_cmd(cmd_streaming)
    # once output received (processed_output) play next audio

    cmd_streaming = "STREAM FILE /root/code_base/recorded_voices/next_instruction  \"\"\n")
    run_cmd(cmd_streaming)

You can create a separate thread (‘pthreads’) for the processing of your background task.

Way, way long ago, I wrote an AGI (in C) to process credit card transactions. The authorization process could take several seconds so I created a separate thread to play a ‘dead air filler’ (‘Thank you for your entry and get ready for a great time’). Usually the authorization finished before the prompt finished so the ‘caller experience’ was that the authorization was instantaneous.

Be aware that while your background thread is playing the prompt, you can’t ask Asterisk to do anything else and any I/O to STDIN/STDOUT will break the AGI protocol.

You can inject the audio file to the channel using chanspy, this is the way, how I play background file

after some RnD found i need to set music on hold … Can anyone help me how to implement music on hold in my code
the documentation has nothing. Asterisk 18 AGICommand_set music - Asterisk Project - Asterisk Project Wiki
The music is at /root/music/onhold.gsm.

You don’t want to use GSM for music on hold. You don’t really want to send music at all if your codec is GSM.

GSM is a vocal tract model based codec, and is specifically designed for human speech. Any sounds that are not human speech are likely to be significantly compromised by using GSM. The same applies for G.729. They both achieve low bits rates at the expense of only being suitable for speech.

It is possible that there are specialist musical arrangements optimised for such codecs.

its a speech only saying we are processing pls hold. If i can implement it i will change the file . But how to add this file and in music on hold is still the issue i tried
run_cmd(“SET MUSIC on “”\n”) didnt work

when there is operation going on in I want to play a music instead of silence.
I saw the function python music on hold available but not sire how to use it in python.

[autoattendant2]
exten => 5555,1,same=>n,Answer() 
same=> n, AGI(/root/code_base/Queue/code2.py)
same=>n,hangup()
   
#!/usr/bin/env python2
import sys

    
    env = {}
    tests = 0;
    while 1:
       line = sys.stdin.readline().strip()
       if line == '':
          break
       key,data = line.split(':')
       if key[:4] <> 'agi_':
          #skip input that doesn't begin with agi_
          sys.stderr.write("Did not work!\n");
          sys.stderr.flush()
          continue
       key = key.strip()
       data = data.strip()
       if key <> '':
          env[key] = data
    
    sys.stderr.write("AGI Environment Dump:\n");
    sys.stderr.flush()
    for key in env.keys():
       sys.stderr.write(" -- %s = %s\n" % (key, env[key]))
       sys.stderr.flush()
    
    def checkresult (params):
       params = params.rstrip()
       if re.search('^200',params):
          result = re.search('result=(\d+)',params)
          if (not result):
             sys.stderr.write("FAIL ('%s')\n" % params)
             sys.stderr.flush()
             return -1
          else:
             result = result.group(1)
             #debug("Result:%s Params:%s" % (result, params))
             sys.stderr.write("PASS (%s)\n" % result)
             sys.stderr.flush()
             return result
       else:
          sys.stderr.write("FAIL (unexpected result '%s')\n" % params)
          sys.stderr.flush()
          return -2
    
    def change_file(path, cid):
    # one of the process example  
       filename = 'complain{0}'.format(cid)
       #filename = 
       pbcheck = requests.get("http://127.0.0.1:8000/STT_complaint/", params = {"address" : output_file, "lang" : language, "cid":cid, "phone":callerid, "start_time":now})
       res = pbcheck.content
       res2 = res.replace('"', "")  
       
       return res2
    
def run_cmd(cmd):
    #This runs the general command 
       sys.stderr.write(cmd)
       sys.stderr.flush()
       sys.stdout.write(cmd)
       sys.stdout.flush()
       result = sys.stdin.readline().strip()
       checkresult(result)
    
    
    #language = "ben"
# asking problem recorded audio
    cmd_streaming = "STREAM FILE /root/code_base/recorded_voices/{0}/plz_tell_problem \"\"\n".format(language, language)
    run_cmd(cmd_streaming)
# listening to caller / recording caller voice    
    cmd_record = "RECORD FILE {0}/complain{1} gsm 1234 {2} s=3 \"\"\n".format(fixed_path, cid, 15)
    run_cmd(cmd_record)
  #processing audio
    processed_output = change_file(path , cid) # while this is executing ad giving output i want to play wait_music and then stop to run 
    # while processing play this 
    cmd_streaming = "STREAM FILE /root/code_base/recorded_voices/wait_music  \"\"\n".format(language, language)
    run_cmd(cmd_streaming)
    # once output received (processed_output) play next audio

    cmd_streaming = "STREAM FILE /root/code_base/recorded_voices/next_instruction  \"\"\n")
    run_cmd(cmd_streaming)

The on hold music is at root/onhold/play.gsm
I tried run_cmd(" SET MUSIC ON “”\n") but didnt work
Also cant set the path of the audio file.
The documentation has nothing
https://wiki.asterisk.org/wiki/display/AST/Asterisk+18+AGICommand_set+music

The auto-generated documentation is broken. I don’t know if that is because the syntax description has been done incorrectly, or because there is no way of validly describing the syntax, but in Cobol type notation, the syntax it seems to be describing is:

SET MUSIC {on|off} <class>

where <class> is mandatory, and must match a section name in musiconhold.conf. However, there is a discrepancy between the attempted formal definition and the free text description, which seems to suggest that the full syntax is:

SET MUSIC {on|off} [<class>]

Either way, the actual file is indirected via a section in musiconhold.conf.

I haven’t sought out the actual implementation to see how it is actually parsed.

Much in the same way ‘all SIP enlightenment is revealed by the packets,’ 'all AGI enlightenment is revealed by ‘agi set debug on.’

The CLI command ‘agi show commands topic set music’ says the class is optional:

Enables/Disables the music on hold generator. If <class> is not specified, then
the ‘default’ music on hold class will be used. This generator will be stopped
automatically when playing a file.
Always returns ‘0’.

This is all generated from structured comments, and, as I said, there is a conflict between the part that generates the description that you have quoted and the part the should have generated the formal syntax in the wiki, which has required=true for both parameters.

Whilst I suspect that the description is correct, one would have to try it, or go to the source code, to be sure.

See:

This line appears to be trying to say that the class is mandatory:

<parameter name="class" required="true" />

1 Like

This need just appeared for me, as in my scripts I use bash script, it worked like a charm.

exten => *879,1,Answer()
 same => n,AGI(test)
 same => n,HangUp()

/var/lib/asterisk/agi-bin/teste

#!/bin/bash

echo "SET MUSIC ON default"
sleep 10
echo "SET MUSIC OFF default"

This script does not read the AGI environment nor does it read the request responses. It may work, but it does not follow the AGI protocol.

Does this satisfy the OP’s requirement:

A casual look says it will play 10 seconds of MOH and then return – allowing no opportunity to run sox while the music is playing.

I put a sleep here as an example, in my environment I am waiting for an answer of a query and the music on hold will play till the process is finished and I received the answer.

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