aws-samples / amazon-chime-sdk-click-to-call

MIT No Attribution
24 stars 15 forks source link

PSTN call is triggered twice #72

Closed dattu046 closed 1 year ago

dattu046 commented 1 year ago

Describe the issue

I'm trying to implement the flow suggested in the tutorial, I'm able to create a chime meeting and able to place an outbound call to PSTN, however, when I answer the first call I get an immediate second call from the application. Secondly, when I speak after answering, all I hear is an echo of myself and I did not provision Asterisk as suggested in the demo application.

Please help me with this issue

@schuettc

Steps to Reproduce

  1. Created a meeting.
  2. Added client and phone attendees.
  3. Placed an outbound call.
  4. Answered the call.
  5. Second call comes immediately.

Current behavior

  1. I expected only one call to be triggered to my phone.

My code preview in call controller:

const meeting = await createMeeting(v4());
console.info("Meeting created : ", meeting);
/*Create attendee*/
const clientAttendee = await addAttendee(meeting.Meeting.MeetingId, 'client-user');
const phoneAttendee = await addAttendee(meeting.Meeting.MeetingId, 'phone-user');
console.info("Phone Attendee created : ", phoneAttendee);
console.info("Client Attendee created : ", clientAttendee);
/*Read participant details*/
console.info("Placing call for participant : ", eventData.participantId);
const participant = await readParticipant(eventData.participantId, event.requestContext);
console.info("Participant found : ", participant.id);
/*Raise dial info command*/
if (participant.id !== undefined) {
    const dialResponse = await dialToParticipant(participant, meeting, phoneAttendee, event.requestContext);
    console.info("Dialing response : ", dialResponse);
    /*Save the call details in the database*/
    const fullMeetingObject = {
        id: meeting.Meeting.MeetingId,
        practitonerId: practitonerId,
        meeting: meeting,
        attendee: clientAttendee,
        callStatus: 1,
        dialResponse: dialResponse
    };
    console.info("Full meeting object response : ", fullMeetingObject);
    await repository.saveCallDetails(fullMeetingObject);
    return { Meeting: meeting.Meeting, Attendee: clientAttendee.Attendee, dialResponse};
}

async function dialToParticipant(pariticipant, meetingInfo, attendeeInfo, requestContext) { let dialAttributes = { RequestedVCArn: '', FromPhoneNumber: fromNumber, SipMediaApplicationId: smaId, ToPhoneNumber: pariticipant.phoneNumber, SipHeaders: { 'X-chime-join-token': attendeeInfo.Attendee.JoinToken, 'X-chime-meeting-id': meetingInfo.Meeting.MeetingId }, ArgumentsMap: { MeetingId: meetingInfo.Meeting.MeetingId, RequestedDialNumber: pariticipant.phoneNumber, RequestorEmail: requestContext.authorizer.claims.email, DialVC: 'false' } }; console.info("Dialing attributes : ", dialAttributes); const dialingResult = await voiceClient.send(new CreateSipMediaApplicationCallCommand(dialAttributes)); return dialingResult; }

Smahandler:

exports.handleCall = async function(event){ let actions; const transactionAttributes = event.CallDetails.TransactionAttributes !== undefined ? event.CallDetails.TransactionAttributes : { RequestedVCArn: '', RequestedDialNumber: '', RequestorEmail: '', DialVC: '', MeetingId: '' };

/*Handle various states of the call*/
switch(event.InvocationEventType){
    case 'NEW_OUTBOUND_CALL':
        console.info("New outbound call");
        transactionAttributes.RequestedVCArn = event.ActionData.Parameters.Arguments.RequestedVCArn;
        transactionAttributes.RequestedDialNumber = event.ActionData.Parameters.Arguments.RequestedDialNumber;
        transactionAttributes.RequestorEmail = event.ActionData.Parameters.Arguments.RequestorEmail;
        transactionAttributes.DialVC = event.ActionData.Parameters.Arguments.DialVC;
        transactionAttributes.MeetingId = event.ActionData.Parameters.Arguments.MeetingId;
        actions = [];
        break;
    case 'RINGING':
        console.info("Ringing");
        actions = [];
        break;
    case 'ACTION_SUCCESSFUL':
        console.info("Action successful");
        actions = [];
        break;
    case 'HANGUP':
        /*Delete the meeting, possible raise an event as well so that the calls db can be updated with the data*/
        console.info("Hang up action");
        await meetingClient.send(new DeleteMeetingCommand({
            MeetingId: transactionAttributes.MeetingId
        }));
        if(event.CallDetails.Participants[1]){
            hangupAction.Parameters.CallId = event.CallDetails.Participants[1].CallId;
            actions = [hangupAction];
        }
        break;
    case 'CALL_ANSWERED':
        /*When ever call is answered we can raise an event to update the call status in the calls db*/
        console.info("Call answered yay!");
        console.info("Transaction attributes : ", JSON.stringify(transactionAttributes));
        console.info("Bridging to PSTN");
        callAndBridgePSTN.Parameters.Endpoints[0].Uri = transactionAttributes.RequestedDialNumber;
        actions = [callAndBridgePSTN];
        break;
    default:
        console.error("Action failed");
        actions = [];
        break;
}
const response = {
    SchemaVersion: '1.0',
    Actions: actions,
    TransactionAttributes: transactionAttributes
};
console.info('Sending response back : ', JSON.stringify(response));
return response;

}

let hangupAction = { Type: 'Hangup', Parameters: { SipResponseCode: '0', CallId: '', }, };

let callAndBridgePSTN = { Type: 'CallAndBridge', Parameters: { CallTimeoutSeconds: 30, CallerIdNumber: fromNumber, Endpoints: [ { BridgeEndpointType: 'PSTN', Uri: '', }, ], }, };

AWS SDK version used

"@aws-sdk/client-chime-sdk-meetings": "^3.266.0", "@aws-sdk/client-chime-sdk-voice": "^3.266.0",

Operating System and version

Linux