pulseaudio 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/bin/pulseaudio_volume.rb +0 -0
- data/gui/choose_active_sink/choose_active_sink.glade +115 -0
- data/gui/choose_active_sink/choose_active_sink.rb +85 -0
- data/include/pulseaudio_gui.rb +8 -0
- data/include/pulseaudio_sink.rb +140 -0
- data/include/pulseaudio_sink_input.rb +52 -0
- data/include/pulseaudio_source.rb +72 -0
- data/include/pulseaudio_source_output.rb +52 -0
- data/lib/pulseaudio.rb +12 -117
- data/pulseaudio.gemspec +12 -3
- data/test_scripts/choose_active_sink.rb +10 -0
- data/test_scripts/set_active.rb +25 -0
- metadata +12 -3
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.3
|
data/bin/pulseaudio_volume.rb
CHANGED
File without changes
|
@@ -0,0 +1,115 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<interface>
|
3
|
+
<requires lib="gtk+" version="2.24"/>
|
4
|
+
<!-- interface-naming-policy project-wide -->
|
5
|
+
<object class="GtkWindow" id="window">
|
6
|
+
<property name="can_focus">False</property>
|
7
|
+
<property name="title" translatable="yes">Choose active sink</property>
|
8
|
+
<property name="window_position">center</property>
|
9
|
+
<property name="default_width">440</property>
|
10
|
+
<property name="default_height">400</property>
|
11
|
+
<child>
|
12
|
+
<object class="GtkVPaned" id="vpaned1">
|
13
|
+
<property name="visible">True</property>
|
14
|
+
<property name="can_focus">True</property>
|
15
|
+
<property name="position">200</property>
|
16
|
+
<child>
|
17
|
+
<object class="GtkFrame" id="frame1">
|
18
|
+
<property name="visible">True</property>
|
19
|
+
<property name="can_focus">False</property>
|
20
|
+
<property name="label_xalign">0</property>
|
21
|
+
<property name="shadow_type">none</property>
|
22
|
+
<child>
|
23
|
+
<object class="GtkAlignment" id="alignment1">
|
24
|
+
<property name="visible">True</property>
|
25
|
+
<property name="can_focus">False</property>
|
26
|
+
<property name="left_padding">12</property>
|
27
|
+
<child>
|
28
|
+
<object class="GtkViewport" id="viewport1">
|
29
|
+
<property name="visible">True</property>
|
30
|
+
<property name="can_focus">False</property>
|
31
|
+
<child>
|
32
|
+
<object class="GtkScrolledWindow" id="scrolledwindow2">
|
33
|
+
<property name="visible">True</property>
|
34
|
+
<property name="can_focus">True</property>
|
35
|
+
<property name="hscrollbar_policy">automatic</property>
|
36
|
+
<property name="vscrollbar_policy">automatic</property>
|
37
|
+
<child>
|
38
|
+
<object class="GtkTreeView" id="tvSinks">
|
39
|
+
<property name="visible">True</property>
|
40
|
+
<property name="can_focus">True</property>
|
41
|
+
<signal name="cursor-changed" handler="on_tvSinks_cursor_changed" swapped="no"/>
|
42
|
+
</object>
|
43
|
+
</child>
|
44
|
+
</object>
|
45
|
+
</child>
|
46
|
+
</object>
|
47
|
+
</child>
|
48
|
+
</object>
|
49
|
+
</child>
|
50
|
+
<child type="label">
|
51
|
+
<object class="GtkLabel" id="label1">
|
52
|
+
<property name="visible">True</property>
|
53
|
+
<property name="can_focus">False</property>
|
54
|
+
<property name="label" translatable="yes"><b>Choose active sink</b></property>
|
55
|
+
<property name="use_markup">True</property>
|
56
|
+
</object>
|
57
|
+
</child>
|
58
|
+
</object>
|
59
|
+
<packing>
|
60
|
+
<property name="resize">False</property>
|
61
|
+
<property name="shrink">True</property>
|
62
|
+
</packing>
|
63
|
+
</child>
|
64
|
+
<child>
|
65
|
+
<object class="GtkFrame" id="frame2">
|
66
|
+
<property name="visible">True</property>
|
67
|
+
<property name="can_focus">False</property>
|
68
|
+
<property name="label_xalign">0</property>
|
69
|
+
<property name="shadow_type">none</property>
|
70
|
+
<child>
|
71
|
+
<object class="GtkAlignment" id="alignment2">
|
72
|
+
<property name="visible">True</property>
|
73
|
+
<property name="can_focus">False</property>
|
74
|
+
<property name="left_padding">12</property>
|
75
|
+
<child>
|
76
|
+
<object class="GtkViewport" id="viewport2">
|
77
|
+
<property name="visible">True</property>
|
78
|
+
<property name="can_focus">False</property>
|
79
|
+
<child>
|
80
|
+
<object class="GtkScrolledWindow" id="scrolledwindow1">
|
81
|
+
<property name="visible">True</property>
|
82
|
+
<property name="can_focus">True</property>
|
83
|
+
<property name="hscrollbar_policy">automatic</property>
|
84
|
+
<property name="vscrollbar_policy">automatic</property>
|
85
|
+
<child>
|
86
|
+
<object class="GtkTreeView" id="tvSources">
|
87
|
+
<property name="visible">True</property>
|
88
|
+
<property name="can_focus">True</property>
|
89
|
+
<signal name="cursor-changed" handler="on_tvSources_cursor_changed" swapped="no"/>
|
90
|
+
</object>
|
91
|
+
</child>
|
92
|
+
</object>
|
93
|
+
</child>
|
94
|
+
</object>
|
95
|
+
</child>
|
96
|
+
</object>
|
97
|
+
</child>
|
98
|
+
<child type="label">
|
99
|
+
<object class="GtkLabel" id="label2">
|
100
|
+
<property name="visible">True</property>
|
101
|
+
<property name="can_focus">False</property>
|
102
|
+
<property name="label" translatable="yes"><b>Choose default source</b></property>
|
103
|
+
<property name="use_markup">True</property>
|
104
|
+
</object>
|
105
|
+
</child>
|
106
|
+
</object>
|
107
|
+
<packing>
|
108
|
+
<property name="resize">True</property>
|
109
|
+
<property name="shrink">True</property>
|
110
|
+
</packing>
|
111
|
+
</child>
|
112
|
+
</object>
|
113
|
+
</child>
|
114
|
+
</object>
|
115
|
+
</interface>
|
@@ -0,0 +1,85 @@
|
|
1
|
+
class PulseAudio::Gui::Choose_active_sink
|
2
|
+
attr_reader :ui
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
require "gtk2"
|
6
|
+
require "knjrbfw"
|
7
|
+
|
8
|
+
@ui = Gtk::Builder.new.add("#{File.dirname(__FILE__)}/choose_active_sink.glade")
|
9
|
+
@ui.connect_signals{|h| method(h)}
|
10
|
+
|
11
|
+
#Init treeviews.
|
12
|
+
Knj::Gtk2::Tv.init(@ui["tvSinks"], ["ID", "Name"])
|
13
|
+
@ui["tvSinks"].columns[0].visible = false
|
14
|
+
self.reload_sinks
|
15
|
+
|
16
|
+
Knj::Gtk2::Tv.init(@ui["tvSources"], ["ID", "Name"])
|
17
|
+
@ui["tvSources"].columns[0].visible = false
|
18
|
+
self.reload_sources
|
19
|
+
|
20
|
+
@ui["window"].show_all
|
21
|
+
end
|
22
|
+
|
23
|
+
def reload_sinks
|
24
|
+
@reloading = true
|
25
|
+
@ui["tvSinks"].model.clear
|
26
|
+
PulseAudio::Sink.list do |sink|
|
27
|
+
append_data = @ui["tvSinks"].append([sink.sink_id, sink.args[:props]["description"]])
|
28
|
+
|
29
|
+
if sink.default?
|
30
|
+
@ui["tvSinks"].selection.select_iter(append_data[:iter])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
@reloading = false
|
35
|
+
end
|
36
|
+
|
37
|
+
def reload_sources
|
38
|
+
@reloading = true
|
39
|
+
|
40
|
+
@ui["tvSources"].model.clear
|
41
|
+
PulseAudio::Source.list do |source|
|
42
|
+
append_data = @ui["tvSources"].append([source.source_id, source.args[:props]["description"]])
|
43
|
+
|
44
|
+
if source.default?
|
45
|
+
@ui["tvSources"].selection.select_iter(append_data[:iter])
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
@reloading = false
|
50
|
+
end
|
51
|
+
|
52
|
+
def on_tvSinks_cursor_changed
|
53
|
+
return nil if @reloading
|
54
|
+
sel = @ui["tvSinks"].sel
|
55
|
+
return nil if !sel
|
56
|
+
|
57
|
+
sink = nil
|
58
|
+
PulseAudio::Sink.list do |sink_i|
|
59
|
+
if sink_i.sink_id.to_i == sel[0].to_i
|
60
|
+
sink = sink_i
|
61
|
+
break
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
raise "Could not find sink." if !sink
|
66
|
+
sink.default!
|
67
|
+
end
|
68
|
+
|
69
|
+
def on_tvSources_cursor_changed
|
70
|
+
return nil if @reloading
|
71
|
+
sel = @ui["tvSources"].sel
|
72
|
+
return nil if !sel
|
73
|
+
|
74
|
+
source = nil
|
75
|
+
PulseAudio::Source.list do |source_i|
|
76
|
+
if source_i.source_id.to_i == sel[0].to_i
|
77
|
+
source = source_i
|
78
|
+
break
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
raise "Could not find source." if !source
|
83
|
+
source.default!
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,140 @@
|
|
1
|
+
#Class for controlling sinks. The sinks on the sytem can be gotten by running the list-method.
|
2
|
+
#===Examples
|
3
|
+
# sinks = PulseAudio::Sink.list
|
4
|
+
# sinks.each do |sink|
|
5
|
+
# sink.vol_decr if sink.active?
|
6
|
+
# end
|
7
|
+
class PulseAudio::Sink
|
8
|
+
#The arguments-hash. Contains various data for the sink.
|
9
|
+
attr_reader :args
|
10
|
+
|
11
|
+
@@sinks = Wref_map.new
|
12
|
+
|
13
|
+
#Returns a list of sinks on the system. It also reloads information for all sinks if the information has been changed.
|
14
|
+
#===Examples
|
15
|
+
# sinks = PulseAudio::Sink.list
|
16
|
+
# sinks.each do |sink|
|
17
|
+
# sink.vol_decr if sink.active?
|
18
|
+
# end
|
19
|
+
def self.list
|
20
|
+
list = %x[pactl list sinks]
|
21
|
+
sinks = [] unless block_given?
|
22
|
+
|
23
|
+
list.scan(/(\n|^)Sink #(\d+)\s+([\s\S]+?)Formats:\s+(.+?)\n/) do |match|
|
24
|
+
props = {}
|
25
|
+
match[2].scan(/(\t|^)([A-z]+?): (.+?)\n/) do |match_prop|
|
26
|
+
props[match_prop[1].downcase] = match_prop[2]
|
27
|
+
end
|
28
|
+
|
29
|
+
sink_id = match[1].to_i
|
30
|
+
args = {:sink_id => sink_id, :props => props}
|
31
|
+
|
32
|
+
sink = @@sinks.get!(sink_id)
|
33
|
+
if !sink
|
34
|
+
sink = PulseAudio::Sink.new
|
35
|
+
@@sinks[sink_id] = sink
|
36
|
+
end
|
37
|
+
|
38
|
+
sink.update(args)
|
39
|
+
|
40
|
+
if block_given?
|
41
|
+
yield(sink)
|
42
|
+
else
|
43
|
+
sinks << sink
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
if block_given?
|
48
|
+
return nil
|
49
|
+
else
|
50
|
+
return sinks
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
#Updates the data on the object. This should not be called.
|
55
|
+
def update(args)
|
56
|
+
@args = args
|
57
|
+
end
|
58
|
+
|
59
|
+
#Returns the ID of the sink.
|
60
|
+
#===Examples
|
61
|
+
# sink.sink_id #=> 2
|
62
|
+
def sink_id
|
63
|
+
return @args[:sink_id].to_i
|
64
|
+
end
|
65
|
+
|
66
|
+
#Returns true if the sink is active. Otherwise false.
|
67
|
+
#===Examples
|
68
|
+
# sink.active? #=> true
|
69
|
+
def active?
|
70
|
+
return true if @args[:props]["state"].to_s.downcase == "running"
|
71
|
+
return false
|
72
|
+
end
|
73
|
+
|
74
|
+
#Returns true if the sink is muted. Otherwise false.
|
75
|
+
#===Examples
|
76
|
+
# sink.muted? #=> false
|
77
|
+
def muted?
|
78
|
+
return true if @args[:props]["mute"] == "yes"
|
79
|
+
return false
|
80
|
+
end
|
81
|
+
|
82
|
+
#Toggles the mute-functionality of the sink. If it is muted: unmutes. If it isnt muted: mutes.
|
83
|
+
#===Examples
|
84
|
+
# sink.mute_toggle #=> nil
|
85
|
+
def mute_toggle
|
86
|
+
self.mute = !self.muted?
|
87
|
+
return nil
|
88
|
+
end
|
89
|
+
|
90
|
+
#Sets the mute to something specific.
|
91
|
+
#===Examples
|
92
|
+
# sink.mute = true #=> nil
|
93
|
+
def mute=(val)
|
94
|
+
if val
|
95
|
+
%x[pactl set-sink-mute #{self.sink_id} 1]
|
96
|
+
else
|
97
|
+
%x[pactl set-sink-mute #{self.sink_id} 0]
|
98
|
+
end
|
99
|
+
|
100
|
+
PulseAudio::Sink.list #reload info.
|
101
|
+
return nil
|
102
|
+
end
|
103
|
+
|
104
|
+
#Increases the volume of the sink by 5%.
|
105
|
+
#===Examples
|
106
|
+
# sink.vol_incr if sink.active? #=> nil
|
107
|
+
def vol_incr
|
108
|
+
%x[pactl set-sink-volume #{self.sink_id} -- +5%]
|
109
|
+
PulseAudio::Sink.list #reload info.
|
110
|
+
return nil
|
111
|
+
end
|
112
|
+
|
113
|
+
#Decreases the volume of the sink by 5%.
|
114
|
+
#===Examples
|
115
|
+
# sink.vol_decr if sink.active? #=> nil
|
116
|
+
def vol_decr
|
117
|
+
%x[pactl set-sink-volume #{self.sink_id} -- -5%]
|
118
|
+
PulseAudio::Sink.list #reload info.
|
119
|
+
return nil
|
120
|
+
end
|
121
|
+
|
122
|
+
#Returns true if this sink is the default one.
|
123
|
+
def default?
|
124
|
+
def_str = %x[pacmd info | grep "Default sink name"]
|
125
|
+
raise "Could not match default sink." if !match = def_str.match(/^Default sink name: (.+?)\s*$/)
|
126
|
+
return true if @args[:props]["name"] == match[1]
|
127
|
+
end
|
128
|
+
|
129
|
+
#Sets this sink to be the default one. Also moves all inputs to this sink.
|
130
|
+
#===Examples
|
131
|
+
# sink.default!
|
132
|
+
def default!
|
133
|
+
PulseAudio::Sink::Input.list do |input|
|
134
|
+
input.sink = self
|
135
|
+
end
|
136
|
+
|
137
|
+
%x[pacmd set-default-sink #{self.sink_id}]
|
138
|
+
return nil
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#Class for controlling inputs.
|
2
|
+
class PulseAudio::Sink::Input
|
3
|
+
@@inputs = Wref_map.new
|
4
|
+
|
5
|
+
#Returns a list of sink-inputs.
|
6
|
+
def self.list
|
7
|
+
list = %x[pacmd list-sink-inputs]
|
8
|
+
|
9
|
+
inputs = [] unless block_given?
|
10
|
+
|
11
|
+
list.scan(/index: (\d+)/) do |match|
|
12
|
+
input_id = match[0].to_i
|
13
|
+
args = {:input_id => input_id}
|
14
|
+
|
15
|
+
input = @@inputs.get!(input_id)
|
16
|
+
if !input
|
17
|
+
input = PulseAudio::Sink::Input.new
|
18
|
+
@@inputs[input_id] = input
|
19
|
+
end
|
20
|
+
|
21
|
+
input.update(args)
|
22
|
+
|
23
|
+
if block_given?
|
24
|
+
yield(input)
|
25
|
+
else
|
26
|
+
inputs << input
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if block_given?
|
31
|
+
return nil
|
32
|
+
else
|
33
|
+
return inputs
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#Should not be called manually but through 'list'.
|
38
|
+
def update(args)
|
39
|
+
@args = args
|
40
|
+
end
|
41
|
+
|
42
|
+
#Returns the input-ID.
|
43
|
+
def input_id
|
44
|
+
return @args[:input_id]
|
45
|
+
end
|
46
|
+
|
47
|
+
#Moves the output to a new sink.
|
48
|
+
def sink=(newsink)
|
49
|
+
%x[pacmd move-sink-input #{self.input_id} #{newsink.sink_id}]
|
50
|
+
return nil
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
class PulseAudio::Source
|
2
|
+
#The arguments-hash. Contains various data for the source.
|
3
|
+
attr_reader :args
|
4
|
+
|
5
|
+
@@sources = Wref_map.new
|
6
|
+
|
7
|
+
def self.list
|
8
|
+
list = %x[pactl list sources]
|
9
|
+
sources = [] unless block_given?
|
10
|
+
|
11
|
+
list.scan(/(\n|^)Source #(\d+)\s+([\s\S]+?)Formats:\s+(.+?)\n/) do |match|
|
12
|
+
props = {}
|
13
|
+
match[2].scan(/(\t|^)([A-z]+?): (.+?)\n/) do |match_prop|
|
14
|
+
props[match_prop[1].downcase] = match_prop[2]
|
15
|
+
end
|
16
|
+
|
17
|
+
source_id = match[1].to_i
|
18
|
+
args = {:source_id => source_id, :props => props}
|
19
|
+
|
20
|
+
source = @@sources.get!(source_id)
|
21
|
+
if !source
|
22
|
+
source = PulseAudio::Source.new
|
23
|
+
@@sources[source_id] = source
|
24
|
+
end
|
25
|
+
|
26
|
+
source.update(args)
|
27
|
+
|
28
|
+
if block_given?
|
29
|
+
yield(source)
|
30
|
+
else
|
31
|
+
sources << source
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
if block_given?
|
36
|
+
return nil
|
37
|
+
else
|
38
|
+
return sources
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#Updates the data on the object. This should not be called.
|
43
|
+
def update(args)
|
44
|
+
@args = args
|
45
|
+
end
|
46
|
+
|
47
|
+
#Returns the ID of the source.
|
48
|
+
#===Examples
|
49
|
+
# source.source_id #=> 2
|
50
|
+
def source_id
|
51
|
+
return @args[:source_id].to_i
|
52
|
+
end
|
53
|
+
|
54
|
+
#Returns true if this source is the default one.
|
55
|
+
def default?
|
56
|
+
def_str = %x[pacmd info | grep "Default source name"]
|
57
|
+
raise "Could not match default source." if !match = def_str.match(/^Default source name: (.+?)\s*$/)
|
58
|
+
return true if @args[:props]["name"] == match[1]
|
59
|
+
end
|
60
|
+
|
61
|
+
#Sets this source to be the default one. Also moves all outputs to this source.
|
62
|
+
#===Examples
|
63
|
+
# source.default!
|
64
|
+
def default!
|
65
|
+
PulseAudio::Source::Output.list do |output|
|
66
|
+
output.source = self
|
67
|
+
end
|
68
|
+
|
69
|
+
%x[pacmd set-default-source #{self.source_id}]
|
70
|
+
return nil
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#Class for controlling outputs.
|
2
|
+
class PulseAudio::Source::Output
|
3
|
+
@@outputs = Wref_map.new
|
4
|
+
|
5
|
+
#Returns a list of source-outputs.
|
6
|
+
def self.list
|
7
|
+
list = %x[pacmd list-source-outputs]
|
8
|
+
|
9
|
+
outputs = [] unless block_given?
|
10
|
+
|
11
|
+
list.scan(/index: (\d+)/) do |match|
|
12
|
+
output_id = match[0].to_i
|
13
|
+
args = {:output_id => output_id}
|
14
|
+
|
15
|
+
output = @@outputs.get!(output_id)
|
16
|
+
if !output
|
17
|
+
output = PulseAudio::Source::Output.new
|
18
|
+
@@outputs[output_id] = output
|
19
|
+
end
|
20
|
+
|
21
|
+
output.update(args)
|
22
|
+
|
23
|
+
if block_given?
|
24
|
+
yield(output)
|
25
|
+
else
|
26
|
+
outputs << output
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if block_given?
|
31
|
+
return nil
|
32
|
+
else
|
33
|
+
return outputs
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
#Should not be called manually but through 'list'.
|
38
|
+
def update(args)
|
39
|
+
@args = args
|
40
|
+
end
|
41
|
+
|
42
|
+
#Returns the output-ID.
|
43
|
+
def output_id
|
44
|
+
return @args[:output_id]
|
45
|
+
end
|
46
|
+
|
47
|
+
#Moves the output to a new source.
|
48
|
+
def source=(newsource)
|
49
|
+
%x[pacmd move-source-output #{self.output_id} #{newsource.source_id}]
|
50
|
+
return nil
|
51
|
+
end
|
52
|
+
end
|
data/lib/pulseaudio.rb
CHANGED
@@ -1,120 +1,15 @@
|
|
1
|
+
require "wref"
|
2
|
+
|
1
3
|
#A framework for controlling various elements of PulseAudio in Ruby.
|
2
4
|
class PulseAudio
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
require "wref"
|
14
|
-
@@sinks = Wref_map.new
|
15
|
-
|
16
|
-
#Returns a list of sinks on the system. It also reloads information for all sinks if the information has been changed.
|
17
|
-
#===Examples
|
18
|
-
# sinks = PulseAudio::Sink.list
|
19
|
-
# sinks.each do |sink|
|
20
|
-
# sink.vol_decr if sink.active?
|
21
|
-
# end
|
22
|
-
def self.list
|
23
|
-
list = %x[pactl list sinks]
|
24
|
-
sinks = [] unless block_given?
|
25
|
-
|
26
|
-
list.scan(/(\n|^)Sink #(\d+)\s+([\s\S]+?)Formats:\s+(.+?)\n/) do |match|
|
27
|
-
props = {}
|
28
|
-
match[2].scan(/(\t|^)([A-z]+?): (.+?)\n/) do |match_prop|
|
29
|
-
props[match_prop[1].downcase] = match_prop[2]
|
30
|
-
end
|
31
|
-
|
32
|
-
sink_id = match[1].to_i
|
33
|
-
args = {:sink_id => sink_id, :props => props}
|
34
|
-
|
35
|
-
sink = @@sinks.get!(sink_id)
|
36
|
-
if !sink
|
37
|
-
sink = PulseAudio::Sink.new
|
38
|
-
@@sinks[sink_id] = sink
|
39
|
-
end
|
40
|
-
|
41
|
-
sink.update(args)
|
42
|
-
|
43
|
-
if block_given?
|
44
|
-
yield(sink)
|
45
|
-
else
|
46
|
-
sinks << sink
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
return sinks if !block_given?
|
51
|
-
end
|
52
|
-
|
53
|
-
def update(args)
|
54
|
-
@args = args
|
55
|
-
end
|
56
|
-
|
57
|
-
#Returns the ID of the sink.
|
58
|
-
#===Examples
|
59
|
-
# sink.sink_id #=> 2
|
60
|
-
def sink_id
|
61
|
-
return @args[:sink_id].to_i
|
62
|
-
end
|
63
|
-
|
64
|
-
#Returns true if the sink is active. Otherwise false.
|
65
|
-
#===Examples
|
66
|
-
# sink.active? #=> true
|
67
|
-
def active?
|
68
|
-
return true if @args[:props]["state"].to_s.downcase == "running"
|
69
|
-
return false
|
70
|
-
end
|
71
|
-
|
72
|
-
#Returns true if the sink is muted. Otherwise false.
|
73
|
-
#===Examples
|
74
|
-
# sink.muted? #=> false
|
75
|
-
def muted?
|
76
|
-
return true if @args[:props]["mute"] == "yes"
|
77
|
-
return false
|
78
|
-
end
|
79
|
-
|
80
|
-
#Toggles the mute-functionality of the sink. If it is muted: unmutes. If it isnt muted: mutes.
|
81
|
-
#===Examples
|
82
|
-
# sink.mute_toggle #=> nil
|
83
|
-
def mute_toggle
|
84
|
-
self.mute = !self.muted?
|
85
|
-
return nil
|
86
|
-
end
|
87
|
-
|
88
|
-
#Sets the mute to something specific.
|
89
|
-
#===Examples
|
90
|
-
# sink.mute = true #=> nil
|
91
|
-
def mute=(val)
|
92
|
-
if val
|
93
|
-
%x[pactl set-sink-mute #{self.sink_id} 1]
|
94
|
-
else
|
95
|
-
%x[pactl set-sink-mute #{self.sink_id} 0]
|
96
|
-
end
|
97
|
-
|
98
|
-
PulseAudio::Sink.list #reload info.
|
99
|
-
return nil
|
100
|
-
end
|
101
|
-
|
102
|
-
#Increases the volume of the sink by 5%.
|
103
|
-
#===Examples
|
104
|
-
# sink.vol_incr if sink.active? #=> nil
|
105
|
-
def vol_incr
|
106
|
-
%x[pactl set-sink-volume #{self.sink_id} -- +5%]
|
107
|
-
PulseAudio::Sink.list #reload info.
|
108
|
-
return nil
|
109
|
-
end
|
110
|
-
|
111
|
-
#Decreases the volume of the sink by 5%.
|
112
|
-
#===Examples
|
113
|
-
# sink.vol_decr if sink.active? #=> nil
|
114
|
-
def vol_decr
|
115
|
-
%x[pactl set-sink-volume #{self.sink_id} -- -5%]
|
116
|
-
PulseAudio::Sink.list #reload info.
|
117
|
-
return nil
|
118
|
-
end
|
119
|
-
end
|
5
|
+
end
|
6
|
+
|
7
|
+
dir = "#{File.dirname(__FILE__)}/../include"
|
8
|
+
files = []
|
9
|
+
Dir.foreach(dir) do |file|
|
10
|
+
files << "#{dir}/#{file}" if file.match(/\.rb$/)
|
11
|
+
end
|
12
|
+
|
13
|
+
files.sort.each do |file|
|
14
|
+
require file
|
120
15
|
end
|
data/pulseaudio.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{pulseaudio}
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Kasper Johansen"]
|
12
|
-
s.date = %q{2012-
|
12
|
+
s.date = %q{2012-06-07}
|
13
13
|
s.default_executable = %q{pulseaudio_volume.rb}
|
14
14
|
s.description = %q{Ruby-library for controlling PulseAudio via 'pactl'.}
|
15
15
|
s.email = %q{k@spernj.org}
|
@@ -28,10 +28,19 @@ Gem::Specification.new do |s|
|
|
28
28
|
"Rakefile",
|
29
29
|
"VERSION",
|
30
30
|
"bin/pulseaudio_volume.rb",
|
31
|
+
"gui/choose_active_sink/choose_active_sink.glade",
|
32
|
+
"gui/choose_active_sink/choose_active_sink.rb",
|
33
|
+
"include/pulseaudio_gui.rb",
|
34
|
+
"include/pulseaudio_sink.rb",
|
35
|
+
"include/pulseaudio_sink_input.rb",
|
36
|
+
"include/pulseaudio_source.rb",
|
37
|
+
"include/pulseaudio_source_output.rb",
|
31
38
|
"lib/pulseaudio.rb",
|
32
39
|
"pulseaudio.gemspec",
|
33
40
|
"spec/pulseaudio_spec.rb",
|
34
|
-
"spec/spec_helper.rb"
|
41
|
+
"spec/spec_helper.rb",
|
42
|
+
"test_scripts/choose_active_sink.rb",
|
43
|
+
"test_scripts/set_active.rb"
|
35
44
|
]
|
36
45
|
s.homepage = %q{http://github.com/kaspernj/pulseaudio}
|
37
46
|
s.licenses = ["MIT"]
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "#{File.dirname(__FILE__)}/../lib/pulseaudio.rb"
|
4
|
+
|
5
|
+
look_for = nil
|
6
|
+
ARGV.each do |arg|
|
7
|
+
if match = arg.match(/^--look_for=(.+)$/)
|
8
|
+
look_for = match[1]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
raise "No '--look_for=[SOMETHING]' was given." if !look_for
|
13
|
+
|
14
|
+
sink = nil
|
15
|
+
PulseAudio::Sink.list do |sink_i|
|
16
|
+
if sink_i.args[:props]["description"].index(look_for) != nil
|
17
|
+
sink = sink_i
|
18
|
+
break
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
raise "Could not find the sink by: '#{look_for}'." if !sink
|
23
|
+
|
24
|
+
print "Setting '#{sink.args[:props]["description"]}'.\n"
|
25
|
+
sink.default!
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: pulseaudio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.3
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Kasper Johansen
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-06-07 00:00:00 +02:00
|
14
14
|
default_executable: pulseaudio_volume.rb
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -98,10 +98,19 @@ files:
|
|
98
98
|
- Rakefile
|
99
99
|
- VERSION
|
100
100
|
- bin/pulseaudio_volume.rb
|
101
|
+
- gui/choose_active_sink/choose_active_sink.glade
|
102
|
+
- gui/choose_active_sink/choose_active_sink.rb
|
103
|
+
- include/pulseaudio_gui.rb
|
104
|
+
- include/pulseaudio_sink.rb
|
105
|
+
- include/pulseaudio_sink_input.rb
|
106
|
+
- include/pulseaudio_source.rb
|
107
|
+
- include/pulseaudio_source_output.rb
|
101
108
|
- lib/pulseaudio.rb
|
102
109
|
- pulseaudio.gemspec
|
103
110
|
- spec/pulseaudio_spec.rb
|
104
111
|
- spec/spec_helper.rb
|
112
|
+
- test_scripts/choose_active_sink.rb
|
113
|
+
- test_scripts/set_active.rb
|
105
114
|
has_rdoc: true
|
106
115
|
homepage: http://github.com/kaspernj/pulseaudio
|
107
116
|
licenses:
|
@@ -116,7 +125,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
116
125
|
requirements:
|
117
126
|
- - ">="
|
118
127
|
- !ruby/object:Gem::Version
|
119
|
-
hash: -
|
128
|
+
hash: -1013676805268999016
|
120
129
|
segments:
|
121
130
|
- 0
|
122
131
|
version: "0"
|