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;
/* 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);
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);
}
g_mutex_init(&screen->transport_lock);
- screen->state = CHIME_SCREEN_STATE_CONNECTING;
screen->call = call;
screen->cancel = g_cancellable_new();
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);
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);
{
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 = {
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)
{
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;
}
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);
enum {
ENDED,
AUDIO_STATE,
+ SCREEN_STATE,
PARTICIPANTS_CHANGED,
NEW_PRESENTER,
LAST_SIGNAL,
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,
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);
}
}
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)
}
}
+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);
}
}
}
-
+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;
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(),
}
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,
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");
}
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);
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,
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);
}
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);
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));