showroom.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #include <util/curl/curl-helper.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <jansson.h>
  5. #include <util/dstr.h>
  6. #include <util/darray.h>
  7. #include "util/base.h"
  8. #include <obs-module.h>
  9. #include <util/platform.h>
  10. #include "showroom.h"
  11. #include <util/threading.h>
  12. struct showroom_ingest_info {
  13. char *access_key;
  14. uint64_t last_time;
  15. struct showroom_ingest ingest;
  16. };
  17. static DARRAY(struct showroom_ingest_info) cur_ingests = {0};
  18. struct showroom_ingest invalid_ingest = {"", ""};
  19. void free_showroom_data(void)
  20. {
  21. for (size_t i = 0; i < cur_ingests.num; i++) {
  22. struct showroom_ingest_info *info = &cur_ingests.array[i];
  23. bfree(info->access_key);
  24. bfree((void *)info->ingest.key);
  25. bfree((void *)info->ingest.url);
  26. }
  27. da_free(cur_ingests);
  28. }
  29. static size_t showroom_write_cb(void *data, size_t size, size_t nmemb, void *user_pointer)
  30. {
  31. struct dstr *json = user_pointer;
  32. size_t realsize = size * nmemb;
  33. dstr_ncat(json, data, realsize);
  34. return realsize;
  35. }
  36. static struct showroom_ingest_info *find_ingest(const char *access_key)
  37. {
  38. struct showroom_ingest_info *ret = NULL;
  39. for (size_t i = 0; i < cur_ingests.num; i++) {
  40. struct showroom_ingest_info *info = &cur_ingests.array[i];
  41. if (strcmp(info->access_key, access_key) == 0) {
  42. ret = info;
  43. break;
  44. }
  45. }
  46. return ret;
  47. }
  48. #ifndef SEC_TO_NSEC
  49. #define SEC_TO_NSEC 1000000000ULL
  50. #endif
  51. static struct showroom_ingest_info *get_ingest_from_json(char *str, const char *access_key)
  52. {
  53. json_error_t error;
  54. json_t *root;
  55. root = json_loads(str, JSON_REJECT_DUPLICATES, &error);
  56. if (!root) {
  57. return NULL;
  58. }
  59. const char *url_str = json_string_value(json_object_get(root, "streaming_url_rtmp"));
  60. const char *key_str = json_string_value(json_object_get(root, "streaming_key"));
  61. struct showroom_ingest_info *info = find_ingest(access_key);
  62. if (!info) {
  63. info = da_push_back_new(cur_ingests);
  64. info->access_key = bstrdup(access_key);
  65. }
  66. bfree((void *)info->ingest.url);
  67. bfree((void *)info->ingest.key);
  68. info->ingest.url = bstrdup(url_str);
  69. info->ingest.key = bstrdup(key_str);
  70. info->last_time = os_gettime_ns() / SEC_TO_NSEC;
  71. json_decref(root);
  72. return info;
  73. }
  74. struct showroom_ingest *showroom_get_ingest(const char *server, const char *access_key)
  75. {
  76. struct showroom_ingest_info *info = find_ingest(access_key);
  77. CURL *curl_handle;
  78. CURLcode res;
  79. struct dstr json = {0};
  80. struct dstr uri = {0};
  81. long response_code;
  82. if (info) {
  83. /* this function is called a bunch of times for the same data,
  84. * so in order to prevent multiple unnecessary queries in a
  85. * short period of time, return the same data for 10 seconds */
  86. uint64_t ts_sec = os_gettime_ns() / SEC_TO_NSEC;
  87. if (ts_sec - info->last_time < 10) {
  88. return &info->ingest;
  89. } else {
  90. info = NULL;
  91. }
  92. }
  93. curl_handle = curl_easy_init();
  94. dstr_copy(&uri, server);
  95. dstr_cat(&uri, access_key);
  96. curl_easy_setopt(curl_handle, CURLOPT_URL, uri.array);
  97. curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, true);
  98. curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2L);
  99. curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 30L);
  100. curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, showroom_write_cb);
  101. curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&json);
  102. curl_obs_set_revoke_setting(curl_handle);
  103. res = curl_easy_perform(curl_handle);
  104. dstr_free(&uri);
  105. if (res != CURLE_OK) {
  106. blog(LOG_WARNING, "showroom_get_ingest: curl_easy_perform() failed: %s", curl_easy_strerror(res));
  107. goto cleanup;
  108. }
  109. curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &response_code);
  110. if (response_code != 200) {
  111. blog(LOG_WARNING,
  112. "showroom_get_ingest: curl_easy_perform() returned "
  113. "code: %ld",
  114. response_code);
  115. goto cleanup;
  116. }
  117. if (json.len == 0) {
  118. blog(LOG_WARNING, "showroom_get_ingest: curl_easy_perform() returned "
  119. "empty response");
  120. goto cleanup;
  121. }
  122. info = get_ingest_from_json(json.array, access_key);
  123. cleanup:
  124. curl_easy_cleanup(curl_handle);
  125. dstr_free(&json);
  126. return info ? &info->ingest : &invalid_ingest;
  127. }