Looping a prerecorded page

I recognize that it is in bad taste to reply to an old abandoned post, but this thread fits what I was looking for exactly.

I was not able to find adequate explanation in the manuals to help me figure out how to accomplish this using @cynjut’s recommendation (Custom Context + Miscellaneous Destination + Multicast Paging device extension). If someone wants to provide additional pointers to documentation for looping a prerecorded audio file in that manner, I would be very appreciative.

So instead this turned into my first FreePBX programming project. I’m posting the result here 1) in case it can help someone else 2) so that someone can tell me that there is a better way.

I set up a custom extension that:

  1. originates a call between a multicast device and an extension that quietly joins a conference bridge
  2. originates a call between an extension that loops the desired audio file and an extension that joins the same conference bridge
  3. connects the caller to the conference bridge muted to prevent feedback and as admin so that the paging stops when the caller disconnects

And it worked.

;;;
;;; Contents of extensions_custom.conf (abbreviated)
;;;

[from-internal-custom]
...
; include the context containing the emergency
; paging extensions
include => custom-emergency

[custom-emergency]
exten => *9001,1,Wait(1)
    same => n,Set(PAGE_LOOP_FILE_ID="all_clear")
    same => n,Goto(custom-page-loop,page_loop,1)

exten => **9002,1,Wait(1)
    same => n,Set(PAGE_LOOP_FILE_ID="severe_weather_drill")
    same => n,Goto(custom-page-loop,page_loop,1)

exten => *9002,1,Wait(1)
    same => n,Set(PAGE_LOOP_FILE_ID="severe_weather")
    same => n,Goto(custom-page-loop,page_loop,1)

[custom-page-loop]
exten => page_loop,1,NoOp()
    same => n,Answer()
    ; connect multicast devices to conference bridge
    same => n,Originate(MulticastRTP/basic/X.X.X.X:XXXXX//c(ulaw),exten,custom-page-loop,page_loop_enter,1)
    ; connect looping audio to conference bridge
    same => n,Originate(Local/page_loop_play_${PAGE_LOOP_FILE_ID}@custom-page-loop,exten,custom-page-loop,page_loop_enter_play,1)
    ; connect caller to conference bridge
    same => n,Set(CONFBRIDGE(user,template)=page_loop_admin)
    same => n,Set(CONFBRIDGE(bridge,template)=page_loop_bridge)
    same => n,Set(CONFBRIDGE(menu,template)=page_loop_admin_menu)
    same => n,ConfBridge(page_loop_1)
    same => n,Hangup()

; output to multicast devices
exten => page_loop_enter,1,NoOp()
    same => n,Answer()
    same => n,Set(CONFBRIDGE(user,template)=page_loop_user)
    same => n,Set(CONFBRIDGE(bridge,template)=page_loop_bridge)
    same => n,Set(CONFBRIDGE(menu,template)=page_loop_user_menu)
    same => n,ConfBridge(page_loop_1)
    same => n,Hangup()

; input from looping audio
exten => page_loop_enter_play,1,NoOp()
    same => n,Answer()
    same => n,Set(CONFBRIDGE(user,template)=page_loop_play)
    same => n,Set(CONFBRIDGE(bridge,template)=page_loop_bridge)
    same => n,Set(CONFBRIDGE(menu,template)=page_loop_user_menu)
    same => n,ConfBridge(page_loop_1)
    same => n,Hangup()

; looping audio with alert tones
exten => _page_loop_play_.,1,NoOp()
    same => n,Answer()
    same => n,Set(PAGE_LOOP_FILE_ID=${EXTEN:15})
    same => n(loop),Wait(1)
    same => n,Playback(/var/lib/asterisk/sounds/en/custom/3tones)
    same => n,Wait(1)
    same => n,Playback(/var/lib/asterisk/sounds/en/custom/${PAGE_LOOP_FILE_ID})
    same => n,Goto(loop)
    same => n,Hangup()


;;;
;;; Contents of confbridge_custom.conf
;;;

[page_loop_user]
type = user
quiet = yes
announce_user_count = no
wait_marked = no
end_marked = yes
dsp_drop_silence = yes
announce_join_leave = no
admin = no
marked = no
startmuted = yes

[page_loop_play]
type = user
quiet = yes
announce_user_count = no
wait_marked = no
end_marked = yes
dsp_drop_silence = yes
announce_join_leave = no
admin = no
marked = no
startmuted = no

[page_loop_admin]
type = user
quiet = yes
announce_user_count = no
wait_marked = no
end_marked = yes
dsp_drop_silence = yes
announce_join_leave = no
admin = yes
marked = yes
startmuted = yes

[page_loop_bridge]
type = bridge

[page_loop_user_menu]
type = menu
* = no_op

[page_loop_admin_menu]
type = menu
* = no_op