End conference when only one participant remains

Does anyone have an idea how this can be done? Once the number of participants drops back down to 1, I’d like the call to hang up. (Of course not hanging up when the first person calls into the conference and is waiting for others to join.)

Within the FreePBX config, the only option appears to be to kick everyone when the admin user leaves. In this case, no one will be an admin user.

The only thing that comes to mind is have all the participate dial a custom extension which adds a hangup handler to the channel.

In the hangup handler use the CONFBRIDGE_INFO function to check the amount of participants left in the conference: Asterisk 19 Function_CONFBRIDGE_INFO - Asterisk Project - Asterisk Project Wiki

If it the amount of participants equals to 1, then use the CONFBRIDGE_CHANNLES function to obtain the channel information and either perform a conference kick or hangup/redirect the channel

https://wiki.asterisk.org/wiki/display/AST/Asterisk+19+Function_CONFBRIDGE_CHANNELS

1 Like

A script I had occasion to use once a long time ago

confkick.php · GitHub

Now if you can figure out when to execute it …

1 Like

Thanks gentlemen. @PitzKey, your idea interests me a lot because if it works, it can all be done in dialplan without making a custom conference (I can make the conference in FreePBX, and then add your suggestion in extensions_custom.conf). @lgaetz suggestion could work for me on a cron job, maybe every 5 minutes. It doesn’t have to hang up immediately when the last person leaves; I’m just trying to make sure someone doesn’t loiter around a long time after the conference is ended.

Another idea came to mind that I want to explore. Documentation says that with the end_marked option set, the conference will “Kick the user from the conference when the last marked user leaves.” So what happens if everyone gets marked? Does “last marked user” include myself? Unfortunately this idea needs to be built in the config files because these conference options aren’t exposed in FreePBX.

How would you determine if it is the first or last user? This could probably kick a user who just started a conference and is waiting for everyone to join.

I worked on a dialplan demo. CONFBRIDGE_INFO works fine

exten => s,n,Noop(Amount of users: ${CONFBRIDGE_INFO(parties,${MEETME_ROOMNUM})})

But CONFBRIDGE_CHANNELS kept on throwing an error

[2022-05-18 17:41:18] ERROR[78368][C-00000001]: pbx_functions.c:608 ast_func_read: Function CONFBRIDGE_CHANNELS not registered

I looked at core show functions and there’s indeed no such a function. Upgraded Asterisk from 16 to 18, same issue.

So I looked at the Asterisk source code, and it is indeed not there:

However, looking at the master branch, it is there…

Looking further, it seems like someone is asking to re-add it?

I am really confused as what happened here?..

Documentation is generated from source, so how could it be that the documentation of Asterisk 16, 18, and 19 all show this function? (Asterisk 16 Function_CONFBRIDGE_CHANNELS - Asterisk Project - Asterisk Project Wiki for 16)

Interesting mystery. :slight_smile:

Specifically, it’s generated from the branch - not the latest release. Meaning CONFBRIDGE_CHANNELS is in the tree, but hasn’t hit a release yet. It was just merged on May 13th.

3 Likes

Cool - I didn’t know it’s an unreleased feature!

… Just in time to experiment this :wink:

I’m excited about the amount of new features recently added to Asterisk.

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

@PitzKey Request complete.

2 Likes

Thanks, Josh!

@billsimon, since the CONFBRIDGE_CHANNELS function is now available in all of the latest versions of Asterisk, which are now available in the FreePBX testing repos, I went ahead and tested this.

In extensions_custom.conf I have a general dialplan to set Hangup Handlers that is being used by many different applications

[set-hangup-handler]
exten => s,1,Noop(Setting Hangup Handler)
exten => s,n,Set(CHANNEL(hangup_handler_push)=${ARG1},${ARG2},${ARG3})
exten => s,n,Return()

Then, I created a Custom Destination:

Finally, the actual Hangup Handler dialplan:

[conf-bridge-handler]
exten => s,1,Noop(In conf bridge hangup handler)
exten => s,n,Gotoif($["${CONFBRIDGE_INFO(parties,${MEETME_ROOMNUM})}"="1"]?kick)
exten => s,n,Return()
exten => s,n(kick),Noop(Redirecting channel ${CONFBRIDGE_CHANNELS(active,${MEETME_ROOMNUM})} to the global hangup)
;This is just hanging up the channel. It would be more ideal to redirect to a custom context that plays a message, something like "You are being removed from the conference because you are the last remaining user.." 
exten => s,n,ChannelRedirect(${CONFBRIDGE_CHANNELS(active,${MEETME_ROOMNUM})},app-blackhole,hangup,1)
exten => s,n,Return()

And it works great.
Asterisk logs:

PJSIP/64066-0000000a Internal Gosub(conf-bridge-handler,s,1) start
    -- Executing [s@conf-bridge-handler:1] NoOp("PJSIP/64066-0000000a", "In conf bridge hangup handler") in new stack
    -- Executing [s@conf-bridge-handler:2] GotoIf("PJSIP/64066-0000000a", "1?kick") in new stack
    -- Goto (conf-bridge-handler,s,4)
    -- Executing [s@conf-bridge-handler:4] NoOp("PJSIP/64066-0000000a", "Redirecting channel PJSIP/2547-0000000b to the global hangup") in new stack
    -- Executing [s@conf-bridge-handler:5] ChannelRedirect("PJSIP/64066-0000000a", "PJSIP/2547-0000000b,app-blackhole,hangup,1") in new stack
    -- Executing [s@conf-bridge-handler:6] Return("PJSIP/64066-0000000a", "") in new stack
  == Spawn extension (ext-meetme, h, 1) exited non-zero on 'PJSIP/64066-0000000a'
    -- PJSIP/64066-0000000a Internal Gosub(conf-bridge-handler,s,1) complete GOSUB_RETVAL=
    -- Stopped music on hold on PJSIP/2547-0000000b
    -- Channel PJSIP/2547-0000000b left 'softmix' base-bridge <ba446779-b34e-47a3-a6e1-3ace014d08c7>
    -- Channel CBAnn/460404-00000005;2 left 'softmix' base-bridge <ba446779-b34e-47a3-a6e1-3ace014d08c7>
    -- Executing [hangup@app-blackhole:1] NoOp("PJSIP/2547-0000000b", "Blackhole Dest: Hangup") in new stack
    -- Executing [hangup@app-blackhole:2] Hangup("PJSIP/2547-0000000b", "") in new stack
  == Spawn extension (app-blackhole, hangup, 2) exited non-zero on 'PJSIP/2547-0000000b'
    -- PJSIP/2547-0000000b Internal Gosub(conf-bridge-handler,s,1) start
    -- Executing [s@conf-bridge-handler:1] NoOp("PJSIP/2547-0000000b", "In conf bridge hangup handler") in new stack
    -- Executing [s@conf-bridge-handler:2] GotoIf("PJSIP/2547-0000000b", "0?kick") in new stack
    -- Executing [s@conf-bridge-handler:3] Return("PJSIP/2547-0000000b", "") in new stack
  == Spawn extension (app-blackhole, hangup, 2) exited non-zero on 'PJSIP/2547-0000000b'

While working on that, I realized that we didn’t actually have to wait for this function… There’s a Asterisk application ConfKick() and it works great as well.

[conf-bridge-handler]
exten => s,1,Noop(In conf bridge hangup handler)
exten => s,n,Gotoif($["${CONFBRIDGE_INFO(parties,${MEETME_ROOMNUM})}"="1"]?kick)
exten => s,n,Return()
exten => s,n(kick),Noop(Kicking all participants from ${MEETME_ROOMNUM})
;Pass the conference number. The channel to kick, 'all' to kick all users, or 'participants' to kick all non-admin participants. Default is all.
exten => s,n,ConfKick(${MEETME_ROOMNUM},all)
exten => s,n,Return()

Asterisk logs:

 Spawn extension (ext-meetme, h, 1) exited non-zero on 'PJSIP/64066-0000000e'
    -- PJSIP/64066-0000000e Internal Gosub(conf-bridge-handler,s,1) start
    -- Executing [s@conf-bridge-handler:1] NoOp("PJSIP/64066-0000000e", "In conf bridge hangup handler") in new stack
    -- Executing [s@conf-bridge-handler:2] GotoIf("PJSIP/64066-0000000e", "1?kick") in new stack
    -- Goto (conf-bridge-handler,s,4)
    -- Executing [s@conf-bridge-handler:4] NoOp("PJSIP/64066-0000000e", "Kicking all participants from 460404") in new stack
    -- Executing [s@conf-bridge-handler:5] ConfKick("PJSIP/64066-0000000e", "460404,all") in new stack
    -- Executing [s@conf-bridge-handler:6] Return("PJSIP/64066-0000000e", "") in new stack
  == Spawn extension (ext-meetme, h, 1) exited non-zero on 'PJSIP/64066-0000000e'
    -- PJSIP/64066-0000000e Internal Gosub(conf-bridge-handler,s,1) complete GOSUB_RETVAL=
    -- Channel PJSIP/2547-0000000f left 'softmix' base-bridge <d2b272ce-de7a-4d2f-a6b3-2df55078a41f>
    -- Stopped music on hold on PJSIP/2547-0000000f
    -- Channel CBAnn/460404-00000007;2 left 'softmix' base-bridge <d2b272ce-de7a-4d2f-a6b3-2df55078a41f>
    -- Executing [STARTMEETME@ext-meetme:6] Macro("PJSIP/2547-0000000f", "hangupcall,") in new stack
    -- Executing [s@macro-hangupcall:1] GotoIf("PJSIP/2547-0000000f", "1?theend") in new stack
    -- Goto (macro-hangupcall,s,3)
    -- Executing [s@macro-hangupcall:3] ExecIf("PJSIP/2547-0000000f", "0?Set(CDR(recordingfile)=)") in new stack
    -- Executing [s@macro-hangupcall:4] NoOp("PJSIP/2547-0000000f", " montior file= ") in new stack
    -- Executing [s@macro-hangupcall:5] GotoIf("PJSIP/2547-0000000f", "1?skipagi") in new stack
    -- Goto (macro-hangupcall,s,7)
    -- Executing [s@macro-hangupcall:7] Hangup("PJSIP/2547-0000000f", "") in new stack
  == Spawn extension (macro-hangupcall, s, 7) exited non-zero on 'PJSIP/2547-0000000f' in macro 'hangupcall'
  == Spawn extension (ext-meetme, STARTMEETME, 6) exited non-zero on 'PJSIP/2547-0000000f'
    -- Executing [h@ext-meetme:1] Macro("PJSIP/2547-0000000f", "hangupcall,") in new stack
    -- Executing [s@macro-hangupcall:1] GotoIf("PJSIP/2547-0000000f", "1?theend") in new stack
    -- Goto (macro-hangupcall,s,3)
    -- Executing [s@macro-hangupcall:3] ExecIf("PJSIP/2547-0000000f", "0?Set(CDR(recordingfile)=)") in new stack
    -- Executing [s@macro-hangupcall:4] NoOp("PJSIP/2547-0000000f", " montior file= ") in new stack
    -- Executing [s@macro-hangupcall:5] GotoIf("PJSIP/2547-0000000f", "1?skipagi") in new stack
    -- Goto (macro-hangupcall,s,7)
    -- Executing [s@macro-hangupcall:7] Hangup("PJSIP/2547-0000000f", "") in new stack
  == Spawn extension (macro-hangupcall, s, 7) exited non-zero on 'PJSIP/2547-0000000f' in macro 'hangupcall'
  == Spawn extension (ext-meetme, h, 1) exited non-zero on 'PJSIP/2547-0000000f'
    -- PJSIP/2547-0000000f Internal Gosub(conf-bridge-handler,s,1) start
    -- Executing [s@conf-bridge-handler:1] NoOp("PJSIP/2547-0000000f", "In conf bridge hangup handler") in new stack
    -- Executing [s@conf-bridge-handler:2] GotoIf("PJSIP/2547-0000000f", "0?kick") in new stack
    -- Executing [s@conf-bridge-handler:3] Return("PJSIP/2547-0000000f", "") in new stack
  == Spawn extension (ext-meetme, h, 1) exited non-zero on 'PJSIP/2547-0000000f'
    -- PJSIP/2547-0000000f Internal Gosub(conf-bridge-handler,s,1) complete GOSUB_RETVAL=
2 Likes

Looks good! I think this would be a good addition to FreePBX proper: a toggle in the conference configuration to close the conference when only one person is left.

3 Likes