Forum Discussion

prasanth2023's avatar
prasanth2023
Copper Contributor
Dec 23, 2023

Create peer-to-peer PSTN call with service hosted media - Not working -Call source identity invalid

Hello, 

 

I am working for a customer to implement  Example 9: Create peer-to-peer PSTN call with service hosted media

 

https://learn.microsoft.com/en-us/graph/api/application-post-calls?view=graph-rest-1.0&tabs=csharp#example-9-create-peer-to-peer-pstn-call-with-service-hosted-media

 

The licenses we have purchased for Azure Intra user(email address removed for privacy reasons) are 

1. Microsoft 365 E3

2.Teams Phone with Calling Plan (country zone 1 - US)

 

Also i have created a resource account in https://admin.teams.microsoft.com/
Username : email address removed for privacy reasons

Assigned license : Microsoft Teams Phone Resource Account


Already We have Purchased a number from https://admin.teams.microsoft.com/
Voice-->Phone --> i can see a number like +175xxxxx(But this is unassigned as of now)

 

My Questions : 

1. To do a peer to Peer PSTN call do we really need a Resource Account user? or can i remove it? we are focused only on the outgoing call at the moment.
2. Should we assign the purchased Phone number to E3 licensee assigned user? or this Phone number should be assigned to Resource account user , i have waited for more than 24 hours and Phone number for some reason is not listing for the Resource user(But i have option to assign it to Teams Phone with Calling Plan User that i created)

 

The code doesnt work as well, so before digging into the code, i would like to ensure the configurations are setup properly . can someone help on this?

  • prasanth2023 - 

    1. To make a peer-to-peer PSTN call, you don't necessarily need a Resource Account user. The Resource Account user is typically used for scenarios where you want to assign a phone number to a specific resource, such as a meeting room or a shared device. Since you are focused on outgoing calls at the moment, you can remove the Resource Account user if it's not required for your use case.

    2. The purchased phone number can be assigned to either an E3 licensee assigned user or a Teams Phone with Calling Plan user. It depends on your specific requirements and how you want to manage the phone number. If you assign the phone number to an E3 licensee assigned user, that user will be able to make and receive calls using that number. On the other hand, if you assign the phone number to a Teams Phone with Calling Plan user, that user will have the calling plan associated with the phone number.

    If you have waited for more than 24 hours and the phone number is not listing for the Resource Account user, it's possible that there might be some delay or issue with the assignment process. You can try assigning the phone number to the Teams Phone with Calling Plan user that you created and see if it gets listed for that user.

     

     

     

    Thanks, 

    Prasad Das

    ------------------------------------------------------------------------------------------ 

    If the response is helpful, please click "**Mark as Best Response**" and like it. You can share your feedback via Microsoft Teams Developer Feedback link.

    • prasanth2023's avatar
      prasanth2023
      Copper Contributor
      Thanks ChetanSharma-msft looking forward for it.

      The current state is like the phone number is assigned to Resource account, but still we are unable to make call via graph API via C#. we are getting the same error - call source identity Invalid
      • prasanth2023's avatar
        prasanth2023
        Copper Contributor

        I am using the below PowerShell script to make the call. The calls are not receiving on the other end, But the call state shows as Established....

         

        $TenantId = "bc2a8d6c-49d3-40ba-a541-XXXXXXX"
        $ClientId = "9cc48ef5-d9e7-40a7-8ed7-XXXXXXX"
        $ClientSecret = "Wm58Q~ecjJdkVWQzWKVSYoTsykcRvpmA67aXXXXXX"
         
        $TokenBody = @{
            Grant_Type    = "client_credentials"
            Scope         = "https://graph.microsoft.com/.default"
            Client_Id     = $ClientId
            Client_Secret = $ClientSecret
        }
         
        $TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" -Method POST -Body $TokenBody -ContentType "application/x-www-form-urlencoded"
         
        $AccessToken = $TokenResponse.access_token
         
        # Convert the AccessToken to a SecureString
        $SecureAccessToken = $AccessToken | ConvertTo-SecureString -AsPlainText -Force
         
        # Connect to Microsoft Graph using SecureString
        Connect-MgGraph -AccessToken $SecureAccessToken
         
        $params = @{
        "@odata.type" = "#microsoft.graph.call"
        source = @{
        "@odata.type" = "#microsoft.graph.participantInfo"
        identity = @{
        "@odata.type" = "#microsoft.graph.identitySet"
        applicationInstance = @{
        "@odata.type" = "#microsoft.graph.identity"
        displayName = "Calling Bot"
        id = "77c05ef4-9f20-4351-9590-XXXXXXXXX"
        }
        }
        countryCode = $null
        endpointType = $null
        region = $null
        languageId = $null
        }
        targets = @(
        @{
        "@odata.type" = "#microsoft.graph.invitationParticipantInfo"
        identity = @{
        "@odata.type" = "#microsoft.graph.identitySet"
        phone = @{
        "@odata.type" = "#microsoft.graph.identity"
        id = "+14086220061"
        }
        }
        }
        )
        requestedModalities = @(
        "audio"
        )
        mediaConfig = @{
        "@odata.type" = "#microsoft.graph.serviceHostedMediaConfig"
        }
        tenantId = "bc2a8d6c-49d3-40ba-a541-XXXXXXXXXX"
        }
         
        New-MgCommunicationCall -BodyParameter $params
         

         

        How to check and fix this issue? can you help?

  • prasanth2023 - 

    1. To make a peer-to-peer PSTN call, you don't necessarily need a Resource Account user. The Resource Account user is typically used for scenarios where you want to assign a phone number to a specific resource, such as a meeting room or a shared device. Since you are focused on outgoing calls at the moment, you can remove the Resource Account user if it's not required for your use case.

    2. The purchased phone number can be assigned to either an E3 licensee assigned user or a Teams Phone with Calling Plan user. It depends on your specific requirements and how you want to manage the phone number. If you assign the phone number to an E3 licensee assigned user, that user will be able to make and receive calls using that number. On the other hand, if you assign the phone number to a Teams Phone with Calling Plan user, that user will have the calling plan associated with the phone number.

    If you have waited for more than 24 hours and the phone number is not listing for the Resource Account user, it's possible that there might be some delay or issue with the assignment process. You can try assigning the phone number to the Teams Phone with Calling Plan user that you created and see if it gets listed for that user.

     

     

     

    Thanks, 

    Prasad Das

    ------------------------------------------------------------------------------------------ 

    If the response is helpful, please click "**Mark as Best Response**" and like it. You can share your feedback via Microsoft Teams Developer Feedback link.

    • prasanth2023's avatar
      prasanth2023
      Copper Contributor

      Prasad_Das-MSFT  yes the licenses are allotted as mentioned below. i am able to make calls from MS teams to my Phone number directly via MS teams . But not through Graph API. 

    • prasanth2023's avatar
      prasanth2023
      Copper Contributor

      Prasad_Das-MSFT  But the problem of establishing call is not yet solved 

       

      https://stackoverflow.com/questions/77805370/graph-api-to-pstn-number-call-state-changes-to-establishing-but-not-receivin

       

      Poweshell code

       

      # Securely storing the credentials
      $TenantId = "XXXXX-49d3-40ba-a541-4b63e8e0fdc5"
      $ClientId = "XXXXX-d9e7-40a7-8ed7-a915969a6833"
      $ClientSecret = ConvertTo-SecureString "XXXXXXXX" -AsPlainText -Force
      
      # Function to obtain an access token
      function Get-GraphAccessToken {
          param (
              [Parameter(Mandatory = $true)][string]$TenantId,
              [Parameter(Mandatory = $true)][string]$ClientId,
              [Parameter(Mandatory = $true)][System.Security.SecureString]$ClientSecret
          )
      
          $TokenBody = @{
              Grant_Type    = "client_credentials"
              Scope         = "https://graph.microsoft.com/.default"
              Client_Id     = $ClientId
              Client_Secret = [System.Net.NetworkCredential]::new("", $ClientSecret).Password
          }
      
          $TokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" -Method POST -Body $TokenBody -ContentType "application/x-www-form-urlencoded"
          return $TokenResponse.access_token
      }
      
      # Obtain Access Token
      $AccessToken = Get-GraphAccessToken -TenantId $TenantId -ClientId $ClientId -ClientSecret $ClientSecret
      
      # Convert the AccessToken to a SecureString
      $SecureAccessToken = $AccessToken | ConvertTo-SecureString -AsPlainText -Force
      
      # Connect to Microsoft Graph using SecureString
      Connect-MgGraph -AccessToken $SecureAccessToken
      
      # Prepare parameters for creating a call
      $params = @{
          "@odata.type" = "#microsoft.graph.call"
          direction = "outgoing"
          subject = "call with application hosted media"
          callbackUri = "https://b744-14-142-211-86.ngrok-free.app/callback"
          source = @{
              "@odata.type" = "#microsoft.graph.participantInfo"
              identity = @{
                  "@odata.type" = "#microsoft.graph.identitySet"
                  applicationInstance = @{
                      "@odata.type" = "#microsoft.graph.identity"
                      displayName = "PPCall"
                      id = "525b3e87-1127-483a-bc43-0a99c51a8db0"
                  }
              }
          }
          targets = @(
              @{
                  "@odata.type" = "#microsoft.graph.invitationParticipantInfo"
                  identity = @{
                      "@odata.type" = "#microsoft.graph.identitySet"
                      phone = @{
                          "@odata.type" = "#microsoft.graph.identity"
                          id = "+14086220061"
                      }
                  }
              }
          )
          requestedModalities = @("audio")
          mediaConfig = @{
              "@odata.type" = "#microsoft.graph.serviceHostedMediaConfig"
              blob = "a.wav"
          }
          tenantId = $TenantId
      }
      
      # Error handling for creating a call
      try {
          $callResponse = New-MgCommunicationCall -BodyParameter $params
          $callId = $callResponse.Id
          Write-Host "Call created successfully. Call ID: $callId"
      } catch {
          Write-Error "Error in creating call: $_"
      }

       

      Console Log: 

      The thread 0x5974 has exited with code 0 (0x0).
      The thread 0x5c94 has exited with code 0 (0x0).
      Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST https://localhost:5001/callback application/json 406
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "OnIncomingBotCallUserRequestAsync", controller = "PlatformCall"}. Executing controller action with signature System.Threading.Tasks.Task OnIncomingBotCallUserRequestAsync() on controller Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController (VoiceRecorderAndPlaybackBot).
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot) - Validation state: Valid
      VoiceRecorderAndPlaybackBot:Information: 2024-01-14T04:47:59.6223Z 526dabeb-988c-4177-ab2b-fa6f17766997 pid:16532 tid:60 (Bot.cs:270 NotificationProcessor_OnNotificationReceivedAsync):
      {
      "value": {
      "$id": "1",
      "$values": [
      {
      "changeType": "Updated",
      "resourceUrl": "/communications/calls/411f5700-550f-4cdb-a342-34f37a6ca70d",
      "resource": "/app/calls/411f5700-550f-4cdb-a342-34f37a6ca70d",
      "resourceData": {
      "callChainId": "526dabeb-988c-4177-ab2b-fa6f17766997",
      "state": "Establishing",
      "@odata.type": "#microsoft.graph.call"
      },
      "@odata.type": "#microsoft.graph.commsNotification"
      }
      ]
      }
      }
      {
      "HttpLogData": {
      "Method": "POST",
      "Url": "https://localhost:5001/callback",
      "Headers": [
      "Scenario-Id: 526dabeb-988c-4177-ab2b-fa6f17766997",
      "Client-Request-Id: e7ceecce-b081-4314-a1c7-7ab4358ffe45",
      "X-Microsoft-Tenant: (redacted)"
      ],
      "TransactionDirection": "Incoming",
      "TraceType": "HttpRequest",
      "TenantId": "00000000-0000-0000-0000-000000000000"
      }
      }

      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot), returned result Microsoft.AspNetCore.Mvc.EmptyResult in 8.8178ms.
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot) in 11.6675ms
      Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 17.2779ms 202
      Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST https://localhost:5001/callback application/json 428
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "OnIncomingBotCallUserRequestAsync", controller = "PlatformCall"}. Executing controller action with signature System.Threading.Tasks.Task OnIncomingBotCallUserRequestAsync() on controller Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController (VoiceRecorderAndPlaybackBot).
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot) - Validation state: Valid
      Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST https://localhost:5001/callback application/json 792
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "OnIncomingBotCallUserRequestAsync", controller = "PlatformCall"}. Executing controller action with signature System.Threading.Tasks.Task OnIncomingBotCallUserRequestAsync() on controller Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController (VoiceRecorderAndPlaybackBot).
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot) - Validation state: Valid
      VoiceRecorderAndPlaybackBot:Information: 2024-01-14T04:48:02.1600Z 526dabeb-988c-4177-ab2b-fa6f17766997 pid:16532 tid:49 (Bot.cs:270 NotificationProcessor_OnNotificationReceivedAsync):
      {
      "value": {
      "$id": "1",
      "$values": [
      {
      "changeType": "Updated",
      "resourceUrl": "/communications/calls/411f5700-550f-4cdb-a342-34f37a6ca70d",
      "resource": "/app/calls/411f5700-550f-4cdb-a342-34f37a6ca70d",
      "resourceData": {
      "callChainId": "526dabeb-988c-4177-ab2b-fa6f17766997",
      "direction": "Outgoing",
      "state": "Established",
      "@odata.type": "#microsoft.graph.call"
      },
      "@odata.type": "#microsoft.graph.commsNotification"
      }
      ]
      }
      }
      {
      "HttpLogData": {
      "Method": "POST",
      "Url": "https://localhost:5001/callback",
      "Headers": [
      "Scenario-Id: 526dabeb-988c-4177-ab2b-fa6f17766997",
      "Client-Request-Id: 952cca9c-ac69-4901-9883-0c9836831c86",
      "X-Microsoft-Tenant: (redacted)"
      ],
      "TransactionDirection": "Incoming",
      "TraceType": "HttpRequest",
      "TenantId": "00000000-0000-0000-0000-000000000000"
      }
      }

      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot), returned result Microsoft.AspNetCore.Mvc.EmptyResult in 9.2287ms.
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot) in 14.4217ms
      VoiceRecorderAndPlaybackBot:Information: 2024-01-14T04:48:02.1637Z 526dabeb-988c-4177-ab2b-fa6f17766997 pid:16532 tid:63 (Bot.cs:270 NotificationProcessor_OnNotificationReceivedAsync):
      {
      "value": {
      "$id": "1",
      "$values": [
      {
      "changeType": "Updated",
      "resourceUrl": "/communications/calls/411f5700-550f-4cdb-a342-34f37a6ca70d",
      "resource": "/app/calls/411f5700-550f-4cdb-a342-34f37a6ca70d",
      "resourceData": {
      "callChainId": "526dabeb-988c-4177-ab2b-fa6f17766997",
      "mediaState": {
      "audio": "Active",
      "@odata.type": "#microsoft.graph.callMediaState"
      },
      "state": "Established",
      "@odata.type": "#microsoft.graph.call",
      "meetingCapability": {
      "@odata.type": "#microsoft.graph.meetingCapability",
      "allowTranslatedCaptions": true,
      "allowTranslatedTranscriptions": true,
      "recorderAllowed": []
      },
      "meetingProperties": {
      "@odata.type": "#microsoft.graph.meetingProperties",
      "meetingLabel": "00000000-0000-0000-0000-000000000000"
      },
      "coOrganizers": []
      },
      "@odata.type": "#microsoft.graph.commsNotification"
      }
      ]
      }
      }
      {
      "HttpLogData": {
      "Method": "POST",
      "Url": "https://localhost:5001/callback",
      "Headers": [
      "Scenario-Id: 526dabeb-988c-4177-ab2b-fa6f17766997",
      "Client-Request-Id: c9944fa9-7eaf-4dfb-b54c-98c18c2778b7",
      "X-Microsoft-Tenant: (redacted)"
      ],
      "TransactionDirection": "Incoming",
      "TraceType": "HttpRequest",
      "TenantId": "00000000-0000-0000-0000-000000000000"
      }
      }

      Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 19.9873ms 202
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot), returned result Microsoft.AspNetCore.Mvc.EmptyResult in 9.9369ms.
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot) in 13.2163ms
      Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 17.533ms 202
      Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST https://localhost:5001/callback application/json 1057
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "OnIncomingBotCallUserRequestAsync", controller = "PlatformCall"}. Executing controller action with signature System.Threading.Tasks.Task OnIncomingBotCallUserRequestAsync() on controller Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController (VoiceRecorderAndPlaybackBot).
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executing action method Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot) - Validation state: Valid
      VoiceRecorderAndPlaybackBot:Information: 2024-01-14T04:48:08.4273Z 526dabeb-988c-4177-ab2b-fa6f17766997 pid:16532 tid:49 (Bot.cs:270 NotificationProcessor_OnNotificationReceivedAsync):
      {
      "value": {
      "$id": "1",
      "$values": [
      {
      "changeType": "Deleted",
      "resourceUrl": "/communications/calls/411f5700-550f-4cdb-a342-34f37a6ca70d",
      "resource": "/app/calls/411f5700-550f-4cdb-a342-34f37a6ca70d",
      "resourceData": {
      "callChainId": "526dabeb-988c-4177-ab2b-fa6f17766997",
      "resultInfo": {
      "code": 200,
      "message": "The conversation has ended. DiagCode: 200#1000003.@",
      "subcode": 1000003,
      "@odata.type": "#microsoft.graph.resultInfo"
      },
      "state": "Terminated",
      "@odata.type": "#microsoft.graph.call",
      "meetingCapability": {
      "@odata.type": "#microsoft.graph.meetingCapability",
      "allowTranslatedCaptions": true,
      "allowTranslatedTranscriptions": true,
      "recorderAllowed": []
      },
      "meetingProperties": {
      "@odata.type": "#microsoft.graph.meetingProperties",
      "meetingLabel": "00000000-0000-0000-0000-000000000000"
      },
      "coOrganizers": [],
      "terminationSender": {
      "application": {
      "id": "56aa0a8f-4cd3-446b-8146-0023476a5ff2",
      "@odata.type": "#microsoft.graph.identity"
      },
      "@odata.type": "#microsoft.graph.identitySet"
      }
      },
      "@odata.type": "#microsoft.graph.commsNotification"
      }
      ]
      }
      }
      {
      "HttpLogData": {
      "Method": "POST",
      "Url": "https://localhost:5001/callback",
      "Headers": [
      "Scenario-Id: 526dabeb-988c-4177-ab2b-fa6f17766997",
      "Client-Request-Id: c7d98660-fe90-4948-a0cd-709a9d53ebf1",
      "X-Microsoft-Tenant: (redacted)"
      ],
      "TransactionDirection": "Incoming",
      "TraceType": "HttpRequest",
      "TenantId": "00000000-0000-0000-0000-000000000000"
      }
      }

      VoiceRecorderAndPlaybackBot:Information: 2024-01-14T04:48:08.4369Z 526dabeb-988c-4177-ab2b-fa6f17766997 pid:16532 tid:49 (Bot.cs:435 CleanupCall):
      Cleaning up call

      VoiceRecorderAndPlaybackBot:Information: 2024-01-14T04:48:08.4397Z 526dabeb-988c-4177-ab2b-fa6f17766997 pid:16532 tid:49 (Bot.cs:449 CleanupCall):
      File to be deleted does not exist.

      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action method Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot), returned result Microsoft.AspNetCore.Mvc.EmptyResult in 18.4511ms.
      Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action Sample.VoiceRecorderAndPlaybackBot.Controller.PlatformCallController.OnIncomingBotCallUserRequestAsync (VoiceRecorderAndPlaybackBot) in 21.3134ms
      Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 26.5816ms 202
      The program '[16532] dotnet.exe' has exited with code 4294967295 (0xffffffff).

       

Resources