Merge lp:~dylanmccall/notify-osd/sounds-support into lp:notify-osd/lucid

Proposed by Dylan McCall
Status: Needs review
Proposed branch: lp:~dylanmccall/notify-osd/sounds-support
Merge into: lp:notify-osd/lucid
Diff against target: 453 lines (+293/-3)
6 files modified
configure.in (+1/-1)
src/bubble.c (+90/-0)
src/bubble.h (+15/-0)
src/notification.c (+134/-0)
src/notification.h (+21/-0)
src/stack.c (+32/-2)
To merge this branch: bzr merge lp:~dylanmccall/notify-osd/sounds-support
Reviewer Review Type Date Requested Status
Mirco Müller (community) Needs Fixing
Review via email: mp+42788@code.launchpad.net

Description of the change

This branch adds sounds support, as specified at https://wiki.ubuntu.com/NotifyOSD#Sound and http://people.canonical.com/~agateau/notifications-1.1/spec/ar01s08.html

The feature can be tested with notify-send:
notify-send --hint=string:sound-name:phone-incoming-call "Yay" "sound-name hint"
notify-send --hint=string:sound-file:/usr/share/sounds/gnome/default/alerts/sonar.ogg "Yay" "sound-file hint"

Note that a bubble's sound plays when it appears, and libcanberra-gtk (+PulseAudio) position the sound so it seems to come from the notification bubble.

To post a comment you must log in.
431. By Dylan McCall

Remove type check for suppress-sound hint. If the hint is there, immediately set suppress_sound to TRUE.

Revision history for this message
Dylan McCall (dylanmccall) wrote :

To test suppress-sound, you'll need a sufficiently long sound (but the file can't be too big or Canberra will refuse to play it). Try something like this:

notify-send --hint=string:sound-file:/home/dylan/Desktop/Freedom.ogg --hint=string:suppress-sound: "Testing" "suppress-sound hint"

Run that twice, giving it your own sound-file. The specification on this one wasn't completely clear to me, but my implementation will stop any other notification sounds generated by notify-osd.

I noticed that pynotify doesn't deal in Boolean hints (which the specification wants), and I couldn't find any other hints that were boolean either. So, in revision 431 I made this not look at the type of the hint. If the hint is there, it's assumed that suppress_sound should be True.

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

This patch causes notification bubbles not to show up at all (but attached sound-files are played). I'm not sure what's causing the bubble not to appear. I've used these to commands to test this on current natty:

notify-send "Incoming call" "Yo dude, answer the damn phone" -i ubuntu-logo --hint=string:sound-file:/usr/share/sounds/ubuntu/stereo/phone-incoming-call.ogg

notify-send "Line busy" "Please call again later" -i gnome-foot --hint=string:sound-file:/usr/share/sounds/ubuntu/stereo/phone-outgoing-busy.ogg

I see and hear the first bubble, but the second bubble does not get displayed. I only hear the sound file played of the second one.

review: Needs Fixing
Revision history for this message
Dylan McCall (dylanmccall) wrote :

Interesting… I tried to reproduce that problem but I haven't seen it yet :o
I tried under both Maverick and Natty (under a VM) with this branch. (I had to rebase it to the current lp:notify-osd to get it to build under Natty).

Was this consistently happening on your end, or should I be looking for more of a chance occurrence?

Revision history for this message
Andrew Somerville (andy-somerville) wrote :

Seems like this died several years ago. Any replacement?

Unmerged revisions

431. By Dylan McCall

Remove type check for suppress-sound hint. If the hint is there, immediately set suppress_sound to TRUE.

430. By Dylan McCall

Renamed sound-id to sound-name, matching specification at http://people.canonical.com/~agateau/notifications-1.1/spec/ar01s08.html

Set ID for sound-file, sounds, too, so suppress-sound works reliably.

429. By Dylan McCall

Implement suppress-sound hint. Haven't been able to test this, but it _should_ work, I think...

428. By Dylan McCall

Initial support for sounds in notify-osd.

This adds a dependency on libcanberra-gtk, which carries out the actual playing of event sounds.
This uses the sound-file hint described in the Desktop Notification Specification.
In addition, there is a non-standard x-sound-id hint.

Implementation so far plays sounds, but does not fully comply with the specification. Still need to implement suppress-sounds :)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'configure.in'
2--- configure.in 2010-10-05 17:54:42 +0000
3+++ configure.in 2010-12-05 20:02:10 +0000
4@@ -26,7 +26,7 @@
5 #
6 # glib, we need 2.16.0 for the unit-tests
7 #
8-PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.16.0 gthread-2.0 gconf-2.0 gio-2.0])
9+PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.16.0 gthread-2.0 gconf-2.0 gio-2.0 libcanberra libcanberra-gtk])
10
11 #
12 # gconf, used by the Defaults class to get system font-face and font-size
13
14=== modified file 'src/bubble.c'
15--- src/bubble.c 2010-10-05 17:54:42 +0000
16+++ src/bubble.c 2010-12-05 20:02:10 +0000
17@@ -42,6 +42,8 @@
18 #include <egg/egg-hack.h>
19 #include <egg/egg-alpha.h>
20
21+#include <canberra-gtk.h>
22+
23 #include "bubble.h"
24 #include "defaults.h"
25 #include "stack.h"
26@@ -96,6 +98,9 @@
27 guint timeout;
28 guint urgency;
29 //notification_t* notification;
30+ gboolean suppress_sound;
31+ gchar* sound_name;
32+ gchar* sound_file;
33
34 // used to prevent unneeded updates of the tile-cache, for append-,
35 // update or replace-cases, needs to move into class Notification
36@@ -167,6 +172,8 @@
37 #define BUBBLE_CONTENT_BLUR_RADIUS 4
38 #define TEXT_DROP_SHADOW_SIZE 2
39
40+#define BUBBLE_CA_GTK_SOUNDS_ID 1
41+
42 //-- private functions ---------------------------------------------------------
43
44 static guint g_bubble_signals[LAST_SIGNAL] = { 0 };
45@@ -2422,6 +2429,65 @@
46 }
47
48 void
49+bubble_set_suppress_sound (Bubble* self,
50+ gboolean suppress_sound)
51+{
52+ if (!self || !IS_BUBBLE (self))
53+ return;
54+
55+ GET_PRIVATE (self)->suppress_sound = suppress_sound;
56+}
57+
58+gboolean
59+bubble_get_suppress_sound (Bubble* self)
60+{
61+ if (!self || !IS_BUBBLE (self))
62+ return FALSE;
63+
64+ return GET_PRIVATE (self)->suppress_sound;
65+}
66+
67+void
68+bubble_set_sound_name (Bubble* self,
69+ const gchar* id)
70+{
71+ BubblePrivate* priv;
72+
73+ if (!self || !IS_BUBBLE (self) || !g_strcmp0 (id, ""))
74+ return;
75+
76+ priv = GET_PRIVATE (self);
77+
78+ if (priv->sound_name)
79+ {
80+ g_object_unref (priv->sound_name);
81+ priv->sound_name = NULL;
82+ }
83+
84+ priv->sound_name = g_strdup (id);
85+}
86+
87+void
88+bubble_set_sound_file (Bubble* self,
89+ const gchar* file)
90+{
91+ BubblePrivate* priv;
92+
93+ if (!self || !IS_BUBBLE (self) || !g_strcmp0 (file, ""))
94+ return;
95+
96+ priv = GET_PRIVATE (self);
97+
98+ if (priv->sound_file)
99+ {
100+ g_object_unref (priv->sound_file);
101+ priv->sound_file = NULL;
102+ }
103+
104+ priv->sound_file = g_strdup (file);
105+}
106+
107+void
108 bubble_set_icon (Bubble* self,
109 const gchar* filename)
110 {
111@@ -2823,6 +2889,30 @@
112 priv->pointer_update_id = g_timeout_add (1000/FPS,
113 (GSourceFunc) pointer_update,
114 self);
115+
116+ // play an attached sound using Canberra
117+ if (priv->suppress_sound)
118+ {
119+ ca_context* c = ca_gtk_context_get ();
120+ ca_context_cancel(c, BUBBLE_CA_GTK_SOUNDS_ID);
121+ }
122+
123+ if (priv->sound_name)
124+ {
125+ ca_gtk_play_for_widget (priv->widget, BUBBLE_CA_GTK_SOUNDS_ID,
126+ CA_PROP_EVENT_ID, priv->sound_name,
127+ /*CA_PROP_EVENT_DESCRIPTION, "event description",
128+ CA_PROP_APPLICATION_ID, "application id",*/
129+ NULL);
130+ }
131+ else if (priv->sound_file)
132+ {
133+ ca_gtk_play_for_widget (priv->widget, BUBBLE_CA_GTK_SOUNDS_ID,
134+ CA_PROP_MEDIA_FILENAME, priv->sound_file,
135+ /*CA_PROP_EVENT_DESCRIPTION, "event description",
136+ CA_PROP_APPLICATION_ID, "application id",*/
137+ NULL);
138+ }
139 }
140
141 /* mostly called when we change the content of the bubble
142
143=== modified file 'src/bubble.h'
144--- src/bubble.h 2009-10-20 08:51:11 +0000
145+++ src/bubble.h 2010-12-05 20:02:10 +0000
146@@ -124,6 +124,21 @@
147 bubble_get_icon_pixbuf (Bubble *self);
148
149 void
150+bubble_set_suppress_sound (Bubble* self,
151+ gboolean suppress_sound);
152+
153+gboolean
154+bubble_get_suppress_sound (Bubble* self);
155+
156+void
157+bubble_set_sound_name (Bubble* self,
158+ const gchar* id);
159+
160+void
161+bubble_set_sound_file (Bubble* self,
162+ const gchar* file);
163+
164+void
165 bubble_set_value (Bubble* self,
166 gint value);
167
168
169=== modified file 'src/notification.c'
170--- src/notification.c 2009-08-04 15:18:03 +0000
171+++ src/notification.c 2010-12-05 20:02:10 +0000
172@@ -40,6 +40,9 @@
173 PROP_ICON_THEMENAME,
174 PROP_ICON_FILENAME,
175 PROP_ICON_PIXBUF,
176+ PROP_SUPPRESS_SOUND,
177+ PROP_SOUND_NAME,
178+ PROP_SOUND_FILE,
179 PROP_ONSCREEN_TIME,
180 PROP_SENDER_NAME,
181 PROP_SENDER_PID,
182@@ -58,6 +61,9 @@
183 GString* icon_themename; // e.g. "notification-message-email"
184 GString* icon_filename; // e.g. "/usr/share/icons/icon.png"
185 GdkPixbuf* icon_pixbuf; // from setter memcpy'ed pixbuf
186+ gboolean suppress_sound; // true to suppress playing sounds
187+ GString* sound_name; // eg. "audio-volume-change"
188+ GString* sound_file; // eg. "/usr/share/sounds/email.wav"
189 gint onscreen_time; // time on-screen in ms
190 GString* sender_name; // app-name, strdup'ed from setter
191 gint sender_pid; // pid of sending application
192@@ -135,6 +141,18 @@
193 g_object_unref (priv->icon_pixbuf);
194 }
195
196+ if (priv->sound_name)
197+ {
198+ g_string_free (priv->sound_name, TRUE);
199+ priv->sound_name = NULL;
200+ }
201+
202+ if (priv->sound_file)
203+ {
204+ g_string_free (priv->sound_file, TRUE);
205+ priv->sound_file = NULL;
206+ }
207+
208 if (priv->sender_name)
209 {
210 g_string_free (priv->sender_name, TRUE);
211@@ -201,6 +219,21 @@
212 notification_get_icon_pixbuf (n));
213 break;
214
215+ case PROP_SUPPRESS_SOUND:
216+ g_value_set_boolean (value,
217+ notification_get_suppress_sound (n));
218+ break;
219+
220+ case PROP_SOUND_NAME:
221+ g_value_set_string (value,
222+ notification_get_sound_name (n));
223+ break;
224+
225+ case PROP_SOUND_FILE:
226+ g_value_set_string (value,
227+ notification_get_sound_file (n));
228+ break;
229+
230 case PROP_ONSCREEN_TIME:
231 g_value_set_int (value,
232 notification_get_onscreen_time (n));
233@@ -278,6 +311,24 @@
234 g_value_get_pointer (value));
235 break;
236
237+ case PROP_SUPPRESS_SOUND:
238+ notification_set_suppress_sound (
239+ n,
240+ g_value_get_boolean (value));
241+ break;
242+
243+ case PROP_SOUND_NAME:
244+ notification_set_sound_name (
245+ n,
246+ g_value_get_string (value));
247+ break;
248+
249+ case PROP_SOUND_FILE:
250+ notification_set_sound_file (
251+ n,
252+ g_value_get_string (value));
253+ break;
254+
255 case PROP_ONSCREEN_TIME:
256 notification_set_onscreen_time (
257 n,
258@@ -325,6 +376,9 @@
259 GParamSpec* property_icon_themename;
260 GParamSpec* property_icon_filename;
261 GParamSpec* property_icon_pixbuf;
262+ GParamSpec* property_suppress_sound;
263+ GParamSpec* property_sound_name;
264+ GParamSpec* property_sound_file;
265 GParamSpec* property_onscreen_time;
266 GParamSpec* property_sender_name;
267 GParamSpec* property_sender_pid;
268@@ -413,6 +467,39 @@
269 PROP_ICON_PIXBUF,
270 property_icon_pixbuf);
271
272+ property_suppress_sound = g_param_spec_boolean (
273+ "suppress-sound",
274+ "suppress-sound",
275+ "whether to suppress playing sounds",
276+ 0,
277+ G_PARAM_CONSTRUCT |
278+ G_PARAM_READWRITE);
279+ g_object_class_install_property (gobject_class,
280+ PROP_SUPPRESS_SOUND,
281+ property_suppress_sound);
282+
283+ property_sound_name = g_param_spec_string (
284+ "sound-id",
285+ "sound-id",
286+ "name of sound to use",
287+ NULL,
288+ G_PARAM_CONSTRUCT |
289+ G_PARAM_READWRITE);
290+ g_object_class_install_property (gobject_class,
291+ PROP_SOUND_NAME,
292+ property_sound_name);
293+
294+ property_sound_file = g_param_spec_string (
295+ "sound-file",
296+ "sound-file",
297+ "file-name of sound to use",
298+ NULL,
299+ G_PARAM_CONSTRUCT |
300+ G_PARAM_READWRITE);
301+ g_object_class_install_property (gobject_class,
302+ PROP_SOUND_FILE,
303+ property_sound_file);
304+
305 property_onscreen_time = g_param_spec_int ("onscreen-time",
306 "onscreen-time",
307 "time on screen sofar",
308@@ -617,6 +704,53 @@
309 return GET_PRIVATE (n)->icon_pixbuf;
310 }
311
312+gboolean
313+notification_get_suppress_sound (Notification* n)
314+{
315+ g_return_val_if_fail (IS_NOTIFICATION (n), -2);
316+
317+ return GET_PRIVATE (n)->suppress_sound;
318+}
319+
320+void
321+notification_set_suppress_sound (Notification* n,
322+ gboolean suppress_sound)
323+{
324+ NotificationPrivate* priv;
325+
326+ g_assert (IS_NOTIFICATION (n));
327+
328+ priv = GET_PRIVATE (n);
329+
330+ priv->suppress_sound = suppress_sound;
331+}
332+
333+gchar*
334+notification_get_sound_name (Notification* n)
335+{
336+ RETURN_GCHAR (n, sound_name)
337+}
338+
339+void
340+notification_set_sound_name (Notification* n,
341+ const gchar* sound_name)
342+{
343+ SET_GCHAR (n, sound_name)
344+}
345+
346+gchar*
347+notification_get_sound_file (Notification* n)
348+{
349+ RETURN_GCHAR (n, sound_file)
350+}
351+
352+void
353+notification_set_sound_file (Notification* n,
354+ const gchar* sound_file)
355+{
356+ SET_GCHAR (n, sound_file)
357+}
358+
359 void
360 notification_set_icon_pixbuf (Notification* n,
361 const GdkPixbuf* icon_pixbuf)
362
363=== modified file 'src/notification.h'
364--- src/notification.h 2009-08-04 09:59:20 +0000
365+++ src/notification.h 2010-12-05 20:02:10 +0000
366@@ -127,6 +127,27 @@
367 notification_set_icon_pixbuf (Notification* n,
368 const GdkPixbuf* icon_pixbuf);
369
370+gboolean
371+notification_get_suppress_sound (Notification* n);
372+
373+void
374+notification_set_suppress_sound (Notification* n,
375+ const gboolean suppress_sound);
376+
377+gchar*
378+notification_get_sound_name (Notification* n);
379+
380+void
381+notification_set_sound_name (Notification* n,
382+ const gchar* sound_name);
383+
384+gchar*
385+notification_get_sound_file (Notification* n);
386+
387+void
388+notification_set_sound_file (Notification* n,
389+ const gchar* sound_file);
390+
391 gint
392 notification_get_onscreen_time (Notification* n);
393
394
395=== modified file 'src/stack.c'
396--- src/stack.c 2009-10-20 08:51:11 +0000
397+++ src/stack.c 2010-12-05 20:02:10 +0000
398@@ -741,6 +741,35 @@
399 bubble_set_icon_from_pixbuf (bubble, pixbuf);
400 }
401 }
402+
403+ if (hints)
404+ {
405+ if ((data = (GValue*) g_hash_table_lookup (hints, "sound-name")))
406+ {
407+ g_debug("Using sound-name hint\n");
408+ if ((data && G_VALUE_HOLDS_STRING (data)))
409+ bubble_set_sound_name (bubble, g_value_get_string(data));
410+ else
411+ g_warning ("sound-name hint is not a string\n");
412+ }
413+ else if ((data = (GValue*) g_hash_table_lookup (hints, "sound-file")))
414+ {
415+ g_debug("Using sound-file hint\n");
416+ if ((data && G_VALUE_HOLDS_STRING (data)))
417+ bubble_set_sound_file (bubble, g_value_get_string(data));
418+ else
419+ g_warning ("sound-file hint is not a string\n");
420+ }
421+ }
422+
423+ if (hints)
424+ {
425+ if ((data = (GValue*) g_hash_table_lookup (hints, "suppress-sound")))
426+ {
427+ g_debug("Using suppress-sound hint\n");
428+ bubble_set_suppress_sound (bubble, TRUE);
429+ }
430+ }
431
432 log_bubble_debug (bubble, app_name,
433 (*icon == '\0' && data != NULL) ?
434@@ -828,7 +857,7 @@
435 stack_get_capabilities (Stack* self,
436 gchar*** out_caps)
437 {
438- *out_caps = g_malloc0 (13 * sizeof(char *));
439+ *out_caps = g_malloc0 (14 * sizeof(char *));
440
441 (*out_caps)[0] = g_strdup ("body");
442 (*out_caps)[1] = g_strdup ("body-markup");
443@@ -846,8 +875,9 @@
444 (*out_caps)[9] = g_strdup ("append");
445 (*out_caps)[10] = g_strdup ("private-icon-only");
446 (*out_caps)[11] = g_strdup ("truncation");
447+ (*out_caps)[12] = g_strdup ("sound");
448
449- (*out_caps)[12] = NULL;
450+ (*out_caps)[13] = NULL;
451
452 return TRUE;
453 }

Subscribers

People subscribed via source and target branches