Merge lp:~indicator-applet-developers/indicator-sound/rtm-extreme-volume-warning into lp:indicator-sound/rtm-14.09

Proposed by Michał Sawicz
Status: Merged
Approved by: Michał Sawicz
Approved revision: 465
Merge reported by: Ted Gould
Merged at revision: not available
Proposed branch: lp:~indicator-applet-developers/indicator-sound/rtm-extreme-volume-warning
Merge into: lp:indicator-sound/rtm-14.09
Prerequisite: lp:~ted/indicator-sound/synchronous-notification
Diff against target: 295 lines (+150/-15)
5 files modified
debian/changelog (+8/-0)
src/service.vala (+16/-0)
src/sound-menu.vala (+39/-1)
src/volume-control.vala (+69/-14)
tests/manual (+18/-0)
To merge this branch: bzr merge lp:~indicator-applet-developers/indicator-sound/rtm-extreme-volume-warning
Reviewer Review Type Date Requested Status
Michał Sawicz Approve
Mirco Müller (community) Approve
Review via email: mp+238259@code.launchpad.net

Commit message

Warn on high audio levels when using headphones

To post a comment you must log in.
Revision history for this message
Mirco Müller (macslow) wrote :

Don't use a notification's summary-text for the "High Volume"-warning. See inline comment.

review: Needs Fixing
Revision history for this message
Mirco Müller (macslow) wrote :

Please see fixes added in lp:~macslow/indicator-sound/rtm-extreme-volume-warning-tweaks

This still does not yet address the sound-playback upon each key-press and the triggering of the sync. notification if the volume is changed via the sound-indicator.

review: Needs Fixing
Revision history for this message
Mirco Müller (macslow) wrote :

The manual-test recipe needs an update... see inline comment at line 270.

review: Needs Fixing
Revision history for this message
Mirco Müller (macslow) wrote :

The icon-to-volume-level mapping is not fully in sync. with the panel-volume-icon (see inline comment at 223).

review: Needs Fixing
Revision history for this message
Ted Gould (ted) wrote :

Fixed. r463

Revision history for this message
Mirco Müller (macslow) wrote :

I'm now ok with this branch. Manually compiled and installed it works nicely.

review: Approve
Revision history for this message
Michał Sawicz (saviq) wrote :

Tested extensively for going into rtm.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2014-10-08 18:55:06 +0000
3+++ debian/changelog 2014-10-15 18:55:30 +0000
4@@ -1,3 +1,11 @@
5+indicator-sound (12.10.2+14.10.20141010-0ubuntu1) utopic; urgency=low
6+
7+ [ Ricardo Salveti de Araujo ]
8+ * volume-control: making sure we're always in sync with accountservice
9+ (LP: #1379618)
10+
11+ -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Fri, 10 Oct 2014 15:40:30 +0000
12+
13 indicator-sound (12.10.2+14.10.20141008-0ubuntu1) utopic; urgency=low
14
15 [ Ted Gould ]
16
17=== modified file 'src/service.vala'
18--- src/service.vala 2014-03-25 19:58:12 +0000
19+++ src/service.vala 2014-10-15 18:55:30 +0000
20@@ -36,6 +36,7 @@
21 this.actions.add_action (this.create_mute_action ());
22 this.actions.add_action (this.create_volume_action ());
23 this.actions.add_action (this.create_mic_volume_action ());
24+ this.actions.add_action (this.create_high_volume_actions ());
25
26 this.menus = new HashTable<string, SoundMenu> (str_hash, str_equal);
27 this.menus.insert ("desktop_greeter", new SoundMenu (null, SoundMenu.DisplayFlags.SHOW_MUTE | SoundMenu.DisplayFlags.HIDE_PLAYERS));
28@@ -47,6 +48,10 @@
29 this.volume_control.bind_property ("active-mic", menu, "show-mic-volume", BindingFlags.SYNC_CREATE);
30 });
31
32+ this.menus.@foreach ( (profile, menu) => {
33+ this.volume_control.bind_property ("high-volume", menu, "show-high-volume-warning", BindingFlags.SYNC_CREATE);
34+ });
35+
36 /* Setup handling for the greeter-export setting */
37 this.settings.changed["greeter-export"].connect( () => this.build_accountsservice() );
38 build_accountsservice();
39@@ -181,6 +186,8 @@
40 double v = this.volume_control.get_volume () + volume_step_percentage * delta;
41 this.volume_control.set_volume (v.clamp (0.0, this.max_volume));
42
43+ /* TODO: Don't want to mess up the desktop today, but we should remove this
44+ scrolling change and merge that into volume control's notification */
45 if (this.notification != null) {
46 string icon;
47 if (v <= 0.0)
48@@ -365,6 +372,15 @@
49 return volume_action;
50 }
51
52+ Action create_high_volume_actions () {
53+ var high_volume_action = new SimpleAction.stateful("high-volume", null, new Variant.boolean (this.volume_control.high_volume));
54+
55+ this.volume_control.notify["high-volume"].connect( () =>
56+ high_volume_action.set_state(new Variant.boolean (this.volume_control.high_volume)));
57+
58+ return high_volume_action;
59+ }
60+
61 void bus_acquired (DBusConnection connection, string name) {
62 try {
63 connection.export_action_group ("/com/canonical/indicator/sound", this.actions);
64
65=== modified file 'src/sound-menu.vala'
66--- src/sound-menu.vala 2014-09-26 13:52:56 +0000
67+++ src/sound-menu.vala 2014-10-15 18:55:30 +0000
68@@ -82,12 +82,49 @@
69 this.mic_volume_shown = true;
70 }
71 else if (!value && this.mic_volume_shown) {
72- this.volume_section.remove (this.volume_section.get_n_items () -1);
73+ int location = -1;
74+ while ((location = find_action(this.volume_section, "indicator.mic-volume")) != -1) {
75+ this.volume_section.remove (location);
76+ }
77 this.mic_volume_shown = false;
78 }
79 }
80 }
81
82+ public bool show_high_volume_warning {
83+ get {
84+ return this.high_volume_warning_shown;
85+ }
86+ set {
87+ if (value && !this.high_volume_warning_shown) {
88+ /* NOTE: Action doesn't really exist, just used to find below when removing */
89+ var item = new MenuItem(_("High volume can damage your hearing."), "indicator.high-volume-warning-item");
90+ volume_section.append_item (item);
91+ this.high_volume_warning_shown = true;
92+ }
93+ else if (!value && this.high_volume_warning_shown) {
94+ int location = -1;
95+ while ((location = find_action(this.volume_section, "indicator.high-volume-warning-item")) != -1) {
96+ this.volume_section.remove (location);
97+ }
98+ this.high_volume_warning_shown = false;
99+ }
100+ }
101+ }
102+
103+ int find_action (Menu menu, string in_action) {
104+ int n = menu.get_n_items ();
105+ for (int i = 0; i < n; i++) {
106+ string action;
107+ menu.get_item_attribute (i, "action", "s", out action);
108+ if (in_action == action)
109+ return i;
110+ }
111+
112+ return -1;
113+ }
114+
115+
116 public void add_player (MediaPlayer player) {
117 if (this.notify_handlers.contains (player))
118 return;
119@@ -130,6 +167,7 @@
120 Menu volume_section;
121 bool mic_volume_shown;
122 bool settings_shown = false;
123+ bool high_volume_warning_shown = false;
124 bool hide_inactive;
125 bool hide_players = false;
126 HashTable<MediaPlayer, ulong> notify_handlers;
127
128=== modified file 'src/volume-control.vala'
129--- src/volume-control.vala 2014-10-15 18:55:30 +0000
130+++ src/volume-control.vala 2014-10-15 18:55:30 +0000
131@@ -70,6 +70,8 @@
132 private double _account_service_volume = 0.0;
133 private Notify.Notification _notification;
134
135+ private bool _active_port_headphone = false;
136+
137 public signal void volume_changed (double v);
138 public signal void mic_volume_changed (double v);
139
140@@ -79,6 +81,9 @@
141 /** true when a microphone is active **/
142 public bool active_mic { get; private set; default = false; }
143
144+ /** true when high volume warnings should be shown */
145+ public bool high_volume { get; set; }
146+
147 public VolumeControl ()
148 {
149 if (loop == null)
150@@ -158,6 +163,8 @@
151
152 private void sink_info_cb_for_props (Context c, SinkInfo? i, int eol)
153 {
154+ bool old_active_port_headphone = this._active_port_headphone;
155+
156 if (i == null)
157 return;
158
159@@ -174,11 +181,27 @@
160 this.notify_property ("is-playing");
161 }
162
163+ /* Check if the current active port is headset/headphone */
164+ /* There is not easy way to check if the port is a headset/headphone besides
165+ * checking for the port name. On touch (with the pulseaudio droid element)
166+ * the headset/headphone port is called 'output-headset' and 'output-headphone'.
167+ * On the desktop this is usually called 'analog-output-headphones' */
168+ if (i.active_port.name == "output-wired_headset" ||
169+ i.active_port.name == "output-wired_headphone" ||
170+ i.active_port.name == "analog-output-headphones") {
171+ _active_port_headphone = true;
172+ } else {
173+ _active_port_headphone = false;
174+ }
175+
176 if (_pulse_use_stream_restore == false &&
177 _volume != volume_to_double (i.volume.max ()))
178 {
179 _volume = volume_to_double (i.volume.max ());
180 volume_changed (_volume);
181+ start_local_volume_timer();
182+ } else if (this._active_port_headphone != old_active_port_headphone) {
183+ volume_changed (_volume);
184 }
185 }
186
187@@ -247,6 +270,7 @@
188 /* Someone else changed the volume for this role, reflect on the indicator */
189 _volume = volume_to_double (volume);
190 volume_changed (_volume);
191+ start_local_volume_timer();
192 }
193 }
194 }
195@@ -289,6 +313,7 @@
196
197 _volume = volume_to_double (volume);
198 volume_changed (_volume);
199+ start_local_volume_timer();
200 } catch (GLib.Error e) {
201 warning ("unable to get volume for active role %s (%s)", sink_input_objp, e.message);
202 }
203@@ -579,22 +604,52 @@
204 {
205 /* Using this to detect whether we're on the phone or not */
206 if (_pulse_use_stream_restore) {
207- if (volume == 0.0)
208- _notification.update (_("Volume"), "", "audio-volume-muted");
209- if (volume > 0.0 && volume <= 0.33)
210- _notification.update (_("Volume"), "", "audio-volume-low");
211- if (volume > 0.33 && volume <= 0.66)
212- _notification.update (_("Volume"), "", "audio-volume-medium");
213- if (volume > 0.66 && volume <= 1.0)
214- _notification.update (_("Volume"), "", "audio-volume-high");
215+ /* Watch for extreme */
216+ if (volume > 0.75 && _active_port_headphone)
217+ high_volume = true;
218+ else
219+ high_volume = false;
220+
221+ /* Determine Label */
222+ string volume_label = "";
223+ if (high_volume)
224+ volume_label = _("High volume");
225+
226+ /* Choose an icon */
227+ string icon = "audio-volume-muted";
228+ if (volume <= 0.0)
229+ icon = "audio-volume-muted";
230+ else if (volume <= 0.3)
231+ icon = "audio-volume-low";
232+ else if (volume <= 0.7)
233+ icon = "audio-volume-medium";
234+ else
235+ icon = "audio-volume-high";
236+
237+ /* Choose a sound */
238+ string? sound = null;
239+ if (!((_active_sink_input >= 0) && (_active_sink_input < _valid_roles.length)
240+ && (_valid_roles[_active_sink_input] == "multimedia")))
241+ sound = "/usr/share/sounds/ubuntu/stereo/message.ogg";
242+
243+ /* Check tint */
244+ string tint = "false";
245+ if (high_volume)
246+ tint = "true";
247+
248+ /* Put it all into the notification */
249+ _notification.clear_hints ();
250+ _notification.update (_("Volume"), volume_label, icon);
251 _notification.set_hint ("value", (int32)(volume * 100.0));
252- if (_active_sink_input == -1 || _valid_roles[_active_sink_input] != "multimedia") {
253- /* No audio ping if we're playing multimedia */
254- _notification.set_hint ("sound-file", "/usr/share/sounds/ubuntu/stereo/message.ogg");
255- } else {
256- _notification.set_hint ("sound-file", null);
257- }
258+ /* TODO: Removing sound until we can get all the roles cleaned up for
259+ when to play it. We expect this to come back, but in another landing.
260+ _notification.set_hint ("sound-file", sound);
261+ */
262+ _notification.set_hint ("x-canonical-value-bar-tint", tint);
263+ _notification.set_hint ("x-canonical-private-synchronous", "true");
264+ _notification.set_hint ("x-canonical-non-shaped-icon", "true");
265
266+ /* Show it */
267 try {
268 _notification.show ();
269 } catch (GLib.Error e) {
270
271=== modified file 'tests/manual'
272--- tests/manual 2014-10-15 18:55:30 +0000
273+++ tests/manual 2014-10-15 18:55:30 +0000
274@@ -39,3 +39,21 @@
275 <dd>A notification bubble should appear with the sound volume</dd>
276 <dd>No notification sound should be heard</dd>
277 </dl>
278+
279+Test-case indicator-sound/unity8-high-volume
280+<dl>
281+ <dt>Plug headphones into the headphone jack</dt>
282+ <dt>Adjust volume so that it is at the midpoint of volume range</dt>
283+ <dd>The slider should be in the middle of the scale</dd>
284+ <dt>Increase the volume once using HW keys if available</dt>
285+ <dd>A notification bubble should appear with the sound volume</dd>
286+ <dd>There should be no text on the notification</dd>
287+ <dt>Increase the volume using HW keys until it is roughly 90% of the range</dt>
288+ <dd>A notification bubble should appear with the sound volume</dd>
289+ <dd>The text on the notification should read "High volume"</dd>
290+ <dd>The range on the notification bubble should have a different color signifying the higher volume</dd>
291+ <dt>Decrease the volume using HW keys until it is roughly 50% of the range</dt>
292+ <dd>A notification bubble should appear with the sound volume</dd>
293+ <dd>There should be no text on the notification</dd>
294+ <dd>The range on the notification bubble should have a standard color</dd>
295+</dl>

Subscribers

People subscribed via source and target branches

to all changes: