diff --git a/CHANGES b/CHANGES
index 9bfa506d333ad5247a895ebf1c5aed621d95df8e..9cd579b65658a395d20dea95ef810c0f1596d853 100644
--- a/CHANGES
+++ b/CHANGES
@@ -30,6 +30,10 @@ res_pjsip
    Some SIP phones like Mitel/Aastra or Snom keep the line busy until
    receive "200 OK".
 
+ * A new endpoint option "notify_early_inuse_ringing" was added to control
+   whether to notify dialog-info state 'early' or 'confirmed' on Ringing
+   when already INUSE.
+
 res_agi
 ------------------
  * The EAGI() application will now look for a dialplan variable named
diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample
index a992ff8b6bd5ccedb3ab542c95211551319ba9e0..3b93bb61fc242285805620580063ba0782504f0e 100644
--- a/configs/samples/pjsip.conf.sample
+++ b/configs/samples/pjsip.conf.sample
@@ -774,6 +774,11 @@
                        ; transfer (default: "yes"). The value "no" is useful
                        ; for some SIP phones (Mitel/Aastra, Snom) which expect
                        ; a sip/frag "200 OK" after REFER has been accepted.
+;notify_early_inuse_ringing = ; Whether to notifies dialog-info 'early'
+                              ; on INUSE && RINGING state (default: "no").
+                              ; The value "yes" is useful for some SIP phones
+                              ; (Cisco SPA) to be able to indicate and pick up
+                              ; ringing devices.
 
 ;==========================AUTH SECTION OPTIONS=========================
 ;[auth]
diff --git a/contrib/ast-db-manage/config/versions/d7983954dd96_add_ps_endpoints_notify_early_inuse_.py b/contrib/ast-db-manage/config/versions/d7983954dd96_add_ps_endpoints_notify_early_inuse_.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1dcdd133b16bd39b0e84e83be172c3d0f9aa40a
--- /dev/null
+++ b/contrib/ast-db-manage/config/versions/d7983954dd96_add_ps_endpoints_notify_early_inuse_.py
@@ -0,0 +1,30 @@
+"""add ps_endpoints.notify_early_inuse_ringing
+
+Revision ID: d7983954dd96
+Revises: 86bb1efa278d
+Create Date: 2017-06-05 15:44:41.152280
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'd7983954dd96'
+down_revision = '86bb1efa278d'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects.postgresql import ENUM
+
+YESNO_NAME = 'yesno_values'
+YESNO_VALUES = ['yes', 'no']
+
+def upgrade():
+    ############################# Enums ##############################
+
+    # yesno_values have already been created, so use postgres enum object
+    # type to get around "already created" issue - works okay with mysql
+    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
+
+    op.add_column('ps_endpoints', sa.Column('notify_early_inuse_ringing', yesno_values))
+
+def downgrade():
+    op.drop_column('ps_endpoints', 'notify_early_inuse_ringing')
diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h
index 8c589ef85ea8bd84c286cd8d65cf334f6cbbce49..b9c50addad4e542ef5a284966c653a6172cba4dd 100644
--- a/include/asterisk/res_pjsip.h
+++ b/include/asterisk/res_pjsip.h
@@ -769,6 +769,8 @@ struct ast_sip_endpoint {
 	unsigned int allow_overlap;
 	/*! Whether to notifies all the progress details on blind transfer */
 	unsigned int refer_blind_progress;
+	/*! Whether to notifies dialog-info 'early' on INUSE && RINGING state */
+	unsigned int notify_early_inuse_ringing;
 };
 
 /*! URI parameter for symmetric transport */
diff --git a/include/asterisk/res_pjsip_presence_xml.h b/include/asterisk/res_pjsip_presence_xml.h
index deed0901e49ebcb02508d3fe0c109f61dda1e0a4..55b79ad6e83733b4de0cc6c1da33331782ad1cf0 100644
--- a/include/asterisk/res_pjsip_presence_xml.h
+++ b/include/asterisk/res_pjsip_presence_xml.h
@@ -69,7 +69,8 @@ void ast_sip_sanitize_xml(const char *input, char *output, size_t len);
  * \param[out] local_state
  */
 void ast_sip_presence_exten_state_to_str(int state, char **statestring,
-		char **pidfstate, char **pidfnote, enum ast_sip_pidf_state *local_state);
+		char **pidfstate, char **pidfnote, enum ast_sip_pidf_state *local_state,
+		unsigned int notify_early_inuse_ringing);
 
 /*!
  * \brief Create XML attribute
diff --git a/res/res_pjsip.c b/res/res_pjsip.c
index d994f28248b04cb6475782cc07e705efe14bd39c..f6d63c6400768cad073a3c6af17a815492f75b36 100644
--- a/res/res_pjsip.c
+++ b/res/res_pjsip.c
@@ -971,6 +971,13 @@
 						will not send the progress details, but immediately will send "200 OK".
 					</para></description>
 				</configOption>
+				<configOption name="notify_early_inuse_ringing" default="no">
+					<synopsis>Whether to notifies dialog-info 'early' on InUse&amp;Ringing state</synopsis>
+					<description><para>
+						Control whether dialog-info subscriptions get 'early' state
+						on Ringing when already INUSE.
+					</para></description>
+				</configOption>
 			</configObject>
 			<configObject name="auth">
 				<synopsis>Authentication type</synopsis>
diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c
index 679c8837d931865ecc85d91a768c7f7215498dbd..7a05f87f08c9097ac822734d03a38cb7196bf499 100644
--- a/res/res_pjsip/pjsip_configuration.c
+++ b/res/res_pjsip/pjsip_configuration.c
@@ -1940,6 +1940,7 @@ int ast_res_pjsip_initialize_configuration(void)
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap));
 	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "refer_blind_progress", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, refer_blind_progress));
+	ast_sorcery_object_field_register(sip_sorcery, "endpoint", "notify_early_inuse_ringing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, notify_early_inuse_ringing));
 
 	if (ast_sip_initialize_sorcery_transport()) {
 		ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
diff --git a/res/res_pjsip/presence_xml.c b/res/res_pjsip/presence_xml.c
index c991a0d68c9c8944cc1466322bc030b26a45fcc9..1aca307e5a098d0bb1293400761fbd47ed43338f 100644
--- a/res/res_pjsip/presence_xml.c
+++ b/res/res_pjsip/presence_xml.c
@@ -82,7 +82,8 @@ void ast_sip_sanitize_xml(const char *input, char *output, size_t len)
 }
 
 void ast_sip_presence_exten_state_to_str(int state, char **statestring, char **pidfstate,
-			       char **pidfnote, enum ast_sip_pidf_state *local_state)
+			       char **pidfnote, enum ast_sip_pidf_state *local_state,
+			       unsigned int notify_early_inuse_ringing)
 {
 	switch (state) {
 	case AST_EXTENSION_RINGING:
@@ -92,7 +93,11 @@ void ast_sip_presence_exten_state_to_str(int state, char **statestring, char **p
 		*pidfnote = "Ringing";
 		break;
 	case (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING):
-		*statestring = "confirmed";
+		if (notify_early_inuse_ringing) {
+			*statestring = "early";
+		} else {
+			*statestring = "confirmed";
+		}
 		*local_state = NOTIFY_INUSE;
 		*pidfstate = "busy";
 		*pidfnote = "Ringing";
diff --git a/res/res_pjsip_dialog_info_body_generator.c b/res/res_pjsip_dialog_info_body_generator.c
index 5006b9efb4ef0c1bfcc02a787fca3698adccb723..7c386e3b2d10bdd00a9b9921fbf808d44cfcbae4 100644
--- a/res/res_pjsip_dialog_info_body_generator.c
+++ b/res/res_pjsip_dialog_info_body_generator.c
@@ -107,6 +107,8 @@ static int dialog_info_generate_body_content(void *body, void *data)
 	enum ast_sip_pidf_state local_state;
 	unsigned int version;
 	char version_str[32], sanitized[PJSIP_MAX_URL_SIZE];
+	struct ast_sip_endpoint *endpoint = NULL;
+	unsigned int notify_early_inuse_ringing = 0;
 
 	if (!local || !state_data->datastores) {
 		return -1;
@@ -120,8 +122,12 @@ static int dialog_info_generate_body_content(void *body, void *data)
 	stripped = ast_strip_quoted(local, "<", ">");
 	ast_sip_sanitize_xml(stripped, sanitized, sizeof(sanitized));
 
+	if (state_data->sub && (endpoint = ast_sip_subscription_get_endpoint(state_data->sub))) {
+	    notify_early_inuse_ringing = endpoint->notify_early_inuse_ringing;
+	    ao2_cleanup(endpoint);
+	}
 	ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring,
-			&pidfstate, &pidfnote, &local_state);
+			&pidfstate, &pidfnote, &local_state, notify_early_inuse_ringing);
 
 	ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "xmlns", "urn:ietf:params:xml:ns:dialog-info");
 
@@ -133,7 +139,7 @@ static int dialog_info_generate_body_content(void *body, void *data)
 
 	dialog = ast_sip_presence_xml_create_node(state_data->pool, dialog_info, "dialog");
 	ast_sip_presence_xml_create_attr(state_data->pool, dialog, "id", state_data->exten);
-	if (state_data->exten_state == AST_EXTENSION_RINGING) {
+	if (!ast_strlen_zero(statestring) && !strcmp(statestring, "early")) {
 		ast_sip_presence_xml_create_attr(state_data->pool, dialog, "direction", "recipient");
 	}
 
diff --git a/res/res_pjsip_pidf_body_generator.c b/res/res_pjsip_pidf_body_generator.c
index 25f0639157bdf957de618322ec886d865a6f3991..cc10082ad38cd57b8a23da006eebbf5b223903a8 100644
--- a/res/res_pjsip_pidf_body_generator.c
+++ b/res/res_pjsip_pidf_body_generator.c
@@ -58,7 +58,7 @@ static int pidf_generate_body_content(void *body, void *data)
 	struct ast_sip_exten_state_data *state_data = data;
 
 	ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring,
-			&pidfstate, &pidfnote, &local_state);
+			&pidfstate, &pidfnote, &local_state, 0);
 
 	if (!pjpidf_pres_add_note(state_data->pool, pres, pj_cstr(&note, pidfnote))) {
 		ast_log(LOG_WARNING, "Unable to add note to PIDF presence\n");
diff --git a/res/res_pjsip_pidf_eyebeam_body_supplement.c b/res/res_pjsip_pidf_eyebeam_body_supplement.c
index cc6dfd125c9068f8f2137990a36444687e17f201..a0f50fddee57215c94ba468a25f488648902f28c 100644
--- a/res/res_pjsip_pidf_eyebeam_body_supplement.c
+++ b/res/res_pjsip_pidf_eyebeam_body_supplement.c
@@ -80,7 +80,7 @@ static int pidf_supplement_body(void *body, void *data)
 	enum ast_sip_pidf_state local_state;
 
 	ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring,
-			&pidfstate, &pidfnote, &local_state);
+			&pidfstate, &pidfnote, &local_state, 0);
 
 	add_eyebeam(state_data->pool, pres, pidfstate);
 	return 0;
diff --git a/res/res_pjsip_xpidf_body_generator.c b/res/res_pjsip_xpidf_body_generator.c
index 924046549a842d16ec21d75174017c4ea4b73c41..41f6224d1a70fcd5f12d761f788f6a4af3101cf1 100644
--- a/res/res_pjsip_xpidf_body_generator.c
+++ b/res/res_pjsip_xpidf_body_generator.c
@@ -63,7 +63,7 @@ static int xpidf_generate_body_content(void *body, void *data)
 	pj_xml_node *msnsubstatus;
 
 	ast_sip_presence_exten_state_to_str(state_data->exten_state, &statestring,
-			&pidfstate, &pidfnote, &local_state);
+			&pidfstate, &pidfnote, &local_state, 0);
 
 	ast_sip_presence_xml_find_node_attr(state_data->pool, pres, "atom", "id",
 			&atom, &attr);