Merge lp:~xavi-garcia-mena/indicator-sound/sync-vivid-wily into lp:indicator-sound/15.04
- sync-vivid-wily
- Merge into trunk.15.04
Proposed by
Xavi Garcia
Status: | Merged |
---|---|
Approved by: | Xavi Garcia |
Approved revision: | 501 |
Merged at revision: | 497 |
Proposed branch: | lp:~xavi-garcia-mena/indicator-sound/sync-vivid-wily |
Merge into: | lp:indicator-sound/15.04 |
Diff against target: |
1204 lines (+616/-182) 10 files modified
data/com.canonical.indicator.sound.gschema.xml (+63/-0) debian/changelog (+42/-0) src/service.vala (+180/-132) src/volume-control-pulse.vala (+162/-15) src/volume-control.vala (+13/-1) tests/CMakeLists.txt (+1/-1) tests/media-player-user.cc (+138/-22) tests/notifications-test.cc (+8/-8) tests/volume-control-mock.vala (+4/-2) tests/volume-control-test.cc (+5/-1) |
To merge this branch: | bzr merge lp:~xavi-garcia-mena/indicator-sound/sync-vivid-wily |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Charles Kerr (community) | Approve | ||
Xavi Garcia | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email: mp+273230@code.launchpad.net |
Commit message
Sync vivid and wily branches
Description of the change
Sync vivid and wily branches
To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : | # |
review:
Approve
(continuous-integration)
Revision history for this message
Xavi Garcia (xavi-garcia-mena) wrote : | # |
Approving as it is just a merge of commits from wily.
Source code should be in sync now with wily.
review:
Approve
- 502. By Xavi Garcia
-
fixed version number in changelog
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'data/com.canonical.indicator.sound.gschema.xml' | |||
2 | --- data/com.canonical.indicator.sound.gschema.xml 2014-12-03 15:12:01 +0000 | |||
3 | +++ data/com.canonical.indicator.sound.gschema.xml 2015-10-13 13:18:26 +0000 | |||
4 | @@ -39,5 +39,68 @@ | |||
5 | 39 | Whether or not to show the sound indicator in the menu bar. | 39 | Whether or not to show the sound indicator in the menu bar. |
6 | 40 | </description> | 40 | </description> |
7 | 41 | </key> | 41 | </key> |
8 | 42 | |||
9 | 43 | <!-- VOLUME --> | ||
10 | 44 | |||
11 | 45 | <key name="warning-volume-enabled" type="b"> | ||
12 | 46 | <default>true</default> | ||
13 | 47 | <summary>Whether or not to show high volume warnings.</summary> | ||
14 | 48 | <description> | ||
15 | 49 | If enabled on a device, a confirmation dialog will be presented to the user if | ||
16 | 50 | (a) something is plugged into the headphone jack (ie, no warnings for speaker volumes) AND | ||
17 | 51 | (b) media is playing (ie, no warnings for ringtone volumes) AND | ||
18 | 52 | (c) the user attempts to set the volume higher than warning-volume-decibels AND | ||
19 | 53 | (d) the user has not indicated approval in the last warning-volume-approval-ttl seconds. | ||
20 | 54 | </description> | ||
21 | 55 | </key> | ||
22 | 56 | <key name="warning-volume-confirmation-ttl" type="i"> | ||
23 | 57 | <default>72000</default> | ||
24 | 58 | <summary>How many seconds a user's warning-volume approval should be remembered.</summary> | ||
25 | 59 | <description> | ||
26 | 60 | How long to remember a user's approval of the confirmation dialog discussed in the | ||
27 | 61 | description of 'warning-volume-enabled'. | ||
28 | 62 | |||
29 | 63 | The default value (72,000 seconds) corresponds to the 20 hours suggested by | ||
30 | 64 | EU standard EN 60950-1/Al2: “The acknowledgement does not need to be repeated | ||
31 | 65 | more than once every 20 h of cumulative listening time.” | ||
32 | 66 | </description> | ||
33 | 67 | </key> | ||
34 | 68 | <key name="warning-volume-decibels" type="d"> | ||
35 | 69 | <default>-8.0</default> | ||
36 | 70 | <summary>Volume level that triggers a high volume warning.</summary> | ||
37 | 71 | <description> | ||
38 | 72 | Volume level that triggers a high volume warning. | ||
39 | 73 | See warning-volume-enabled for details. | ||
40 | 74 | </description> | ||
41 | 75 | </key> | ||
42 | 76 | |||
43 | 77 | <key name="normal-volume-decibels" type="d"> | ||
44 | 78 | <default>0</default> | ||
45 | 79 | <summary>Normal output volume.</summary> | ||
46 | 80 | <description> | ||
47 | 81 | The maximum volume when com.ubuntu.sound's 'allow-amplified-volume' setting is disabled. | ||
48 | 82 | |||
49 | 83 | To conform with EU standard EN 60950-1/Al2, this value should never be | ||
50 | 84 | set to a dB that causes headphone sound output to exceed 100 dBA, nor | ||
51 | 85 | electric output to exceed 150 mV. | ||
52 | 86 | |||
53 | 87 | The default value (0) corresponds to PulseAudio's PA_VOLUME_NORM. | ||
54 | 88 | </description> | ||
55 | 89 | </key> | ||
56 | 90 | |||
57 | 91 | <key name="amplified-volume-decibels" type="d"> | ||
58 | 92 | <default>11</default> | ||
59 | 93 | <summary>Output volume to use when com.ubuntu.sound's 'allow-amplified-volume' setting is enabled.</summary> | ||
60 | 94 | <description> | ||
61 | 95 | The maximum volume when com.ubuntu.sound's 'allow-amplified-volume' setting is enabled. | ||
62 | 96 | |||
63 | 97 | To conform with EU standard EN 60950-1/Al2, this value should never be | ||
64 | 98 | set to a dB that causes headphone sound output to exceed 100 dBA, nor | ||
65 | 99 | electric output to exceed 150 mV. | ||
66 | 100 | |||
67 | 101 | The default value (11) corresponds to PulseAudio's PA_VOLUME_UI_MAX. | ||
68 | 102 | </description> | ||
69 | 103 | </key> | ||
70 | 104 | |||
71 | 42 | </schema> | 105 | </schema> |
72 | 43 | </schemalist> | 106 | </schemalist> |
73 | 44 | 107 | ||
74 | === modified file 'debian/changelog' | |||
75 | --- debian/changelog 2015-05-08 12:20:07 +0000 | |||
76 | +++ debian/changelog 2015-10-13 13:18:26 +0000 | |||
77 | @@ -1,3 +1,45 @@ | |||
78 | 1 | indicator-sound (12.10.2+15.04.20150812.3-0ubuntu1) vivid; urgency=medium | ||
79 | 2 | |||
80 | 3 | [ CI Train Bot ] | ||
81 | 4 | * New rebuild forced. | ||
82 | 5 | |||
83 | 6 | [ Charles Kerr ] | ||
84 | 7 | * When showing a "Loud volumes can damage your hearing" confirmation | ||
85 | 8 | warning, clamp the volume until the user hits "OK". (LP: #1481913) | ||
86 | 9 | |||
87 | 10 | -- CI Train Bot <ci-train-bot@canonical.com> Wed, 12 Aug 2015 20:55:05 +0000 | ||
88 | 11 | |||
89 | 12 | indicator-sound (12.10.2+15.04.20150807.6-0ubuntu1) vivid; urgency=medium | ||
90 | 13 | |||
91 | 14 | [ CI Train Bot ] | ||
92 | 15 | * New rebuild forced. | ||
93 | 16 | |||
94 | 17 | [ Charles Kerr ] | ||
95 | 18 | * Revised UI volume warnings to comply with EU requirements. (LP: | ||
96 | 19 | #1481913) | ||
97 | 20 | |||
98 | 21 | -- CI Train Bot <ci-train-bot@canonical.com> Fri, 07 Aug 2015 22:35:58 +0000 | ||
99 | 22 | |||
100 | 23 | indicator-sound (12.10.2+15.04.20150605-0ubuntu1) vivid; urgency=medium | ||
101 | 24 | |||
102 | 25 | * | ||
103 | 26 | |||
104 | 27 | -- CI Train Bot <ci-train-bot@canonical.com> Fri, 05 Jun 2015 19:50:06 +0000 | ||
105 | 28 | |||
106 | 29 | indicator-sound (12.10.2+15.04.20150507+eventually4-0ubuntu1) vivid; urgency=medium | ||
107 | 30 | |||
108 | 31 | * Using eventually to avoid arbitrary timeouts in tests | ||
109 | 32 | |||
110 | 33 | -- Ted Gould <ted@ubuntu.com> Wed, 27 May 2015 11:11:19 -0500 | ||
111 | 34 | |||
112 | 35 | indicator-sound (12.10.2+15.04.20150507-0ubuntu1) vivid; urgency=medium | ||
113 | 36 | |||
114 | 37 | [ Charles Kerr ] | ||
115 | 38 | * Use the BusWatcher to look for org.freedesktop.Notifications | ||
116 | 39 | ownership changes on the bus. (LP: #1432446) | ||
117 | 40 | |||
118 | 41 | -- CI Train Bot <ci-train-bot@canonical.com> Thu, 07 May 2015 15:27:00 +0000 | ||
119 | 42 | |||
120 | 1 | indicator-sound (12.10.2+15.04.20150508-0ubuntu1) vivid; urgency=medium | 43 | indicator-sound (12.10.2+15.04.20150508-0ubuntu1) vivid; urgency=medium |
121 | 2 | 44 | ||
122 | 3 | [ CI Train Bot ] | 45 | [ CI Train Bot ] |
123 | 4 | 46 | ||
124 | === modified file 'src/service.vala' | |||
125 | --- src/service.vala 2015-04-20 21:02:32 +0000 | |||
126 | +++ src/service.vala 2015-10-13 13:18:26 +0000 | |||
127 | @@ -20,6 +20,13 @@ | |||
128 | 20 | public class IndicatorSound.Service: Object { | 20 | public class IndicatorSound.Service: Object { |
129 | 21 | DBusConnection bus; | 21 | DBusConnection bus; |
130 | 22 | 22 | ||
131 | 23 | /** | ||
132 | 24 | * A copy of volume_control.volume made before just warn_notification | ||
133 | 25 | * is shown. Since the volume is clamped during the warning, we cache | ||
134 | 26 | * the previous volume to use iff the user hits "OK". | ||
135 | 27 | */ | ||
136 | 28 | VolumeControl.Volume _pre_warn_volume = null; | ||
137 | 29 | |||
138 | 23 | public Service (MediaPlayerList playerlist, VolumeControl volume, AccountsServiceUser? accounts) { | 30 | public Service (MediaPlayerList playerlist, VolumeControl volume, AccountsServiceUser? accounts) { |
139 | 24 | try { | 31 | try { |
140 | 25 | bus = Bus.get_sync(GLib.BusType.SESSION); | 32 | bus = Bus.get_sync(GLib.BusType.SESSION); |
141 | @@ -27,14 +34,19 @@ | |||
142 | 27 | error("Unable to get DBus session bus: %s", e.message); | 34 | error("Unable to get DBus session bus: %s", e.message); |
143 | 28 | } | 35 | } |
144 | 29 | 36 | ||
146 | 30 | sync_notification = new Notify.Notification(_("Volume"), "", "audio-volume-muted"); | 37 | info_notification = new Notify.Notification(_("Volume"), "", "audio-volume-muted"); |
147 | 38 | |||
148 | 39 | warn_notification = new Notify.Notification(_("Volume"), _("High volume can damage your hearing."), "audio-volume-high"); | ||
149 | 40 | warn_notification.set_hint ("x-canonical-non-shaped-icon", "true"); | ||
150 | 41 | warn_notification.set_hint ("x-canonical-snap-decisions", "true"); | ||
151 | 42 | warn_notification.set_hint ("x-canonical-private-affirmative-tint", "true"); | ||
152 | 43 | warn_notification.closed.connect((n) => { n.clear_actions(); }); | ||
153 | 31 | BusWatcher.watch_namespace (GLib.BusType.SESSION, | 44 | BusWatcher.watch_namespace (GLib.BusType.SESSION, |
154 | 32 | "org.freedesktop.Notifications", | 45 | "org.freedesktop.Notifications", |
157 | 33 | () => { debug("Notifications name appeared"); check_sync_notification = false; }, | 46 | () => { debug("Notifications name appeared"); notify_server_caps_checked = false; }, |
158 | 34 | () => { debug("Notifications name vanshed"); check_sync_notification = false; }); | 47 | () => { debug("Notifications name vanshed"); notify_server_caps_checked = false; }); |
159 | 35 | 48 | ||
160 | 36 | this.settings = new Settings ("com.canonical.indicator.sound"); | 49 | this.settings = new Settings ("com.canonical.indicator.sound"); |
161 | 37 | this.sharedsettings = new Settings ("com.ubuntu.sound"); | ||
162 | 38 | 50 | ||
163 | 39 | this.settings.bind ("visible", this, "visible", SettingsBindFlags.GET); | 51 | this.settings.bind ("visible", this, "visible", SettingsBindFlags.GET); |
164 | 40 | this.notify["visible"].connect ( () => this.update_root_icon () ); | 52 | this.notify["visible"].connect ( () => this.update_root_icon () ); |
165 | @@ -83,19 +95,13 @@ | |||
166 | 83 | this.sync_preferred_players (); | 95 | this.sync_preferred_players (); |
167 | 84 | }); | 96 | }); |
168 | 85 | 97 | ||
169 | 86 | sharedsettings.bind ("allow-amplified-volume", this, "allow-amplified-volume", SettingsBindFlags.GET); | ||
170 | 87 | |||
171 | 88 | /* Hide the notification when the menu is shown */ | 98 | /* Hide the notification when the menu is shown */ |
172 | 89 | var shown_action = actions.lookup_action ("indicator-shown") as SimpleAction; | 99 | var shown_action = actions.lookup_action ("indicator-shown") as SimpleAction; |
173 | 90 | shown_action.change_state.connect ((state) => { | 100 | shown_action.change_state.connect ((state) => { |
176 | 91 | block_notifications = state.get_boolean(); | 101 | block_info_notifications = state.get_boolean(); |
177 | 92 | if (block_notifications) { | 102 | if (block_info_notifications) { |
178 | 93 | debug("Indicator is shown"); | 103 | debug("Indicator is shown"); |
184 | 94 | try { | 104 | close_notification(info_notification); |
180 | 95 | sync_notification.close(); | ||
181 | 96 | } catch (Error e) { | ||
182 | 97 | warning("Unable to close synchronous volume notification: %s", e.message); | ||
183 | 98 | } | ||
185 | 99 | } else { | 105 | } else { |
186 | 100 | debug("Indicator is hidden"); | 106 | debug("Indicator is hidden"); |
187 | 101 | } | 107 | } |
188 | @@ -111,11 +117,33 @@ | |||
189 | 111 | this.menus.@foreach ( (profile, menu) => menu.export (bus, @"/com/canonical/indicator/sound/$profile")); | 117 | this.menus.@foreach ( (profile, menu) => menu.export (bus, @"/com/canonical/indicator/sound/$profile")); |
190 | 112 | } | 118 | } |
191 | 113 | 119 | ||
192 | 120 | private void close_notification(Notify.Notification? n) { | ||
193 | 121 | return_if_fail (n != null); | ||
194 | 122 | if (n.id != 0) { | ||
195 | 123 | try { | ||
196 | 124 | n.close(); | ||
197 | 125 | } catch (GLib.Error e) { | ||
198 | 126 | warning("Unable to close notification: %s", e.message); | ||
199 | 127 | } | ||
200 | 128 | } | ||
201 | 129 | } | ||
202 | 130 | |||
203 | 131 | private void show_notification(Notify.Notification? n) { | ||
204 | 132 | return_if_fail (n != null); | ||
205 | 133 | try { | ||
206 | 134 | n.show (); | ||
207 | 135 | } catch (GLib.Error e) { | ||
208 | 136 | warning ("Unable to show notification: %s", e.message); | ||
209 | 137 | } | ||
210 | 138 | } | ||
211 | 139 | |||
212 | 114 | ~Service() { | 140 | ~Service() { |
213 | 115 | debug("Destroying Service Object"); | 141 | debug("Destroying Service Object"); |
214 | 116 | 142 | ||
215 | 117 | clear_acts_player(); | 143 | clear_acts_player(); |
216 | 118 | 144 | ||
217 | 145 | stop_clamp_to_high_timeout(); | ||
218 | 146 | |||
219 | 119 | if (this.player_action_update_id > 0) { | 147 | if (this.player_action_update_id > 0) { |
220 | 120 | Source.remove (this.player_action_update_id); | 148 | Source.remove (this.player_action_update_id); |
221 | 121 | this.player_action_update_id = 0; | 149 | this.player_action_update_id = 0; |
222 | @@ -145,28 +173,6 @@ | |||
223 | 145 | 173 | ||
224 | 146 | public bool visible { get; set; } | 174 | public bool visible { get; set; } |
225 | 147 | 175 | ||
226 | 148 | public bool allow_amplified_volume { | ||
227 | 149 | get { | ||
228 | 150 | return this.max_volume > 1.0; | ||
229 | 151 | } | ||
230 | 152 | |||
231 | 153 | set { | ||
232 | 154 | if (this.allow_amplified_volume == value) | ||
233 | 155 | return; | ||
234 | 156 | |||
235 | 157 | if (value) { | ||
236 | 158 | /* from pulse/volume.h: #define PA_VOLUME_UI_MAX (pa_sw_volume_from_dB(+11.0)) */ | ||
237 | 159 | this.max_volume = (double)PulseAudio.Volume.sw_from_dB(11.0) / PulseAudio.Volume.NORM; | ||
238 | 160 | } | ||
239 | 161 | else { | ||
240 | 162 | this.max_volume = 1.0; | ||
241 | 163 | } | ||
242 | 164 | |||
243 | 165 | /* Normalize volume, because the volume action's state is [0.0, 1.0], see create_volume_action() */ | ||
244 | 166 | this.actions.change_action_state ("volume", this.volume_control.volume.volume / this.max_volume); | ||
245 | 167 | } | ||
246 | 168 | } | ||
247 | 169 | |||
248 | 170 | const ActionEntry[] action_entries = { | 176 | const ActionEntry[] action_entries = { |
249 | 171 | { "root", null, null, "@a{sv} {}", null }, | 177 | { "root", null, null, "@a{sv} {}", null }, |
250 | 172 | { "scroll", activate_scroll_action, "i", null, null }, | 178 | { "scroll", activate_scroll_action, "i", null, null }, |
251 | @@ -178,7 +184,6 @@ | |||
252 | 178 | SimpleActionGroup actions; | 184 | SimpleActionGroup actions; |
253 | 179 | HashTable<string, SoundMenu> menus; | 185 | HashTable<string, SoundMenu> menus; |
254 | 180 | Settings settings; | 186 | Settings settings; |
255 | 181 | Settings sharedsettings; | ||
256 | 182 | VolumeControl volume_control; | 187 | VolumeControl volume_control; |
257 | 183 | MediaPlayerList players; | 188 | MediaPlayerList players; |
258 | 184 | uint player_action_update_id; | 189 | uint player_action_update_id; |
259 | @@ -187,28 +192,27 @@ | |||
260 | 187 | bool syncing_preferred_players = false; | 192 | bool syncing_preferred_players = false; |
261 | 188 | AccountsServiceUser? accounts_service = null; | 193 | AccountsServiceUser? accounts_service = null; |
262 | 189 | bool export_to_accounts_service = false; | 194 | bool export_to_accounts_service = false; |
269 | 190 | private Notify.Notification sync_notification; | 195 | private Notify.Notification info_notification; |
270 | 191 | 196 | private Notify.Notification warn_notification; | |
265 | 192 | /* Maximum volume as a scaling factor between the volume action's state and the value in | ||
266 | 193 | * this.volume_control. See create_volume_action(). | ||
267 | 194 | */ | ||
268 | 195 | double max_volume = 1.0; | ||
271 | 196 | 197 | ||
272 | 197 | const double volume_step_percentage = 0.06; | 198 | const double volume_step_percentage = 0.06; |
273 | 198 | 199 | ||
275 | 199 | void activate_scroll_action (SimpleAction action, Variant? param) { | 200 | private void activate_scroll_action (SimpleAction action, Variant? param) { |
276 | 200 | int delta = param.get_int32(); /* positive for up, negative for down */ | 201 | int delta = param.get_int32(); /* positive for up, negative for down */ |
283 | 201 | 202 | double v = volume_control.volume.volume + volume_step_percentage * delta; | |
284 | 202 | var scrollvol = new VolumeControl.Volume(); | 203 | volume_control.set_volume_clamp (v, VolumeControl.VolumeReasons.USER_KEYPRESS); |
279 | 203 | double v = this.volume_control.volume.volume + volume_step_percentage * delta; | ||
280 | 204 | scrollvol.volume = v.clamp (0.0, this.max_volume); | ||
281 | 205 | scrollvol.reason = VolumeControl.VolumeReasons.USER_KEYPRESS; | ||
282 | 206 | this.volume_control.volume = scrollvol; | ||
285 | 207 | } | 204 | } |
286 | 208 | 205 | ||
287 | 209 | void activate_desktop_settings (SimpleAction action, Variant? param) { | 206 | void activate_desktop_settings (SimpleAction action, Variant? param) { |
288 | 210 | var env = Environment.get_variable ("DESKTOP_SESSION"); | 207 | var env = Environment.get_variable ("DESKTOP_SESSION"); |
289 | 211 | string cmd; | 208 | string cmd; |
290 | 209 | |||
291 | 210 | if (Environment.get_variable ("MIR_SOCKET") != null) | ||
292 | 211 | { | ||
293 | 212 | UrlDispatch.send ("settings:///system/sound"); | ||
294 | 213 | return; | ||
295 | 214 | } | ||
296 | 215 | |||
297 | 212 | if (env == "xubuntu" || env == "ubuntustudio") | 216 | if (env == "xubuntu" || env == "ubuntustudio") |
298 | 213 | cmd = "pavucontrol"; | 217 | cmd = "pavucontrol"; |
299 | 214 | else if (env == "mate") | 218 | else if (env == "mate") |
300 | @@ -242,12 +246,10 @@ | |||
301 | 242 | void update_root_icon () { | 246 | void update_root_icon () { |
302 | 243 | double volume = this.volume_control.volume.volume; | 247 | double volume = this.volume_control.volume.volume; |
303 | 244 | string icon; | 248 | string icon; |
305 | 245 | if (this.volume_control.mute) | 249 | if (this.volume_control.mute || volume <= 0.0) |
306 | 246 | icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; | 250 | icon = this.mute_blocks_sound ? "audio-volume-muted-blocking-panel" : "audio-volume-muted-panel"; |
307 | 247 | else if (this.accounts_service != null && this.accounts_service.silentMode) | 251 | else if (this.accounts_service != null && this.accounts_service.silentMode) |
308 | 248 | icon = "audio-volume-muted-panel"; | 252 | icon = "audio-volume-muted-panel"; |
309 | 249 | else if (volume <= 0.0) | ||
310 | 250 | icon = "audio-volume-low-zero-panel"; | ||
311 | 251 | else if (volume <= 0.3) | 253 | else if (volume <= 0.3) |
312 | 252 | icon = "audio-volume-low-panel"; | 254 | icon = "audio-volume-low-panel"; |
313 | 253 | else if (volume <= 0.7) | 255 | else if (volume <= 0.7) |
314 | @@ -275,60 +277,83 @@ | |||
315 | 275 | root_action.set_state (builder.end()); | 277 | root_action.set_state (builder.end()); |
316 | 276 | } | 278 | } |
317 | 277 | 279 | ||
325 | 278 | private bool check_sync_notification = false; | 280 | private bool notify_server_caps_checked = false; |
326 | 279 | private bool support_sync_notification = false; | 281 | private bool notify_server_supports_actions = false; |
327 | 280 | private bool block_notifications = false; | 282 | private bool notify_server_supports_sync = false; |
328 | 281 | 283 | private bool block_info_notifications = false; | |
329 | 282 | void update_sync_notification () { | 284 | |
330 | 283 | if (!check_sync_notification) { | 285 | private void update_notification () { |
331 | 284 | support_sync_notification = false; | 286 | |
332 | 287 | if (!notify_server_caps_checked) { | ||
333 | 285 | List<string> caps = Notify.get_server_caps (); | 288 | List<string> caps = Notify.get_server_caps (); |
338 | 286 | if (caps.find_custom ("x-canonical-private-synchronous", strcmp) != null) { | 289 | notify_server_supports_actions = caps.find_custom ("actions", strcmp) != null; |
339 | 287 | support_sync_notification = true; | 290 | notify_server_supports_sync = caps.find_custom ("x-canonical-private-synchronous", strcmp) != null; |
340 | 288 | } | 291 | notify_server_caps_checked = true; |
337 | 289 | check_sync_notification = true; | ||
341 | 290 | } | 292 | } |
342 | 291 | 293 | ||
383 | 292 | if (!support_sync_notification) | 294 | var loud = volume_control.high_volume; |
384 | 293 | return; | 295 | var warn = loud |
385 | 294 | 296 | && this.notify_server_supports_actions | |
386 | 295 | if (block_notifications) | 297 | && !this.volume_control.high_volume_approved; |
387 | 296 | return; | 298 | |
388 | 297 | 299 | if (warn) { | |
389 | 298 | /* Determine Label */ | 300 | close_notification(info_notification); |
390 | 299 | string volume_label = ""; | 301 | if (_pre_warn_volume == null) { |
391 | 300 | if (volume_control.high_volume) | 302 | _pre_warn_volume = new VolumeControl.Volume(); |
392 | 301 | volume_label = _("High volume"); | 303 | _pre_warn_volume.volume = volume_control.volume.volume; |
393 | 302 | 304 | _pre_warn_volume.reason = volume_control.volume.reason; | |
394 | 303 | /* Choose an icon */ | 305 | } |
395 | 304 | string icon = "audio-volume-muted"; | 306 | warn_notification.clear_actions(); |
396 | 305 | if (volume_control.volume.volume <= 0.0) | 307 | warn_notification.add_action ("ok", _("OK"), (n, a) => { |
397 | 306 | icon = "audio-volume-muted"; | 308 | stop_clamp_to_high_timeout(); |
398 | 307 | else if (volume_control.volume.volume <= 0.3) | 309 | volume_control.approve_high_volume (); |
399 | 308 | icon = "audio-volume-low"; | 310 | if (_pre_warn_volume != null) { |
400 | 309 | else if (volume_control.volume.volume <= 0.7) | 311 | var tmp = _pre_warn_volume; |
401 | 310 | icon = "audio-volume-medium"; | 312 | _pre_warn_volume = null; |
402 | 311 | else | 313 | volume_control.volume = tmp; |
403 | 312 | icon = "audio-volume-high"; | 314 | } |
404 | 313 | 315 | }); | |
405 | 314 | /* Check tint */ | 316 | warn_notification.add_action ("cancel", _("Cancel"), (n, a) => { |
406 | 315 | string tint = "false"; | 317 | _pre_warn_volume = null; |
407 | 316 | if (volume_control.high_volume) | 318 | }); |
408 | 317 | tint = "true"; | 319 | show_notification(warn_notification); |
409 | 318 | 320 | } else { | |
410 | 319 | /* Put it all into the notification */ | 321 | close_notification(warn_notification); |
411 | 320 | sync_notification.clear_hints (); | 322 | |
412 | 321 | sync_notification.update (_("Volume"), volume_label, icon); | 323 | if (notify_server_supports_sync && !block_info_notifications) { |
413 | 322 | sync_notification.set_hint ("value", (int32)Math.round(volume_control.volume.volume / this.max_volume * 100.0)); | 324 | |
414 | 323 | sync_notification.set_hint ("x-canonical-value-bar-tint", tint); | 325 | /* Determine Label */ |
415 | 324 | sync_notification.set_hint ("x-canonical-private-synchronous", "true"); | 326 | unowned string volume_label = loud |
416 | 325 | sync_notification.set_hint ("x-canonical-non-shaped-icon", "true"); | 327 | ? _("High volume can damage your hearing.") |
417 | 326 | 328 | : ""; | |
418 | 327 | /* Show it */ | 329 | |
419 | 328 | try { | 330 | /* Choose an icon */ |
420 | 329 | sync_notification.show (); | 331 | unowned string icon; |
421 | 330 | } catch (GLib.Error e) { | 332 | if (loud) { |
422 | 331 | warning("Unable to send volume change notification: %s", e.message); | 333 | icon = "audio-volume-high"; |
423 | 334 | } else { | ||
424 | 335 | var volume = volume_control.volume.volume; | ||
425 | 336 | |||
426 | 337 | if (volume <= 0.0) | ||
427 | 338 | icon = "audio-volume-muted"; | ||
428 | 339 | else if (volume <= 0.3) | ||
429 | 340 | icon = "audio-volume-low"; | ||
430 | 341 | else if (volume <= 0.7) | ||
431 | 342 | icon = "audio-volume-medium"; | ||
432 | 343 | else | ||
433 | 344 | icon = "audio-volume-high"; | ||
434 | 345 | } | ||
435 | 346 | |||
436 | 347 | /* Reset the notification */ | ||
437 | 348 | var n = this.info_notification; | ||
438 | 349 | n.update (_("Volume"), volume_label, icon); | ||
439 | 350 | n.clear_hints(); | ||
440 | 351 | n.set_hint ("x-canonical-non-shaped-icon", "true"); | ||
441 | 352 | n.set_hint ("x-canonical-private-synchronous", "true"); | ||
442 | 353 | n.set_hint ("x-canonical-value-bar-tint", loud ? "true" : "false"); | ||
443 | 354 | n.set_hint ("value", (int32)Math.round(get_volume_percent() * 100.0)); | ||
444 | 355 | show_notification(n); | ||
445 | 356 | } | ||
446 | 332 | } | 357 | } |
447 | 333 | } | 358 | } |
448 | 334 | 359 | ||
449 | @@ -408,49 +433,49 @@ | |||
450 | 408 | return mute_action; | 433 | return mute_action; |
451 | 409 | } | 434 | } |
452 | 410 | 435 | ||
465 | 411 | SimpleAction volume_action; | 436 | /* return the current volume in the range of [0.0, 1.0] */ |
466 | 412 | Action create_volume_action () { | 437 | private double get_volume_percent() { |
467 | 413 | /* The action's state is between be in [0.0, 1.0] instead of [0.0, | 438 | return volume_control.volume.volume / this.volume_control.max_volume; |
468 | 414 | * max_volume], so that we don't need to update the slider menu item | 439 | } |
469 | 415 | * every time allow-amplified-volume is changed. Convert between the | 440 | |
470 | 416 | * two here, so that we always pass the full range into | 441 | /* volume control's range can vary depending on its max_volume property, |
471 | 417 | * volume_control.set_volume(). | 442 | * but the action always needs to be in [0.0, 1.0]... */ |
472 | 418 | */ | 443 | private Variant create_volume_action_state() { |
473 | 419 | 444 | return new Variant.double (get_volume_percent()); | |
474 | 420 | double volume = this.volume_control.volume.volume / this.max_volume; | 445 | } |
475 | 421 | 446 | ||
476 | 422 | volume_action = new SimpleAction.stateful ("volume", VariantType.INT32, new Variant.double (volume)); | 447 | private void update_volume_action_state() { |
477 | 448 | volume_action.set_state(create_volume_action_state()); | ||
478 | 449 | } | ||
479 | 450 | |||
480 | 451 | private SimpleAction volume_action; | ||
481 | 452 | private Action create_volume_action () { | ||
482 | 453 | volume_action = new SimpleAction.stateful ("volume", VariantType.INT32, create_volume_action_state()); | ||
483 | 423 | 454 | ||
484 | 424 | volume_action.change_state.connect ( (action, val) => { | 455 | volume_action.change_state.connect ( (action, val) => { |
491 | 425 | double v = val.get_double () * this.max_volume; | 456 | double v = val.get_double () * this.volume_control.max_volume; |
492 | 426 | 457 | volume_control.set_volume_clamp (v, VolumeControl.VolumeReasons.USER_KEYPRESS); | |
487 | 427 | var vol = new VolumeControl.Volume(); | ||
488 | 428 | vol.volume = v.clamp (0.0, this.max_volume); | ||
489 | 429 | vol.reason = VolumeControl.VolumeReasons.USER_KEYPRESS; | ||
490 | 430 | volume_control.volume = vol; | ||
493 | 431 | }); | 458 | }); |
494 | 432 | 459 | ||
495 | 433 | /* activating this action changes the volume by the amount given in the parameter */ | 460 | /* activating this action changes the volume by the amount given in the parameter */ |
499 | 434 | volume_action.activate.connect ( (action, param) => { | 461 | volume_action.activate.connect ((a,p) => activate_scroll_action(a,p)); |
497 | 435 | int delta = param.get_int32 (); | ||
498 | 436 | double v = volume_control.volume.volume + volume_step_percentage * delta; | ||
500 | 437 | 462 | ||
505 | 438 | var vol = new VolumeControl.Volume(); | 463 | this.volume_control.notify["max-volume"].connect(() => { |
506 | 439 | vol.volume = v.clamp (0.0, this.max_volume); | 464 | update_volume_action_state(); |
503 | 440 | vol.reason = VolumeControl.VolumeReasons.USER_KEYPRESS; | ||
504 | 441 | volume_control.volume = vol; | ||
507 | 442 | }); | 465 | }); |
508 | 443 | 466 | ||
509 | 444 | this.volume_control.notify["volume"].connect (() => { | 467 | this.volume_control.notify["volume"].connect (() => { |
512 | 445 | /* Normalize volume, because the volume action's state is [0.0, 1.0], see create_volume_action() */ | 468 | update_volume_action_state(); |
511 | 446 | volume_action.set_state (new Variant.double (this.volume_control.volume.volume / this.max_volume)); | ||
513 | 447 | 469 | ||
514 | 448 | this.update_root_icon (); | 470 | this.update_root_icon (); |
515 | 449 | 471 | ||
516 | 450 | var reason = volume_control.volume.reason; | 472 | var reason = volume_control.volume.reason; |
517 | 451 | if (reason == VolumeControl.VolumeReasons.USER_KEYPRESS || | 473 | if (reason == VolumeControl.VolumeReasons.USER_KEYPRESS || |
518 | 452 | reason == VolumeControl.VolumeReasons.DEVICE_OUTPUT_CHANGE) | 474 | reason == VolumeControl.VolumeReasons.DEVICE_OUTPUT_CHANGE) |
520 | 453 | this.update_sync_notification (); | 475 | this.update_notification (); |
521 | 476 | |||
522 | 477 | if ((warn_notification.id != 0) && (_pre_warn_volume != null)) | ||
523 | 478 | clamp_to_high_soon(); | ||
524 | 454 | }); | 479 | }); |
525 | 455 | 480 | ||
526 | 456 | this.volume_control.bind_property ("ready", volume_action, "enabled", BindingFlags.SYNC_CREATE); | 481 | this.volume_control.bind_property ("ready", volume_action, "enabled", BindingFlags.SYNC_CREATE); |
527 | @@ -481,7 +506,7 @@ | |||
528 | 481 | 506 | ||
529 | 482 | this.volume_control.notify["high-volume"].connect( () => { | 507 | this.volume_control.notify["high-volume"].connect( () => { |
530 | 483 | high_volume_action.set_state(new Variant.boolean (this.volume_control.high_volume)); | 508 | high_volume_action.set_state(new Variant.boolean (this.volume_control.high_volume)); |
532 | 484 | update_sync_notification(); | 509 | update_notification(); |
533 | 485 | }); | 510 | }); |
534 | 486 | 511 | ||
535 | 487 | return high_volume_action; | 512 | return high_volume_action; |
536 | @@ -604,4 +629,27 @@ | |||
537 | 604 | 629 | ||
538 | 605 | this.update_preferred_players (); | 630 | this.update_preferred_players (); |
539 | 606 | } | 631 | } |
540 | 632 | |||
541 | 633 | /** VOLUME CLAMPING **/ | ||
542 | 634 | |||
543 | 635 | private uint _clamp_to_high_timeout = 0; | ||
544 | 636 | |||
545 | 637 | private void stop_clamp_to_high_timeout() { | ||
546 | 638 | if (_clamp_to_high_timeout != 0) { | ||
547 | 639 | Source.remove(_clamp_to_high_timeout); | ||
548 | 640 | _clamp_to_high_timeout = 0; | ||
549 | 641 | } | ||
550 | 642 | } | ||
551 | 643 | |||
552 | 644 | private void clamp_to_high_soon() { | ||
553 | 645 | const uint interval_msec = 200; | ||
554 | 646 | if (_clamp_to_high_timeout == 0) | ||
555 | 647 | _clamp_to_high_timeout = Timeout.add(interval_msec, clamp_to_high_idle); | ||
556 | 648 | } | ||
557 | 649 | |||
558 | 650 | private bool clamp_to_high_idle() { | ||
559 | 651 | _clamp_to_high_timeout = 0; | ||
560 | 652 | volume_control.clamp_to_high_volume(); | ||
561 | 653 | return false; // Source.REMOVE; | ||
562 | 654 | } | ||
563 | 607 | } | 655 | } |
564 | 608 | 656 | ||
565 | === modified file 'src/volume-control-pulse.vala' | |||
566 | --- src/volume-control-pulse.vala 2015-04-17 17:10:28 +0000 | |||
567 | +++ src/volume-control-pulse.vala 2015-10-13 13:18:26 +0000 | |||
568 | @@ -28,8 +28,8 @@ | |||
569 | 28 | [DBus (name="com.canonical.UnityGreeter.List")] | 28 | [DBus (name="com.canonical.UnityGreeter.List")] |
570 | 29 | interface GreeterListInterface : Object | 29 | interface GreeterListInterface : Object |
571 | 30 | { | 30 | { |
574 | 31 | public abstract async string get_active_entry () throws IOError; | 31 | public abstract async string get_active_entry () throws IOError; |
575 | 32 | public signal void entry_selected (string entry_name); | 32 | public signal void entry_selected (string entry_name); |
576 | 33 | } | 33 | } |
577 | 34 | 34 | ||
578 | 35 | public class VolumeControlPulse : VolumeControl | 35 | public class VolumeControlPulse : VolumeControl |
579 | @@ -44,6 +44,8 @@ | |||
580 | 44 | private bool _is_playing = false; | 44 | private bool _is_playing = false; |
581 | 45 | private VolumeControl.Volume _volume = new VolumeControl.Volume(); | 45 | private VolumeControl.Volume _volume = new VolumeControl.Volume(); |
582 | 46 | private double _mic_volume = 0.0; | 46 | private double _mic_volume = 0.0; |
583 | 47 | private Settings _settings = new Settings ("com.canonical.indicator.sound"); | ||
584 | 48 | private Settings _shared_settings = new Settings ("com.ubuntu.sound"); | ||
585 | 47 | 49 | ||
586 | 48 | /* Used by the pulseaudio stream restore extension */ | 50 | /* Used by the pulseaudio stream restore extension */ |
587 | 49 | private DBusConnection _pconn; | 51 | private DBusConnection _pconn; |
588 | @@ -92,13 +94,6 @@ | |||
589 | 92 | /** true when a microphone is active **/ | 94 | /** true when a microphone is active **/ |
590 | 93 | public override bool active_mic { get; private set; default = false; } | 95 | public override bool active_mic { get; private set; default = false; } |
591 | 94 | 96 | ||
592 | 95 | /** true when high volume warnings should be shown */ | ||
593 | 96 | public override bool high_volume { | ||
594 | 97 | get { | ||
595 | 98 | return this._volume.volume > 0.75 && _active_port_headphone && stream == "multimedia"; | ||
596 | 99 | } | ||
597 | 100 | } | ||
598 | 101 | |||
599 | 102 | public VolumeControlPulse () | 97 | public VolumeControlPulse () |
600 | 103 | { | 98 | { |
601 | 104 | _volume.volume = 0.0; | 99 | _volume.volume = 0.0; |
602 | @@ -110,19 +105,34 @@ | |||
603 | 110 | _mute_cancellable = new Cancellable (); | 105 | _mute_cancellable = new Cancellable (); |
604 | 111 | _volume_cancellable = new Cancellable (); | 106 | _volume_cancellable = new Cancellable (); |
605 | 112 | 107 | ||
606 | 108 | init_all_properties(); | ||
607 | 109 | |||
608 | 113 | setup_accountsservice.begin (); | 110 | setup_accountsservice.begin (); |
609 | 114 | 111 | ||
610 | 115 | this.reconnect_to_pulse (); | 112 | this.reconnect_to_pulse (); |
611 | 116 | } | 113 | } |
612 | 117 | 114 | ||
613 | 115 | private void init_all_properties() | ||
614 | 116 | { | ||
615 | 117 | init_max_volume(); | ||
616 | 118 | init_high_volume(); | ||
617 | 119 | init_high_volume_approved(); | ||
618 | 120 | } | ||
619 | 121 | |||
620 | 118 | ~VolumeControlPulse () | 122 | ~VolumeControlPulse () |
621 | 119 | { | 123 | { |
622 | 124 | stop_all_timers(); | ||
623 | 125 | } | ||
624 | 126 | |||
625 | 127 | private void stop_all_timers() | ||
626 | 128 | { | ||
627 | 120 | if (_reconnect_timer != 0) { | 129 | if (_reconnect_timer != 0) { |
628 | 121 | Source.remove (_reconnect_timer); | 130 | Source.remove (_reconnect_timer); |
629 | 122 | _reconnect_timer = 0; | 131 | _reconnect_timer = 0; |
630 | 123 | } | 132 | } |
631 | 124 | stop_local_volume_timer(); | 133 | stop_local_volume_timer(); |
632 | 125 | stop_account_service_volume_timer(); | 134 | stop_account_service_volume_timer(); |
633 | 135 | stop_high_volume_approved_timer(); | ||
634 | 126 | } | 136 | } |
635 | 127 | 137 | ||
636 | 128 | /* PulseAudio logic*/ | 138 | /* PulseAudio logic*/ |
637 | @@ -212,7 +222,7 @@ | |||
638 | 212 | vol.volume = volume_to_double (i.volume.max ()); | 222 | vol.volume = volume_to_double (i.volume.max ()); |
639 | 213 | vol.reason = VolumeControl.VolumeReasons.PULSE_CHANGE; | 223 | vol.reason = VolumeControl.VolumeReasons.PULSE_CHANGE; |
640 | 214 | this.volume = vol; | 224 | this.volume = vol; |
642 | 215 | } | 225 | } |
643 | 216 | } | 226 | } |
644 | 217 | 227 | ||
645 | 218 | private void source_info_cb (Context c, SourceInfo? i, int eol) | 228 | private void source_info_cb (Context c, SourceInfo? i, int eol) |
646 | @@ -619,7 +629,6 @@ | |||
647 | 619 | var volume_changed = (value.volume != _volume.volume); | 629 | var volume_changed = (value.volume != _volume.volume); |
648 | 620 | debug("Setting volume to %f for profile %d because %d", value.volume, _active_sink_input, value.reason); | 630 | debug("Setting volume to %f for profile %d because %d", value.volume, _active_sink_input, value.reason); |
649 | 621 | 631 | ||
650 | 622 | var old_high_volume = this.high_volume; | ||
651 | 623 | _volume = value; | 632 | _volume = value; |
652 | 624 | 633 | ||
653 | 625 | /* Make sure we're connected to Pulse and pulse didn't give us the change */ | 634 | /* Make sure we're connected to Pulse and pulse didn't give us the change */ |
654 | @@ -631,15 +640,153 @@ | |||
655 | 631 | else | 640 | else |
656 | 632 | context.get_server_info (server_info_cb_for_set_volume); | 641 | context.get_server_info (server_info_cb_for_set_volume); |
657 | 633 | 642 | ||
658 | 634 | if (this.high_volume != old_high_volume) | ||
659 | 635 | this.notify_property("high-volume"); | ||
660 | 636 | 643 | ||
661 | 637 | if (volume.reason != VolumeControl.VolumeReasons.ACCOUNTS_SERVICE_SET | 644 | if (volume.reason != VolumeControl.VolumeReasons.ACCOUNTS_SERVICE_SET |
662 | 638 | && volume_changed) { | 645 | && volume_changed) { |
663 | 639 | start_local_volume_timer(); | 646 | start_local_volume_timer(); |
664 | 640 | } | 647 | } |
667 | 641 | } | 648 | |
668 | 642 | } | 649 | update_high_volume(); |
669 | 650 | } | ||
670 | 651 | } | ||
671 | 652 | |||
672 | 653 | /** MAX VOLUME PROPERTY **/ | ||
673 | 654 | |||
674 | 655 | private void init_max_volume() { | ||
675 | 656 | _settings.changed["normal-volume-decibels"].connect(() => update_max_volume()); | ||
676 | 657 | _settings.changed["amplified-volume-decibels"].connect(() => update_max_volume()); | ||
677 | 658 | _shared_settings.changed["allow-amplified-volume"].connect(() => update_max_volume()); | ||
678 | 659 | update_max_volume(); | ||
679 | 660 | } | ||
680 | 661 | private void update_max_volume () { | ||
681 | 662 | var new_max_volume = calculate_max_volume(); | ||
682 | 663 | if (max_volume != new_max_volume) { | ||
683 | 664 | debug("changing max_volume from %f to %f", this.max_volume, new_max_volume); | ||
684 | 665 | max_volume = calculate_max_volume(); | ||
685 | 666 | } | ||
686 | 667 | } | ||
687 | 668 | private double calculate_max_volume () { | ||
688 | 669 | unowned string decibel_key = _shared_settings.get_boolean("allow-amplified-volume") | ||
689 | 670 | ? "amplified-volume-decibels" | ||
690 | 671 | : "normal-volume-decibels"; | ||
691 | 672 | var volume_dB = _settings.get_double(decibel_key); | ||
692 | 673 | var volume_sw = PulseAudio.Volume.sw_from_dB (volume_dB); | ||
693 | 674 | return volume_to_double (volume_sw); | ||
694 | 675 | } | ||
695 | 676 | |||
696 | 677 | /** HIGH VOLUME PROPERTY **/ | ||
697 | 678 | |||
698 | 679 | private bool _warning_volume_enabled; | ||
699 | 680 | private double _warning_volume_norms; /* 1.0 == PA_VOLUME_NORM */ | ||
700 | 681 | private bool _high_volume = false; | ||
701 | 682 | public override bool high_volume { | ||
702 | 683 | get { return this._high_volume; } | ||
703 | 684 | private set { this._high_volume = value; } | ||
704 | 685 | } | ||
705 | 686 | private void init_high_volume() { | ||
706 | 687 | _settings.changed["warning-volume-enabled"].connect(() => update_high_volume_cache()); | ||
707 | 688 | _settings.changed["warning-volume-decibels"].connect(() => update_high_volume_cache()); | ||
708 | 689 | update_high_volume_cache(); | ||
709 | 690 | } | ||
710 | 691 | private void update_high_volume_cache() { | ||
711 | 692 | var volume_dB = _settings.get_double ("warning-volume-decibels"); | ||
712 | 693 | var volume_sw = PulseAudio.Volume.sw_from_dB (volume_dB); | ||
713 | 694 | var volume_norms = volume_to_double (volume_sw); | ||
714 | 695 | _warning_volume_norms = volume_norms; | ||
715 | 696 | _warning_volume_enabled = _settings.get_boolean("warning-volume-enabled"); | ||
716 | 697 | debug("updating high volume cache... enabled %d dB %f sw %lu norm %f", (int)_warning_volume_enabled, volume_dB, volume_sw, volume_norms); | ||
717 | 698 | update_high_volume(); | ||
718 | 699 | } | ||
719 | 700 | private void update_high_volume() { | ||
720 | 701 | var new_high_volume = calculate_high_volume(); | ||
721 | 702 | if (high_volume != new_high_volume) { | ||
722 | 703 | debug("changing high_volume from %d to %d", (int)high_volume, (int)new_high_volume); | ||
723 | 704 | high_volume = new_high_volume; | ||
724 | 705 | } | ||
725 | 706 | } | ||
726 | 707 | private bool calculate_high_volume() { | ||
727 | 708 | return calculate_high_volume_from_volume(_volume.volume); | ||
728 | 709 | } | ||
729 | 710 | private bool calculate_high_volume_from_volume(double volume) { | ||
730 | 711 | return _active_port_headphone | ||
731 | 712 | && _warning_volume_enabled | ||
732 | 713 | && volume >= _warning_volume_norms | ||
733 | 714 | && (stream == "multimedia"); | ||
734 | 715 | } | ||
735 | 716 | |||
736 | 717 | public override void clamp_to_high_volume() { | ||
737 | 718 | if (_high_volume && (_volume.volume > _warning_volume_norms)) { | ||
738 | 719 | var vol = new VolumeControl.Volume(); | ||
739 | 720 | vol.volume = _volume.volume.clamp(0, _warning_volume_norms); | ||
740 | 721 | vol.reason = _volume.reason; | ||
741 | 722 | debug("Clamping from %f down to %f", _volume.volume, vol.volume); | ||
742 | 723 | volume = vol; | ||
743 | 724 | } | ||
744 | 725 | } | ||
745 | 726 | |||
746 | 727 | /** HIGH VOLUME APPROVED PROPERTY **/ | ||
747 | 728 | |||
748 | 729 | private bool _high_volume_approved = false; | ||
749 | 730 | private uint _high_volume_approved_timer = 0; | ||
750 | 731 | private int64 _high_volume_approved_at = 0; | ||
751 | 732 | private int64 _high_volume_approved_ttl_usec = 0; | ||
752 | 733 | public override bool high_volume_approved { | ||
753 | 734 | get { return this._high_volume_approved; } | ||
754 | 735 | private set { this._high_volume_approved = value; } | ||
755 | 736 | } | ||
756 | 737 | private void init_high_volume_approved() { | ||
757 | 738 | _settings.changed["warning-volume-confirmation-ttl"].connect(() => update_high_volume_approved_cache()); | ||
758 | 739 | update_high_volume_approved_cache(); | ||
759 | 740 | } | ||
760 | 741 | private void update_high_volume_approved_cache() { | ||
761 | 742 | _high_volume_approved_ttl_usec = _settings.get_int("warning-volume-confirmation-ttl"); | ||
762 | 743 | _high_volume_approved_ttl_usec *= 1000000; | ||
763 | 744 | |||
764 | 745 | update_high_volume_approved(); | ||
765 | 746 | update_high_volume_approved_timer(); | ||
766 | 747 | } | ||
767 | 748 | private void update_high_volume_approved_timer() { | ||
768 | 749 | stop_high_volume_approved_timer(); | ||
769 | 750 | if (_high_volume_approved_at != 0) { | ||
770 | 751 | int64 expires_at = _high_volume_approved_at + _high_volume_approved_ttl_usec; | ||
771 | 752 | int64 now = GLib.get_monotonic_time(); | ||
772 | 753 | if (expires_at > now) { | ||
773 | 754 | var seconds_left = 1 + ((expires_at - now) / 1000000); | ||
774 | 755 | _high_volume_approved_timer = Timeout.add_seconds((uint)seconds_left, on_high_volume_approved_timer); | ||
775 | 756 | } | ||
776 | 757 | } | ||
777 | 758 | } | ||
778 | 759 | private void stop_high_volume_approved_timer() { | ||
779 | 760 | if (_high_volume_approved_timer != 0) { | ||
780 | 761 | Source.remove (_high_volume_approved_timer); | ||
781 | 762 | _high_volume_approved_timer = 0; | ||
782 | 763 | } | ||
783 | 764 | } | ||
784 | 765 | private bool on_high_volume_approved_timer() { | ||
785 | 766 | _high_volume_approved_timer = 0; | ||
786 | 767 | update_high_volume_approved(); | ||
787 | 768 | return false; /* Source.REMOVE */ | ||
788 | 769 | } | ||
789 | 770 | private void update_high_volume_approved() { | ||
790 | 771 | var new_high_volume_approved = calculate_high_volume_approved(); | ||
791 | 772 | if (high_volume_approved != new_high_volume_approved) { | ||
792 | 773 | debug("changing high_volume_approved from %d to %d", (int)high_volume_approved, (int)new_high_volume_approved); | ||
793 | 774 | high_volume_approved = new_high_volume_approved; | ||
794 | 775 | } | ||
795 | 776 | } | ||
796 | 777 | private bool calculate_high_volume_approved() { | ||
797 | 778 | int64 now = GLib.get_monotonic_time(); | ||
798 | 779 | return (_high_volume_approved_at != 0) | ||
799 | 780 | && (_high_volume_approved_at + _high_volume_approved_ttl_usec >= now); | ||
800 | 781 | } | ||
801 | 782 | public override void approve_high_volume() { | ||
802 | 783 | _high_volume_approved_at = GLib.get_monotonic_time(); | ||
803 | 784 | update_high_volume_approved(); | ||
804 | 785 | update_high_volume_approved_timer(); | ||
805 | 786 | } | ||
806 | 787 | |||
807 | 788 | |||
808 | 789 | /** MIC VOLUME PROPERTY */ | ||
809 | 643 | 790 | ||
810 | 644 | public override double mic_volume { | 791 | public override double mic_volume { |
811 | 645 | get { | 792 | get { |
812 | 646 | 793 | ||
813 | === modified file 'src/volume-control.vala' | |||
814 | --- src/volume-control.vala 2015-02-17 16:54:33 +0000 | |||
815 | +++ src/volume-control.vala 2015-10-13 13:18:26 +0000 | |||
816 | @@ -36,12 +36,24 @@ | |||
817 | 36 | public virtual string stream { get { return ""; } } | 36 | public virtual string stream { get { return ""; } } |
818 | 37 | public virtual bool ready { get { return false; } set { } } | 37 | public virtual bool ready { get { return false; } set { } } |
819 | 38 | public virtual bool active_mic { get { return false; } set { } } | 38 | public virtual bool active_mic { get { return false; } set { } } |
821 | 39 | public virtual bool high_volume { get { return false; } } | 39 | public virtual bool high_volume { get { return false; } protected set { } } |
822 | 40 | public virtual bool mute { get { return false; } } | 40 | public virtual bool mute { get { return false; } } |
823 | 41 | public virtual bool is_playing { get { return false; } } | 41 | public virtual bool is_playing { get { return false; } } |
824 | 42 | private Volume _volume; | 42 | private Volume _volume; |
825 | 43 | public virtual Volume volume { get { return _volume; } set { } } | 43 | public virtual Volume volume { get { return _volume; } set { } } |
826 | 44 | public virtual double mic_volume { get { return 0.0; } set { } } | 44 | public virtual double mic_volume { get { return 0.0; } set { } } |
827 | 45 | public virtual double max_volume { get { return 1.0; } protected set { } } | ||
828 | 46 | |||
829 | 47 | public virtual bool high_volume_approved { get { return false; } protected set { } } | ||
830 | 48 | public virtual void approve_high_volume() { } | ||
831 | 49 | public virtual void clamp_to_high_volume() { } | ||
832 | 45 | 50 | ||
833 | 46 | public abstract void set_mute (bool mute); | 51 | public abstract void set_mute (bool mute); |
834 | 52 | |||
835 | 53 | public void set_volume_clamp (double unclamped, VolumeControl.VolumeReasons reason) { | ||
836 | 54 | var v = new VolumeControl.Volume(); | ||
837 | 55 | v.volume = unclamped.clamp (0.0, this.max_volume); | ||
838 | 56 | v.reason = reason; | ||
839 | 57 | this.volume = v; | ||
840 | 58 | } | ||
841 | 47 | } | 59 | } |
842 | 48 | 60 | ||
843 | === modified file 'tests/CMakeLists.txt' | |||
844 | --- tests/CMakeLists.txt 2015-02-09 22:10:22 +0000 | |||
845 | +++ tests/CMakeLists.txt 2015-10-13 13:18:26 +0000 | |||
846 | @@ -163,7 +163,7 @@ | |||
847 | 163 | ########################### | 163 | ########################### |
848 | 164 | 164 | ||
849 | 165 | include_directories(${CMAKE_SOURCE_DIR}/src) | 165 | include_directories(${CMAKE_SOURCE_DIR}/src) |
851 | 166 | add_executable (volume-control-test volume-control-test.cc) | 166 | add_executable (volume-control-test volume-control-test.cc gschemas.compiled) |
852 | 167 | target_link_libraries ( | 167 | target_link_libraries ( |
853 | 168 | volume-control-test | 168 | volume-control-test |
854 | 169 | indicator-sound-service-lib | 169 | indicator-sound-service-lib |
855 | 170 | 170 | ||
856 | === modified file 'tests/media-player-user.cc' | |||
857 | --- tests/media-player-user.cc 2015-01-30 16:05:10 +0000 | |||
858 | +++ tests/media-player-user.cc 2015-10-13 13:18:26 +0000 | |||
859 | @@ -17,6 +17,9 @@ | |||
860 | 17 | * Ted Gould <ted@canonical.com> | 17 | * Ted Gould <ted@canonical.com> |
861 | 18 | */ | 18 | */ |
862 | 19 | 19 | ||
863 | 20 | #include <chrono> | ||
864 | 21 | #include <future> | ||
865 | 22 | |||
866 | 20 | #include <gtest/gtest.h> | 23 | #include <gtest/gtest.h> |
867 | 21 | #include <gio/gio.h> | 24 | #include <gio/gio.h> |
868 | 22 | #include <libdbustest/dbus-test.h> | 25 | #include <libdbustest/dbus-test.h> |
869 | @@ -31,24 +34,55 @@ | |||
870 | 31 | { | 34 | { |
871 | 32 | 35 | ||
872 | 33 | protected: | 36 | protected: |
874 | 34 | DbusTestService * service = NULL; | 37 | DbusTestService * testsystem = NULL; |
875 | 35 | AccountsServiceMock service_mock; | 38 | AccountsServiceMock service_mock; |
876 | 36 | 39 | ||
877 | 40 | DbusTestService * testsession = NULL; | ||
878 | 41 | |||
879 | 42 | DbusTestProcess * systemmonitor = nullptr; | ||
880 | 43 | DbusTestProcess * sessionmonitor = nullptr; | ||
881 | 44 | |||
882 | 37 | GDBusConnection * system = NULL; | 45 | GDBusConnection * system = NULL; |
883 | 46 | GDBusConnection * session = NULL; | ||
884 | 38 | GDBusProxy * proxy = NULL; | 47 | GDBusProxy * proxy = NULL; |
885 | 39 | 48 | ||
886 | 49 | std::chrono::milliseconds _eventuallyTime = std::chrono::seconds{5}; | ||
887 | 50 | |||
888 | 40 | virtual void SetUp() { | 51 | virtual void SetUp() { |
894 | 41 | service = dbus_test_service_new(NULL); | 52 | /* System Bus */ |
895 | 42 | dbus_test_service_set_bus(service, DBUS_TEST_SERVICE_BUS_SYSTEM); | 53 | testsystem = dbus_test_service_new(NULL); |
896 | 43 | 54 | dbus_test_service_set_bus(testsystem, DBUS_TEST_SERVICE_BUS_SYSTEM); | |
897 | 44 | dbus_test_service_add_task(service, (DbusTestTask*)service_mock); | 55 | |
898 | 45 | dbus_test_service_start_tasks(service); | 56 | systemmonitor = dbus_test_process_new("dbus-monitor"); |
899 | 57 | dbus_test_process_append_param(systemmonitor, "--system"); | ||
900 | 58 | dbus_test_task_set_name(DBUS_TEST_TASK(systemmonitor), "System"); | ||
901 | 59 | dbus_test_service_add_task(testsystem, DBUS_TEST_TASK(systemmonitor)); | ||
902 | 60 | |||
903 | 61 | dbus_test_service_add_task(testsystem, (DbusTestTask*)service_mock); | ||
904 | 62 | dbus_test_service_start_tasks(testsystem); | ||
905 | 46 | 63 | ||
906 | 47 | system = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL); | 64 | system = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL); |
907 | 48 | ASSERT_NE(nullptr, system); | 65 | ASSERT_NE(nullptr, system); |
908 | 49 | g_dbus_connection_set_exit_on_close(system, FALSE); | 66 | g_dbus_connection_set_exit_on_close(system, FALSE); |
909 | 50 | g_object_add_weak_pointer(G_OBJECT(system), (gpointer *)&system); | 67 | g_object_add_weak_pointer(G_OBJECT(system), (gpointer *)&system); |
910 | 51 | 68 | ||
911 | 69 | /* Session Bus */ | ||
912 | 70 | testsession = dbus_test_service_new(NULL); | ||
913 | 71 | dbus_test_service_set_bus(testsession, DBUS_TEST_SERVICE_BUS_SESSION); | ||
914 | 72 | |||
915 | 73 | sessionmonitor = dbus_test_process_new("dbus-monitor"); | ||
916 | 74 | dbus_test_process_append_param(sessionmonitor, "--session"); | ||
917 | 75 | dbus_test_task_set_name(DBUS_TEST_TASK(sessionmonitor), "Session"); | ||
918 | 76 | dbus_test_service_add_task(testsession, DBUS_TEST_TASK(sessionmonitor)); | ||
919 | 77 | |||
920 | 78 | dbus_test_service_start_tasks(testsession); | ||
921 | 79 | |||
922 | 80 | session = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL); | ||
923 | 81 | ASSERT_NE(nullptr, session); | ||
924 | 82 | g_dbus_connection_set_exit_on_close(session, FALSE); | ||
925 | 83 | g_object_add_weak_pointer(G_OBJECT(session), (gpointer *)&session); | ||
926 | 84 | |||
927 | 85 | /* Setup proxy */ | ||
928 | 52 | proxy = g_dbus_proxy_new_sync(system, | 86 | proxy = g_dbus_proxy_new_sync(system, |
929 | 53 | G_DBUS_PROXY_FLAGS_NONE, | 87 | G_DBUS_PROXY_FLAGS_NONE, |
930 | 54 | NULL, | 88 | NULL, |
931 | @@ -60,10 +94,15 @@ | |||
932 | 60 | } | 94 | } |
933 | 61 | 95 | ||
934 | 62 | virtual void TearDown() { | 96 | virtual void TearDown() { |
935 | 97 | g_clear_object(&sessionmonitor); | ||
936 | 98 | g_clear_object(&systemmonitor); | ||
937 | 99 | |||
938 | 63 | g_clear_object(&proxy); | 100 | g_clear_object(&proxy); |
940 | 64 | g_clear_object(&service); | 101 | g_clear_object(&testsystem); |
941 | 102 | g_clear_object(&testsession); | ||
942 | 65 | 103 | ||
943 | 66 | g_object_unref(system); | 104 | g_object_unref(system); |
944 | 105 | g_object_unref(session); | ||
945 | 67 | 106 | ||
946 | 68 | #if 0 | 107 | #if 0 |
947 | 69 | /* Accounts Service keeps a bunch of references around so we | 108 | /* Accounts Service keeps a bunch of references around so we |
948 | @@ -95,8 +134,78 @@ | |||
949 | 95 | void set_property (const gchar * name, GVariant * value) { | 134 | void set_property (const gchar * name, GVariant * value) { |
950 | 96 | dbus_test_dbus_mock_object_update_property((DbusTestDbusMock *)service_mock, service_mock.get_sound(), name, value, NULL); | 135 | dbus_test_dbus_mock_object_update_property((DbusTestDbusMock *)service_mock, service_mock.get_sound(), name, value, NULL); |
951 | 97 | } | 136 | } |
952 | 137 | |||
953 | 138 | testing::AssertionResult expectEventually (std::function<testing::AssertionResult(void)> &testfunc) { | ||
954 | 139 | auto loop = std::shared_ptr<GMainLoop>(g_main_loop_new(nullptr, FALSE), [](GMainLoop * loop) { if (loop != nullptr) g_main_loop_unref(loop); }); | ||
955 | 140 | |||
956 | 141 | std::promise<testing::AssertionResult> retpromise; | ||
957 | 142 | auto retfuture = retpromise.get_future(); | ||
958 | 143 | auto start = std::chrono::steady_clock::now(); | ||
959 | 144 | |||
960 | 145 | /* The core of the idle function as an object so we can use the C++-isms | ||
961 | 146 | of attaching the variables and make this code reasonably readable */ | ||
962 | 147 | std::function<void(void)> idlefunc = [&loop, &retpromise, &testfunc, &start, this]() -> void { | ||
963 | 148 | auto result = testfunc(); | ||
964 | 149 | |||
965 | 150 | if (result == false && _eventuallyTime > (std::chrono::steady_clock::now() - start)) { | ||
966 | 151 | return; | ||
967 | 152 | } | ||
968 | 153 | |||
969 | 154 | retpromise.set_value(result); | ||
970 | 155 | g_main_loop_quit(loop.get()); | ||
971 | 156 | }; | ||
972 | 157 | |||
973 | 158 | auto idlesrc = g_idle_add([](gpointer data) -> gboolean { | ||
974 | 159 | auto func = reinterpret_cast<std::function<void(void)> *>(data); | ||
975 | 160 | (*func)(); | ||
976 | 161 | return G_SOURCE_CONTINUE; | ||
977 | 162 | }, &idlefunc); | ||
978 | 163 | |||
979 | 164 | g_main_loop_run(loop.get()); | ||
980 | 165 | g_source_remove(idlesrc); | ||
981 | 166 | |||
982 | 167 | return retfuture.get(); | ||
983 | 168 | } | ||
984 | 169 | |||
985 | 170 | /* Eventually Helpers */ | ||
986 | 171 | #define _EVENTUALLY_HELPER(oper) \ | ||
987 | 172 | template <typename... Args> testing::AssertionResult expectEventually##oper (Args&& ... args) { \ | ||
988 | 173 | std::function<testing::AssertionResult(void)> func = [&]() { \ | ||
989 | 174 | return testing::internal::CmpHelper##oper(std::forward<Args>(args)...); \ | ||
990 | 175 | }; \ | ||
991 | 176 | return expectEventually(func); \ | ||
992 | 177 | } | ||
993 | 178 | |||
994 | 179 | _EVENTUALLY_HELPER(EQ); | ||
995 | 180 | _EVENTUALLY_HELPER(NE); | ||
996 | 181 | _EVENTUALLY_HELPER(LT); | ||
997 | 182 | _EVENTUALLY_HELPER(GT); | ||
998 | 183 | _EVENTUALLY_HELPER(STREQ); | ||
999 | 184 | _EVENTUALLY_HELPER(STRNE); | ||
1000 | 185 | |||
1001 | 186 | #undef _EVENTUALLY_HELPER | ||
1002 | 98 | }; | 187 | }; |
1003 | 99 | 188 | ||
1004 | 189 | /* Helpers */ | ||
1005 | 190 | #define EXPECT_EVENTUALLY_EQ(expected, actual) \ | ||
1006 | 191 | EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallyEQ, expected, actual) | ||
1007 | 192 | |||
1008 | 193 | #define EXPECT_EVENTUALLY_NE(expected, actual) \ | ||
1009 | 194 | EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallyNE, expected, actual) | ||
1010 | 195 | |||
1011 | 196 | #define EXPECT_EVENTUALLY_LT(expected, actual) \ | ||
1012 | 197 | EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallyLT, expected, actual) | ||
1013 | 198 | |||
1014 | 199 | #define EXPECT_EVENTUALLY_GT(expected, actual) \ | ||
1015 | 200 | EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallyGT, expected, actual) | ||
1016 | 201 | |||
1017 | 202 | #define EXPECT_EVENTUALLY_STREQ(expected, actual) \ | ||
1018 | 203 | EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallySTREQ, expected, actual) | ||
1019 | 204 | |||
1020 | 205 | #define EXPECT_EVENTUALLY_STRNE(expected, actual) \ | ||
1021 | 206 | EXPECT_PRED_FORMAT2(MediaPlayerUserTest::expectEventuallySTRNE, expected, actual) | ||
1022 | 207 | |||
1023 | 208 | |||
1024 | 100 | TEST_F(MediaPlayerUserTest, BasicObject) { | 209 | TEST_F(MediaPlayerUserTest, BasicObject) { |
1025 | 101 | MediaPlayerUser * player = media_player_user_new("user"); | 210 | MediaPlayerUser * player = media_player_user_new("user"); |
1026 | 102 | ASSERT_NE(nullptr, player); | 211 | ASSERT_NE(nullptr, player); |
1027 | @@ -125,7 +234,12 @@ | |||
1028 | 125 | g_clear_object(&player); | 234 | g_clear_object(&player); |
1029 | 126 | } | 235 | } |
1030 | 127 | 236 | ||
1032 | 128 | TEST_F(MediaPlayerUserTest, DataSet) { | 237 | void |
1033 | 238 | running_update (GObject * obj, GParamSpec * pspec, bool * running) { | ||
1034 | 239 | *running = media_player_get_is_running(MEDIA_PLAYER(obj)) == TRUE; | ||
1035 | 240 | }; | ||
1036 | 241 | |||
1037 | 242 | TEST_F(MediaPlayerUserTest, DISABLED_DataSet) { | ||
1038 | 129 | /* Put data into Acts */ | 243 | /* Put data into Acts */ |
1039 | 130 | set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time())); | 244 | set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time())); |
1040 | 131 | set_property("PlayerName", g_variant_new_string("The Player Formerly Known as Prince")); | 245 | set_property("PlayerName", g_variant_new_string("The Player Formerly Known as Prince")); |
1041 | @@ -141,11 +255,11 @@ | |||
1042 | 141 | MediaPlayerUser * player = media_player_user_new("user"); | 255 | MediaPlayerUser * player = media_player_user_new("user"); |
1043 | 142 | ASSERT_NE(nullptr, player); | 256 | ASSERT_NE(nullptr, player); |
1044 | 143 | 257 | ||
1045 | 144 | /* Get the proxy -- and it's precious precious data -- oh, my, precious! */ | ||
1046 | 145 | loop(100); | ||
1047 | 146 | |||
1048 | 147 | /* Ensure even with the proxy we don't have anything */ | 258 | /* Ensure even with the proxy we don't have anything */ |
1050 | 148 | EXPECT_TRUE(media_player_get_is_running(MEDIA_PLAYER(player))); | 259 | bool running = false; |
1051 | 260 | g_signal_connect(G_OBJECT(player), "notify::is-running", G_CALLBACK(running_update), &running); | ||
1052 | 261 | running_update(G_OBJECT(player), nullptr, &running); | ||
1053 | 262 | EXPECT_EVENTUALLY_EQ(true, running); | ||
1054 | 149 | EXPECT_TRUE(media_player_get_can_raise(MEDIA_PLAYER(player))); | 263 | EXPECT_TRUE(media_player_get_can_raise(MEDIA_PLAYER(player))); |
1055 | 150 | EXPECT_STREQ("user", media_player_get_id(MEDIA_PLAYER(player))); | 264 | EXPECT_STREQ("user", media_player_get_id(MEDIA_PLAYER(player))); |
1056 | 151 | EXPECT_STREQ("The Player Formerly Known as Prince", media_player_get_name(MEDIA_PLAYER(player))); | 265 | EXPECT_STREQ("The Player Formerly Known as Prince", media_player_get_name(MEDIA_PLAYER(player))); |
1057 | @@ -168,7 +282,7 @@ | |||
1058 | 168 | g_clear_object(&player); | 282 | g_clear_object(&player); |
1059 | 169 | } | 283 | } |
1060 | 170 | 284 | ||
1062 | 171 | TEST_F(MediaPlayerUserTest, TimeoutTest) { | 285 | TEST_F(MediaPlayerUserTest, DISABLED_TimeoutTest) { |
1063 | 172 | /* Put data into Acts -- but 15 minutes ago */ | 286 | /* Put data into Acts -- but 15 minutes ago */ |
1064 | 173 | set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time() - 15 * 60 * 1000 * 1000)); | 287 | set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time() - 15 * 60 * 1000 * 1000)); |
1065 | 174 | set_property("PlayerName", g_variant_new_string("The Player Formerly Known as Prince")); | 288 | set_property("PlayerName", g_variant_new_string("The Player Formerly Known as Prince")); |
1066 | @@ -180,24 +294,26 @@ | |||
1067 | 180 | set_property("Album", g_variant_new_string("Vinyl is dead")); | 294 | set_property("Album", g_variant_new_string("Vinyl is dead")); |
1068 | 181 | set_property("ArtUrl", g_variant_new_string("http://art.url")); | 295 | set_property("ArtUrl", g_variant_new_string("http://art.url")); |
1069 | 182 | 296 | ||
1070 | 183 | /* Ensure the properties get set before we pull them */ | ||
1071 | 184 | loop(100); | ||
1072 | 185 | |||
1073 | 186 | /* Build our media player */ | 297 | /* Build our media player */ |
1074 | 187 | MediaPlayerUser * player = media_player_user_new("user"); | 298 | MediaPlayerUser * player = media_player_user_new("user"); |
1075 | 188 | ASSERT_NE(nullptr, player); | 299 | ASSERT_NE(nullptr, player); |
1076 | 189 | 300 | ||
1079 | 190 | /* Get the proxy -- and the old data, so old, like forever */ | 301 | bool running = false; |
1080 | 191 | loop(100); | 302 | g_signal_connect(G_OBJECT(player), "notify::is-running", G_CALLBACK(running_update), &running); |
1081 | 303 | running_update(G_OBJECT(player), nullptr, &running); | ||
1082 | 192 | 304 | ||
1083 | 193 | /* Ensure that we show up as not running */ | 305 | /* Ensure that we show up as not running */ |
1085 | 194 | EXPECT_FALSE(media_player_get_is_running(MEDIA_PLAYER(player))); | 306 | EXPECT_EVENTUALLY_EQ(false, running); |
1086 | 195 | 307 | ||
1087 | 196 | /* Update to make running */ | 308 | /* Update to make running */ |
1088 | 197 | set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time())); | 309 | set_property("Timestamp", g_variant_new_uint64(g_get_monotonic_time())); |
1092 | 198 | loop(100); | 310 | |
1093 | 199 | 311 | EXPECT_EVENTUALLY_EQ(true, running); | |
1094 | 200 | EXPECT_TRUE(media_player_get_is_running(MEDIA_PLAYER(player))); | 312 | |
1095 | 313 | /* Clear to not run */ | ||
1096 | 314 | set_property("Timestamp", g_variant_new_uint64(1)); | ||
1097 | 315 | |||
1098 | 316 | EXPECT_EVENTUALLY_EQ(false, running); | ||
1099 | 201 | 317 | ||
1100 | 202 | g_clear_object(&in_icon); | 318 | g_clear_object(&in_icon); |
1101 | 203 | g_clear_object(&player); | 319 | g_clear_object(&player); |
1102 | 204 | 320 | ||
1103 | === modified file 'tests/notifications-test.cc' | |||
1104 | --- tests/notifications-test.cc 2015-02-24 19:05:10 +0000 | |||
1105 | +++ tests/notifications-test.cc 2015-10-13 13:18:26 +0000 | |||
1106 | @@ -350,29 +350,29 @@ | |||
1107 | 350 | 350 | ||
1108 | 351 | /* Set high volume with volume change */ | 351 | /* Set high volume with volume change */ |
1109 | 352 | notifications->clearNotifications(); | 352 | notifications->clearNotifications(); |
1111 | 353 | volume_control_mock_set_mock_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), TRUE); | 353 | volume_control_mock_set_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), true); |
1112 | 354 | setMockVolume(volumeControl, 0.90); | 354 | setMockVolume(volumeControl, 0.90); |
1113 | 355 | loop(50); | 355 | loop(50); |
1114 | 356 | notev = notifications->getNotifications(); | 356 | notev = notifications->getNotifications(); |
1115 | 357 | ASSERT_LT(0, notev.size()); /* This passes with one or two since it would just be an update to the first if a second was sent */ | 357 | ASSERT_LT(0, notev.size()); /* This passes with one or two since it would just be an update to the first if a second was sent */ |
1116 | 358 | EXPECT_EQ("Volume", notev[0].summary); | 358 | EXPECT_EQ("Volume", notev[0].summary); |
1118 | 359 | EXPECT_EQ("High volume", notev[0].body); | 359 | EXPECT_EQ("High volume can damage your hearing.", notev[0].body); |
1119 | 360 | EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]); | 360 | EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]); |
1120 | 361 | 361 | ||
1121 | 362 | /* Move it back */ | 362 | /* Move it back */ |
1123 | 363 | volume_control_mock_set_mock_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), FALSE); | 363 | volume_control_mock_set_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), false); |
1124 | 364 | setMockVolume(volumeControl, 0.50); | 364 | setMockVolume(volumeControl, 0.50); |
1125 | 365 | loop(50); | 365 | loop(50); |
1126 | 366 | 366 | ||
1127 | 367 | /* Set high volume without level change */ | 367 | /* Set high volume without level change */ |
1128 | 368 | /* NOTE: This can happen if headphones are plugged in */ | 368 | /* NOTE: This can happen if headphones are plugged in */ |
1129 | 369 | notifications->clearNotifications(); | 369 | notifications->clearNotifications(); |
1131 | 370 | volume_control_mock_set_mock_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), TRUE); | 370 | volume_control_mock_set_high_volume(VOLUME_CONTROL_MOCK(volumeControl.get()), TRUE); |
1132 | 371 | loop(50); | 371 | loop(50); |
1133 | 372 | notev = notifications->getNotifications(); | 372 | notev = notifications->getNotifications(); |
1134 | 373 | ASSERT_EQ(1, notev.size()); | 373 | ASSERT_EQ(1, notev.size()); |
1135 | 374 | EXPECT_EQ("Volume", notev[0].summary); | 374 | EXPECT_EQ("Volume", notev[0].summary); |
1137 | 375 | EXPECT_EQ("High volume", notev[0].body); | 375 | EXPECT_EQ("High volume can damage your hearing.", notev[0].body); |
1138 | 376 | EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]); | 376 | EXPECT_GVARIANT_EQ("@s 'true'", notev[0].hints["x-canonical-value-bar-tint"]); |
1139 | 377 | } | 377 | } |
1140 | 378 | 378 | ||
1141 | @@ -406,7 +406,7 @@ | |||
1142 | 406 | EXPECT_EQ(1, notev.size()); | 406 | EXPECT_EQ(1, notev.size()); |
1143 | 407 | } | 407 | } |
1144 | 408 | 408 | ||
1146 | 409 | TEST_F(NotificationsTest, ExtendendVolumeNotification) { | 409 | TEST_F(NotificationsTest, DISABLED_ExtendendVolumeNotification) { |
1147 | 410 | auto volumeControl = volumeControlMock(); | 410 | auto volumeControl = volumeControlMock(); |
1148 | 411 | auto soundService = standardService(volumeControl, playerListMock()); | 411 | auto soundService = standardService(volumeControl, playerListMock()); |
1149 | 412 | 412 | ||
1150 | @@ -424,7 +424,7 @@ | |||
1151 | 424 | 424 | ||
1152 | 425 | /* Allow an amplified volume */ | 425 | /* Allow an amplified volume */ |
1153 | 426 | notifications->clearNotifications(); | 426 | notifications->clearNotifications(); |
1155 | 427 | indicator_sound_service_set_allow_amplified_volume(soundService.get(), TRUE); | 427 | //indicator_sound_service_set_allow_amplified_volume(soundService.get(), TRUE); |
1156 | 428 | loop(50); | 428 | loop(50); |
1157 | 429 | notev = notifications->getNotifications(); | 429 | notev = notifications->getNotifications(); |
1158 | 430 | ASSERT_EQ(1, notev.size()); | 430 | ASSERT_EQ(1, notev.size()); |
1159 | @@ -440,7 +440,7 @@ | |||
1160 | 440 | 440 | ||
1161 | 441 | /* Put back */ | 441 | /* Put back */ |
1162 | 442 | notifications->clearNotifications(); | 442 | notifications->clearNotifications(); |
1164 | 443 | indicator_sound_service_set_allow_amplified_volume(soundService.get(), FALSE); | 443 | //indicator_sound_service_set_allow_amplified_volume(soundService.get(), FALSE); |
1165 | 444 | loop(50); | 444 | loop(50); |
1166 | 445 | notev = notifications->getNotifications(); | 445 | notev = notifications->getNotifications(); |
1167 | 446 | ASSERT_EQ(1, notev.size()); | 446 | ASSERT_EQ(1, notev.size()); |
1168 | 447 | 447 | ||
1169 | === modified file 'tests/volume-control-mock.vala' | |||
1170 | --- tests/volume-control-mock.vala 2015-02-17 16:54:53 +0000 | |||
1171 | +++ tests/volume-control-mock.vala 2015-10-13 13:18:26 +0000 | |||
1172 | @@ -20,12 +20,14 @@ | |||
1173 | 20 | 20 | ||
1174 | 21 | public class VolumeControlMock : VolumeControl | 21 | public class VolumeControlMock : VolumeControl |
1175 | 22 | { | 22 | { |
1176 | 23 | private bool _high_volume = false; | ||
1177 | 24 | public override bool high_volume { get { return _high_volume; } protected set { _high_volume = value; } } | ||
1178 | 25 | public void set_high_volume(bool b) { high_volume = b; } | ||
1179 | 26 | |||
1180 | 23 | public string mock_stream { get; set; default = "multimedia"; } | 27 | public string mock_stream { get; set; default = "multimedia"; } |
1181 | 24 | public override string stream { get { return mock_stream; } } | 28 | public override string stream { get { return mock_stream; } } |
1182 | 25 | public override bool ready { get; set; } | 29 | public override bool ready { get; set; } |
1183 | 26 | public override bool active_mic { get; set; } | 30 | public override bool active_mic { get; set; } |
1184 | 27 | public bool mock_high_volume { get; set; } | ||
1185 | 28 | public override bool high_volume { get { return mock_high_volume; } } | ||
1186 | 29 | public bool mock_mute { get; set; } | 31 | public bool mock_mute { get; set; } |
1187 | 30 | public override bool mute { get { return mock_mute; } } | 32 | public override bool mute { get { return mock_mute; } } |
1188 | 31 | public bool mock_is_playing { get; set; } | 33 | public bool mock_is_playing { get; set; } |
1189 | 32 | 34 | ||
1190 | === modified file 'tests/volume-control-test.cc' | |||
1191 | --- tests/volume-control-test.cc 2015-02-09 20:14:15 +0000 | |||
1192 | +++ tests/volume-control-test.cc 2015-10-13 13:18:26 +0000 | |||
1193 | @@ -32,7 +32,11 @@ | |||
1194 | 32 | DbusTestService * service = NULL; | 32 | DbusTestService * service = NULL; |
1195 | 33 | GDBusConnection * session = NULL; | 33 | GDBusConnection * session = NULL; |
1196 | 34 | 34 | ||
1198 | 35 | virtual void SetUp() { | 35 | virtual void SetUp() override { |
1199 | 36 | |||
1200 | 37 | g_setenv("GSETTINGS_SCHEMA_DIR", SCHEMA_DIR, TRUE); | ||
1201 | 38 | g_setenv("GSETTINGS_BACKEND", "memory", TRUE); | ||
1202 | 39 | |||
1203 | 36 | service = dbus_test_service_new(NULL); | 40 | service = dbus_test_service_new(NULL); |
1204 | 37 | dbus_test_service_start_tasks(service); | 41 | dbus_test_service_start_tasks(service); |
1205 | 38 | 42 |
PASSED: Continuous integration, rev:501 jenkins. qa.ubuntu. com/job/ indicator- sound-15. 04-ci/1/ jenkins. qa.ubuntu. com/job/ indicator- sound-15. 04-vivid- amd64-ci/ 1 jenkins. qa.ubuntu. com/job/ indicator- sound-15. 04-vivid- armhf-ci/ 1 jenkins. qa.ubuntu. com/job/ indicator- sound-15. 04-vivid- armhf-ci/ 1/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/indicator- sound-15. 04-ci/1/ rebuild
http://