Build a Rapid Response Kit with Voice Conference and Broadcasting

Help your company stay organized with two helpful features - voice conference and broadcast. In a few minutes, you can build a moderated conference line that allows people to listen, speak or moderate during the call. Voice Broadcasting allows you to immediately broadcast a pre-recorded voice message to a list of contacts.

This tutorial and sample application are inspired by the Rapid Response Kit, built by Twilio and used all over the world by organizations who need to act quickly in disastrous situations.

In this tutorial, we'll walk through building a Rapid Response Kit with a Voice Conference line and Voice Broadcasting. Aid workers can use the tools in this app to communicate immediately with a large group of volunteers. In situations where all parties need to talk at once, the organizer can quickly spin up a conference line. In other situations, an organizer can broadcast a spoken message to a list of volunteer phone numbers.

Loading Code Samples...
Language
class TwilioController < ApplicationController
  TWILIO_API_HOST = 'https://api.twilio.com'

  before_action :set_client_and_number, only: [:start_call_record, :broadcast_send, :fetch_recordings, :conference]

  # GET /conference
  def conference
    @conference_number = @twilio_number
  end

  # POST /conference
  def join_conference
    response = Twilio::TwiML::VoiceResponse.new
    response.say("You are about to join the Rapid Response conference")
    gather = Twilio::TwiML::Gather.new(action: 'conference/connect')
    gather.say("Press 1 to join as a listener.")
    gather.say("Press 2 to join as a speaker.")
    gather.say("Press 3 to join as the moderator.")
    response.append(gather)

    render xml: response.to_s
  end

  # POST /conference/connect
  def conference_connect
    case params['Digits']
    when "1" # listener
      @muted = "true"
    when "3" # moderator
      @moderator = "true"
    end

    response = Twilio::TwiML::VoiceResponse.new
    response.say("You have joined the conference.")
    dial = Twilio::TwiML::Dial.new
    dial.conference("RapidResponseRoom",
      wait_url: "http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient",
      muted: @muted || "false",
      start_conference_on_enter: @moderator || "false",
      endConference_on_exit: @moderator || "false")
    response.append(dial)

    render xml: response.to_s
  end

  # POST /broadcast/record
  def broadcast_record
    response = Twilio::TwiML::VoiceResponse.new
    response.say("Please record your message after the beep. Press star to end your recording.")
    response.record(finish_on_key: "*")

    render xml: response.to_s
  end

  # POST /broadcast/send
  def broadcast_send
    numbers = CSV.parse(params[:numbers])
    recording = params[:recording_url]
    url = request.base_url + '/broadcast/play?recording_url=' + recording

    numbers.each do |number|
      @client.calls.create(
        from: @twilio_number,
        to: number,
        url: url
      )
    end
  end

  # POST /broadcast/play
  def broadcast_play
    recording_url = params[:recording_url]
    response = Twilio::TwiML::VoiceResponse.new
    response.play(recording_url)

    render xml: response.to_s
  end

  # GET /broadcast
  def broadcast
  end

  # POST /call_recording
  def start_call_record
    phone_number = params[:phone_number]

    @client.calls.create(
      from: @twilio_number,
      to: phone_number,
      url: "#{request.base_url}/broadcast/record"
    )
  end

  # GET /fetch_recordings
  def fetch_recordings
    recordings = @client.recordings.list.map do |recording|
      {
        url:  full_recording_uri(recording.uri),
        date: recording.date_created
      }
    end

    render json: recordings
  end

  private

  # returns full uri given partial recording uri
  def full_recording_uri(uri)
    # remove json extension from uri
    clean_uri = uri.sub!('.json', '')

    "#{TWILIO_API_HOST}#{clean_uri}"
  end

  def set_client_and_number
    @client = Twilio::REST::Client.new ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN']
    @twilio_number = ENV['TWILIO_NUMBER']
  end
end
app/controllers/twilio_controller.rb
Conference Call Controller Code

app/controllers/twilio_controller.rb

Find your language and framework of choice below to get to the source code in your language and follow step-by-step instructions to learn how to build conference and broadcast apps yourself:

Kat King

Need some help?

We all do sometimes; code is hard. Get help now from our support team, or lean on the wisdom of the crowd browsing the Twilio tag on Stack Overflow.

Loading Code Samples...
class TwilioController < ApplicationController
  TWILIO_API_HOST = 'https://api.twilio.com'

  before_action :set_client_and_number, only: [:start_call_record, :broadcast_send, :fetch_recordings, :conference]

  # GET /conference
  def conference
    @conference_number = @twilio_number
  end

  # POST /conference
  def join_conference
    response = Twilio::TwiML::VoiceResponse.new
    response.say("You are about to join the Rapid Response conference")
    gather = Twilio::TwiML::Gather.new(action: 'conference/connect')
    gather.say("Press 1 to join as a listener.")
    gather.say("Press 2 to join as a speaker.")
    gather.say("Press 3 to join as the moderator.")
    response.append(gather)

    render xml: response.to_s
  end

  # POST /conference/connect
  def conference_connect
    case params['Digits']
    when "1" # listener
      @muted = "true"
    when "3" # moderator
      @moderator = "true"
    end

    response = Twilio::TwiML::VoiceResponse.new
    response.say("You have joined the conference.")
    dial = Twilio::TwiML::Dial.new
    dial.conference("RapidResponseRoom",
      wait_url: "http://twimlets.com/holdmusic?Bucket=com.twilio.music.ambient",
      muted: @muted || "false",
      start_conference_on_enter: @moderator || "false",
      endConference_on_exit: @moderator || "false")
    response.append(dial)

    render xml: response.to_s
  end

  # POST /broadcast/record
  def broadcast_record
    response = Twilio::TwiML::VoiceResponse.new
    response.say("Please record your message after the beep. Press star to end your recording.")
    response.record(finish_on_key: "*")

    render xml: response.to_s
  end

  # POST /broadcast/send
  def broadcast_send
    numbers = CSV.parse(params[:numbers])
    recording = params[:recording_url]
    url = request.base_url + '/broadcast/play?recording_url=' + recording

    numbers.each do |number|
      @client.calls.create(
        from: @twilio_number,
        to: number,
        url: url
      )
    end
  end

  # POST /broadcast/play
  def broadcast_play
    recording_url = params[:recording_url]
    response = Twilio::TwiML::VoiceResponse.new
    response.play(recording_url)

    render xml: response.to_s
  end

  # GET /broadcast
  def broadcast
  end

  # POST /call_recording
  def start_call_record
    phone_number = params[:phone_number]

    @client.calls.create(
      from: @twilio_number,
      to: phone_number,
      url: "#{request.base_url}/broadcast/record"
    )
  end

  # GET /fetch_recordings
  def fetch_recordings
    recordings = @client.recordings.list.map do |recording|
      {
        url:  full_recording_uri(recording.uri),
        date: recording.date_created
      }
    end

    render json: recordings
  end

  private

  # returns full uri given partial recording uri
  def full_recording_uri(uri)
    # remove json extension from uri
    clean_uri = uri.sub!('.json', '')

    "#{TWILIO_API_HOST}#{clean_uri}"
  end

  def set_client_and_number
    @client = Twilio::REST::Client.new ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN']
    @twilio_number = ENV['TWILIO_NUMBER']
  end
end