microsoft-graph-comms-samples icon indicating copy to clipboard operation
microsoft-graph-comms-samples copied to clipboard

Tracking a call through transfers using compliance bot

Open rugt0r opened this issue 5 years ago • 14 comments

I'm trying to come up with a way to track calls that are occurring in Teams, both peer to peer and calls from PSTN. Sadly there is no easy way to do this. One thing that sort of works is setting the bot & all Teams users up for recording compliance, so it gets dragged into every call and is aware of the participants.

I have the bot set up and it is being notified of calls being created/updated/terminated, but I'm struggling to find the documentation needed to decipher the messages it receives. I'm currently using the API rather than the SDK.

The questions I currently have are:

  • In a PSTN-Teams call, the bot gets two calls- when the callee picks up, one of the calls is deleted, and one persists. In a Teams-Teams call, the bot receives 4 calls- one seems to end when the bot answers the call, another ends when the callee picks up, and the remaining two calls persist until someone leaves or transfers the call. What is the meaning of these extra calls that disappear?

  • When a call gets transferred, the bot essentially sees the current call end and a completely new one begin. Is there a reliable way to relate a call that is the result of a transfer to the call it was transferred from? It seems that for PSTN-Teams calls there is a CallChainId in the message the bot receives, which seems to remain the same through each call that results from a transfer. This is not the case for Teams-Teams calls however, where each transfer seems to result in a new call CallChainId so you can't use it to determine if a new Teams-Teams call is the result of a transfer.

rugt0r avatar Apr 20 '20 14:04 rugt0r

I too have the same questions as @rugt0r.

jsweiler avatar Apr 22 '20 13:04 jsweiler

Me too, the same questions as @rugt0r. Especially with the legs, I get 2 legs per call. One is terminated fast.

stefan2410 avatar Apr 23 '20 15:04 stefan2410

It is always 2 legs for 1 call as I could see. the 1st leg is finished very quick. The second leg is actual call. I guess the 1st leg is ringtone.

vnguyenau avatar Apr 23 '20 23:04 vnguyenau

@ssulzer @ksikorsk please can you help us with this question. It is very important for us to understand the workflow with the call legs. Is there a document somewhere? I can see that you are going for GA.

stefan2410 avatar Apr 24 '20 15:04 stefan2410

@zhengni-msft @yizhenww

ksikorsk avatar Apr 24 '20 15:04 ksikorsk

I'm trying to come up with a way to track calls that are occurring in Teams, both peer to peer and calls from PSTN. Sadly there is no easy way to do this.

Are you just trying to track the calls occurring in Teams? Take a look at the call records API as it's more relevant to what you're trying to do: https://docs.microsoft.com/en-us/graph/api/resources/callrecords-api-overview?view=graph-rest-beta. If you're trying to record audio, video, and/or video-based screen sharing, then it's fine to use the compliance recording APIs.

aditdalvi avatar Apr 28 '20 21:04 aditdalvi

In a PSTN-Teams call, the bot gets two calls- when the callee picks up, one of the calls is deleted, and one persists. In a Teams-Teams call, the bot receives 4 calls- one seems to end when the bot answers the call, another ends when the callee picks up, and the remaining two calls persist until someone leaves or transfers the call. What is the meaning of these extra calls that disappear?

This is a natural consequence of call forking. The core requirement is that the compliance recording bot must be in the call before call setup is allowed to complete. Since call forking is a recursive runtime decision, every such fork will result in compliance recording bots getting invited for that fork.

In the case of a call made to a Teams user, there are two natural forks created -- 1) to the Teams endpoints of that user, 2) to the Skype for Business IP phone endpoints of that user. Each of those forks will have compliance recording bots for both the caller and the callee as applicable. However, only one of those forks will survive when the call is accepted and the other fork (along with its bots) is terminated. This should explain exactly why you're seeing what you see and why it's done this way.

This same situation can occur in other forking situations. For example, if a call is unanswered and goes to a forwarding target like a phone number, then the original fork (along with its bots) is terminated prior to forwarding.

What can you do about this? The core logic on the bot side should be: The overall call is set up and the bot has survived if the bot gets a roster with its assigned participant in it. It can then do what's needed to record at that time (call updateRecordingStatus with status = Active and then start recording). If the bot gets a termination before that specific roster with its assigned participant in it, that means the fork was terminated because the another fork got set up or the overall call was unanswered.

aditdalvi avatar Apr 28 '20 21:04 aditdalvi

When a call gets transferred, the bot essentially sees the current call end and a completely new one begin. Is there a reliable way to relate a call that is the result of a transfer to the call it was transferred from? It seems that for PSTN-Teams calls there is a CallChainId in the message the bot receives, which seems to remain the same through each call that results from a transfer. This is not the case for Teams-Teams calls however, where each transfer seems to result in a new call CallChainId so you can't use it to determine if a new Teams-Teams call is the result of a transfer.

If you just need to know whether the call is the result of a transfer or not, then you can look at the incomingContext.transferor field to find out: https://docs.microsoft.com/en-us/graph/api/resources/call?view=graph-rest-1.0#properties

If you need to correlate the new call (which is the result of the transfer) with the original call where the transfer was initiated, you'll need to do the correlation after the new call has ended using the data from the callRecords: https://docs.microsoft.com/en-us/graph/api/resources/callrecords-api-overview?view=graph-rest-beta. Due to the complex nature of blind vs attended transfers and the fact that there's no communication API with the bot to notify it of a transfer attempt, callRecords is the only correlation mechanism possible.

aditdalvi avatar Apr 28 '20 21:04 aditdalvi

@aditdalvi thank you for your answers At first, As we are working with Bots, we don't use mainly the call tracking. But the GraphServiceClient.Communications, last version, does not have Communications.CallRecords. What to do? Your other answers need detailed reading and of course I've questions about.

stefan2410 avatar Apr 28 '20 23:04 stefan2410

@aditdalvi you wrote

In the case of a call made to a Teams user, there are two natural forks created -- 1) to the Teams endpoints of that user, 2) to the Skype for Business IP phone endpoints of that user. Each of those forks will have compliance recording bots for both the caller and the callee as applicable. However, only one of those forks will survive

Is this why I can see 2 invites? If the tenant is in "Teams only mode" the behavior is the same? we have noticed a delay in ringing. Is the "two natural forks" the reason? or something else?

stefan2410 avatar May 11 '20 13:05 stefan2410

Is this why I can see 2 invites? If the tenant is in "Teams only mode" the behavior is the same?

Yes, this is why you're seeing 2 invites. This is true even if the tenant is in Teams only mode. See this blog post for more info on why there is a separate fork for Skype for Business IP phone endpoints. Refer to my previous post on why this is expected behavior for any such forking situation, and what the core logic should be on the bot side to handle this.

The delay in ringing is because the invite to the bot must complete and the bot must be in the call, before normal call setup between the users can continue. This is to allow the bot to record from time-zero.

aditdalvi avatar May 16 '20 17:05 aditdalvi

@aditdalvi I have some questions about this call forking.

Thank you for your very helpful explanation I now understand it why i have the multiple calls with different legs IDs but matching correlation IDs. However, the part I'm confused about is that from the sample (on which my implementation is strongly based) the logic is such that events raised for the ICallCollection.OnUpdated create a new CallHandler for args.AddedResources. For my testing, this happens 4 times, i.e. there are 4 call legs, however upon call connection of the (human) participants only one event is ever received for the args.RemovedResources for one of the other 3 legs. I am yet to determine a pattern as to which is dropped. Then when I finally terminate the connected call I get an event on ICallCollection.OnUpdated for the args.RemovedResources for that too.

This then leaves me with two 'orphaned' call legs that have a CallHandler instance hanging about. Do you understand or now why this would be?

andir78 avatar Sep 25 '20 13:09 andir78

@andir78 - I know it has been almost 5 years since you posted this question - but I am here in 2025 and troubleshooting exactly the same scenario, and I have the same questions you outlined. Did you ever find answers? Would love if you can share more about what you found out.

CDSFounder avatar Jun 27 '25 17:06 CDSFounder

@ssulzer @ksikorsk please can you help us with this question. It is very important for us to understand the workflow with the call legs. Is there a document somewhere? I can see that you are going for GA.

I hope so too.

SharePointX avatar Jun 30 '25 01:06 SharePointX