You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

316 lines
6.7 KiB

6 years ago
6 years ago
6 years ago
3 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
3 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
3 years ago
6 years ago
3 years ago
6 years ago
3 years ago
3 years ago
6 years ago
6 years ago
3 years ago
6 years ago
3 years ago
6 years ago
6 years ago
3 years ago
3 years ago
6 years ago
  1. /*
  2. Copyright Jeroen Vreeken (jeroen@vreeken.net), 2015, 2016
  3. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <dml/dml_client.h>
  15. #include <dml/dml_connection.h>
  16. #include <dml/dml_poll.h>
  17. #include <dml/dml_packet.h>
  18. #include <dml/dml.h>
  19. #include <dml/dml_id.h>
  20. #include <dml/dml_crypto.h>
  21. #include "dml_config.h"
  22. #include "ogg.h"
  23. #include "isom.h"
  24. #include "matroska.h"
  25. #include <stdlib.h>
  26. #include <unistd.h>
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <time.h>
  30. #include <inttypes.h>
  31. uint8_t ref_id[DML_ID_SIZE];
  32. char *mime;
  33. char *name;
  34. char *alias;
  35. char *description;
  36. uint32_t bps = 0;
  37. uint16_t packet_id = 0;
  38. struct dml_connection *dml_con;
  39. bool header_done = false;
  40. uint8_t *header;
  41. size_t header_size = 0;
  42. struct dml_crypto_key *dk;
  43. void rx_packet(struct dml_connection *dc, void *arg,
  44. uint16_t id, uint16_t len, uint8_t *data)
  45. {
  46. // printf("got id: %d\n", id);
  47. switch(id) {
  48. case DML_PACKET_REQ_DESCRIPTION: {
  49. /* No need to unpack the request,
  50. we only have one stream...*/
  51. dml_packet_send_description(dc, ref_id,
  52. DML_PACKET_DESCRIPTION_VERSION_0, bps, mime,
  53. name, alias, description);
  54. break;
  55. }
  56. case DML_PACKET_CONNECT: {
  57. uint8_t id[DML_ID_SIZE];
  58. dml_con = dc;
  59. dml_packet_parse_connect(data, len, id, &packet_id);
  60. break;
  61. }
  62. case DML_PACKET_REQ_DISC: {
  63. packet_id = 0;
  64. dml_con = NULL;
  65. dml_packet_send_disc(dc, ref_id, DML_PACKET_DISC_REQUESTED);
  66. break;
  67. }
  68. case DML_PACKET_REQ_CERTIFICATE: {
  69. void *cert;
  70. size_t cert_size;
  71. if (dml_crypto_cert_get(&cert, &cert_size))
  72. break;
  73. dml_packet_send_certificate(dc, ref_id, cert, cert_size);
  74. break;
  75. }
  76. case DML_PACKET_REQ_HEADER: {
  77. uint8_t header_sig[DML_SIG_SIZE];
  78. dml_crypto_sign(header_sig, header, header_size, dk);
  79. dml_packet_send_header(dc, ref_id, header_sig, header, header_size);
  80. break;
  81. }
  82. default: {
  83. break;
  84. }
  85. }
  86. return;
  87. }
  88. int client_reconnect(void *clientv)
  89. {
  90. struct dml_client *client = clientv;
  91. if (dml_client_connect(client)) {
  92. printf("Reconnect to DML server failed\n");
  93. dml_poll_timeout(client, &(struct timespec){ 2, 0 });
  94. }
  95. return 0;
  96. }
  97. int client_connection_close(struct dml_connection *dc, void *arg)
  98. {
  99. dml_con = NULL;
  100. packet_id = 0;
  101. dml_poll_add(arg, NULL, NULL, client_reconnect);
  102. dml_poll_timeout(arg, &(struct timespec){ 1, 0 });
  103. if (dc)
  104. return dml_connection_destroy(dc);
  105. else
  106. return 0;
  107. }
  108. void client_connect(struct dml_client *client, void *arg)
  109. {
  110. struct dml_connection *dc;
  111. int fd;
  112. printf("Connected to DML server\n");
  113. fd = dml_client_fd_get(client);
  114. dc = dml_connection_create(fd, client, rx_packet, client_connection_close);
  115. dml_packet_send_hello(dc, DML_PACKET_HELLO_LEAF, "dml_streamer_ogg " DML_VERSION);
  116. dml_packet_send_route(dc, ref_id, 0);
  117. }
  118. time_t prev_sec;
  119. uint16_t prev_ctr;
  120. void send_data(void *data, size_t size)
  121. {
  122. uint64_t timestamp;
  123. struct timespec ts;
  124. if (!packet_id)
  125. return;
  126. clock_gettime(CLOCK_REALTIME, &ts);
  127. if (prev_sec != ts.tv_sec) {
  128. prev_ctr = 0;
  129. prev_sec = ts.tv_sec;
  130. } else {
  131. prev_ctr++;
  132. }
  133. timestamp = (uint64_t)ts.tv_sec << 16;
  134. timestamp |= prev_ctr;
  135. printf("timestamp: 0x%016"PRIx64"\n", timestamp);
  136. dml_packet_send_data(dml_con, packet_id, data, size, timestamp, dk);
  137. }
  138. void send_data_check(void *data, size_t size)
  139. {
  140. printf("size %zd ", size);
  141. char *cdata = data;
  142. while (size) {
  143. size_t copysize = size;
  144. if (copysize > 60000) {
  145. copysize = 60000;
  146. }
  147. printf(" %zd ", copysize);
  148. send_data(cdata, copysize);
  149. cdata += copysize;
  150. size -= copysize;
  151. }
  152. printf("\n");
  153. }
  154. int fd_ogg = 0;
  155. uint8_t *pkt_data;
  156. size_t pkt_size;
  157. ssize_t data_cb(void *data, size_t size)
  158. {
  159. if (!header_done) {
  160. header = realloc(header, header_size + size);
  161. memcpy(header + header_size, data, size);
  162. header_size += size;
  163. } else {
  164. pkt_data = realloc(pkt_data, pkt_size + size);
  165. memcpy(pkt_data + pkt_size, data, size);
  166. pkt_size += size;
  167. }
  168. return size;
  169. }
  170. int trigger_cb(enum fileparse_trigger trig)
  171. {
  172. if (trig == FILEPARSE_TRIGGER_HEADER_COMPLETE) {
  173. printf("header size %zd\n", header_size);
  174. header_done = true;
  175. } else {
  176. send_data_check(pkt_data, pkt_size);
  177. free(pkt_data);
  178. pkt_data = NULL;
  179. pkt_size = 0;
  180. }
  181. return 0;
  182. }
  183. struct fileparse *fileparse;
  184. int (*parse)(struct fileparse *ogg, void *buffer, size_t size);
  185. int fd_in(void *arg)
  186. {
  187. char buffer[4096];
  188. ssize_t r;
  189. r = read(fd_ogg, buffer, sizeof(buffer));
  190. if (r > 0) {
  191. return parse(fileparse, buffer, r);
  192. }
  193. return 0;
  194. }
  195. int main(int argc, char **argv)
  196. {
  197. struct dml_client *dc;
  198. char *file = "dml_streamer.conf";
  199. char *certificate;
  200. char *key;
  201. char *server;
  202. bool use_ogg = true;
  203. bool use_isom = false;
  204. if (argc > 1)
  205. file = argv[1];
  206. if (dml_config_load(file)) {
  207. printf("Failed to load config file %s\n", file);
  208. return -1;
  209. }
  210. mime = dml_config_value("mime", NULL, "application/ogg");
  211. if (strcmp(mime + strlen(mime) - 3, "ogg"))
  212. use_ogg = false;
  213. if (!strcmp(mime + strlen(mime) - 3, "mp4"))
  214. use_isom = true;
  215. name = dml_config_value("name", NULL, "example");
  216. alias = dml_config_value("alias", NULL, "");
  217. description = dml_config_value("description", NULL, "Test stream");
  218. bps = atoi(dml_config_value("bps", NULL, "300000"));
  219. server = dml_config_value("server", NULL, "localhost");
  220. certificate = dml_config_value("certificate", NULL, "");
  221. key = dml_config_value("key", NULL, "");
  222. if (dml_crypto_init(NULL, NULL))
  223. return -1;
  224. if (dml_crypto_load_cert(certificate)) {
  225. printf("Could not load certificate\n");
  226. return -1;
  227. }
  228. if (!(dk = dml_crypto_private_load(key))) {
  229. printf("Could not load key\n");
  230. return -1;
  231. }
  232. if (dml_id_gen(ref_id, DML_PACKET_DESCRIPTION_VERSION_0, bps,
  233. mime, name, alias, description))
  234. return -1;
  235. dc = dml_client_create(server, 0, client_connect, NULL);
  236. if (dml_client_connect(dc)) {
  237. printf("Could not connect to server\n");
  238. return -1;
  239. }
  240. if (use_ogg)
  241. fileparse = ogg_create(data_cb, trigger_cb, &parse);
  242. else if (use_isom)
  243. fileparse = isom_create(data_cb, trigger_cb, &parse);
  244. else
  245. fileparse = matroska_create(data_cb, trigger_cb, &parse);
  246. dml_poll_add(&fd_ogg, fd_in, NULL, NULL);
  247. dml_poll_fd_set(&fd_ogg, 0);
  248. dml_poll_in_set(&fd_ogg, true);
  249. dml_poll_loop();
  250. return 0;
  251. }