Index: pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c
===================================================================
--- pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 3338)
+++ pjproject/trunk/pjsip-apps/src/pjsua/pjsua_app.c	(revision 3339)
@@ -2798,4 +2798,35 @@
 
 
+/*
+ * Subscription state has changed.
+ */
+static void on_buddy_evsub_state(pjsua_buddy_id buddy_id,
+				 pjsip_evsub *sub,
+				 pjsip_event *event)
+{
+    char event_info[80];
+
+    PJ_UNUSED_ARG(sub);
+
+    event_info[0] = '\0';
+
+    if (event->type == PJSIP_EVENT_TSX_STATE &&
+	    event->body.tsx_state.type == PJSIP_EVENT_RX_MSG)
+    {
+	pjsip_rx_data *rdata = event->body.tsx_state.src.rdata;
+	snprintf(event_info, sizeof(event_info),
+		 " (RX %s)",
+		 pjsip_rx_data_get_info(rdata));
+    }
+
+    PJ_LOG(4,(THIS_FILE,
+	      "Buddy %d: subscription state: %s (event: %s%s)",
+	      buddy_id, pjsip_evsub_get_state_name(sub),
+	      pjsip_event_str(event->type),
+	      event_info));
+
+}
+
+
 /**
  * Incoming IM message (i.e. MESSAGE request)!
@@ -4603,4 +4634,5 @@
     app_config.cfg.cb.on_incoming_subscribe = &on_incoming_subscribe;
     app_config.cfg.cb.on_buddy_state = &on_buddy_state;
+    app_config.cfg.cb.on_buddy_evsub_state = &on_buddy_evsub_state;
     app_config.cfg.cb.on_pager = &on_pager;
     app_config.cfg.cb.on_typing = &on_typing;
Index: pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 3338)
+++ pjproject/trunk/pjsip/include/pjsua-lib/pjsua.h	(revision 3339)
@@ -687,4 +687,19 @@
      */
     void (*on_buddy_state)(pjsua_buddy_id buddy_id);
+
+
+    /**
+     * Notify application when the state of client subscription session
+     * associated with a buddy has changed. Application may use this
+     * callback to retrieve more detailed information about the state
+     * changed event.
+     *
+     * @param buddy_id	    The buddy id.
+     * @param sub	    Event subscription session.
+     * @param event	    The event which triggers state change event.
+     */
+    void (*on_buddy_evsub_state)(pjsua_buddy_id buddy_id,
+				 pjsip_evsub *sub,
+				 pjsip_event *event);
 
     /**
Index: pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c	(revision 3338)
+++ pjproject/trunk/pjsip/src/pjsua-lib/pjsua_pres.c	(revision 3339)
@@ -1558,5 +1558,9 @@
 	}
 
-	/* Call callback */
+	/* Call callbacks */
+	if (pjsua_var.ua_cfg.cb.on_buddy_evsub_state)
+	    (*pjsua_var.ua_cfg.cb.on_buddy_evsub_state)(buddy->index, sub,
+							event);
+
 	if (pjsua_var.ua_cfg.cb.on_buddy_state)
 	    (*pjsua_var.ua_cfg.cb.on_buddy_state)(buddy->index);
@@ -1657,28 +1661,8 @@
 
 
-/* Event subscription callback. */
-static pjsip_evsub_user pres_callback = 
-{
-    &pjsua_evsub_on_state,  
-    &pjsua_evsub_on_tsx_state,
-
-    NULL,   /* on_rx_refresh: don't care about SUBSCRIBE refresh, unless 
-	     * we want to authenticate 
-	     */
-
-    &pjsua_evsub_on_rx_notify,
-
-    NULL,   /* on_client_refresh: Use default behaviour, which is to 
-	     * refresh client subscription. */
-
-    NULL,   /* on_server_timeout: Use default behaviour, which is to send 
-	     * NOTIFY to terminate. 
-	     */
-};
-
-
 /* It does what it says.. */
 static void subscribe_buddy_presence(pjsua_buddy_id buddy_id)
 {
+    pjsip_evsub_user pres_callback;
     pj_pool_t *tmp_pool = NULL;
     pjsua_buddy *buddy;
@@ -1688,4 +1672,10 @@
     pjsip_tx_data *tdata;
     pj_status_t status;
+
+    /* Event subscription callback. */
+    pj_bzero(&pres_callback, sizeof(pres_callback));
+    pres_callback.on_evsub_state = &pjsua_evsub_on_state;
+    pres_callback.on_tsx_state = &pjsua_evsub_on_tsx_state;
+    pres_callback.on_rx_notify = &pjsua_evsub_on_rx_notify;
 
     buddy = &pjsua_var.buddy[buddy_id];
