Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .ruby-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.3.5
4 changes: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
95 changes: 68 additions & 27 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -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)
Expand All @@ -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
Expand All @@ -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
63 changes: 31 additions & 32 deletions include/pulseaudio_sink.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 = {}

Expand All @@ -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"]
Expand All @@ -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)
Expand All @@ -99,52 +98,52 @@ 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
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
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
def mute_toggle
self.mute = !self.muted?
return nil
end

#Sets the mute to something specific.
#===Examples
# sink.mute = true #=> nil
Expand All @@ -154,47 +153,47 @@ 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
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
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!
Expand All @@ -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
Expand Down
Loading