/* GStreamer * Copyright (C) 2017 Sebastian Dröge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include "iniparser/iniparser.h" #define CONF "/oem/etc/config.xml" #define SPK_CONF "/etc/speaker.conf" #define MAX_LINE_LENGTH 256 struct SPEAKER_CONF { char hw_version[16]; char dev_type[32]; char enable_mic[8]; char media_stream[8]; }; void find_tag_in_file(const char* file_path, const char* tag, char *value); void confParse(struct SPEAKER_CONF *conf); void confParse(struct SPEAKER_CONF *conf) { dictionary * ini ; ini = iniparser_load(SPK_CONF); if (ini==NULL) { fprintf(stderr, "cannot parse file: %s\n", SPK_CONF); exit(-1); } strcpy(conf->dev_type, iniparser_getstring(ini, "system:ui_model", "")); strcpy(conf->hw_version, iniparser_getstring(ini, "system:hard_version", "")); strcpy(conf->enable_mic, iniparser_getstring(ini, "onvif:enable_mic", "no")); strcpy(conf->media_stream, iniparser_getstring(ini, "onvif:media_stream", "main")); iniparser_freedict(ini); } static gchar *htdigest_path = NULL; static gchar *realm = NULL; static GOptionEntry entries[] = { {"htdigest-path", 'h', 0, G_OPTION_ARG_STRING, &htdigest_path, "Path to an htdigest file to parse (default: None)", "PATH"}, {"realm", 'r', 0, G_OPTION_ARG_STRING, &realm, "Authentication realm (default: None)", "REALM"}, {NULL} }; int main (int argc, char *argv[]) { GMainLoop *loop; GstRTSPServer *server; GstRTSPMountPoints *mounts; GstRTSPMediaFactory *factory; GstRTSPAuth *auth; GstRTSPToken *token; GOptionContext *optctx; GError *error = NULL; struct SPEAKER_CONF conf; confParse(&conf);; char launchstr[512]; char username[64] = { 0 }; char password[64] = { 0 }; find_tag_in_file(CONF, "auth_user", username); find_tag_in_file(CONF, "auth_pass", password); if (strlen(username) == 0 || strlen(password) == 0) { g_print ("Please username or password in config.xml\n"); return -1; } // putenv("GST_DEBUG=4"); gst_init (&argc, &argv); optctx = g_option_context_new (NULL); g_option_context_add_main_entries (optctx, entries, NULL); g_option_context_add_group (optctx, gst_init_get_option_group ()); if (!g_option_context_parse (optctx, &argc, &argv, &error)) { g_printerr ("Error parsing options: %s\n", error->message); g_option_context_free (optctx); g_clear_error (&error); return -1; } g_option_context_free (optctx); loop = g_main_loop_new (NULL, FALSE); /* create a server instance */ server = gst_rtsp_onvif_server_new (); /* get the mount points for this server, every server has a default object * that be used to map uri mount points to media factories */ mounts = gst_rtsp_server_get_mount_points (server); /* make a media factory for a test stream. The default media factory can use * gst-launch syntax to create pipelines. * any launch line works as long as it contains elements named pay%d. Each * element with pay%d names will be a stream */ factory = gst_rtsp_onvif_media_factory_new (); //! video/x-raw, format=(string)RGB, width=(int)640, height=(int)480 strcpy(launchstr, "( filesrc loop=true location=\"/usr/share/onvif/speaker.h264\" ! video/x-h264 ! h264parse ! rtph264pay pt=96 config-interval=5 name=pay0 "); if(strcmp(conf.enable_mic, "yes") == 0) { strcat(launchstr, "alsasrc device=plug:mixmic ! queue ! audioconvert ! audioresample ! mulawenc ! rtppcmupay name=pay1 )"); } else { strcat(launchstr, " )"); } gst_rtsp_media_factory_set_launch (factory,launchstr); gst_rtsp_onvif_media_factory_set_backchannel_launch (GST_RTSP_ONVIF_MEDIA_FACTORY (factory), "( capsfilter caps=\"application/x-rtp, media=audio, payload=0, clock-rate=8000, encoding-name=PCMU, channels=1\" name=depay_backchannel ! rtppcmudepay ! mulawdec ! audioconvert ! audio/x-raw,channels=2 ! audioresample ! alsasink async=false sync=false )"); //"( capsfilter caps=\"application/x-rtp, media=audio, payload=8, clock-rate=8000, encoding-name=PCMA, channels=1\" name=depay_backchannel ! rtpjitterbuffer latency=80 ! rtppcmadepay ! alawdec ! identity drop-probability=0.01 sync=true ! audioconvert ! audioresample ! alsasink async=false sync=false )"); gst_rtsp_media_factory_set_shared (factory, FALSE); gst_rtsp_media_factory_set_media_gtype (factory, GST_TYPE_RTSP_ONVIF_MEDIA); /* attach the test factory to the /test url */ gst_rtsp_mount_points_add_factory (mounts, "/MainStream", factory); /* allow admin to access this resource */ gst_rtsp_media_factory_add_role (factory, username, GST_RTSP_PERM_MEDIA_FACTORY_ACCESS, G_TYPE_BOOLEAN, TRUE, GST_RTSP_PERM_MEDIA_FACTORY_CONSTRUCT, G_TYPE_BOOLEAN, TRUE, NULL); /* don't need the ref to the mapper anymore */ g_object_unref (mounts); /* make a new authentication manager */ auth = gst_rtsp_auth_new (); gst_rtsp_auth_set_supported_methods (auth, GST_RTSP_AUTH_DIGEST); if (realm) gst_rtsp_auth_set_realm (auth, realm); /* make admin token */ token = gst_rtsp_token_new (GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, username, NULL); gst_rtsp_auth_add_digest (auth, username, password, token); gst_rtsp_token_unref (token); /* set as the server authentication manager */ gst_rtsp_server_set_auth (server, auth); g_object_unref (auth); /* attach the server to the default maincontext */ gst_rtsp_server_attach (server, NULL); /* start serving */ g_print ("stream ready at rtsp://0.0.0.0:554/MainStream\n"); g_main_loop_run (loop); return 0; } void find_tag_in_file(const char* file_path, const char* tag, char *value) { FILE* file = fopen(file_path, "r"); if (file == NULL) { g_print ("Failed to open file: %s\n", file_path); return; } char line[MAX_LINE_LENGTH]; char start_tag[MAX_LINE_LENGTH] = { 0 }; char end_tag[MAX_LINE_LENGTH] = { 0 }; sprintf(start_tag, "<%s>", tag); sprintf(end_tag, "", tag); while (fgets(line, MAX_LINE_LENGTH, file)) { if (strstr(line, start_tag) && strstr(line, end_tag)) { // Extract the data between the start and end tags. char* start = strstr(line, start_tag) + strlen(start_tag); char* end = strstr(line, end_tag); *end = '\0'; // Null-terminate the string at the end of the data. strcpy(value, start); break; } } fclose(file); }