jp9000 0b4a259e56 Remove 'locale' parameter from all callbacks
The locale parameter was a mistake, because it puts extra needless
burden upon the module developer to have to handle this variable for
each and every single callback function.  The parameter is being removed
in favor of a single centralized module callback function that
specifically updates locale information for a module only when needed.
2014-06-25 12:36:26 -07:00

345 lines
8.3 KiB
C

#include <util/platform.h>
#include <obs-module.h>
#include <jansson.h>
struct rtmp_common {
char *service;
char *server;
char *key;
};
static const char *rtmp_common_getname(void)
{
/* TODO: locale */
return "Streaming Services";
}
static void rtmp_common_update(void *data, obs_data_t settings)
{
struct rtmp_common *service = data;
bfree(service->service);
bfree(service->server);
bfree(service->key);
service->service = bstrdup(obs_data_getstring(settings, "service"));
service->server = bstrdup(obs_data_getstring(settings, "server"));
service->key = bstrdup(obs_data_getstring(settings, "key"));
}
static void rtmp_common_destroy(void *data)
{
struct rtmp_common *service = data;
bfree(service->service);
bfree(service->server);
bfree(service->key);
bfree(service);
}
static void *rtmp_common_create(obs_data_t settings, obs_service_t service)
{
struct rtmp_common *data = bzalloc(sizeof(struct rtmp_common));
rtmp_common_update(data, settings);
UNUSED_PARAMETER(service);
return data;
}
static inline const char *get_string_val(json_t *service, const char *key)
{
json_t *str_val = json_object_get(service, key);
if (!str_val || !json_is_string(str_val))
return NULL;
return json_string_value(str_val);
}
static void add_service(obs_property_t list, json_t *service)
{
json_t *servers;
const char *name;
if (!json_is_object(service)) {
blog(LOG_WARNING, "rtmp-common.c: [add_service] service "
"is not an object");
return;
}
name = get_string_val(service, "name");
if (!name) {
blog(LOG_WARNING, "rtmp-common.c: [add_service] service "
"has no name");
return;
}
servers = json_object_get(service, "servers");
if (!servers || !json_is_array(servers)) {
blog(LOG_WARNING, "rtmp-common.c: [add_service] service "
"'%s' has no servers", name);
return;
}
obs_property_list_add_string(list, name, name);
}
static void add_services(obs_property_t list, const char *file, json_t *root)
{
json_t *service;
size_t index;
if (!json_is_array(root)) {
blog(LOG_WARNING, "rtmp-common.c: [add_services] JSON file "
"'%s' root is not an array", file);
return;
}
json_array_foreach (root, index, service) {
add_service(list, service);
}
}
static json_t *open_json_file(const char *file)
{
char *file_data = os_quick_read_utf8_file(file);
json_error_t error;
json_t *root;
if (!file_data)
return NULL;
root = json_loads(file_data, JSON_REJECT_DUPLICATES, &error);
bfree(file_data);
if (!root) {
blog(LOG_WARNING, "rtmp-common.c: [open_json_file] "
"Error reading JSON file '%s' (%d): %s",
file, error.line, error.text);
return NULL;
}
return root;
}
static json_t *build_service_list(obs_property_t list, const char *file)
{
json_t *root = open_json_file(file);
add_services(list, file, root);
return root;
}
static void properties_data_destroy(void *data)
{
json_t *root = data;
if (root)
json_decref(root);
}
static void fill_servers(obs_property_t servers_prop, json_t *service,
const char *name)
{
json_t *servers, *server;
size_t index;
obs_property_list_clear(servers_prop);
servers = json_object_get(service, "servers");
if (!json_is_array(servers)) {
blog(LOG_WARNING, "rtmp-common.c: [fill_servers] "
"Servers for service '%s' not a valid object",
name);
return;
}
json_array_foreach (servers, index, server) {
const char *server_name = get_string_val(server, "name");
const char *url = get_string_val(server, "url");
if (!server_name || !url)
continue;
obs_property_list_add_string(servers_prop, server_name, url);
}
}
static inline json_t *find_service(json_t *root, const char *name)
{
size_t index;
json_t *service;
json_array_foreach (root, index, service) {
const char *cur_name = get_string_val(service, "name");
if (strcmp(name, cur_name) == 0)
return service;
}
return NULL;
}
static bool service_selected(obs_properties_t props, obs_property_t p,
obs_data_t settings)
{
const char *name = obs_data_getstring(settings, "service");
json_t *root = obs_properties_get_param(props);
json_t *service;
if (!name || !*name)
return false;
service = find_service(root, name);
if (!service)
return false;
fill_servers(obs_properties_get(props, "server"), service, name);
UNUSED_PARAMETER(p);
return true;
}
static obs_properties_t rtmp_common_properties(void)
{
obs_properties_t ppts = obs_properties_create();
obs_property_t list;
char *file;
/* TODO: locale */
list = obs_properties_add_list(ppts, "service", "Service",
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
file = obs_find_plugin_file("rtmp-services/services.json");
if (file) {
json_t *root = build_service_list(list, file);
obs_properties_set_param(ppts, root, properties_data_destroy);
obs_property_set_modified_callback(list, service_selected);
bfree(file);
}
obs_properties_add_list(ppts, "server", "Server",
OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
obs_properties_add_text(ppts, "key", "Stream Key", OBS_TEXT_PASSWORD);
return ppts;
}
static void apply_video_encoder_settings(obs_encoder_t encoder,
json_t *recommended)
{
obs_data_t settings = obs_encoder_get_settings(encoder);
json_t *item = json_object_get(recommended, "keyint");
if (item && json_is_integer(item)) {
int keyint = (int)json_integer_value(item);
obs_data_setint(settings, "keyint_sec", keyint);
}
item = json_object_get(recommended, "cbr");
if (item && json_is_boolean(item)) {
bool cbr = json_is_true(item);
obs_data_setbool(settings, "cbr", cbr);
}
item = json_object_get(recommended, "profile");
if (item && json_is_string(item)) {
const char *profile = json_string_value(item);
obs_data_setbool(settings, "profile", profile);
}
item = json_object_get(recommended, "max video bitrate");
if (item && json_is_integer(item)) {
int max_bitrate = (int)json_integer_value(item);
if (obs_data_getint(settings, "bitrate") > max_bitrate) {
obs_data_setint(settings, "bitrate", max_bitrate);
obs_data_setint(settings, "buffer_size", max_bitrate);
}
}
obs_encoder_update(encoder, settings);
obs_data_release(settings);
}
static void apply_audio_encoder_settings(obs_encoder_t encoder,
json_t *recommended)
{
obs_data_t settings = obs_encoder_get_settings(encoder);
json_t *item = json_object_get(recommended, "max audio bitrate");
if (item && json_is_integer(item)) {
int max_bitrate = (int)json_integer_value(item);
if (obs_data_getint(settings, "bitrate") > max_bitrate)
obs_data_setint(settings, "bitrate", max_bitrate);
}
obs_encoder_update(encoder, settings);
obs_data_release(settings);
}
static void initialize_output(struct rtmp_common *service, obs_output_t output,
json_t *root)
{
obs_encoder_t video_encoder = obs_output_get_video_encoder(output);
obs_encoder_t audio_encoder = obs_output_get_audio_encoder(output);
json_t *json_service = find_service(root, service->service);
json_t *recommended;
if (!json_service) {
blog(LOG_WARNING, "rtmp-common.c: [initialize_output] "
"Could not find service '%s'",
service->service);
return;
}
recommended = json_object_get(json_service, "recommended");
if (!recommended)
return;
if (video_encoder)
apply_video_encoder_settings(video_encoder, recommended);
if (audio_encoder)
apply_audio_encoder_settings(audio_encoder, recommended);
}
static bool rtmp_common_initialize(void *data, obs_output_t output)
{
struct rtmp_common *service = data;
char *file;
file = obs_find_plugin_file("rtmp-services/services.json");
if (file) {
json_t *root = open_json_file(file);
if (root) {
initialize_output(service, output, root);
json_decref(root);
}
bfree(file);
}
return true;
}
static const char *rtmp_common_url(void *data)
{
struct rtmp_common *service = data;
return service->server;
}
static const char *rtmp_common_key(void *data)
{
struct rtmp_common *service = data;
return service->key;
}
struct obs_service_info rtmp_common_service = {
.id = "rtmp_common",
.getname = rtmp_common_getname,
.create = rtmp_common_create,
.destroy = rtmp_common_destroy,
.update = rtmp_common_update,
.properties = rtmp_common_properties,
.initialize = rtmp_common_initialize,
.get_url = rtmp_common_url,
.get_key = rtmp_common_key
};