mirror of
https://github.com/kunkundi/crossdesk.git
synced 2025-10-27 04:35:34 +08:00
Add libnice as ice agent
This commit is contained in:
276
tests/peerconnection/nicesdp.cpp
Normal file
276
tests/peerconnection/nicesdp.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright 2013 University of Chicago
|
||||
* Contact: Bryce Allen
|
||||
* Copyright 2013 Collabora Ltd.
|
||||
* Contact: Youness Alaoui
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of the
|
||||
* the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
|
||||
* case the provisions of LGPL are applicable instead of those above. If you
|
||||
* wish to allow use of your version of this file only under the terms of the
|
||||
* LGPL and not to allow others to use your version of this file under the
|
||||
* MPL, indicate your decision by deleting the provisions above and replace
|
||||
* them with the notice and other provisions required by the LGPL. If you do
|
||||
* not delete the provisions above, a recipient may use your version of this
|
||||
* file under either the MPL or the LGPL.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Example using libnice to negotiate a UDP connection between two clients,
|
||||
* possibly on the same network or behind different NATs and/or stateful
|
||||
* firewalls.
|
||||
*
|
||||
* Build:
|
||||
* gcc -o sdp-example sdp-example.c `pkg-config --cflags --libs nice`
|
||||
*
|
||||
* Run two clients, one controlling and one controlled:
|
||||
* sdp-example 0 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }')
|
||||
* sdp-example 1 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }')
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "gio/gnetworking.h"
|
||||
#include "nice/agent.h"
|
||||
|
||||
static GMainLoop *gloop;
|
||||
static gchar *stun_addr = NULL;
|
||||
static guint stun_port;
|
||||
static gboolean controlling;
|
||||
static gboolean exit_thread, candidate_gathering_done, negotiation_done;
|
||||
static GMutex gather_mutex, negotiate_mutex;
|
||||
static GCond gather_cond, negotiate_cond;
|
||||
|
||||
static const gchar *state_name[] = {"disconnected", "gathering", "connecting",
|
||||
"connected", "ready", "failed"};
|
||||
|
||||
static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id,
|
||||
gpointer data);
|
||||
static void cb_component_state_changed(NiceAgent *agent, guint stream_id,
|
||||
guint component_id, guint state,
|
||||
gpointer data);
|
||||
static void cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id,
|
||||
guint len, gchar *buf, gpointer data);
|
||||
|
||||
static void *example_thread(void *data);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
GThread *gexamplethread;
|
||||
|
||||
// Parse arguments
|
||||
// if (argc > 4 || argc < 2 || argv[1][1] != '\0') {
|
||||
// fprintf(stderr, "Usage: %s 0|1 stun_addr [stun_port]\n", argv[0]);
|
||||
// return EXIT_FAILURE;
|
||||
// }
|
||||
// controlling = argv[1][0] - '0';
|
||||
// if (controlling != 0 && controlling != 1) {
|
||||
// fprintf(stderr, "Usage: %s 0|1 stun_addr [stun_port]\n", argv[0]);
|
||||
// return EXIT_FAILURE;
|
||||
// }
|
||||
|
||||
stun_addr = "120.77.216.215";
|
||||
|
||||
// if (argc > 2) {
|
||||
// stun_addr = argv[2];
|
||||
// if (argc > 3)
|
||||
// stun_port = atoi(argv[3]);
|
||||
// else
|
||||
stun_port = 3478;
|
||||
|
||||
// g_debug("Using stun server '[%s]:%u'\n", stun_addr, stun_port);
|
||||
// }
|
||||
|
||||
g_networking_init();
|
||||
|
||||
gloop = g_main_loop_new(NULL, FALSE);
|
||||
|
||||
// Run the mainloop and the example thread
|
||||
exit_thread = FALSE;
|
||||
gexamplethread = g_thread_new("example thread", &example_thread, NULL);
|
||||
g_main_loop_run(gloop);
|
||||
exit_thread = TRUE;
|
||||
|
||||
g_thread_join(gexamplethread);
|
||||
g_main_loop_unref(gloop);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
static void *example_thread(void *data) {
|
||||
NiceAgent *agent;
|
||||
GIOChannel *io_stdin;
|
||||
guint stream_id;
|
||||
gchar *line = NULL;
|
||||
gchar *sdp, *sdp64;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
io_stdin = g_io_channel_win32_new_fd(_fileno(stdin));
|
||||
#else
|
||||
io_stdin = g_io_channel_unix_new(fileno(stdin));
|
||||
#endif
|
||||
g_io_channel_set_flags(io_stdin, G_IO_FLAG_NONBLOCK, NULL);
|
||||
|
||||
// Create the nice agent
|
||||
agent = nice_agent_new(g_main_loop_get_context(gloop),
|
||||
NICE_COMPATIBILITY_RFC5245);
|
||||
if (agent == NULL) g_error("Failed to create agent");
|
||||
|
||||
// Set the STUN settings and controlling mode
|
||||
if (stun_addr) {
|
||||
g_object_set(agent, "stun-server", stun_addr, NULL);
|
||||
g_object_set(agent, "stun-server-port", stun_port, NULL);
|
||||
}
|
||||
g_object_set(agent, "controlling-mode", controlling, NULL);
|
||||
|
||||
// Connect to the signals
|
||||
g_signal_connect(agent, "candidate-gathering-done",
|
||||
G_CALLBACK(cb_candidate_gathering_done), NULL);
|
||||
g_signal_connect(agent, "component-state-changed",
|
||||
G_CALLBACK(cb_component_state_changed), NULL);
|
||||
|
||||
// Create a new stream with one component
|
||||
stream_id = nice_agent_add_stream(agent, 1);
|
||||
if (stream_id == 0) g_error("Failed to add stream");
|
||||
nice_agent_set_stream_name(agent, stream_id, "text");
|
||||
|
||||
// Attach to the component to receive the data
|
||||
// Without this call, candidates cannot be gathered
|
||||
nice_agent_attach_recv(agent, stream_id, 1, g_main_loop_get_context(gloop),
|
||||
cb_nice_recv, NULL);
|
||||
|
||||
// Start gathering local candidates
|
||||
if (!nice_agent_gather_candidates(agent, stream_id))
|
||||
g_error("Failed to start candidate gathering");
|
||||
|
||||
g_debug("waiting for candidate-gathering-done signal...");
|
||||
|
||||
g_mutex_lock(&gather_mutex);
|
||||
while (!exit_thread && !candidate_gathering_done)
|
||||
g_cond_wait(&gather_cond, &gather_mutex);
|
||||
g_mutex_unlock(&gather_mutex);
|
||||
if (exit_thread) goto end;
|
||||
|
||||
// Candidate gathering is done. Send our local candidates on stdout
|
||||
sdp = nice_agent_generate_local_sdp(agent);
|
||||
printf("Generated SDP from agent :\n%s\n\n", sdp);
|
||||
printf("Copy the following line to remote client:\n");
|
||||
sdp64 = g_base64_encode((const guchar *)sdp, strlen(sdp));
|
||||
printf("\n %s\n", sdp64);
|
||||
g_free(sdp);
|
||||
g_free(sdp64);
|
||||
|
||||
// Listen on stdin for the remote candidate list
|
||||
printf("Enter remote data (single line, no wrapping):\n");
|
||||
printf("> ");
|
||||
fflush(stdout);
|
||||
while (!exit_thread) {
|
||||
// GIOStatus s = g_io_channel_read_line(io_stdin, &line, NULL, NULL, NULL);
|
||||
GIOStatus s = G_IO_STATUS_NORMAL;
|
||||
if (s == G_IO_STATUS_NORMAL) {
|
||||
char sdp_str[5120];
|
||||
std::cin >> sdp_str;
|
||||
gsize sdp_len;
|
||||
|
||||
sdp = (gchar *)g_base64_decode(sdp_str, &sdp_len);
|
||||
// Parse remote candidate list and set it on the agent
|
||||
if (sdp && nice_agent_parse_remote_sdp(agent, sdp) > 0) {
|
||||
g_free(sdp);
|
||||
// g_free(line);
|
||||
break;
|
||||
} else {
|
||||
fprintf(stderr, "ERROR: failed to parse remote data\n");
|
||||
printf("Enter remote data (single line, no wrapping):\n");
|
||||
printf("> ");
|
||||
fflush(stdout);
|
||||
}
|
||||
g_free(sdp);
|
||||
// g_free(line);
|
||||
} else if (s == G_IO_STATUS_AGAIN) {
|
||||
g_usleep(100000);
|
||||
}
|
||||
}
|
||||
|
||||
g_debug("waiting for state READY or FAILED signal...");
|
||||
g_mutex_lock(&negotiate_mutex);
|
||||
while (!exit_thread && !negotiation_done)
|
||||
g_cond_wait(&negotiate_cond, &negotiate_mutex);
|
||||
g_mutex_unlock(&negotiate_mutex);
|
||||
if (exit_thread) goto end;
|
||||
|
||||
// Listen to stdin and send data written to it
|
||||
printf("\nSend lines to remote (Ctrl-D to quit):\n");
|
||||
printf("> ");
|
||||
fflush(stdout);
|
||||
while (!exit_thread) {
|
||||
GIOStatus s = g_io_channel_read_line(io_stdin, &line, NULL, NULL, NULL);
|
||||
|
||||
if (s == G_IO_STATUS_NORMAL) {
|
||||
nice_agent_send(agent, stream_id, 1, strlen(line), line);
|
||||
g_free(line);
|
||||
printf("> ");
|
||||
fflush(stdout);
|
||||
} else if (s == G_IO_STATUS_AGAIN) {
|
||||
g_usleep(100000);
|
||||
} else {
|
||||
// Ctrl-D was pressed.
|
||||
nice_agent_send(agent, stream_id, 1, 1, "\0");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
g_object_unref(agent);
|
||||
g_io_channel_unref(io_stdin);
|
||||
g_main_loop_quit(gloop);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id,
|
||||
gpointer data) {
|
||||
g_debug("SIGNAL candidate gathering done\n");
|
||||
|
||||
g_mutex_lock(&gather_mutex);
|
||||
candidate_gathering_done = TRUE;
|
||||
g_cond_signal(&gather_cond);
|
||||
g_mutex_unlock(&gather_mutex);
|
||||
}
|
||||
|
||||
static void cb_component_state_changed(NiceAgent *agent, guint stream_id,
|
||||
guint component_id, guint state,
|
||||
gpointer data) {
|
||||
g_debug("SIGNAL: state changed %d %d %s[%d]\n", stream_id, component_id,
|
||||
state_name[state], state);
|
||||
|
||||
if (state == NICE_COMPONENT_STATE_READY) {
|
||||
g_mutex_lock(&negotiate_mutex);
|
||||
negotiation_done = TRUE;
|
||||
g_cond_signal(&negotiate_cond);
|
||||
g_mutex_unlock(&negotiate_mutex);
|
||||
} else if (state == NICE_COMPONENT_STATE_FAILED) {
|
||||
g_main_loop_quit(gloop);
|
||||
}
|
||||
}
|
||||
|
||||
static void cb_nice_recv(NiceAgent *agent, guint stream_id, guint component_id,
|
||||
guint len, gchar *buf, gpointer data) {
|
||||
if (len == 1 && buf[0] == '\0') g_main_loop_quit(gloop);
|
||||
|
||||
printf("%.*s", len, buf);
|
||||
fflush(stdout);
|
||||
}
|
||||
Reference in New Issue
Block a user