Class: CallRecordTwilioRecordingImporter

Inherits:
Object
  • Object
show all
Defined in:
app/services/call_record_twilio_recording_importer.rb

Overview

Imports call recordings from Twilio SIP Trunk — scoped to BPO calls only.

Switchvox records all internal/extensions calls itself; the only conversations
that exist solely as Twilio trunk recordings are calls transferred to the BPO
(outsourced 24/7 answering service, see Phone::Bpo). To keep Twilio storage at
~$0, every recording is classified:

  • BPO-related -> imported as a CallRecord, then pruned from Twilio once the
    audio is safely attached to the record.
  • Not BPO-related and older than BPO_EVALUATION_DELAY -> deleted from Twilio
    (Switchvox already has these).
  • Not BPO-related but younger -> skipped and re-evaluated on the next run, so
    a BPO call log that hasn't been imported yet (CDRs land every 15 min) can't
    condemn a recording prematurely.

Key features:

  • Downloads dual-channel (stereo) WAV recordings, compressed to AAC
  • Stores separately from Switchvox records via recording_source field
  • Tracks twilio_recording_sid to avoid duplicate imports
  • Filters to specific trunk ID if configured

Usage:
CallRecordTwilioRecordingImporter.new.import_new_recordings

Configuration (via Setting):

  • call_recording_twilio_trunk_id: Filter to specific trunk (optional)
  • call_recording_twilio_enabled: Enable/disable Twilio import

Constant Summary collapse

TRUNK_ID =

Target trunk ID for SIP recordings
Set via Setting.call_recording_twilio_trunk_id or override in options

'TKc7c6b6bb675a29978a90a617c207a3e1'
BPO_EVALUATION_DELAY =

How long a non-BPO recording is kept before deletion. CDRs land every
15 min via CallLogImporterWorker, so within an hour a BPO call log would
exist if the recording were BPO-related.

1.hour
BPO_TIME_TOLERANCE =

How close a trunk call's start must be to a BPO CallLog's start_time to
count as that call's originating (full inbound) leg.

3.minutes

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ CallRecordTwilioRecordingImporter

Returns a new instance of CallRecordTwilioRecordingImporter.

Parameters:

  • options (Hash) (defaults to: {})

    importer configuration

Options Hash (options):

  • :logger (Logger)

    log target (defaults to Rails.logger)

  • :dry_run (Boolean)

    report what would change without writing

  • :trunk_id (String)

    Twilio trunk SID to filter recordings by
    (defaults to Setting.call_recording_twilio_trunk_id or TRUNK_ID)



51
52
53
54
55
56
# File 'app/services/call_record_twilio_recording_importer.rb', line 51

def initialize(options = {})
  @options = options
  @logger = options[:logger] || Rails.logger
  @twilio = TwilioClient.instance
  @dry_run = options[:dry_run] || false
end

Instance Attribute Details

#loggerObject (readonly)

Returns the value of attribute logger.



31
32
33
# File 'app/services/call_record_twilio_recording_importer.rb', line 31

def logger
  @logger
end

#optionsObject (readonly)

Returns the value of attribute options.



31
32
33
# File 'app/services/call_record_twilio_recording_importer.rb', line 31

def options
  @options
end

#twilioObject (readonly)

Returns the value of attribute twilio.



31
32
33
# File 'app/services/call_record_twilio_recording_importer.rb', line 31

def twilio
  @twilio
end

Instance Method Details

#import_new_recordings(limit: 50, since: nil) ⇒ Hash

Import new recordings from Twilio

Parameters:

  • limit (Integer) (defaults to: 50)

    Maximum recordings to process

  • since (Time) (defaults to: nil)

    Only import recordings created after this time

Returns:

  • (Hash)

    Summary of import results



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'app/services/call_record_twilio_recording_importer.rb', line 62

def import_new_recordings(limit: 50, since: nil)
  since ||= last_import_time || 24.hours.ago
  logger.info "[TwilioRecordingImporter] Starting import (since: #{since}, limit: #{limit})"

  recordings = fetch_recordings(since: since, limit: limit)
  logger.info "[TwilioRecordingImporter] Found #{recordings.count} recordings to process"

  results = { processed: 0, imported: 0, skipped: 0, errors: 0, deleted_not_bpo: 0, pending_evaluation: 0 }

  recordings.each do |recording|
    result = process_recording(recording)
    results[:processed] += 1

    case result
    when :imported
      results[:imported] += 1
    when :skipped, :already_imported, :wrong_trunk
      results[:skipped] += 1
    when :deleted_not_bpo
      results[:deleted_not_bpo] += 1
    when :pending_evaluation
      results[:pending_evaluation] += 1
    when :error
      results[:errors] += 1
    end
  end

  logger.info "[TwilioRecordingImporter] Complete: #{results.inspect}"
  results
end