main.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. #include <arpa/inet.h>
  2. #include <gst/gst.h>
  3. #include <ifaddrs.h>
  4. #include <net/if.h>
  5. #include <netinet/in.h>
  6. #include <pthread.h>
  7. #include <signal.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <sys/ioctl.h>
  11. #include <sys/socket.h>
  12. #include <sys/time.h>
  13. #include <unistd.h>
  14. #include "peer.h"
  15. const char CAMERA_PIPELINE[] = "libcamerasrc ! video/x-raw, format=(string)NV12, width=(int)1280, height=(int)960, framerate=(fraction)30/1, interlace-mode=(string)progressive, colorimetry=(string)bt709 ! v4l2h264enc capture-io-mode=4 output-io-mode=4 ! video/x-h264, stream-format=(string)byte-stream, level=(string)4, alighnment=(string)au ! h264parse config-interval=-1 ! appsink name=camera-sink";
  16. const char MIC_PIPELINE[] = "alsasrc latency-time=20000 device=plughw:seeed2micvoicec,0 ! audio/x-raw,format=S16LE,rate=8000,channels=1 ! alawenc ! appsink name=mic-sink";
  17. const char SPK_PIPELINE[] = "appsrc name=spk-src format=time ! alawdec ! audio/x-raw,format=S16LE,rate=8000,channels=1 ! alsasink sync=false device=plughw:seeed2micvoicec,0";
  18. int g_interrupted = 0;
  19. PeerConnection* g_pc = NULL;
  20. PeerConnectionState g_state;
  21. typedef struct Media {
  22. // Camera elements
  23. GstElement* camera_pipeline;
  24. GstElement* camera_sink;
  25. // Microphone elements
  26. GstElement* mic_pipeline;
  27. GstElement* mic_sink;
  28. // Speaker elements
  29. GstElement* spk_pipeline;
  30. GstElement* spk_src;
  31. } Media;
  32. Media g_media;
  33. static void onconnectionstatechange(PeerConnectionState state, void* data) {
  34. printf("state is changed: %d\n", state);
  35. g_state = state;
  36. if (g_state == PEER_CONNECTION_COMPLETED) {
  37. gst_element_set_state(g_media.camera_pipeline, GST_STATE_PLAYING);
  38. gst_element_set_state(g_media.mic_pipeline, GST_STATE_PLAYING);
  39. gst_element_set_state(g_media.spk_pipeline, GST_STATE_PLAYING);
  40. }
  41. }
  42. static GstFlowReturn on_video_data(GstElement* sink, void* data) {
  43. GstSample* sample;
  44. GstBuffer* buffer;
  45. GstMapInfo info;
  46. g_signal_emit_by_name(sink, "pull-sample", &sample);
  47. if (sample) {
  48. buffer = gst_sample_get_buffer(sample);
  49. gst_buffer_map(buffer, &info, GST_MAP_READ);
  50. peer_connection_send_video(g_pc, info.data, info.size);
  51. gst_buffer_unmap(buffer, &info);
  52. gst_sample_unref(sample);
  53. return GST_FLOW_OK;
  54. }
  55. return GST_FLOW_ERROR;
  56. }
  57. static GstFlowReturn on_audio_data(GstElement* sink, void* data) {
  58. GstSample* sample;
  59. GstBuffer* buffer;
  60. GstMapInfo info;
  61. g_signal_emit_by_name(sink, "pull-sample", &sample);
  62. if (sample) {
  63. buffer = gst_sample_get_buffer(sample);
  64. gst_buffer_map(buffer, &info, GST_MAP_READ);
  65. peer_connection_send_audio(g_pc, info.data, info.size);
  66. gst_buffer_unmap(buffer, &info);
  67. gst_sample_unref(sample);
  68. return GST_FLOW_OK;
  69. }
  70. return GST_FLOW_ERROR;
  71. }
  72. static void onopen(void* user_data) {
  73. }
  74. static void onclose(void* user_data) {
  75. }
  76. static void onmessasge(char* msg, size_t len, void* user_data, uint16_t sid) {
  77. printf("on message: %s", msg);
  78. if (strncmp(msg, "ping", 4) == 0) {
  79. printf(", send pong\n");
  80. peer_connection_datachannel_send(g_pc, "pong", 4);
  81. }
  82. }
  83. static void on_request_keyframe(void* data) {
  84. printf("request keyframe\n");
  85. }
  86. static void signal_handler(int signal) {
  87. g_interrupted = 1;
  88. }
  89. static void* peer_singaling_task(void* data) {
  90. while (!g_interrupted) {
  91. peer_signaling_loop();
  92. usleep(1000);
  93. }
  94. pthread_exit(NULL);
  95. }
  96. static void* peer_connection_task(void* data) {
  97. while (!g_interrupted) {
  98. peer_connection_loop(g_pc);
  99. usleep(1000);
  100. }
  101. pthread_exit(NULL);
  102. }
  103. void print_usage(const char* prog_name) {
  104. printf("Usage: %s -u <url> [-t <token>]\n", prog_name);
  105. }
  106. void parse_arguments(int argc, char* argv[], const char** url, const char** token) {
  107. *token = NULL;
  108. *url = NULL;
  109. for (int i = 1; i < argc; i++) {
  110. if (strcmp(argv[i], "-u") == 0 && (i + 1) < argc) {
  111. *url = argv[++i];
  112. } else if (strcmp(argv[i], "-t") == 0 && (i + 1) < argc) {
  113. *token = argv[++i];
  114. } else {
  115. print_usage(argv[0]);
  116. exit(1);
  117. }
  118. }
  119. if (*url == NULL) {
  120. print_usage(argv[0]);
  121. exit(1);
  122. }
  123. }
  124. int main(int argc, char* argv[]) {
  125. const char* url = NULL;
  126. const char* token = NULL;
  127. parse_arguments(argc, argv, &url, &token);
  128. printf("=========== Parsed Arguments ===========\n");
  129. printf(" %-5s : %s\n", "URL", url);
  130. printf(" %-5s : %s\n", "Token", token ? token : "");
  131. printf("========================================\n");
  132. pthread_t peer_singaling_thread;
  133. pthread_t peer_connection_thread;
  134. signal(SIGINT, signal_handler);
  135. PeerConfiguration config = {
  136. .ice_servers = {
  137. {.urls = "stun:stun.l.google.com:19302"},
  138. },
  139. .datachannel = DATA_CHANNEL_STRING,
  140. .video_codec = CODEC_H264,
  141. .audio_codec = CODEC_PCMA,
  142. .on_request_keyframe = on_request_keyframe};
  143. gst_init(&argc, &argv);
  144. g_media.camera_pipeline = gst_parse_launch(CAMERA_PIPELINE, NULL);
  145. g_media.camera_sink = gst_bin_get_by_name(GST_BIN(g_media.camera_pipeline), "camera-sink");
  146. g_signal_connect(g_media.camera_sink, "new-sample", G_CALLBACK(on_video_data), NULL);
  147. g_object_set(g_media.camera_sink, "emit-signals", TRUE, NULL);
  148. g_media.mic_pipeline = gst_parse_launch(MIC_PIPELINE, NULL);
  149. g_media.mic_sink = gst_bin_get_by_name(GST_BIN(g_media.mic_pipeline), "mic-sink");
  150. g_signal_connect(g_media.mic_sink, "new-sample", G_CALLBACK(on_audio_data), NULL);
  151. g_object_set(g_media.mic_sink, "emit-signals", TRUE, NULL);
  152. g_media.spk_pipeline = gst_parse_launch(SPK_PIPELINE, NULL);
  153. g_media.spk_src = gst_bin_get_by_name(GST_BIN(g_media.spk_pipeline), "spk-src");
  154. g_object_set(g_media.spk_src, "emit-signals", TRUE, NULL);
  155. peer_init();
  156. g_pc = peer_connection_create(&config);
  157. peer_connection_oniceconnectionstatechange(g_pc, onconnectionstatechange);
  158. peer_connection_ondatachannel(g_pc, onmessasge, onopen, onclose);
  159. peer_signaling_connect(url, token, g_pc);
  160. pthread_create(&peer_connection_thread, NULL, peer_connection_task, NULL);
  161. pthread_create(&peer_singaling_thread, NULL, peer_singaling_task, NULL);
  162. while (!g_interrupted) {
  163. sleep(1);
  164. }
  165. gst_element_set_state(g_media.camera_pipeline, GST_STATE_NULL);
  166. gst_element_set_state(g_media.mic_pipeline, GST_STATE_NULL);
  167. gst_element_set_state(g_media.spk_pipeline, GST_STATE_NULL);
  168. pthread_join(peer_singaling_thread, NULL);
  169. pthread_join(peer_connection_thread, NULL);
  170. peer_signaling_disconnect();
  171. peer_connection_destroy(g_pc);
  172. peer_deinit();
  173. return 0;
  174. }