diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..cc6c9a4 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.3.5 diff --git a/Gemfile b/Gemfile index 9ba46a4..9bda059 100644 --- a/Gemfile +++ b/Gemfile @@ -4,11 +4,11 @@ source "http://rubygems.org" # gem "activesupport", ">= 2.3.5" gem "autogc" -gem "wref" +gem "wref", ">= 0.0.8" gem "gir_ffi" gem "gtk3assist" gem "gettext" -gem "knjrbfw" +gem "knjrbfw", ">= 0.0.113" # Add dependencies to develop your gem here. # Include everything needed to run rake, tests, features, etc. diff --git a/Gemfile.lock b/Gemfile.lock index e3de2cc..bf70ef1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,43 +1,74 @@ GEM remote: http://rubygems.org/ specs: + addressable (2.3.6) autogc (0.0.3) - datet (0.0.21) + builder (3.2.2) + datet (0.0.25) diff-lcs (1.1.3) - ffi (1.2.1) - gettext (2.3.7) - levenshtein - locale - gir_ffi (0.5.0) - ffi (~> 1.2.0) - indentation (~> 0.0.6) - gir_ffi-gtk (0.5.0) - gir_ffi (~> 0.5.0) - git (1.2.5) + faraday (0.8.9) + multipart-post (~> 1.2.0) + ffi (1.9.3) + gettext (3.1.3) + locale (>= 2.0.5) + text + gir_ffi (0.7.5) + ffi (~> 1.8) + indentation (~> 0.1.1) + gir_ffi-gtk (0.7.1) + gir_ffi (~> 0.7.3) + git (1.2.7) + github_api (0.10.1) + addressable + faraday (~> 0.8.1) + hashie (>= 1.2) + multi_json (~> 1.4) + nokogiri (~> 1.5.2) + oauth2 gtk3assist (0.0.9) gir_ffi-gtk xml-simple - http2 (0.0.13) - indentation (0.0.7) - jeweler (1.8.4) + hashie (3.2.0) + highline (1.6.21) + http2 (0.0.32) + string-cases (~> 0) + indentation (0.1.1) + jeweler (1.8.8) + builder bundler (~> 1.0) git (>= 1.2.5) + github_api (= 0.10.1) + highline (>= 1.6.15) + nokogiri (= 1.5.10) rake rdoc - json (1.7.7) - knjrbfw (0.0.101) + json (1.8.6) + jwt (1.0.0) + knjrbfw (0.0.113) datet http2 php4r + ruby_process tsafe - wref - levenshtein (0.2.2) - locale (2.0.8) - php4r (0.0.3) + wref (>= 0.0.8) + locale (2.1.0) + multi_json (1.10.1) + multi_xml (0.5.5) + multipart-post (1.2.0) + nokogiri (1.5.10) + oauth2 (1.0.0) + faraday (>= 0.8, < 0.10) + jwt (~> 1.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (~> 1.2) + php4r (0.0.4) datet http2 - rake (10.0.3) - rdoc (3.12.1) + string-strtr + rack (1.5.2) + rake (10.3.2) + rdoc (3.12.2) json (~> 1.4) rspec (2.8.0) rspec-core (~> 2.8.0) @@ -47,9 +78,16 @@ GEM rspec-expectations (2.8.0) diff-lcs (~> 1.1.2) rspec-mocks (2.8.0) - tsafe (0.0.11) - wref (0.0.6) - xml-simple (1.1.2) + ruby_process (0.0.13) + string-cases + tsafe + wref + string-cases (0.0.4) + string-strtr (0.0.3) + text (1.3.0) + tsafe (0.0.12) + wref (0.0.8) + xml-simple (1.1.4) PLATFORMS ruby @@ -61,7 +99,10 @@ DEPENDENCIES gir_ffi gtk3assist jeweler (~> 1.8.3) - knjrbfw + knjrbfw (>= 0.0.113) rdoc (~> 3.12) rspec (~> 2.8.0) - wref + wref (>= 0.0.8) + +BUNDLED WITH + 1.16.1 diff --git a/include/pulseaudio_sink.rb b/include/pulseaudio_sink.rb index ea11fe8..7d1da31 100644 --- a/include/pulseaudio_sink.rb +++ b/include/pulseaudio_sink.rb @@ -7,18 +7,18 @@ class PulseAudio::Sink #The arguments-hash. Contains various data for the sink. attr_reader :args - - @@sinks = Wref_map.new - + + @@sinks = Wref::Map.new + #Used to look up IDs from names (like when getting default sink). @@sink_name_to_id_ref = {} - + #Autoloader for subclasses. def self.const_missing(name) require "#{File.realpath(File.dirname(__FILE__))}/pulseaudio_sink_#{name.to_s.downcase}.rb" return PulseAudio::Sink.const_get(name) end - + #Returns a list of sinks on the system. It also reloads information for all sinks if the information has been changed. #===Examples # sinks = PulseAudio::Sink.list @@ -28,7 +28,7 @@ def self.const_missing(name) def self.list list = %x[pactl list sinks] sinks = [] unless block_given? - + list.scan(/(\n|^)Sink #(\d+)\s+([\s\S]+?)Formats:\s+(.+?)\n/) do |match| props = {} @@ -41,35 +41,34 @@ def self.list sink_internal_properties.scan(/\t([A-z]+(?:\.[A-z]+)+) = "(.+?)"\n/) do |match_prop| internal_props[match_prop[0].downcase] = match_prop[1] end - + props["internal_props"] = internal_props sink_id = match[1].to_i args = {:sink_id => sink_id, :props => props} - sink = @@sinks.get!(sink_id) if !sink sink = PulseAudio::Sink.new @@sinks[sink_id] = sink @@sink_name_to_id_ref[props["name"]] = sink_id end - + sink.update(args) - + if block_given? yield(sink) else sinks << sink end end - + if block_given? return nil else return sinks end end - + #Returns the default sink by doing a smart lookup and using the 'name-to-id-ref'-cache. def self.by_default def_str = %x[pacmd info | grep "Default sink name"] @@ -78,19 +77,19 @@ def self.by_default raise "Could not figure out sink-ID." if !sink_id return PulseAudio::Sink.by_id(sink_id.to_i) end - + #This automatically reloads a sink when a 'change'-event appears. PulseAudio::Events.instance.connect(:event => :change, :element => "sink") do |args| if @@sinks.key?(args[:args][:element_id]) and sink = @@sinks.get!(args[:args][:element_id]) sink.reload end end - + #Reloads the information on the sink. def reload PulseAudio::Sink.list #Reloads information on all sinks. end - + #Returns a sink by its sink-ID. #===Examples # sink = PulseAudio::Sink.by_id(3) @@ -99,28 +98,28 @@ def self.by_id(id) if sink = @@sinks.get!(id) return sink end - + #Read the sinks one-by-one and return it when found. PulseAudio::Sink.list do |sink| return sink if sink.sink_id == id end - + #Sink could not be found by the given ID - raise error. raise NameError, "No sink by that ID: '#{id}' (#{id.class.name})." end - + #Updates the data on the object. This should not be called. def update(args) @args = args end - + #Returns the ID of the sink. #===Examples # sink.sink_id #=> 2 def sink_id return @args[:sink_id].to_i end - + #Returns true if the sink is active. Otherwise false. #===Examples # sink.active? #=> true @@ -128,7 +127,7 @@ def active? return true if @args[:props]["state"].to_s.downcase == "running" return false end - + #Returns true if the sink is muted. Otherwise false. #===Examples # sink.muted? #=> false @@ -136,7 +135,7 @@ def muted? return true if @args[:props]["mute"] == "yes" return false end - + #Toggles the mute-functionality of the sink. If it is muted: unmutes. If it isnt muted: mutes. #===Examples # sink.mute_toggle #=> nil @@ -144,7 +143,7 @@ def mute_toggle self.mute = !self.muted? return nil end - + #Sets the mute to something specific. #===Examples # sink.mute = true #=> nil @@ -154,10 +153,10 @@ def mute=(val) else %x[pactl set-sink-mute #{self.sink_id} 0] end - + return nil end - + #Increases the volume of the sink by 5%. #===Examples # sink.vol_incr if sink.active? #=> nil @@ -165,7 +164,7 @@ def vol_incr %x[pactl set-sink-volume #{self.sink_id} -- +5%] return nil end - + #Decreases the volume of the sink by 5%. #===Examples # sink.vol_decr if sink.active? #=> nil @@ -173,28 +172,28 @@ def vol_decr %x[pactl set-sink-volume #{self.sink_id} -- -5%] return nil end - + def vol_perc=(newval) %x[pactl set-sink-volume #{self.sink_id} #{newval.to_i}%] return nil end - + #Returns the current percent of the volume. def vol_perc if match = @args[:props]["volume"].to_s.match(/(\d+):\s*(\d+)%/) return match[2].to_i end - + raise "Could not figure out the volume." end - + #Returns true if this sink is the default one. def default? def_str = %x[pacmd info | grep "Default sink name"] raise "Could not match default sink." if !match = def_str.match(/^Default sink name: (.+?)\s*$/) return true if @args[:props]["name"] == match[1] end - + #Sets this sink to be the default one. Also moves all inputs to this sink. #===Examples # sink.default! @@ -203,7 +202,7 @@ def default! PulseAudio::Sink::Input.list do |input| input.sink = self end - + %x[pacmd set-default-sink #{self.sink_id}] return nil end diff --git a/include/pulseaudio_sink_input.rb b/include/pulseaudio_sink_input.rb index 8aefe6c..c6caeeb 100644 --- a/include/pulseaudio_sink_input.rb +++ b/include/pulseaudio_sink_input.rb @@ -2,15 +2,15 @@ class PulseAudio::Sink::Input #The arguments-hash. Contains various data for the input. attr_reader :args - - @@inputs = Wref_map.new - + + @@inputs = Wref::Map.new + #Starts automatically redirect new opened inputs to the default sink. #===Examples # PulseAudio::Sink::Input.auto_redirect_new_inputs_to_default_sink def self.auto_redirect_new_inputs_to_default_sink raise "Already redirecting!" if @auto_redirect_connect_id - + @auto_redirect_connect_id = PulseAudio::Events.instance.connect(:event => :new, :element => "sink-input") do |data| begin sink_input = PulseAudio::Sink::Input.by_id(data[:args][:element_id]) @@ -20,7 +20,7 @@ def self.auto_redirect_new_inputs_to_default_sink end end end - + #Stops automatically redirecting new opened inputs to the default sink. #===Examples # PulseAudio::Sink::Input.stop_auto_redirect_new_inputs_to_default_sink @@ -29,12 +29,12 @@ def self.stop_auto_redirect_new_inputs_to_default_sink PulseAudio::Events.instance.unconnect(@auto_redirect_connect_id) @auto_redirect_connect_id = nil end - + #Returns a list of sink-inputs. def self.list list = %x[pactl list sink-inputs] inputs = [] unless block_given? - + list.scan(/(\n|^)Sink Input #(\d+)\s+([\s\S]+?)(\n\n|\Z)/) do |match| props = {} match[2].scan(/(\s+|^)([A-z]+?): (.+?)\n/) do |match_prop| @@ -62,14 +62,14 @@ def self.list inputs << input end end - + if block_given? return nil else return inputs end end - + #Returns a sink-input by its input-ID. #===Examples # sink_input = PulseAudio::Sink::Input.by_id(53) @@ -78,21 +78,21 @@ def self.by_id(id) if input = @@inputs.get!(id) return input end - + #Read the inputs one-by-one and return it when found. PulseAudio::Sink::Input.list do |input| return input if input.input_id == id end - + #Input could not be found by the given ID - raise error. raise NameError, "No sink-input by that ID: '#{id}' (#{id.class.name})." end - + #Should not be called manually but through 'list'. def update(args) @args = args end - + #Returns the name of the input as a string. def name if app_name = @args[:props]["application_name"].to_s.strip and !app_name.empty? @@ -101,25 +101,25 @@ def name raise "Could not figure out the input-name." end end - + #Returns the input-ID. def input_id return @args[:input_id] end - + #Moves the output to a new sink. def sink=(newsink) %x[pacmd move-sink-input #{self.input_id} #{newsink.sink_id}] return nil end - + #Returns true if the sink is muted. Otherwise false. #===Examples # sink.muted? #=> false def muted? @args[:props]["mute"] == "yes" end - + #Toggles the mute-functionality of the sink. If it is muted: unmutes. If it isnt muted: mutes. #===Examples # sink.mute_toggle #=> nil @@ -127,7 +127,7 @@ def mute_toggle self.mute = !self.muted? return nil end - + #Sets the mute to something specific. #===Examples # sink.mute = true #=> nil @@ -139,10 +139,10 @@ def mute=(val) %x[pactl set-sink-input-mute #{self.input_id} 0] @args[:props]["mute"] = "no" end - + return nil end - + #Increases the volume of the sink by 5%. #===Examples # sink.vol_incr if sink.active? #=> nil @@ -153,7 +153,7 @@ def vol_incr @args[:props]["volume"] = "0: #{new_vol}% 1: #{new_vol}%" return nil end - + #Decreases the volume of the sink by 5%. #===Examples # sink.vol_decr if sink.active? #=> nil @@ -164,20 +164,20 @@ def vol_decr @args[:props]["volume"] = "0: #{new_vol}% 1: #{new_vol}%" return nil end - + def vol_perc=(newval) newval = newval.to_i %x[pactl set-sink-input-volume #{self.input_id} #{newval}%] @args[:props]["volume"] = "0: #{newval}% 1: #{newval}%" return nil end - + #Returns the current percent of the volume. def vol_perc if match = @args[:props]["volume"].to_s.match(/(\d+):\s*([\d\.]+)%/) return match[2].to_i end - + raise "Could not figure out the volume from properties: '#{@args[:props]}'." end diff --git a/include/pulseaudio_source.rb b/include/pulseaudio_source.rb index 64bf027..ff922ff 100644 --- a/include/pulseaudio_source.rb +++ b/include/pulseaudio_source.rb @@ -1,52 +1,52 @@ class PulseAudio::Source #The arguments-hash. Contains various data for the source. attr_reader :args - - @@sources = Wref_map.new + + @@sources = Wref::Map.new @@sources_name_to_id_ref = {} - + #Autoloader for subclasses. def self.const_missing(name) require "#{File.realpath(File.dirname(__FILE__))}/pulseaudio_source_#{name.to_s.downcase}.rb" return PulseAudio::Source.const_get(name) end - + def self.list list = %x[pactl list sources] sources = [] unless block_given? - + list.scan(/(\n|^)Source #(\d+)\s+([\s\S]+?)Formats:\s+(.+?)\n/) do |match| props = {} match[2].scan(/(\t|^)([A-z]+?): (.+?)\n/) do |match_prop| props[match_prop[1].downcase] = match_prop[2] end - + source_id = match[1].to_i args = {:source_id => source_id, :props => props} - + source = @@sources.get!(source_id) if !source source = PulseAudio::Source.new @@sources[source_id] = source @@sources_name_to_id_ref[props["name"]] = source_id end - + source.update(args) - + if block_given? yield(source) else sources << source end end - + if block_given? return nil else return sources end end - + #Returns the default source by doing a smart lookup and using the 'name-to-id-ref'-cache. def self.by_default def_str = %x[pacmd info | grep "Default source name"] @@ -55,7 +55,7 @@ def self.by_default raise "Could not figure out source-ID." if !source_id return PulseAudio::Source.by_id(source_id.to_i) end - + #Returns a source by its source-ID. #===Examples # source = PulseAudio::Source.by_id(3) @@ -64,33 +64,33 @@ def self.by_id(id) if source = @@sources.get!(id) return source end - + #Read the sources one-by-one and return it when found. PulseAudio::Source.list do |source| return source if source.source_id == id end - + #Source could not be found by the given ID - raise error. raise NameError, "No source by that ID: '#{id}' (#{id.class.name})." end - + #This automatically reloads a source when a 'change'-event appears. PulseAudio::Events.instance.connect(:event => :change, :element => "source") do |args| if @@sources.key?(args[:args][:element_id]) and source = @@sources.get!(args[:args][:element_id]) source.reload end end - + #Reloads the information on the source. def reload PulseAudio::Source.list #Reloads info on all sources. end - + #Updates the data on the object. This should not be called. def update(args) @args = args end - + #Returns true if the source is muted. Otherwise false. #===Examples # source.muted? #=> false @@ -98,7 +98,7 @@ def muted? return true if @args[:props]["mute"] == "yes" return false end - + #Toggles the mute-functionality of the source. If it is muted: unmutes. If it isnt muted: mutes. #===Examples # source.mute_toggle #=> nil @@ -106,7 +106,7 @@ def mute_toggle self.mute = !self.muted? return nil end - + #Sets the mute to something specific. #===Examples # source.mute = true #=> nil @@ -116,10 +116,10 @@ def mute=(val) else %x[pactl set-source-mute #{self.source_id} 0] end - + return nil end - + #Increases the volume of the source by 5%. #===Examples # source.vol_incr if source.active? #=> nil @@ -127,7 +127,7 @@ def vol_incr %x[pactl set-source-volume #{self.source_id} -- +5%] return nil end - + #Decreases the volume of the source by 5%. #===Examples # source.vol_decr if source.active? #=> nil @@ -135,35 +135,35 @@ def vol_decr %x[pactl set-source-volume #{self.source_id} -- -5%] return nil end - + def vol_perc=(newval) %x[pactl set-source-volume #{self.source_id} #{newval.to_i}%] return nil end - + #Returns the current percent of the volume. def vol_perc if match = @args[:props]["volume"].to_s.match(/(\d+):\s*(\d+)%/) return match[2].to_i end - + raise "Could not figure out the volume." end - + #Returns the ID of the source. #===Examples # source.source_id #=> 2 def source_id return @args[:source_id].to_i end - + #Returns true if this source is the default one. def default? def_str = %x[pacmd info | grep "Default source name"] raise "Could not match default source." if !match = def_str.match(/^Default source name: (.+?)\s*$/) return true if @args[:props]["name"] == match[1] end - + #Sets this source to be the default one. Also moves all outputs to this source. #===Examples # source.default! @@ -171,7 +171,7 @@ def default! PulseAudio::Source::Output.list do |output| output.source = self end - + %x[pacmd set-default-source #{self.source_id}] return nil end diff --git a/include/pulseaudio_source_output.rb b/include/pulseaudio_source_output.rb index 1f4005b..765a751 100644 --- a/include/pulseaudio_source_output.rb +++ b/include/pulseaudio_source_output.rb @@ -1,13 +1,13 @@ #Class for controlling outputs. class PulseAudio::Source::Output - @@outputs = Wref_map.new - + @@outputs = Wref::Map.new + #Starts automatically redirect new opened outputs to the default source. #===Examples # PulseAudio::Source::Output.auto_redirect_new_outputs_to_default_source def self.auto_redirect_new_outputs_to_default_source raise "Already redirecting!" if @auto_redirect_connect_id - + @auto_redirect_connect_id = PulseAudio::Events.instance.connect(:event => :new, :element => "source-output") do |data| begin source_output = PulseAudio::Source::Output.by_id(data[:args][:element_id]) @@ -17,7 +17,7 @@ def self.auto_redirect_new_outputs_to_default_source end end end - + #Stops automatically redirecting new opened outputs to the default source. #===Examples # PulseAudio::Source::Output.stop_auto_redirect_new_outputs_to_default_source @@ -26,49 +26,49 @@ def self.stop_auto_redirect_new_outputs_to_default_source PulseAudio::Events.instance.unconnect(@auto_redirect_connect_id) @auto_redirect_connect_id = nil end - + #Returns a list of source-outputs. def self.list list = %x[pacmd list-source-outputs] - + outputs = [] unless block_given? - + list.scan(/index: (\d+)/) do |match| output_id = match[0].to_i args = {:output_id => output_id} - + output = @@outputs.get!(output_id) if !output output = PulseAudio::Source::Output.new @@outputs[output_id] = output end - + output.update(args) - + if block_given? yield(output) else outputs << output end end - + if block_given? return nil else return outputs end end - + #Should not be called manually but through 'list'. def update(args) @args = args end - + #Returns the output-ID. def output_id return @args[:output_id] end - + #Moves the output to a new source. def source=(newsource) %x[pacmd move-source-output #{self.output_id} #{newsource.source_id}] diff --git a/peak_flow.yml b/peak_flow.yml new file mode 100644 index 0000000..0790e31 --- /dev/null +++ b/peak_flow.yml @@ -0,0 +1,4 @@ +before_script: + - sudo apt-get install -y pulseaudio pulseaudio-utils +script: + - bundle exec rspec diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a562fd7..349c38f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -8,5 +8,4 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f} RSpec.configure do |config| - end