1

I was able to implement basic Voice Conferencing but I feel my implementation may be lacking.

client = Client('ACxxxxxxxx', '34xxxxxxxxx')

@app.route('/', methods=["GET", "POST"])
def home():
    form = ConferenceList() #form made using flask-wtf
    if form.validate_on_submit():
        contact_1 = form.data['contact_1'] #callee1
        contact_2 = form.data['contact_2'] #callee2
        from_ = form.data['from_'] #caller

        response = VoiceResponse()
        with Dial() as dial:
            if from_ == MODERATOR:
                dial.conference(
                   'Conf',
                   start_conference_on_enter=True,
                   end_conference_on_exit=True
                   )
            else:
                dial.conference('Conf', start_conference_on_enter=False)
        response.append(dial)

        '''here I feel could be a bottleneck'''
        add_user(contact_1, conference_name='Conf', label='laed#1')
        add_user(contact_2, conference_name='Conf', label="consumer")
        return Response(str(response), 'text/xml')
    
    return render_template('hello.html', form=form)


def add_user(contact, conference_name, label):
    participant = client.conferences(conference_name).\
            participants.create(
                label=label, #label for participant
                beep='onEnter',
                record=True,
                from_='from_', #same as above
                to=str(contact)
            )

if __name__ == '__main__':
    app.run(debug=True, port=8000)

Basically the submit button triggers the / endpoint and the conference starts.

I feel there could be an issue with this implementation as I plan on cleaning it up and pushing to production (salesperson can make a conference call to leads on the app). Is there something I could have done better?

The voice(one client-one client) utilizes the Twilio Voice SDK, it there a way I could tweak it for conferencing?

Emmanuel
  • 52
  • 4

1 Answers1

0

You only need to respond with TwiML to a webhook from Twilio. In this case it appears that you are responding with TwiML to your application's front end when a submit button is pressed.

So, you can drop all the TwiML:

@app.route('/', methods=["GET", "POST"])
def home():
    form = ConferenceList() #form made using flask-wtf
    if form.validate_on_submit():
        contact_1 = form.data['contact_1'] #callee1
        contact_2 = form.data['contact_2'] #callee2

        '''here I feel could be a bottleneck'''
        add_user(contact_1, conference_name='Conf', label='laed#1')
        add_user(contact_2, conference_name='Conf', label="consumer")
        return "whatever"

Since the settings you are trying to apply in the TwiML do not apply to the participants joining the conference, you need to adjust your add_user function to use them. In this case, the startConferenceOnEnter and endConferenceOnExit parameters for the moderator should be sent when you create the participant. It might be easier to write two methods, add_user and add_moderator, to make things clear:

def add_user(contact, conference_name, label):
    participant = client.conferences(conference_name).\
            participants.create(
                label=label, #label for participant
                beep='onEnter',
                record=True,
                from_='from_', #same as above
                to=str(contact),
                start_conference_on_enter=False
            )

def add_moderator(contact, conference_name, label):
    participant = client.conferences(conference_name).\
        participants.create(
            label=label,
            beep='onEnter',
            record=True,
            from_='from_',
            to=str(contact),
            start_conference_on_enter=True,
            end_conference_on_exit=True
        )

Then call different functions for the different participants:

        add_moderator(contact_1, conference_name='Conf', label='laed#1')
        add_user(contact_2, conference_name='Conf', label="consumer")

When you call add_user or add_moderator it will make an API request and slow down your server response. If you wanted to offload those requests to a worker, that would make your response quicker. But for 2 API requests, it is likely not a problem.

One other thing you might want to consider is the consumer experience. If they answer the phone before your agent does, then they will be greeted with hold music. You might want to architect it so that the application calls the agent first and only once they have picked up it then dials the consumer. Just worth considering.

Edit

After further explanation, you are now telling me that you want to make the call from the browser using the Twilio Voice SDK for JS.

To make outbound calls with the JS SDK you need to create an access token which includes an outgoing application sid, which refers to a TwiML application. That TwiML application has a voice URL. When you place the call with the SDK, Twilio makes a webhook request to the voice URL of your TwiML app. Your application can perform actions and return TwiML to tell Twilio what to do with the call.

When you create the call with the JS SDK you can pass parameters to the call.

const device = new Device(token);

const call = await device.connect({
  params: {
    To: ["+15551234567", "+145557654321"]
  }
});

Those parameters are sent with the webhook request to your TwiML App voice URL. You can then use a response very similar to your original code to respond here, because you need to return TwiML to the request from Twilio, and start calls to the other participants in the call.

@app.route('/conference', methods=["POST"])
def conference():
    const numbers = request.form["To"]

    response = VoiceResponse()
    with Dial() as dial:
        dial.conference(
           'Conf',
           start_conference_on_enter=True,
           end_conference_on_exit=True
       )
    response.append(dial)

    for number in numbers:
        add_user(number, conference_name='Conf')

    return Response(str(response), 'text/xml')

This code receives the To parameter, a list of numbers to dial into this conference, builds the TwiML response that will put the browser caller into a conference call, places outbound calls to the numbers to dial them into the conference and then returns the TwiML to Twilio. The dialler in the browser will start the conference and the other participants will arrive in the conference when they answer the phone.

In this case you don't make the request to your server yourself, you use the JS SDK to trigger the call and let Twilio make the request to your server. As mentioned in the comments, you may want to offload the API calls to create participants to a background job so that you can respond to the webhook request quicker, but that is beyond the scope of this answer.

philnash
  • 70,667
  • 10
  • 60
  • 88
  • Hm. Thanks for the contributions to Twilio related questions, it's been useful in my project. "You only need to respond with TwiML to a webhook from Twilio. In this case it appears that you are responding with TwiML to your application's front end when a submit button is pressed," I do not fully grasp this but on my Twilio console voice configuration is tied to my TWIML app (for inbound calls, using the ```/voice``` endpoint) , and one can allow pick twiml app or "webhook/twiml bin/function..." not both. So I'm a bit confused by the webhook implementation you are suggesting. – Emmanuel Jun 14 '22 at 15:57
  • You said "Basically the submit button triggers the `/` endpoint and the conference starts.". What submit button is that? Can you explain more how a user creates a conference call? – philnash Jun 14 '22 at 23:21
  • I have a flask form that collects contacts for the conference call, in which there's a submit button attached, which starts onrolling when clicked and ```form.validate_on_submit()``` is true, hence triggering the call. – Emmanuel Jun 15 '22 at 08:15
  • Right, so you don’t need to respond to that form submission with TwiML, you only need to respond to Twilio webhook requests with TwiML. I would not recommend that this form submission URL is the same URL you set up for inbound calls to the number. – philnash Jun 15 '22 at 09:42
  • Inbound calls are addressed by ```/voice``` (TWIML app configured), while this is ```/conference```. I would actually prefer using TWIML for conference. But right now I'm tailoring the app_user function, there's a possibility for a conference call to be among 50 participants, and a for-loop to add participants would drain memory. Tbh I'm frustrated. – Emmanuel Jun 15 '22 at 10:42
  • Ok, but you showed it to me as `/`, so I’m trying to direct you from what I know about your app. What you’re saying now is you need to find the quickest way to make 50 API requests? Can you offload them to a background process like Celery to free up your web process? – philnash Jun 15 '22 at 10:45
  • I never mentioned, but this is meant to be a browser-to-browser and browser-to-phone calling system, the outgoing call with the twilio JS SDK works fine, because I can communicate on my pc to a phone, now this conference is failing as it does not use the sdk instead the python package, the conference connects but I can not communicate from my pc, the two other phones ring and I can only hear the conference wait tone. Can I implement conference using the js SDK? that way I can utilize the pc's mic. – Emmanuel Jun 16 '22 at 09:27
  • And it's meant to be an outbound conference call to participants to join in the conference. Not participants calling the twilio number to join the conference. Sales person should add participants to a conference and click on a Start conference button, which should now dial out to these participants and conference is started. – Emmanuel Jun 16 '22 at 09:36
  • That's some new information! I added a new section to my answer at the bottom under "Edit" – philnash Jun 16 '22 at 23:59
  • Excellent! I understand you a lot better now having read quite a bit on Twilio. I really appreciate you taking your time to answer these questions. I have implemented my code just like so: so far two of my phones ring out and are connected to the conference, except my twilio number (i.e, the browser making the call, it does not ring, in fact my console shows call disconnected - i'm using the add_user function to add the twilio number to the conference, essentially it is dialing itself by joining as a participant). It's late in the night here so I'll look into it later in the morning. Thanks. – Emmanuel Jun 17 '22 at 00:13
  • Until your latest update, I had no idea you were trying to dial with the JS SDK from the browser. My latest update should help you get everything connected. Good luck with it when you get back to it. – philnash Jun 17 '22 at 00:14