From 2bd7f3c1cc18f53eb4e0547595be13b2f7a869c3 Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Thu, 21 Sep 2017 16:03:52 -0500 Subject: [PATCH 01/10] add play_audio instruction - need to add mu-law encoding --- lib/sippy_cup/media.rb | 31 ++++++++++++++++++++++++++++++- lib/sippy_cup/scenario.rb | 10 ++++++++++ sippy_cup.gemspec | 3 ++- 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/sippy_cup/media.rb b/lib/sippy_cup/media.rb index acae59e..43017aa 100644 --- a/lib/sippy_cup/media.rb +++ b/lib/sippy_cup/media.rb @@ -1,11 +1,12 @@ # encoding: utf-8 require 'ipaddr' +require 'wavefile' require 'sippy_cup/media/pcmu_payload' require 'sippy_cup/media/dtmf_payload' module SippyCup class Media - VALID_STEPS = %w{silence dtmf}.freeze + VALID_STEPS = %w{silence dtmf play}.freeze USEC = 1_000_000 MSEC = 1_000 attr_accessor :sequence @@ -83,6 +84,34 @@ def compile! end # Now bump up the timestamp to cover the gap timestamp += count * DTMFPayload::TIMESTAMP_INTERVAL + when 'play' + # value is wav file path + wav = WaveFile::Reader.new(value, WaveFile::Format.new(:mono, :pcm_8, 8000)) + duration = wav.total_sample_frames * 1000 / wav.native_format.sample_rate # in milliseconds + + (duration / @generator::PTIME).times do |i| + packet = new_packet + rtp_frame = @generator.new + + # The first RTP audio packet should have the marker bit set + if first_audio + rtp_frame.rtp_marker = 1 + first_audio = false + end + + rtp_frame.rtp_timestamp = timestamp += rtp_frame.timestamp_interval + elapsed += rtp_frame.ptime + rtp_frame.rtp_sequence_num = sequence_number += 1 + rtp_frame.rtp_ssrc_id = ssrc_id + + len = wav.native_format.sample_rate * rtp_frame.ptime / 1000 + data = wav.read(len).samples + puts len, data.flatten.pack('n*'), "--" + packet.headers.last.body = rtp_frame.header.to_s << data.flatten.pack('c*') + packet.recalc + @pcap_file.body << get_pcap_packet(packet, next_ts(start_time, elapsed)) + end + wav.close else end end diff --git a/lib/sippy_cup/scenario.rb b/lib/sippy_cup/scenario.rb index cf31b25..06e937f 100644 --- a/lib/sippy_cup/scenario.rb +++ b/lib/sippy_cup/scenario.rb @@ -472,6 +472,16 @@ def sleep(seconds) @media << "silence:#{milliseconds}" if @media end + # + # add audio to pcap from wav file + # + # @param [String] path of wav file + # + def play_audio(wav_file) + raise "Media not started" unless @media + @media << "play:#{wav_file}" + end + # # Send DTMF digits # diff --git a/sippy_cup.gemspec b/sippy_cup.gemspec index 1f88f78..1d91085 100644 --- a/sippy_cup.gemspec +++ b/sippy_cup.gemspec @@ -19,9 +19,10 @@ Gem::Specification.new do |s| s.require_paths = ["lib"] s.add_runtime_dependency 'packetfu', ["= 1.1.11"] # 1.1.12 introduces a breaking change, removing PacketFu::UDPPacket - s.add_runtime_dependency 'nokogiri', ["~> 1.6.0"] + s.add_runtime_dependency 'nokogiri', ["~> 1.7.0"] s.add_runtime_dependency 'activesupport', [">= 3.0"] s.add_runtime_dependency 'psych', ["~> 2.0.1"] unless RUBY_PLATFORM == 'java' + s.add_runtime_dependency 'wavefile', [">= 0.8.0"] s.add_development_dependency 'guard-rspec' s.add_development_dependency 'rspec', ["~> 3.4"] From 9353d53c1ae4d83a018937c2d714c6b6c57eb477 Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Thu, 21 Sep 2017 22:10:18 -0500 Subject: [PATCH 02/10] add G711 encoding feature using ffi --- lib/sippy_cup/g711.rb | 36 ++++++++++++++++++++++++++++++++++++ lib/sippy_cup/media.rb | 10 ++++++---- sippy_cup.gemspec | 1 + 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 lib/sippy_cup/g711.rb diff --git a/lib/sippy_cup/g711.rb b/lib/sippy_cup/g711.rb new file mode 100644 index 0000000..96c2a14 --- /dev/null +++ b/lib/sippy_cup/g711.rb @@ -0,0 +1,36 @@ +# ffi interface to freeswitch's g711 +require 'ffi' + +module SippyCup + module G711 + extend FFI::Library + ffi_lib 'spandsp' + + enum :EncodeState, [ + :G711_ALAW, 0, + :G711_ULAW, 1, + ] + + class G711State < FFI::Struct + layout :mode, :EncodeState + end + + attach_function :g711_encode, [ G711State, :pointer, :pointer, :int ], :int + + def encode(samples) + state = G711State.new + state[:mode] = :G711_ULAW # u-law only + + iptr = FFI::MemoryPointer.new(:int16, samples.size) + optr = FFI::MemoryPointer.new(:uint8, samples.size) + + puts samples.join(' ') + iptr.write_array_of_type(:int16, :write_int16, samples) + g711_encode(state, optr, iptr, samples.size) + output = optr.read_array_of_type(:uint8, :read_uint8, samples.size) + puts output.join(' ') + output + end + module_function :encode + end +end diff --git a/lib/sippy_cup/media.rb b/lib/sippy_cup/media.rb index 43017aa..fc0c3c4 100644 --- a/lib/sippy_cup/media.rb +++ b/lib/sippy_cup/media.rb @@ -1,8 +1,10 @@ # encoding: utf-8 require 'ipaddr' require 'wavefile' +require 'ffi' require 'sippy_cup/media/pcmu_payload' require 'sippy_cup/media/dtmf_payload' +require 'sippy_cup/g711' module SippyCup class Media @@ -86,7 +88,7 @@ def compile! timestamp += count * DTMFPayload::TIMESTAMP_INTERVAL when 'play' # value is wav file path - wav = WaveFile::Reader.new(value, WaveFile::Format.new(:mono, :pcm_8, 8000)) + wav = WaveFile::Reader.new(value, WaveFile::Format.new(:mono, :pcm_16, 8000)) duration = wav.total_sample_frames * 1000 / wav.native_format.sample_rate # in milliseconds (duration / @generator::PTIME).times do |i| @@ -105,9 +107,9 @@ def compile! rtp_frame.rtp_ssrc_id = ssrc_id len = wav.native_format.sample_rate * rtp_frame.ptime / 1000 - data = wav.read(len).samples - puts len, data.flatten.pack('n*'), "--" - packet.headers.last.body = rtp_frame.header.to_s << data.flatten.pack('c*') + lin_data = wav.read(len).samples + enc_data = G711::encode(lin_data) + packet.headers.last.body = rtp_frame.header.to_s << enc_data.flatten.pack('c*') packet.recalc @pcap_file.body << get_pcap_packet(packet, next_ts(start_time, elapsed)) end diff --git a/sippy_cup.gemspec b/sippy_cup.gemspec index 1d91085..cec31cf 100644 --- a/sippy_cup.gemspec +++ b/sippy_cup.gemspec @@ -23,6 +23,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'activesupport', [">= 3.0"] s.add_runtime_dependency 'psych', ["~> 2.0.1"] unless RUBY_PLATFORM == 'java' s.add_runtime_dependency 'wavefile', [">= 0.8.0"] + s.add_runtime_dependency 'ffi' s.add_development_dependency 'guard-rspec' s.add_development_dependency 'rspec', ["~> 3.4"] From 31dbacf99ee70e981fd211c3978b2eb194206359 Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Fri, 22 Sep 2017 12:24:17 -0500 Subject: [PATCH 03/10] update to make dtmf working --- README.markdown | 2 +- lib/sippy_cup/g711.rb | 4 ++-- lib/sippy_cup/media.rb | 24 +++++++++++------------- lib/sippy_cup/scenario.rb | 15 ++++++++------- 4 files changed, 22 insertions(+), 23 deletions(-) diff --git a/README.markdown b/README.markdown index 2f8f412..b85341d 100644 --- a/README.markdown +++ b/README.markdown @@ -223,7 +223,7 @@ Each parameter has an impact on the test, and may either be changed once the XML
By default, SIPp assigns RTP ports dynamically. However, if there is a need for a static RTP port (say, for data collection purposes), it can be done by supplying a port number here. Default: SIPp's default of 6000
dtmf_mode
-
Specify the mechanism by which DTMF is signaled. Valid options are `rfc2833` for within the RTP media, or `info` for SIP INFO. Default: rfc2833
+
Specify the mechanism by which DTMF is signaled. Valid options are `rfc4733` for within the RTP media, or `info` for SIP INFO. Default: rfc4733
scenario_variables
If you're using sippy_cup to run a SIPp XML file, there may be CSV fields in the scenario ([field0], [field1], etc.). Specify a path to a CSV file containing the required information using this option. (File is semicolon delimeted, information can be found [here](http://sipp.sourceforge.net/doc/reference.html#inffile).) Default: unused
diff --git a/lib/sippy_cup/g711.rb b/lib/sippy_cup/g711.rb index 96c2a14..7d88d3b 100644 --- a/lib/sippy_cup/g711.rb +++ b/lib/sippy_cup/g711.rb @@ -24,11 +24,11 @@ def encode(samples) iptr = FFI::MemoryPointer.new(:int16, samples.size) optr = FFI::MemoryPointer.new(:uint8, samples.size) - puts samples.join(' ') + #puts samples.join(' ') iptr.write_array_of_type(:int16, :write_int16, samples) g711_encode(state, optr, iptr, samples.size) output = optr.read_array_of_type(:uint8, :read_uint8, samples.size) - puts output.join(' ') + #puts output.join(' ') output end module_function :encode diff --git a/lib/sippy_cup/media.rb b/lib/sippy_cup/media.rb index fc0c3c4..54fb67d 100644 --- a/lib/sippy_cup/media.rb +++ b/lib/sippy_cup/media.rb @@ -51,13 +51,11 @@ def compile! (value.to_i / @generator::PTIME).times do packet = new_packet rtp_frame = @generator.new - # The first RTP audio packet should have the marker bit set if first_audio rtp_frame.rtp_marker = 1 first_audio = false end - rtp_frame.rtp_timestamp = timestamp += rtp_frame.timestamp_interval elapsed += rtp_frame.ptime rtp_frame.rtp_sequence_num = sequence_number += 1 @@ -68,18 +66,22 @@ def compile! end when 'dtmf' # value is the DTMF digit to send - # append that RFC2833 digit - # Assume 0.25 second duration for now - count = 250 / DTMFPayload::PTIME + # append that RFC4733 digit + # Assume 0.2 second duration for now + count = 200 / DTMFPayload::PTIME count.times do |i| packet = new_packet dtmf_frame = DTMFPayload.new value - dtmf_frame.rtp_marker = 1 if i == 0 - dtmf_frame.rtp_timestamp = timestamp # Is this correct? This is what Blink does... - #dtmf_frame.rtp_timestamp = timestamp += dtmf_frame.timestamp_interval + # The first RTP audio packet should have the marker bit set + if first_audio + rtp_frame.rtp_marker = 1 + first_audio = false + end + dtmf_frame.rtp_timestamp = timestamp += dtmf_frame.timestamp_interval + elapsed += dtmf_frame.ptime dtmf_frame.rtp_sequence_num = sequence_number += 1 dtmf_frame.rtp_ssrc_id = ssrc_id - dtmf_frame.end_of_event = (count == i) # Last packet? + dtmf_frame.end_of_event = (i == count-1) # Last packet packet.headers.last.body = dtmf_frame.to_bytes packet.recalc @pcap_file.body << get_pcap_packet(packet, next_ts(start_time, elapsed)) @@ -90,22 +92,18 @@ def compile! # value is wav file path wav = WaveFile::Reader.new(value, WaveFile::Format.new(:mono, :pcm_16, 8000)) duration = wav.total_sample_frames * 1000 / wav.native_format.sample_rate # in milliseconds - (duration / @generator::PTIME).times do |i| packet = new_packet rtp_frame = @generator.new - # The first RTP audio packet should have the marker bit set if first_audio rtp_frame.rtp_marker = 1 first_audio = false end - rtp_frame.rtp_timestamp = timestamp += rtp_frame.timestamp_interval elapsed += rtp_frame.ptime rtp_frame.rtp_sequence_num = sequence_number += 1 rtp_frame.rtp_ssrc_id = ssrc_id - len = wav.native_format.sample_rate * rtp_frame.ptime / 1000 lin_data = wav.read(len).samples enc_data = G711::encode(lin_data) diff --git a/lib/sippy_cup/scenario.rb b/lib/sippy_cup/scenario.rb index 06e937f..439129a 100644 --- a/lib/sippy_cup/scenario.rb +++ b/lib/sippy_cup/scenario.rb @@ -92,7 +92,7 @@ def self.from_manifest(manifest, options = {}) # @option options [String] :stats_file The path at which to dump statistics. # @option options [String, Numeric] :stats_interval The interval (in seconds) at which to dump statistics (defaults to 1s). # @option options [String] :transport_mode The transport mode over which to direct SIP traffic. - # @option options [String] :dtmf_mode The output DTMF mode, either rfc2833 (default) or info. + # @option options [String] :dtmf_mode The output DTMF mode, either rfc4733 (default) or info. # @option options [String] :scenario_variables A path to a CSV file of variables to be interpolated with the scenario at runtime. # @option options [Hash] :options A collection of options to pass through to SIPp, as key-value pairs. In cases of value-less options (eg -trace_err), specify a nil value. # @option options [Array] :steps A collection of steps @@ -175,8 +175,9 @@ def invite(opts = {}) s=- c=IN IP[media_ip_type] [media_ip] t=0 0 -m=audio [media_port] RTP/AVP 0 101 +m=audio [auto_media_port] RTP/AVP 0 8 101 a=rtpmap:0 PCMU/8000 +a=rtpmap:8 PCMA/8000 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-15 MSG @@ -495,12 +496,12 @@ def play_audio(wav_file) # def send_digits(digits) raise "Media not started" unless @media - delay = (0.250 * MSEC).to_i # FIXME: Need to pass this down to the media layer + delay = (0.2 * MSEC).to_i # FIXME: Need to pass this down to the media layer digits.split('').each do |digit| raise ArgumentError, "Invalid DTMF digit requested: #{digit}" unless VALID_DTMF.include? digit case @dtmf_mode - when :rfc2833 + when :rfc4733 @media << "dtmf:#{digit}" @media << "silence:#{delay}" when :info @@ -528,7 +529,7 @@ def send_digits(digits) end end - if @dtmf_mode == :rfc2833 + if @dtmf_mode == :rfc4733 pause delay * 2 * digits.size end end @@ -783,9 +784,9 @@ def scenario_node def parse_args(args) if args[:dtmf_mode] @dtmf_mode = args[:dtmf_mode].to_sym - raise ArgumentError, "dtmf_mode must be rfc2833 or info" unless [:rfc2833, :info].include?(@dtmf_mode) + raise ArgumentError, "dtmf_mode must be rfc4733 or info" unless [:rfc4733, :info].include?(@dtmf_mode) else - @dtmf_mode = :rfc2833 + @dtmf_mode = :rfc4733 end @from_user = args[:from_user] || "sipp" From e416b94444f3e45d2e5008efc81c965e5c0da17b Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Fri, 22 Sep 2017 12:29:43 -0500 Subject: [PATCH 04/10] update README --- README.markdown | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.markdown b/README.markdown index b85341d..49f7645 100644 --- a/README.markdown +++ b/README.markdown @@ -6,6 +6,12 @@ # Sippy Cup +## NOTES for this fork + +* New instruction is added to insert wav file into pcap + `- play_audio ""` +* Debug the DTMF packet generation (end of event) + ## Overview ### The Problem From 3bb5638e02d8ce84ee2cd06ea470c8195b5cfeb5 Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Fri, 22 Sep 2017 12:33:29 -0500 Subject: [PATCH 05/10] update README --- README.markdown | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 49f7645..63c7026 100644 --- a/README.markdown +++ b/README.markdown @@ -9,8 +9,11 @@ ## NOTES for this fork * New instruction is added to insert wav file into pcap - `- play_audio ""` + - `- play_audio ""` + - need spandsp library for encoidng a-law and u-law * Debug the DTMF packet generation (end of event) + - reduce the duration to 200 milliseconds + - change obsolete rfc2833 to rfc4733 ## Overview From 1ad637a52c703b5a31cfb5a57927d69c750931d2 Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Fri, 22 Sep 2017 14:42:10 -0500 Subject: [PATCH 06/10] make nested yamls capable using yaml_extends --- bin/sippy_cup | 6 +++++- sippy_cup.gemspec | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/sippy_cup b/bin/sippy_cup index f154a94..2a5a57a 100755 --- a/bin/sippy_cup +++ b/bin/sippy_cup @@ -2,6 +2,7 @@ require 'sippy_cup' require 'getoptlong' +require 'yaml_extend' def usage puts "#{$0} [OPTS] " @@ -59,7 +60,10 @@ unless compile || run exit 1 end -scenario = SippyCup::Scenario.from_manifest File.read(manifest_path), input_filename: manifest_path +config = YAML.ext_load_file(manifest_path) +manifest = config.to_yaml + +scenario = SippyCup::Scenario.from_manifest manifest, input_filename: manifest_path if scenario.valid? scenario.compile! if compile else diff --git a/sippy_cup.gemspec b/sippy_cup.gemspec index cec31cf..5eef5d8 100644 --- a/sippy_cup.gemspec +++ b/sippy_cup.gemspec @@ -24,6 +24,7 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'psych', ["~> 2.0.1"] unless RUBY_PLATFORM == 'java' s.add_runtime_dependency 'wavefile', [">= 0.8.0"] s.add_runtime_dependency 'ffi' + s.add_runtime_dependency 'yaml_extend' s.add_development_dependency 'guard-rspec' s.add_development_dependency 'rspec', ["~> 3.4"] From 2c08294321c0c718853fdf2405a36d330baa5160 Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Fri, 22 Sep 2017 14:44:16 -0500 Subject: [PATCH 07/10] update readme --- README.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/README.markdown b/README.markdown index 63c7026..0b459d1 100644 --- a/README.markdown +++ b/README.markdown @@ -14,6 +14,7 @@ * Debug the DTMF packet generation (end of event) - reduce the duration to 200 milliseconds - change obsolete rfc2833 to rfc4733 +* Can use nested yamls, provided by yaml_extend ## Overview From ad529e08dbb9f16c2b9348bb64804f8b394ca810 Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Fri, 22 Sep 2017 15:09:00 -0500 Subject: [PATCH 08/10] remove alaw codec from SDP --- lib/sippy_cup/scenario.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/sippy_cup/scenario.rb b/lib/sippy_cup/scenario.rb index 439129a..3eb16a2 100644 --- a/lib/sippy_cup/scenario.rb +++ b/lib/sippy_cup/scenario.rb @@ -175,9 +175,8 @@ def invite(opts = {}) s=- c=IN IP[media_ip_type] [media_ip] t=0 0 -m=audio [auto_media_port] RTP/AVP 0 8 101 +m=audio [auto_media_port] RTP/AVP 0 101 a=rtpmap:0 PCMU/8000 -a=rtpmap:8 PCMA/8000 a=rtpmap:101 telephone-event/8000 a=fmtp:101 0-15 MSG From 063cbbf712fe6358ad94827301606a3310764eab Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Fri, 22 Sep 2017 15:27:29 -0500 Subject: [PATCH 09/10] rollback nested yaml --- bin/sippy_cup | 6 +----- sippy_cup.gemspec | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/bin/sippy_cup b/bin/sippy_cup index 2a5a57a..f154a94 100755 --- a/bin/sippy_cup +++ b/bin/sippy_cup @@ -2,7 +2,6 @@ require 'sippy_cup' require 'getoptlong' -require 'yaml_extend' def usage puts "#{$0} [OPTS] " @@ -60,10 +59,7 @@ unless compile || run exit 1 end -config = YAML.ext_load_file(manifest_path) -manifest = config.to_yaml - -scenario = SippyCup::Scenario.from_manifest manifest, input_filename: manifest_path +scenario = SippyCup::Scenario.from_manifest File.read(manifest_path), input_filename: manifest_path if scenario.valid? scenario.compile! if compile else diff --git a/sippy_cup.gemspec b/sippy_cup.gemspec index 5eef5d8..cec31cf 100644 --- a/sippy_cup.gemspec +++ b/sippy_cup.gemspec @@ -24,7 +24,6 @@ Gem::Specification.new do |s| s.add_runtime_dependency 'psych', ["~> 2.0.1"] unless RUBY_PLATFORM == 'java' s.add_runtime_dependency 'wavefile', [">= 0.8.0"] s.add_runtime_dependency 'ffi' - s.add_runtime_dependency 'yaml_extend' s.add_development_dependency 'guard-rspec' s.add_development_dependency 'rspec', ["~> 3.4"] From c2445b2ddd024eed0d8d64fb439909a84796b6c7 Mon Sep 17 00:00:00 2001 From: Jinserk Baik Date: Tue, 26 Sep 2017 11:59:04 -0500 Subject: [PATCH 10/10] change calls_per_second to call_rate and add call_period --- CHANGELOG.md | 4 ++-- README.markdown | 19 +++++++++---------- examples/navigate_ivr.yml | 2 +- examples/simple_call.yml | 2 +- examples/wait_for_call.yml | 2 +- lib/sippy_cup/runner.rb | 12 +++++++----- lib/sippy_cup/scenario.rb | 2 +- spec/sippy_cup/fixtures/test.yml | 2 +- spec/sippy_cup/runner_spec.rb | 30 +++++++++++++++--------------- spec/sippy_cup/scenario_spec.rb | 16 ++++++++-------- 10 files changed, 46 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 111a1f9..696b1c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,8 +11,8 @@ * Feature: Permit `To` domain to be different from the destination. This permits testing multi-tenant systems more easily. # [0.6.0](https://github.com/mojolingo/sippy_cup/compare/v0.5.0...v0.6.0) - * Change: Call limits (`number_of_calls`, `concurrent_max` and `calls_per_second`) no longer have default values for simplicity of UAS scenarios. The value of `to_user` now defaults to the SIPp default of `s`. - * Feature: Support for setting rate scaling independently of reporting frequency via the new `calls_per_second_interval` option. See also https://github.com/SIPp/sipp/pull/107 and https://github.com/SIPp/sipp/pull/126. + * Change: Call limits (`number_of_calls`, `concurrent_max` and `call_rate`) no longer have default values for simplicity of UAS scenarios. The value of `to_user` now defaults to the SIPp default of `s`. + * Feature: Support for setting rate scaling independently of reporting frequency via the new `call_rate_interval` option. See also https://github.com/SIPp/sipp/pull/107 and https://github.com/SIPp/sipp/pull/126. # [0.5.0](https://github.com/mojolingo/sippy_cup/compare/v0.4.1...v0.5.0) SYNTAX CHANGES! diff --git a/README.markdown b/README.markdown index 0b459d1..069200e 100644 --- a/README.markdown +++ b/README.markdown @@ -14,7 +14,6 @@ * Debug the DTMF packet generation (end of event) - reduce the duration to 200 milliseconds - change obsolete rfc2833 to rfc4733 -* Can use nested yamls, provided by yaml_extend ## Overview @@ -88,7 +87,7 @@ Using `bundle` will then install the gem dependencies and allow you to run `sipp source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 steps: - invite @@ -245,19 +244,19 @@ Each parameter has an impact on the test, and may either be changed once the XML
The total number of calls permitted for the entire test. When this limit is reached, the test is over. Defaults to nil.
concurrent_max
-
The maximum number of calls permitted to be active at any given time. When this limit is reached, SIPp will slow down or stop sending new calls until there it falls below the limit. Defaults to SIPp's default: (3 * call_duration (seconds) * calls_per_second)
+
The maximum number of calls permitted to be active at any given time. When this limit is reached, SIPp will slow down or stop sending new calls until there it falls below the limit. Defaults to SIPp's default: (3 * call_duration (seconds) * call_rate)
-
calls_per_second
+
call_rate
The rate at which new calls should be created. Note that SIPp will automatically adjust this downward to stay at or beneath the maximum number of concurrent calls (`concurrent_max`). Defaults to SIP's default of 10 -
calls_per_second_incr
-
When used with `calls_per_second_max`, tells SIPp the amount by which `calls_per_second` should be incremented. CPS rate is adjusted each `calls_per_second_interval`. Default: 1.
+
call_rate_incr
+
When used with `call_rate_max`, tells SIPp the amount by which `call_rate` should be incremented. CPS rate is adjusted each `call_rate_interval`. Default: 1.
-
calls_per_second_interval
-
When used with `calls_per_second_max`, tells SIPp the time interval (in seconds) by which calls-per-second should be incremented. Default: Unset; SIPp's default (60s). NOTE: Requires a development build of SIPp; see https://github.com/SIPp/sipp/pull/107
+
call_rate_interval
+
When used with `call_rate_max`, tells SIPp the time interval (in seconds) by which calls-per-second should be incremented. Default: Unset; SIPp's default (60s). NOTE: Requires a development build of SIPp; see https://github.com/SIPp/sipp/pull/107
-
calls_per_second_max
-
The maximum rate of calls-per-second. Default: unused (`calls_per_second` will not change)
+
call_rate_max
+
The maximum rate of calls-per-second. Default: unused (`call_rate` will not change)
advertise_address
The IP address to advertise in SIP and SDP if different from the bind IP. Default: `source` IP address
diff --git a/examples/navigate_ivr.yml b/examples/navigate_ivr.yml index a58241d..4b8f94d 100644 --- a/examples/navigate_ivr.yml +++ b/examples/navigate_ivr.yml @@ -1,7 +1,7 @@ source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 steps: - invite diff --git a/examples/simple_call.yml b/examples/simple_call.yml index b897a9e..b436d85 100644 --- a/examples/simple_call.yml +++ b/examples/simple_call.yml @@ -1,7 +1,7 @@ source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 steps: - invite diff --git a/examples/wait_for_call.yml b/examples/wait_for_call.yml index 7c4efc7..f78554d 100644 --- a/examples/wait_for_call.yml +++ b/examples/wait_for_call.yml @@ -2,7 +2,7 @@ source: 10.3.18.108 destination: 10.3.18.134 max_concurrent: 1 -calls_per_second: 1 +call_rate: 1 number_of_calls: 1 steps: - wait_for_call diff --git a/lib/sippy_cup/runner.rb b/lib/sippy_cup/runner.rb index 7ffeaa4..7f26ca1 100644 --- a/lib/sippy_cup/runner.rb +++ b/lib/sippy_cup/runner.rb @@ -105,17 +105,19 @@ def command_options max_concurrent = @scenario_options[:concurrent_max] || @scenario_options[:max_concurrent] options[:l] = max_concurrent if max_concurrent options[:m] = @scenario_options[:number_of_calls] if @scenario_options[:number_of_calls] - options[:r] = @scenario_options[:calls_per_second] if @scenario_options[:calls_per_second] + options[:r] = @scenario_options[:call_rate] if @scenario_options[:call_rate] + options[:rp] = @scenario_options[:call_period] if @scenario_options[:call_period] options[:s] = @scenario_options[:to].to_s.split('@').first if @scenario_options[:to] options[:i] = @scenario_options[:source] if @scenario_options[:source] options[:mp] = @scenario_options[:media_port] if @scenario_options[:media_port] + options[:trace_logs] = nil - if @scenario_options[:calls_per_second_max] + if @scenario_options[:call_rate_max] options[:no_rate_quit] = nil - options[:rate_max] = @scenario_options[:calls_per_second_max] - options[:rate_increase] = @scenario_options[:calls_per_second_incr] || 1 - options[:rate_interval] = @scenario_options[:calls_per_second_interval] if @scenario_options[:calls_per_second_interval] + options[:rate_max] = @scenario_options[:call_rate_max] + options[:rate_increase] = @scenario_options[:call_rate_incr] || 1 + options[:rate_interval] = @scenario_options[:call_rate_interval] if @scenario_options[:call_rate_interval] end if @scenario_options[:stats_file] diff --git a/lib/sippy_cup/scenario.rb b/lib/sippy_cup/scenario.rb index 3eb16a2..6b50d02 100644 --- a/lib/sippy_cup/scenario.rb +++ b/lib/sippy_cup/scenario.rb @@ -88,7 +88,7 @@ def self.from_manifest(manifest, options = {}) # @option options [Integer] :media_port The RTCP (media) port to bind to locally. # @option options [String, Numeric] :max_concurrent The maximum number of concurrent calls to execute. # @option options [String, Numeric] :number_of_calls The maximum number of calls to execute in the test run. - # @option options [String, Numeric] :calls_per_second The rate at which to initiate calls. + # @option options [String, Numeric] :call_rate The rate at which to initiate calls. # @option options [String] :stats_file The path at which to dump statistics. # @option options [String, Numeric] :stats_interval The interval (in seconds) at which to dump statistics (defaults to 1s). # @option options [String] :transport_mode The transport mode over which to direct SIP traffic. diff --git a/spec/sippy_cup/fixtures/test.yml b/spec/sippy_cup/fixtures/test.yml index df1acc8..0ce6b3d 100644 --- a/spec/sippy_cup/fixtures/test.yml +++ b/spec/sippy_cup/fixtures/test.yml @@ -3,7 +3,7 @@ name: My test scenario source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 steps: - invite diff --git a/spec/sippy_cup/runner_spec.rb b/spec/sippy_cup/runner_spec.rb index c1194c6..6818b32 100644 --- a/spec/sippy_cup/runner_spec.rb +++ b/spec/sippy_cup/runner_spec.rb @@ -97,7 +97,7 @@ def expect_command_execution(command = anything) destination: 'bar.com' to: 1 concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 steps: - invite @@ -124,7 +124,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 options: trace_err: ~ @@ -154,7 +154,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 source_port: 1234 steps: @@ -182,7 +182,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 from_user: pat to: frank@there.com @@ -211,7 +211,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 media_port: 6000 steps: @@ -239,7 +239,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 stats_file: stats.csv steps: @@ -266,7 +266,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 stats_file: stats.csv stats_interval: 3 @@ -310,7 +310,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 summary_report_file: report.txt steps: @@ -338,7 +338,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 errors_report_file: errors.txt steps: @@ -366,10 +366,10 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 -calls_per_second_max: 5 -calls_per_second_incr: 2 -calls_per_second_interval: 20 +call_rate: 2 +call_rate_max: 5 +call_rate_incr: 2 +call_rate_interval: 20 number_of_calls: 10 errors_report_file: errors.txt steps: @@ -397,7 +397,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 scenario_variables: /path/to/vars.csv steps: @@ -427,7 +427,7 @@ def expect_command_execution(command = anything) source: 'dah.com' destination: 'bar.com' concurrent_max: 5 -calls_per_second: 2 +call_rate: 2 number_of_calls: 10 transport_mode: t1 steps: diff --git a/spec/sippy_cup/scenario_spec.rb b/spec/sippy_cup/scenario_spec.rb index 1f7a2ea..f767378 100644 --- a/spec/sippy_cup/scenario_spec.rb +++ b/spec/sippy_cup/scenario_spec.rb @@ -713,7 +713,7 @@ source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 from_user: #{specs_from} steps: @@ -822,7 +822,7 @@ 'source' => '192.0.2.15', 'destination' => '192.0.2.200', 'max_concurrent' => 10, - 'calls_per_second' => 5, + 'call_rate' => 5, 'number_of_calls' => 20, 'from_user' => "#{specs_from}" }) @@ -835,7 +835,7 @@ source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 from_user: #{specs_from} scenario: #{scenario_path} @@ -857,7 +857,7 @@ source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 from_user: #{specs_from} scenario: #{scenario_path} @@ -881,7 +881,7 @@ source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 from_user: #{specs_from} steps: @@ -914,7 +914,7 @@ source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 from_user: #{specs_from} steps: @@ -950,7 +950,7 @@ 'source' => '192.0.2.15', 'destination' => '192.0.2.200', 'max_concurrent' => 10, - 'calls_per_second' => 5, + 'call_rate' => 5, 'number_of_calls' => override_options[:number_of_calls], 'from_user' => "#{specs_from}" }) @@ -963,7 +963,7 @@ source: 192.0.2.15 destination: 192.0.2.200 max_concurrent: 10 -calls_per_second: 5 +call_rate: 5 number_of_calls: 20 from_user: #{specs_from} steps: