Swap channels in Asterisk

Is there any way to swap channels in Asterisk?

I have tried playing with ChannelRedirect and Bridge a little bit, but I’ve gotten stuck.

Say Device A originates call A. Then, at some point, Device A (or really, any arbitrary device) originates call B. I need call B to be able to “steal” call A, so that whatever Device A’s first call/channel was connected to, the second call is now connected to, in the same place, inheriting all channel state.

Channel redirect, at least with what I’ve tried, doesn’t work because redirecting the first channel and then trying to use bridge actually moves the first call out of the dialplan. All I want to do is take whatever the first incoming channel is connected to and move that to the second channel (swapping it).

ChannelRedirect, however, only redirects a channel to an application - not to another channel. Is there any way to accomplish? I don’t need specific dialplan details, but I’m lost on a general approach at the moment.

Thanks!

I got lost trying to work our what you are trying to do.

Firstly could you explain why you are trying to to it, as there may be a better solution.

Secondly could you provide a worked example in terms of PBX threads, and bridges.

Note that ChannelRedirect redirects to an extension, not an application.

Basically, I want one channel to be able to steal a channel away from another channel, either bridging into it or replacing its own channel.

For instance, say you have SIP/device1
SIP/device1 originates a call, SIP/device1-0001 (for simplicity) and it ends up somewhere arbitrary in the dialplan. The important thing is it could be anywhere. In the middle of call, reading digits, whatever.

Then, another call gets originated, let’s say by SIP/device1 for simplicity (in my use case, it would be the same device, but it could be any arbitrary device). So, this channel is, say, SIP/device-0002. What I want to do is have SIP/device-0002 “seize” SIP/device-0001 and for the first call to get disconnected. So, in this case, for a brief split second, there are two simultaneous calls, but then the second one seizes the first one and the first channel hangs up.

In other words, I want to redirect the old channel to the new channel, and hang up the first call so that the first device only sees the new call. Similar to the experience of if you were originating a 3-way call and the first call hung up on you while you were doing that.

The key thing here is seizing the call, not merely bridging into it. This should be able to repeated multiple times with the result that there is no net increase in the number of calls, as the same call in the dialplan gets seized and passed around.

Another thing: I think it might work if I have every incoming call immediately make a Local Dial(), and then I could redirect the Local channel instead of the peer itself, and then bridge into that. But, I’m already at a place where each actual call is at 10 or 15 channels, so if I can avoid adding to that, that would be ideal. If not, I understand.

This sounds like it might be an Asterisk masquerade operation. I’m not aware that naked masquerades are exposed in Asterisk. In any case, masquerade was a difficult concept to grasp, even using the C API, and you would probably have to read the code several times to be clear about the side effects.

I think you will need to write a new application, in C, but it isn’t a place you really want to go.

I think this particular case of masquerade would result in the channel name changing, but its unique ID remaining the same.

I believe that a lot of masquerades were eliminated from the code by rewriting the bridge handling. You should probably look at the source code for chan_sip and chan_pjsip, to see how they handle incoming INVITE/Replaces requests.

You didn’t answer the question on Why?

More clarification: this code would be channel-agnostic and not related to the actual device technology. I would need to trigger this manually in the dialplan when this behavior is desirable. In reality, this is for FXS ports so would only ever likely be used with DAHDI or SIP endpoints.

Here’s a simple example: say you have a POTS phone hooked up to an ATA or channel bank set to hotline into Asterisk so you get dial tone from the switch instead of fake dial tone from the ATA, and if you hook flash, it places another call to the hotline code as well (as Cisco/Linksys ATAs do). All is good. With the goal of making it work like an actual POTS switch, you should NOT be able to hook flash if there is not currently 1 answered call (any incoming call, or an outgoing call that has been answered). Currently, I have Asterisk just hang up if a second call comes in without 1 answered call. The caller hears reorder locally from the ATA, flashes once, and connects back to the first call - which could be dial tone, ringing, or whatever. This is better than the scenario where you have to flash twice to get rid of the second call. For obvious reasons, the second call can’t simply be silence - it needs to be disconnected sot that he could hook flash later when it is allowed.

People have complained about this and want it to work exactly like a POTS switch such as a 5ESS. The goal here is maximal realism, since my Asterisk is not really a PBX but more a Class 5 end office. So, rather than the caller being jarred by hearing local reorder, I would like an invalid hook flash to simply appear as if it had no effect. One cannot prevent the ATA from placing a second call, so this must be done Asterisk side. The idea somebody suggested to me was essentially hanging up the first call the ATA originated and “resuming” it on the second call. Rejecting the incoming call with any kind of SIP cause code won’t work, since that will trigger the ATA to provide local reorder. Instead, it should seem as if nothing has happened - the first call will drop, which means that if the caller hook flashes again, it will try yet another time to make a second call, rather than bridging the two channels together.

That’s the backstory in a nutshell. Calls are already confbridge and Local dial hell enough to this end, and I would like to avoid using yet more confbridges or local dials in order to achieve this.

Implementation wise, I don’t care if the old or the new channel ID number becomes the new one. The only requirements are that the literal channel state is inherited in the same way - so any channel variables set are now accessible on the new call, and the caller ends up thinking that the hook flash had no effect, even though it did.

I’m choosing to tackle this problem first, as I think about how I want to implement Call Hold and other features that will involve doing similar things. Call Hold involves hook flashing and dialing the call hold code, which can be done over and over again, and since one would need to prevent a 3-way call from happening, I’d need to drop the call appearance to the device and only bridge him again once the call hold code is dialed again.

By the way, one natural question is why not send hook flash events to Asterisk instead of relying on an ATA’s dumb capability of trying to make a 3-way call? Apparently, Asterisk has no way of handling these or exposing these, even though they make it into Asterisk (and I can see them do so). Additionally, I don’t know if channel banks or non-Grandstream ATAs have this capability, and I need a unified way of handling all technologies.

Won’t simply hanging up the second “line” call from the ATA result in the ATA resuming on the original “line”?

That would make sense, wouldn’t it? Unfortunately, it doesn’t. That’s what I currently do, and the ATA plays a local reorder tone. Even if it did, I’m guessing I can’t assume any consistent behavior in how different ATAs handle certain events. My guess is I’ll need to do this in more complicated scenarios (like Call Hold) anyhow, so this is a simple POC for that as well.

You know what, I didn’t think it was, but after messing with this some more, I think that:

a) My approach is not going to work anyways, since I keep getting “Can’t bridge a channel with itself”
b) Even if I redirect a local channel, that still kills whatever was executing. In short, it’s a flawed approach
c) This is more similar to call parking than I thought initially.

However, in this case, I need the second channel to park the first channel and then retrieve it immediately. However, the Park() application only parks the current channel. It doesn’t look like there’s an option to specify another channel instead of the current one. Any ideas? I can see how I would use ParkedCall(), so I think if I can figure out how to park an arbitrary channel, then I’m all set…

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