diff --git a/packages/addons/service/boblightd/package.mk b/packages/addons/service/boblightd/package.mk index 0efb5537fc..2336ec6129 100644 --- a/packages/addons/service/boblightd/package.mk +++ b/packages/addons/service/boblightd/package.mk @@ -48,7 +48,6 @@ addon() { mkdir -p $ADDON_BUILD/$PKG_ADDON_ID/bin cp -P $PKG_BUILD/.$TARGET_NAME/src/boblightd $ADDON_BUILD/$PKG_ADDON_ID/bin cp -P $PKG_BUILD/.$TARGET_NAME/src/boblight-constant $ADDON_BUILD/$PKG_ADDON_ID/bin - cp -P $PKG_BUILD/.$TARGET_NAME/src/boblight-aml $ADDON_BUILD/$PKG_ADDON_ID/bin if [ "$DISPLAYSERVER" = "x11" ] ; then cp -P $PKG_BUILD/.$TARGET_NAME/src/boblight-X11 $ADDON_BUILD/$PKG_ADDON_ID/bin fi diff --git a/packages/addons/service/boblightd/patches/boblightd-2.0.5-add_aml_client.patch b/packages/addons/service/boblightd/patches/boblightd-2.0.5-add_aml_client.patch deleted file mode 100644 index 9051c2011c..0000000000 --- a/packages/addons/service/boblightd/patches/boblightd-2.0.5-add_aml_client.patch +++ /dev/null @@ -1,632 +0,0 @@ -diff --git a/src/Makefile.am b/src/Makefile.am -index 9ba5381..c5a4dc6 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -7,6 +7,7 @@ AM_CFLAGS =\ - -g - - bin_PROGRAMS = boblightd \ -+ boblight-aml \ - boblight-constant - - -@@ -19,6 +20,11 @@ endif - - endif - -+boblight_aml_SOURCES = clients/boblight-aml/boblight-aml.cpp -+boblight_aml_SOURCES += clients/boblight-aml/flagmanager-aml.cpp -+boblight_aml_SOURCES += clients/flagmanager.cpp -+boblight_aml_SOURCES += util/misc.cpp -+ - boblight_v4l_SOURCES = \ - clients/boblight-v4l/boblight-v4l.cpp \ - clients/boblight-v4l/flagmanager-v4l.cpp \ -diff -urPp src/clients/boblight-aml.cpp src/clients/boblight-aml/boblight-aml.cpp ---- /dev/null Thu Jan 1 00:00:00 1970 -+++ b/src/clients/boblight-aml/boblight-aml.cpp Thu Jan 15 10:24:16 2015 -@@ -0,0 +1,491 @@ -+/* -+ * boblight -+ * Copyright (C) Bob 2009 -+ * -+ * boblight is free software: you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * boblight 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 General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program. If not, see . -+ */ -+ -+#define BOBLIGHT_DLOPEN -+#include "lib/boblight.h" -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#include "config.h" -+#include "util/misc.h" -+#include "util/timeutils.h" -+#include "flagmanager-aml.h" -+ -+using namespace std; -+ -+//from linux/amlogic/amports/amvideocap.h -+#define AMVIDEOCAP_IOC_MAGIC 'V' -+#define AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH _IOW(AMVIDEOCAP_IOC_MAGIC, 0x02, int) -+#define AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT _IOW(AMVIDEOCAP_IOC_MAGIC, 0x03, int) -+ -+ -+// helper class - tries to load the "movie" settings from the script.xbmc.boblight addon -+// and pass them to the boblight-aml client -+class CBoblightAddonSettings -+{ -+ public: -+ CBoblightAddonSettings() : m_bobdisable(false), m_settingsLoaded(false) -+ { -+ m_settingsLoaded = loadBoblightAddonSettings(); -+ } -+ -+ std::string getBoblightClientCmdLine() -+ { -+ std::string cmdLine = ""; -+ //convert bool string to lowercase -+ transform(m_interpolation.begin(), m_interpolation.end(), m_interpolation.begin(), ::tolower); -+ -+ cmdLine += "-s " + m_ip + ":" + m_port; -+ cmdLine += " -o autospeed=" + m_autospeed; -+ cmdLine += " -o interpolation=" + m_interpolation; -+ cmdLine += " -o saturation=" + m_saturation; -+ cmdLine += " -o speed=" + m_speed; -+ cmdLine += " -o threshold=" + m_threshold; -+ cmdLine += " -o value=" + m_value; -+ return cmdLine; -+ } -+ -+ bool m_bobdisable; -+ bool m_settingsLoaded; -+ std::string m_ip; -+ std::string m_port; -+ std::string m_autospeed; -+ std::string m_interpolation; -+ std::string m_saturation; -+ std::string m_speed; -+ std::string m_threshold; -+ std::string m_value; -+ -+ private: -+ #define SETTINGS_ATTR_BOBDISABLE "bobdisable" -+ #define SETTINGS_ATTR_IP "hostip" -+ #define SETTINGS_ATTR_PORT "hostport" -+ #define SETTINGS_ATTR_AUTOSPEED "movie_autospeed" -+ #define SETTINGS_ATTR_INTERPOLATION "movie_interpolation" -+ #define SETTINGS_ATTR_SATURATION "movie_saturation" -+ #define SETTINGS_ATTR_SPEED "movie_speed" -+ #define SETTINGS_ATTR_THRESHOLD "movie_threshold" -+ #define SETTINGS_ATTR_VALUE "movie_value" -+ #define KODI_HOME_ENV_VAR "HOME" -+ -+ bool loadBoblightAddonSettings() -+ { -+ bool ret = false; -+ char *kodiHome = getenv(KODI_HOME_ENV_VAR); -+ //fallback to custom settings file in case boblight addon is not installed -+ std::string settingsFile = "/storage/boblight-aml.xml"; -+ -+ if (kodiHome != NULL) -+ { -+ settingsFile = std::string(kodiHome) + "/.kodi/userdata/addon_data/script.xbmc.boblight/settings.xml"; -+ } -+ -+ FILE *fd = fopen(settingsFile.c_str(), "r"); -+ -+ if (fd != NULL) -+ { -+ fseek(fd, 0, SEEK_END); -+ size_t fileSize = ftell(fd); -+ fseek(fd, 0, SEEK_SET); -+ if (fileSize > 0) -+ { -+ if (fileSize > 32000)//read 16k max - there shouldn't be a bigger settings.xml from boblight [tm] -+ fileSize = 32000; -+ char *xmlBuffer = new char[fileSize]; -+ size_t readCount = fread(xmlBuffer, fileSize, 1, fd); -+ fclose(fd); -+ -+ if (readCount == 1) -+ { -+ parseBoblightSettings(std::string(xmlBuffer)); -+ ret = true; -+ } -+ else -+ { -+ fprintf(stderr, "Failed reading boblight addon settings.xml"); -+ } -+ delete[] xmlBuffer; -+ } -+ } -+ return ret; -+ } -+ -+ void parseBoblightSettings(std::string xmlBuffer) -+ { -+ std::string settings_bobdisable_str; -+ settings_bobdisable_str = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_BOBDISABLE); -+ if (settings_bobdisable_str == "true" || settings_bobdisable_str == "True") -+ m_bobdisable = true; -+ -+ m_ip = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_IP); -+ m_port = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_PORT); -+ m_autospeed = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_AUTOSPEED); -+ m_interpolation = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_INTERPOLATION); -+ m_saturation = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_SATURATION); -+ m_speed = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_SPEED); -+ m_threshold = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_THRESHOLD); -+ m_value = getValueFromXmlBuffer(xmlBuffer, SETTINGS_ATTR_VALUE); -+ } -+ -+ std::string getValueFromXmlBuffer(const std::string &xmlBuffer, const char* xmlAttribute) -+ { -+ size_t strPos = 0; -+ std::string valueStr; -+ -+ // each line in the xml looks like this: -+ // -+ // find the attribute -+ if ((strPos = xmlBuffer.find(xmlAttribute)) != std::string::npos) -+ { -+ size_t strPos2 = 0; -+ // from movie_value" value="1.000006" /> look for "value" -+ if ((strPos2 = xmlBuffer.find("value", strPos)) != std::string::npos) -+ { -+ size_t strPos3 = 0; -+ // from value="1.000006" /> look for "=" -+ if ((strPos3 = xmlBuffer.find("=", strPos2)) != std::string::npos) -+ { -+ //extract the value - strPos3 points to ="1.000006" -+ int valueOffset = 1; //skip the "=" -+ if (xmlBuffer[strPos3 + valueOffset] == '"') -+ valueOffset++;//skip " if needed -+ int strLen = 0; -+ do -+ { -+ // value stops with " or space -+ if (xmlBuffer[strPos3 + valueOffset + strLen] == '"' || -+ xmlBuffer[strPos3 + valueOffset + strLen] == ' ') -+ break; -+ strLen++; -+ } while (strLen < 20);// no insane xml garbage ... -+ -+ valueStr = xmlBuffer.substr(strPos3 + valueOffset, strLen); -+ } -+ } -+ } -+ return valueStr; -+ } -+}; -+ -+struct aml_snapshot_t { -+ unsigned int dst_width; -+ unsigned int dst_height; -+ unsigned int dst_stride; -+ unsigned int dst_size; -+ void *dst_vaddr; -+}; -+ -+volatile bool g_stop = false; -+CFlagManagerAML g_flagmanager; -+/********************************************************* -+ *********************************************************/ -+static void SignalHandler(int signum) -+{ -+ if (signum == SIGTERM) -+ { -+ fprintf(stderr, "caught SIGTERM\n"); -+ g_stop = true; -+ } -+ else if (signum == SIGINT) -+ { -+ fprintf(stderr, "caught SIGTERM\n"); -+ g_stop = true; -+ } -+} -+ -+#define VIDEO_PATH "/dev/amvideo" -+#define AMSTREAM_IOC_MAGIC 'S' -+#define AMSTREAM_IOC_GET_VIDEO_DISABLE _IOR(AMSTREAM_IOC_MAGIC, 0x48, unsigned long) -+static int amvideo_utils_video_playing() -+{ -+ int video_fd; -+ int video_disable; -+ -+ video_fd = open(VIDEO_PATH, O_RDWR); -+ if (video_fd < 0) { -+ return -1; -+ } -+ -+ ioctl(video_fd, AMSTREAM_IOC_GET_VIDEO_DISABLE, &video_disable); -+ if (video_disable) -+ { -+ close(video_fd); -+ return 1; -+ } -+ -+ close(video_fd); -+ -+// fprintf(stderr, "pos x %d y %d w %d h %d\n",snapshot.src_x, snapshot.src_y,snapshot.src_width,snapshot.src_height); -+ return 0; -+} -+ -+static int capture_frame(int fd, aml_snapshot_t &snapshot) -+{ -+ int ret = 0; -+ -+ ssize_t readResult = pread(fd, snapshot.dst_vaddr, snapshot.dst_size, 0); -+ -+ if (readResult < snapshot.dst_size) -+ { -+ fprintf(stderr, "frame read returned %d\n", readResult); -+ } -+ //fprintf(stderr, "requ: %d read %d \n", snapshot.dst_size, readResult); -+ fprintf(stderr, "."); -+ return ret; -+} -+ -+static int configure_capture(int fd, aml_snapshot_t &snapshot) -+{ -+ int ret = 0; -+ int ioctlret = 0; -+ -+ if ((ioctlret = ioctl(fd, AMVIDEOCAP_IOW_SET_WANTFRAME_WIDTH, snapshot.dst_width)) != 0) -+ { -+ ret = 2; -+ fprintf(stderr, "Error setting frame width (ret: %d errno: %d)\n", ioctlret, errno); -+ } -+ -+ -+ if ((ioctlret = ioctl(fd, AMVIDEOCAP_IOW_SET_WANTFRAME_HEIGHT, snapshot.dst_height)) != 0) -+ { -+ ret = 3; -+ fprintf(stderr, "Error setting frame height (ret: %d errno: %d)\n", ioctlret, errno); -+ } -+ -+ return ret; -+} -+ -+static void frameToboblight(void *boblight, uint8_t* outputptr, int w, int h, int stride) -+{ -+ if (!boblight) -+ { -+ fprintf(stderr, "no boblight\n"); -+ return; -+ } -+ if (!outputptr) -+ { -+ fprintf(stderr, "no outputptr\n"); -+ return; -+ } -+ //read out pixels and hand them to libboblight -+ uint8_t* buffptr; -+ for (int y = h; y > 0; y--) { -+ buffptr = outputptr + stride * y; -+ for (int x = 0; x < w; x++) { -+ int rgb[3]; -+ rgb[2] = *(buffptr++); -+ rgb[1] = *(buffptr++); -+ rgb[0] = *(buffptr++); -+ -+ //fprintf(stdout, "frameToboblight: x(%d), y(%d)\n", x, y); -+ -+ boblight_addpixelxy(boblight, x, y, rgb); -+ } -+ } -+} -+ -+static int Run(void* boblight) -+{ -+ int snapshot_fd = -1; -+ aml_snapshot_t aml_snapshot = {0}; -+ int lastPriority = 255; -+ -+ aml_snapshot.dst_width = 160; -+ aml_snapshot.dst_height = 160; -+ -+ // calc stride, size and alloc mem -+ aml_snapshot.dst_stride = aml_snapshot.dst_width * 3; -+ aml_snapshot.dst_size = aml_snapshot.dst_stride * aml_snapshot.dst_height; -+ aml_snapshot.dst_vaddr = calloc(aml_snapshot.dst_size, 1); -+ -+ fprintf(stdout, "Connection to boblightd config: width(%d), height(%d)\n", -+ aml_snapshot.dst_width, aml_snapshot.dst_height); -+ //tell libboblight how big our image is -+ boblight_setscanrange(boblight, (int)aml_snapshot.dst_width, (int)aml_snapshot.dst_height); -+ -+ while(!g_stop) -+ { -+ int64_t bgn = GetTimeUs(); -+ -+ if (snapshot_fd == -1) { -+ snapshot_fd = open(g_flagmanager.m_device.c_str(), O_RDWR, 0); -+ -+ if (snapshot_fd == -1) { -+ sleep(1); -+ continue; -+ } else { -+ fprintf(stdout, "snapshot_fd(%d) \n", snapshot_fd); -+ } -+ } -+ -+ // match source ratio if possible -+ if (amvideo_utils_video_playing() != 0) { -+ if ( lastPriority != 255) -+ { -+ boblight_setpriority(boblight, 255); -+ lastPriority = 255; -+ } -+ sleep(1); -+ continue; -+ } -+ -+ if (configure_capture(snapshot_fd, aml_snapshot) == 0) -+ { -+ if (capture_frame(snapshot_fd, aml_snapshot) == 0) -+ { -+ // image to boblight convert. -+ frameToboblight(boblight, (uint8_t*)aml_snapshot.dst_vaddr, -+ aml_snapshot.dst_width, aml_snapshot.dst_height, aml_snapshot.dst_stride); -+ -+ if (lastPriority != g_flagmanager.m_priority) -+ { -+ boblight_setpriority(boblight, g_flagmanager.m_priority); -+ lastPriority = g_flagmanager.m_priority; -+ } -+ if (!boblight_sendrgb(boblight, 1, NULL)) -+ { -+ // some error happened, probably connection broken, so bitch and try again -+ PrintError(boblight_geterror(boblight)); -+ boblight_destroy(boblight); -+ continue; -+ } -+ } -+ else -+ { -+ fprintf(stdout, "nap time\n"); -+ sleep(1); -+ } -+ } -+ int64_t end = GetTimeUs(); -+ float calc_time_ms = (float)(end - bgn) / 1000.0; -+ // throttle to 100ms max cycle rate -+ calc_time_ms -= 100.0; -+ if ((int)calc_time_ms < 0) -+ usleep((int)(-calc_time_ms * 1000)); -+ } -+ -+ // last image is black -+ boblight_setpriority(boblight, 255); -+ boblight_destroy(boblight); -+ close(snapshot_fd); -+ return 0; -+} -+ -+/********************************************************* -+ *********************************************************/ -+int main(int argc, char *argv[]) -+{ -+ //load the boblight lib, if it fails we get a char* from dlerror() -+ const char* boblight_error = boblight_loadlibrary(NULL); -+ if (boblight_error) -+ { -+ PrintError(boblight_error); -+ return 1; -+ } -+ -+ //try to parse the flags and bitch to stderr if there's an error -+ try { -+ g_flagmanager.ParseFlags(argc, argv); -+ } -+ catch (string error) { -+ PrintError(error); -+ g_flagmanager.PrintHelpMessage(); -+ return 1; -+ } -+ -+ if (g_flagmanager.m_printhelp) { -+ g_flagmanager.PrintHelpMessage(); -+ return 1; -+ } -+ -+ if (g_flagmanager.m_printboblightoptions) { -+ g_flagmanager.PrintBoblightOptions(); -+ return 1; -+ } -+ -+ // check if we only should generate a cmdline based -+ // on settings from possible found boblight addon -+ if (g_flagmanager.generateCmdLine) -+ { -+ CBoblightAddonSettings settings; -+ string cmdLine = "-p 100"; //default cmdline just contains priority 100 -+ -+ if (settings.m_settingsLoaded) -+ cmdLine += " " + settings.getBoblightClientCmdLine(); -+ fprintf(stdout, "%s", cmdLine.c_str()); -+ return 0;//exit -+ } -+ -+ fprintf(stderr, "Using device: %s \n", g_flagmanager.m_device.c_str()); -+ -+ //set up signal handlers -+ signal(SIGINT, SignalHandler); -+ signal(SIGTERM, SignalHandler); -+ -+ //keep running until we want to quit -+ while(!g_stop) { -+ //init boblight -+ void* boblight = boblight_init(); -+ -+ fprintf(stdout, "Connecting to boblightd(%p)\n", boblight); -+ -+ //try to connect, if we can't then bitch to stderr and destroy boblight -+ if (!boblight_connect(boblight, g_flagmanager.m_address, g_flagmanager.m_port, 5000000) || -+ !boblight_setpriority(boblight, 255)) { -+ PrintError(boblight_geterror(boblight)); -+ fprintf(stdout, "Waiting 10 seconds before trying again\n"); -+ boblight_destroy(boblight); -+ sleep(2); -+ continue; -+ } -+ -+ fprintf(stdout, "Connection to boblightd opened\n"); -+ -+ //try to parse the boblight flags and bitch to stderr if we can't -+ try { -+ g_flagmanager.ParseBoblightOptions(boblight); -+ } -+ catch (string error) { -+ PrintError(error); -+ return 1; -+ } -+ -+ try { -+ Run(boblight); -+ } -+ catch (string error) { -+ PrintError(error); -+ boblight_destroy(boblight); -+ return 1; -+ } -+ } -+ fprintf(stdout, "Exiting\n"); -+} -diff -urPp src/clients/flagmanager-aml.cpp src/clients/boblight-aml/flagmanager-aml.cpp ---- /dev/null Thu Jan 1 00:00:00 1970 -+++ b/src/clients/boblight-aml/flagmanager-aml.cpp Thu Jan 15 10:21:40 2015 -@@ -0,0 +1,68 @@ -+/* -+ * boblight -+ * Copyright (C) Bob 2009 -+ * -+ * boblight is free software: you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * boblight 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 General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program. If not, see . -+ */ -+ -+#include -+ -+#include "flagmanager-aml.h" -+#include "util/misc.h" -+#include "config.h" -+ -+#define DEFAULT_CAPTURE_DEVICE "/dev/amvideocap0" -+ -+using namespace std; -+ -+CFlagManagerAML::CFlagManagerAML() -+{ -+ // extend the flags -d -> device -+ // -g -> only generate cmdline from possible found boblight addon settings.xml -+ m_flags += "d:g"; -+ m_device = DEFAULT_CAPTURE_DEVICE; -+ generateCmdLine = false; -+} -+ -+void CFlagManagerAML::ParseFlagsExtended(int& argc, char**& argv, int& c, char*& optarg) -+{ -+ if (c == 'd') //devicename -+ { -+ if (optarg) //optional device -+ { -+ m_device = optarg; -+ } -+ } -+ -+ if (c == 'g') //generate cmdline -+ { -+ generateCmdLine = true; -+ } -+} -+ -+void CFlagManagerAML::PrintHelpMessage() -+{ -+ cout << "Usage: boblight-aml\n"; -+ cout << "\n"; -+ cout << " options:\n"; -+ cout << "\n"; -+ cout << " -p priority, from 0 to 255, default is 128\n"; -+ cout << " -s address[:port], set the address and optional port to connect to\n"; -+ cout << " -o add libboblight option, syntax: [light:]option=value\n"; -+ cout << " -l list libboblight options\n"; -+ cout << " -f fork\n"; -+ cout << " -d (defaults to " << m_device << ")\n"; -+ cout << " -g try to find the settings.xml file from boblight addon and return the cmdline to use its options\n"; -+ cout << "\n"; -+} -diff -urPp src/clients/flagmanager-aml.h src/clients/boblight-aml/flagmanager-aml.h ---- /dev/null Thu Jan 1 00:00:00 1970 -+++ b/src/clients/boblight-aml/flagmanager-aml.h Thu Jan 15 10:20:15 2015 -@@ -0,0 +1,36 @@ -+/* -+ * boblight -+ * Copyright (C) Bob 2009 -+ * -+ * boblight is free software: you can redistribute it and/or modify it -+ * under the terms of the GNU General Public License as published by the -+ * Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * boblight 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 General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License along -+ * with this program. If not, see . -+ */ -+ -+#ifndef FLAGMANAGERAML -+#define FLAGMANAGERAML -+ -+#include "clients/flagmanager.h" -+ -+class CFlagManagerAML : public CFlagManager -+{ -+ public: -+ CFlagManagerAML(); -+ void ParseFlagsExtended(int& argc, char**& argv, int& c, char*& optarg); -+ -+ void PrintHelpMessage(); -+ std::string m_device; //device to open for amvideocap -+ bool generateCmdLine; -+ -+}; -+ -+#endif //FLAGMANAGERAML -\ No newline at end of file diff --git a/packages/addons/service/boblightd/source/bin/boblightd.start b/packages/addons/service/boblightd/source/bin/boblightd.start index 0d99d7652f..6d991d94a0 100755 --- a/packages/addons/service/boblightd/source/bin/boblightd.start +++ b/packages/addons/service/boblightd/source/bin/boblightd.start @@ -18,10 +18,4 @@ if [ -x $ADDON_DIR/bin/boblight-X11 -a -e $ADDON_HOME/boblight.X11 ] ; then boblight-X11 -f >/dev/null 2>&1 fi -if [ -x $ADDON_DIR/bin/boblight-aml -a -e /dev/amvideocap0 ] ; then - #generates cmdline from boblight addon settings - CMDLINE=`boblight-aml -g` - boblight-aml $CMDLINE >/dev/null 2>&1 & -fi - exec boblightd -c $ADDON_HOME/boblight.conf > $ADDON_LOG_FILE 2>&1