From: David Woodhouse Date: Sun, 15 Apr 2018 21:20:12 +0000 (+0200) Subject: Attempt state management X-Git-Tag: v0.9~20 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=07dee5da65bc94a067d5b510829cf73d6bca7d83;p=pidgin-chime.git Attempt state management --- diff --git a/chime/chime-call-screen.c b/chime/chime-call-screen.c index d310cb1..e4db706 100644 --- a/chime/chime-call-screen.c +++ b/chime/chime-call-screen.c @@ -159,6 +159,7 @@ static void on_screenws_message(SoupWebsocketConnection *ws, gint type, gst_app_sink_set_callbacks(screen->screen_sink, &no_appsink_callbacks, NULL, NULL); screen->screen_sink = NULL; + chime_call_screen_set_state(screen, CHIME_SCREEN_STATE_CONNECTED); } break; @@ -183,7 +184,6 @@ static void screen_ws_connect_cb(GObject *obj, GAsyncResult *res, gpointer _scre /* If it was cancelled, 'screen' may have been freed. */ if (!g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { chime_debug("screen ws error %s\n", error->message); - screen->state = CHIME_SCREEN_STATE_FAILED; } g_clear_error(&error); g_object_unref(cxn); @@ -193,7 +193,13 @@ static void screen_ws_connect_cb(GObject *obj, GAsyncResult *res, gpointer _scre g_signal_connect(G_OBJECT(ws), "closed", G_CALLBACK(on_screenws_closed), screen); g_signal_connect(G_OBJECT(ws), "message", G_CALLBACK(on_screenws_message), screen); screen->ws = ws; - screen->state = CHIME_SCREEN_STATE_CONNECTED; + + if (screen->screen_src) + chime_call_screen_install_appsrc(screen, screen->screen_src); + else if (screen->screen_sink) + chime_call_screen_install_appsink(screen, screen->screen_sink); + else + chime_call_screen_set_state(screen, CHIME_SCREEN_STATE_CONNECTED); g_object_unref(cxn); } @@ -205,7 +211,6 @@ ChimeCallScreen *chime_call_screen_open(ChimeConnection *cxn, ChimeCall *call) g_mutex_init(&screen->transport_lock); - screen->state = CHIME_SCREEN_STATE_CONNECTING; screen->call = call; screen->cancel = g_cancellable_new(); @@ -224,6 +229,8 @@ ChimeCallScreen *chime_call_screen_open(ChimeConnection *cxn, ChimeCall *call) gchar *origin = g_strdup_printf("http://%s", soup_uri_get_host(uri)); soup_uri_free(uri); + chime_call_screen_set_state(screen, CHIME_SCREEN_STATE_CONNECTING); + chime_connection_websocket_connect_async(g_object_ref(cxn), msg, origin, protocols, screen->cancel, screen_ws_connect_cb, screen); g_free(origin); @@ -239,6 +246,8 @@ static void on_final_screenws_close(SoupWebsocketConnection *ws, gpointer _unuse void chime_call_screen_close(ChimeCallScreen *screen) { + chime_call_screen_set_state(screen, CHIME_SCREEN_STATE_HANGUP); + if (screen->cancel) { g_cancellable_cancel(screen->cancel); g_object_unref(screen->cancel); @@ -277,9 +286,11 @@ static void screen_appsrc_destroy(gpointer _screen) { ChimeCallScreen *screen = _screen; - screen_send_packet(screen, SCREEN_PKT_TYPE_VIEWER_END, NULL, 0); - screen->screen_src = NULL; - screen->state = CHIME_SCREEN_STATE_CONNECTED; + if (screen->state == CHIME_SCREEN_STATE_VIEWING) { + screen_send_packet(screen, SCREEN_PKT_TYPE_VIEWER_END, NULL, 0); + screen->screen_src = NULL; + chime_call_screen_set_state(screen, CHIME_SCREEN_STATE_CONNECTED); + } } static GstAppSrcCallbacks screen_appsrc_callbacks = { @@ -290,18 +301,23 @@ static GstAppSrcCallbacks screen_appsrc_callbacks = { void chime_call_screen_install_appsrc(ChimeCallScreen *screen, GstAppSrc *appsrc) { - if (screen->screen_sink) { + screen->screen_src = appsrc; + gst_app_src_set_callbacks(appsrc, &screen_appsrc_callbacks, screen, screen_appsrc_destroy); + + if (screen->state == CHIME_SCREEN_STATE_SENDING) screen_send_packet(screen, SCREEN_PKT_TYPE_PRESENTER_END, NULL, 0); + if (screen->ws) { + screen_send_packet(screen, SCREEN_PKT_TYPE_VIEWER_BEGIN, NULL, 0); + chime_call_screen_set_state(screen, CHIME_SCREEN_STATE_VIEWING); + } + + if (screen->screen_sink) { gst_app_sink_set_callbacks(screen->screen_sink, &no_appsink_callbacks, NULL, NULL); screen->screen_sink = NULL; } - screen_send_packet(screen, SCREEN_PKT_TYPE_VIEWER_BEGIN, NULL, 0); - screen->screen_src = appsrc; - gst_app_src_set_callbacks(appsrc, &screen_appsrc_callbacks, screen, screen_appsrc_destroy); - screen->state = CHIME_SCREEN_STATE_VIEWING; } static GstFlowReturn screen_appsink_new_sample(GstAppSink* self, gpointer data) @@ -342,23 +358,29 @@ static void screen_appsink_destroy(gpointer _screen) { ChimeCallScreen *screen = _screen; - screen_send_packet(screen, SCREEN_PKT_TYPE_PRESENTER_END, NULL, 0); - screen->screen_sink = NULL; - screen->state = CHIME_SCREEN_STATE_CONNECTED; + if (screen->state == CHIME_SCREEN_STATE_SENDING) { + screen_send_packet(screen, SCREEN_PKT_TYPE_PRESENTER_END, NULL, 0); + screen->screen_sink = NULL; + chime_call_screen_set_state(screen, CHIME_SCREEN_STATE_CONNECTED); + } } void chime_call_screen_install_appsink(ChimeCallScreen *screen, GstAppSink *appsink) { - if (screen->screen_src) { + screen->screen_sink = appsink; + gst_app_sink_set_callbacks(appsink, &screen_appsink_callbacks, screen, screen_appsink_destroy); + + if (screen->state == CHIME_SCREEN_STATE_VIEWING) screen_send_packet(screen, SCREEN_PKT_TYPE_VIEWER_END, NULL, 0); + if (screen->ws) { + screen_send_packet(screen, SCREEN_PKT_TYPE_PRESENTER_BEGIN, NULL, 0); + chime_call_screen_set_state(screen, CHIME_SCREEN_STATE_SENDING); + } + + if (screen->screen_src) { gst_app_src_set_callbacks(screen->screen_src, &no_appsrc_callbacks, NULL, NULL); screen->screen_src = NULL; } - screen_send_packet(screen, SCREEN_PKT_TYPE_PRESENTER_BEGIN, NULL, 0); - - screen->screen_sink = appsink; - gst_app_sink_set_callbacks(appsink, &screen_appsink_callbacks, screen, screen_appsink_destroy); - screen->state = CHIME_SCREEN_STATE_SENDING; } diff --git a/chime/chime-call-screen.h b/chime/chime-call-screen.h index e48cf10..b18f665 100644 --- a/chime/chime-call-screen.h +++ b/chime/chime-call-screen.h @@ -43,6 +43,7 @@ ChimeCallScreen *chime_call_screen_open(ChimeConnection *cxn, ChimeCall *call); void chime_call_screen_close(ChimeCallScreen *screen); void chime_call_screen_view(ChimeCallScreen *screen); void chime_call_screen_unview(ChimeCallScreen *screen); +void chime_call_screen_set_state(ChimeCallScreen *audio, ChimeScreenState state); void chime_call_screen_install_appsrc(ChimeCallScreen *screen, GstAppSrc *appsrc); void chime_call_screen_install_appsink(ChimeCallScreen *screen, GstAppSink *appsink); diff --git a/chime/chime-call.c b/chime/chime-call.c index cec5633..fae7bbb 100644 --- a/chime/chime-call.c +++ b/chime/chime-call.c @@ -56,6 +56,7 @@ static GParamSpec *props[LAST_PROP]; enum { ENDED, AUDIO_STATE, + SCREEN_STATE, PARTICIPANTS_CHANGED, NEW_PRESENTER, LAST_SIGNAL, @@ -182,6 +183,11 @@ static void chime_call_class_init(ChimeCallClass *klass) G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); + signals[SCREEN_STATE] = + g_signal_new ("screen-state", + G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_INT); + signals[PARTICIPANTS_CHANGED] = g_signal_new ("participants-changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, @@ -558,7 +564,6 @@ void chime_connection_open_call(ChimeConnection *cxn, ChimeCall *call, gboolean chime_jugg_subscribe(cxn, call->channel, "Call", call_jugg_cb, NULL); chime_jugg_subscribe(cxn, call->roster_channel, "Roster", call_roster_cb, call); call->audio = chime_call_audio_open(cxn, call, muted); - call->screen = chime_call_screen_open(cxn, call); } } @@ -593,6 +598,17 @@ void chime_call_audio_set_state(ChimeCallAudio *audio, ChimeAudioState state) g_signal_emit(audio->call, signals[AUDIO_STATE], 0, state); } +void chime_call_screen_set_state(ChimeCallScreen *screen, ChimeScreenState state) +{ + chime_debug("Screen state %d (was %d)\n", state, screen->state); + + if (screen->state == state) + return; + + screen->state = state; + g_signal_emit(screen->call, signals[SCREEN_STATE], 0, state); +} + void chime_call_install_gst_app_callbacks(ChimeCall *call, GstAppSrc *appsrc, GstAppSink *appsink) { if (call->audio) diff --git a/prpl/chat.c b/prpl/chat.c index ddba96a..f8b767d 100644 --- a/prpl/chat.c +++ b/prpl/chat.c @@ -431,6 +431,32 @@ static void on_room_membership(ChimeRoom *room, ChimeRoomMember *member, struct } } +static void on_screen_state(ChimeCall *call, ChimeScreenState screen_state, struct chime_chat *chat) +{ + purple_debug(PURPLE_DEBUG_INFO, "chime", "Screen state %d\n", screen_state); + + if (screen_state == CHIME_SCREEN_STATE_CONNECTING) + return; + + if (chat->share_media) { + if (screen_state == CHIME_SCREEN_STATE_SENDING) { + purple_media_stream_info(chat->share_media, PURPLE_MEDIA_INFO_ACCEPT, "chime", _("Sharing screen"), FALSE); + } else { + purple_debug(PURPLE_DEBUG_INFO, "chime", "Screen presentation ends\n"); + purple_media_end(chat->share_media, NULL, NULL); + chat->share_media = NULL; + } + } else if (chat->screen_media) { + if (screen_state == CHIME_SCREEN_STATE_VIEWING) { + purple_media_stream_info(chat->screen_media, PURPLE_MEDIA_INFO_ACCEPT, "chime", chat->screen_title, FALSE); + } else { + purple_debug(PURPLE_DEBUG_INFO, "chime", "Screen viewing ends\n"); + purple_media_end(chat->screen_media, NULL, NULL); + chat->screen_media = NULL; + } + } +} + static void share_media_changed(PurpleMedia *media, PurpleMediaState state, const gchar *id, const gchar *participant, struct chime_chat *chat) { purple_debug(PURPLE_DEBUG_INFO, "chime", "Share media state %d\n", state); @@ -446,7 +472,7 @@ static void share_media_changed(PurpleMedia *media, PurpleMediaState state, cons } } } - +static void on_call_presenter(ChimeCall *call, ChimeCallParticipant *presenter, struct chime_chat *chat); static void share_screen(PurpleBuddy *buddy, gpointer _chat) { struct chime_chat *chat = _chat; @@ -454,7 +480,10 @@ static void share_screen(PurpleBuddy *buddy, gpointer _chat) if (chat->share_media) return; - const gchar *name = "Sharing screen"; + /* Stop receiving so we can send */ + on_call_presenter(chat->call, NULL, chat); + + const gchar *name = _("Sharing screen"); PurpleMediaManager *mgr = purple_media_manager_get(); chat->share_media = purple_media_manager_create_media(purple_media_manager_get(), @@ -480,7 +509,7 @@ static void share_screen(PurpleBuddy *buddy, gpointer _chat) } gchar *sinkname = g_strdup_printf("chime_screen_sink_%p", chat->call); - gchar *sinkpipe = g_strdup_printf("videorate ! video/x-raw,framerate=3/1 ! videoconvert ! vp8enc ! appsink name=%s async=false", sinkname); + gchar *sinkpipe = g_strdup_printf("videorate ! video/x-raw,format=YUY2,framerate=3/1 ! videoconvert ! vp8enc ! appsink name=%s async=false", sinkname); PurpleMediaCandidate *cand = purple_media_candidate_new(NULL, 1, PURPLE_MEDIA_CANDIDATE_TYPE_HOST, @@ -511,7 +540,6 @@ static void share_screen(PurpleBuddy *buddy, gpointer _chat) chime_call_send_screen(PURPLE_CHIME_CXN(chat->conv->account->gc), chat->call, GST_APP_SINK(appsink)); g_object_unref(appsink); - purple_media_stream_info(chat->share_media, PURPLE_MEDIA_INFO_ACCEPT, "chime", name, FALSE); GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(purple_media_manager_get_pipeline(mgr)), GST_DEBUG_GRAPH_SHOW_ALL, "chime share graph"); } @@ -602,13 +630,28 @@ static void screen_ask_cb(gpointer _chat, int choice) chime_call_view_screen(PURPLE_CHIME_CXN(chat->conv->account->gc), chat->call, GST_APP_SRC(appsrc)); g_object_unref(appsrc); - purple_media_stream_info(chat->screen_media, PURPLE_MEDIA_INFO_ACCEPT, "chime", name, FALSE); GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(purple_media_manager_get_pipeline(mgr)), GST_DEBUG_GRAPH_SHOW_ALL, "chime screen graph"); } +static void view_screen(PurpleBuddy *buddy, gpointer _chat) +{ + struct chime_chat *chat = _chat; + + if (chat->screen_ask_ui) { + purple_request_close(PURPLE_REQUEST_ACTION, chat->screen_ask_ui); + chat->screen_ask_ui = NULL; + } + screen_ask_cb(chat, 0); +} + static void on_call_presenter(ChimeCall *call, ChimeCallParticipant *presenter, struct chime_chat *chat) { + /* If we are the sender, don't offer to receive... */ + if (chat->share_media && presenter && + !g_strcmp0(presenter->participant_id, chime_connection_get_profile_id(PURPLE_CHIME_CXN(chat->conv->account->gc)))) + presenter = NULL; + if (!presenter || g_strcmp0(chat->presenter_id, presenter->participant_id)) { if (chat->screen_ask_ui) { purple_request_close(PURPLE_REQUEST_ACTION, chat->screen_ask_ui); @@ -632,7 +675,7 @@ static void on_call_presenter(ChimeCall *call, ChimeCallParticipant *presenter, gchar *primary = g_strdup_printf(_("%s is now sharing a screen."), presenter->full_name); chat->screen_ask_ui = purple_request_action(chat, _("Screenshare available"), primary, - chat->conv->account->username, 1, + chime_call_get_alert_body(chat->call), 1, chat->conv->account, presenter->email, chat->conv, chat, 2, _("Ignore"), screen_ask_cb, @@ -681,7 +724,7 @@ void chime_destroy_chat(struct chime_chat *chat) PurpleMedia *media = chat->share_media; chat->share_media = NULL; - purple_media_end(media, "chime", "Sharing screen"); + purple_media_end(media, "chime", _("Sharing screen")); purple_media_manager_remove_media(purple_media_manager_get(), media); } @@ -752,6 +795,7 @@ struct chime_chat *do_join_chat(PurpleConnection *conn, ChimeConnection *cxn, Ch chat->meeting = g_object_ref(meeting); chat->call = chime_meeting_get_call(meeting); if (chat->call) { + g_signal_connect(chat->call, "screen-state", G_CALLBACK(on_screen_state), chat); g_signal_connect(chat->call, "audio-state", G_CALLBACK(on_audio_state), chat); g_signal_connect(chat->call, "participants-changed", G_CALLBACK(on_call_participants), chat); g_signal_connect(chat->call, "new-presenter", G_CALLBACK(on_call_presenter), chat); @@ -1065,6 +1109,10 @@ GList *chime_purple_chat_menu(PurpleChat *pchat) items = g_list_append(items, purple_menu_action_new(_("Join audio call"), PURPLE_CALLBACK(join_audio), chat, NULL)); + if (chat->screen_title) + items = g_list_append(items, + purple_menu_action_new(chat->screen_title, + PURPLE_CALLBACK(view_screen), chat, NULL)); items = g_list_append(items, purple_menu_action_new(_("Share screen (well, camera)"), PURPLE_CALLBACK(share_screen), chat, NULL));