Home of the Squeezebox™ & Transporter® network music players.
Page 4 of 6 FirstFirst ... 23456 LastLast
Results 31 to 40 of 55
  1. #31
    Senior Member
    Join Date
    Jan 2011
    Location
    Germany
    Posts
    220
    Quote Originally Posted by philippe_44 View Post
    It's not very clean and, as pippin said, if the hue bridge is acting too weird, then better use something like libcurl or a library that handles everything for you (I was not expecting that)
    Okay, as simple as the hue communication seems, I think I will check for using libcurl... Although it seems quite extravagant to use a whole library for such quite simple http communication, the issue with the unknown content length seems to make it reasonable to use libcurl for the first shoot... It will make me go on with parsing the JSON responses and extract some variables, writing them into the config and make the plugin have it's basic functionality. Once that hopefully works, I can change the details.

    The thing that made me puzzled a little bit about the communication was that you did some non-blocking communication via http with the chromecasts. But I think chomecast-communication is more complex... And then I always remember Michael telleong me and other peple to use non-blocking communication... When I run into trouble I can adapt that later...

    Does that seem reasonable to you or should I consider non-blocking communication from now on?
    LMS-7.9@solaris. 2x Radio, 2x Duet, 1x Chromecast v1, ShairTunes, 1x Philips Hue System

  2. #32
    Senior Member
    Join Date
    May 2008
    Location
    Canada
    Posts
    2,964
    Quote Originally Posted by chincheta0815 View Post
    Okay, as simple as the hue communication seems, I think I will check for using libcurl... Although it seems quite extravagant to use a whole library for such quite simple http communication, the issue with the unknown content length seems to make it reasonable to use libcurl for the first shoot... It will make me go on with parsing the JSON responses and extract some variables, writing them into the config and make the plugin have it's basic functionality. Once that hopefully works, I can change the details.

    The thing that made me puzzled a little bit about the communication was that you did some non-blocking communication via http with the chromecasts. But I think chomecast-communication is more complex... And then I always remember Michael telleong me and other peple to use non-blocking communication... When I run into trouble I can adapt that later...

    Does that seem reasonable to you or should I consider non-blocking communication from now on?
    You can also look at the http more simple communication that is being used in the shairtunes plugin, that I think you know well . It does take care of this complexity , I think.

    Blocking when used without select() can be dangerous as a thread might stall when the socket does not close gracefully. But the code snippet I posted before does not assume non-blocking, but it uses select() to be sure to not be stuck in a recv(). For example, if you are using recv(), you cannot have another thread closing the socket and expect to exit from recv() ... it's platform dependant. So, threads can loop using select() then recv() on blocking sockets, and it's probably what you should use first as it's more simple.

    I think Michael insists on non-blocking in general because LMS is using a single loop for everything, including plugin code callbacks. So if you block in there for any reason (including waiting for some network data) you basically block the whole system. Hence looping on select() is not a solution there.
    LMS 7.7, 7.8 and 7.9 - 5xRadio, 3xBoom, 4xDuet, 1xTouch, 1 SB2. Sonos PLAY:3, PLAY:5, Marantz NR1603, JBL OnBeat, XBoxOne, XBMC, Foobar2000, ShairPortW, JRiver 21, 2xChromecast Audio, Chromecast v1 and v2, , Pi B3, B2, Pi B+, 2xPi A+, Odroid-C1, Odroid-C2, Cubie2, Yamaha WX-010, AppleTV 4, Airport Express

  3. #33
    Senior Member
    Join Date
    Jan 2011
    Location
    Germany
    Posts
    220
    Quote Originally Posted by philippe_44 View Post
    You can also look at the http more simple communication that is being used in the shairtunes plugin, that I think you know well . It does take care of this complexity , I think.

    Blocking when used without select() can be dangerous as a thread might stall when the socket does not close gracefully. But the code snippet I posted before does not assume non-blocking, but it uses select() to be sure to not be stuck in a recv(). For example, if you are using recv(), you cannot have another thread closing the socket and expect to exit from recv() ... it's platform dependant. So, threads can loop using select() then recv() on blocking sockets, and it's probably what you should use first as it's more simple.

    I think Michael insists on non-blocking in general because LMS is using a single loop for everything, including plugin code callbacks. So if you block in there for any reason (including waiting for some network data) you basically block the whole system. Hence looping on select() is not a solution there.
    Concerning this response receving issue, everything was easier to understand in perl as there were no segfaults... Message parsing seemed easier to me...

    I now tried curl but this is also a mess as it block. The effort for getting that to work is harder than writing my own request parsing I think.

    So I gave your code a try and I got the request. But I have to think now about how to set the conditions you mentioned in the code. Especially this stupid message parsing... But I will see...
    LMS-7.9@solaris. 2x Radio, 2x Duet, 1x Chromecast v1, ShairTunes, 1x Philips Hue System

  4. #34
    Senior Member
    Join Date
    May 2008
    Location
    Canada
    Posts
    2,964
    You can try this (not compiled, not tested, likley contains a few stupid things)

    Code:
    bool somefunc(void) {
    	int len = 0, wait = 100;
    	char response[RSP_LEN];
    	int bodyRemain = 0;
    	
    	while (wait-- && len < RSP_LEN - 1) {
    		fd_set rfds;
    		struct timeval timeout = {0, 10000};
    		
    		FD_ZERO(&rfds);
    		FD_SET(huebridge->sock, &rfds);
    				
    		if (select(huebridge->sock + 1, &rfds, NULL, NULL, &timeout) < 0) {
    			// socket has closed, which seems to be what you are expecting with Hue bridge
    			break;
    		}
    		
    		if (FD_ISSET(huebridge->sock, &rfds)) {
    			int n;
    			char *p;
    			
    			// something usefull received
    			n = recv(huebridge->sock, response + len, RSP_LEN - len - 1, 0);
    			
    			if (n < 0) {
    				// oops ... should not happen
    				break;
    			}
    			
    			len += n;
    			
    			if (bodyRemain)	{
    				bodyRemain -= n;
    				if (bodyRemain <= 0) break;
    			}	
    			else if ((p = strnstr(response, "Content-Length", len)) != NULL) {
    				if (!strstr(p, "\r\n")) continue;	// EoL not in buffer, next time then
    				sscanf(p, "Content-Length: %d", &bodyRemain);
    				bodyRemain -=  len - (strstr(p, "\r\n") + 2 - response);
    			}	
    		}	
    	}
    	
    	if (!wait) {
    		// timeout occured
    	}
    	
    	if (len)
            char *p;
    
    		len = min(len, RSP_LEN - 1);
    		response[len] = '\0';
    		
    		if ((p = strstr(response, "\r\n\r\n")) != NULL)
    			// here is in p your json content !
    		} else {
    			// error, no body
    		}
    	} else {
            // error, nothing received
        }
    
        // do what you need to do to close the socket
    }
    Last edited by philippe_44; 2017-04-24 at 21:21.
    LMS 7.7, 7.8 and 7.9 - 5xRadio, 3xBoom, 4xDuet, 1xTouch, 1 SB2. Sonos PLAY:3, PLAY:5, Marantz NR1603, JBL OnBeat, XBoxOne, XBMC, Foobar2000, ShairPortW, JRiver 21, 2xChromecast Audio, Chromecast v1 and v2, , Pi B3, B2, Pi B+, 2xPi A+, Odroid-C1, Odroid-C2, Cubie2, Yamaha WX-010, AppleTV 4, Airport Express

  5. #35
    Senior Member
    Join Date
    Jan 2011
    Location
    Germany
    Posts
    220
    Quote Originally Posted by philippe_44 View Post
    You can try this (not compiled, not tested, likley contains a few stupid things)
    Cool, I will try that in the evening.

    The response from the hue developer forum was:
    The bridge sends a "connection: close" header which basically says that the connection will be closed when the response is done.

    So just read all data until the connection is closed.
    As far as I understand your code snippet mainly does that except, that it searches for "Content-Length", right?

    A thing I now realized is: I could have forgotten the break and check whether the connection is closed... (Well, stupid me...)
    LMS-7.9@solaris. 2x Radio, 2x Duet, 1x Chromecast v1, ShairTunes, 1x Philips Hue System

  6. #36
    Senior Member
    Join Date
    May 2008
    Location
    Canada
    Posts
    2,964

    How to best send asynchronous HTTP client requests in C?

    Quote Originally Posted by chincheta0815 View Post
    Cool, I will try that in the evening.

    The response from the hue developer forum was:


    As far as I understand your code snippet mainly does that except, that it searches for "Content-Length", right?

    A thing I now realized is: I could have forgotten the break and check whether the connection is closed... (Well, stupid me...)
    Yes my code searches for an optional "content-length". If it is not found, it will exit from the loop anyway on the close, otherwise it exits when expected buys are received. So if you're sure that the content-length will never be sent, even in a future release, you can remove everything that refers to bodyRemain
    Last edited by philippe_44; 2017-04-25 at 10:26.
    LMS 7.7, 7.8 and 7.9 - 5xRadio, 3xBoom, 4xDuet, 1xTouch, 1 SB2. Sonos PLAY:3, PLAY:5, Marantz NR1603, JBL OnBeat, XBoxOne, XBMC, Foobar2000, ShairPortW, JRiver 21, 2xChromecast Audio, Chromecast v1 and v2, , Pi B3, B2, Pi B+, 2xPi A+, Odroid-C1, Odroid-C2, Cubie2, Yamaha WX-010, AppleTV 4, Airport Express

  7. #37
    Senior Member
    Join Date
    Jan 2011
    Location
    Germany
    Posts
    220
    I used your code snippet and implemented the first two commands ;o)

    One for switching on and off a lamp, another for getting the hue config. The latter is not parsed correctly when using a response length or 2048. Then there are some values missing. I increased it to 4096. Is there a way to loop over that, when there is more data available?

    The code is here: https://github.com/chincheta0815/Hue...er/application

    I used the old framework as I did not want to mess up right from the beginning. The old one is more or less for testing...

    In the squeeze2hue you will find an area marke //TEST. In there you find two command...

    If you want to play, feel free to do so. You might need to add the UserName you configure in the hue and change the lamp id.

    I also tried to use the mutexes, but that did not work quite well so far...
    LMS-7.9@solaris. 2x Radio, 2x Duet, 1x Chromecast v1, ShairTunes, 1x Philips Hue System

  8. #38
    Senior Member
    Join Date
    May 2008
    Location
    Canada
    Posts
    2,964
    Quote Originally Posted by chincheta0815 View Post
    I used your code snippet and implemented the first two commands ;o)

    One for switching on and off a lamp, another for getting the hue config. The latter is not parsed correctly when using a response length or 2048. Then there are some values missing. I increased it to 4096. Is there a way to loop over that, when there is more data available?

    The code is here: https://github.com/chincheta0815/Hue...er/application

    I used the old framework as I did not want to mess up right from the beginning. The old one is more or less for testing...

    In the squeeze2hue you will find an area marke //TEST. In there you find two command...

    If you want to play, feel free to do so. You might need to add the UserName you configure in the hue and change the lamp id.

    I also tried to use the mutexes, but that did not work quite well so far...
    What's hapenning with mutexes?

    You can try that to expand the buffer (again, not tested)

    Code:
    #define HUE_MSG_CHUNK 1024
    /*----------------------------------------------------------------------------*/
    extern int hue_receive_response(hue_bridge_t *bridge, hue_response_t *response) {
        int len = 0;
        int wait = 100;
        int size = HUE_MSG_CHUNK;
        int remainingBodyLength = 0;
        int ret = 1;
        char *response_message = malloc(size);
    	
        if (!response_message) return 1;
    	
        while (wait--) {
            fd_set rfds;
            struct timeval timeout = {0, 10000};
    
            FD_ZERO(&rfds);
            FD_SET(bridge->sock, &rfds);
    
            if (select(bridge->sock + 1, &rfds, NULL, NULL, &timeout) < 0) {
                // socket has closed, which seems to be what you are expecting with Hue bridge
                break;
            }
    
            if (FD_ISSET(bridge->sock, &rfds)) {
                int bytesReceived;
    			char *p;
    
                // something usefull received
    			bytesReceived = recv(bridge->sock, response_message + len, size - len - 1, 0);
    
                if (bytesReceived < 0) {
                    // oops ... should not happen
                    break;
                }
    
                len += bytesReceived;
    			
    	    if (len == size - 1) {
    	 	size += HUE_MSG_CHUNK;	
    		response_message = realloc(response_message, size);
    		if (!response_message) break;
    	    }
    
                if (remainingBodyLength) {
                    remainingBodyLength -= bytesReceived;
    				if (remainingBodyLength <= 0) {
                        break;
                    }
                }
                else if ((p = strnstr(response_message, "Content-Length", len)) != NULL) {
                    if (!strstr(p, "\r\n")) {
                        continue;	// EoL not in buffer, next time then
                    }
                    sscanf(p, "Content-Length: %d", &remainingBodyLength);
                    remainingBodyLength -=  len - (strstr(p, "\r\n") + 2 - response_message);
                }
            }
        }
    
        if (!wait) {
            // timeout occured
            // return 1; // I would rather log a warning here as timeout does not mean failure
        }
    
        if (len && response_message) {
            char *p;
    
            response_message[len] = '\0';
    
            if ((p = strstr(response_message, "\r\n\r\n")) != NULL) {
                response->body = strdup(p) + 4;
    	    ret = 0;
            }
            		
    	free(response_message);
        }
        
        // do what you need to do to close the socket
        close(bridge->sock); // are you sure you want to close it there, knowing that it was opened somewhere ele
    
        return ret;
    }
    Last edited by philippe_44; 2017-04-25 at 20:22.
    LMS 7.7, 7.8 and 7.9 - 5xRadio, 3xBoom, 4xDuet, 1xTouch, 1 SB2. Sonos PLAY:3, PLAY:5, Marantz NR1603, JBL OnBeat, XBoxOne, XBMC, Foobar2000, ShairPortW, JRiver 21, 2xChromecast Audio, Chromecast v1 and v2, , Pi B3, B2, Pi B+, 2xPi A+, Odroid-C1, Odroid-C2, Cubie2, Yamaha WX-010, AppleTV 4, Airport Express

  9. #39
    Senior Member
    Join Date
    Jan 2011
    Location
    Germany
    Posts
    220
    Quote Originally Posted by philippe_44 View Post
    What's hapenning with mutexes?

    You can try that to expand the buffer (again, not tested)
    I will try this snippet. For "not tested code" your code is of good quality ;o)

    Concerning the mutexes I just tries to use them in my self-made functions of the "hue lib".
    I have in mind that you told me that I should lock and unlock them when I use my structures.
    Using the mutexes made my program stop when receiving a message.
    So for now I will take care of:
    1. Finish the two command functions I started,
    2. Parse the JSON response into the bridge structure.
    3. Try to change the lamp state with the LMS WebGUI
    4. Integrate them into the new framework (incl. getting the username from the config.xml)

    Then I will go on with the mutexes, etc.

    At least: That's the plan!

    Up to know I really do not know how to say thank you for all your help!
    I you wouldn't be located in Canada (I think, right?) I would invite you for a beer ;o)
    LMS-7.9@solaris. 2x Radio, 2x Duet, 1x Chromecast v1, ShairTunes, 1x Philips Hue System

  10. #40
    Senior Member
    Join Date
    Jan 2011
    Location
    Germany
    Posts
    220
    Quote Originally Posted by philippe_44 View Post
    Code:
        // do what you need to do to close the socket
        close(bridge->sock); // are you sure you want to close it there, knowing that it was opened somewhere ele
    
        return ret;
    }
    Well, actually I think I will close it in a hue_disconnect function. I have not thought about that in detail.
    My first thought:
    It might be a lot of "traffic" opening and closing sockets while steering the hue when visualizing the music.
    That would mean open it once, leave it open until the program stops, involving threads.
    So far, I am just working on those first two command for the hue as theses are the most essential ones.
    And since I try to make use of seperate functions I think a rewrite will be easy.
    What are you with your experieence thinking about that?
    LMS-7.9@solaris. 2x Radio, 2x Duet, 1x Chromecast v1, ShairTunes, 1x Philips Hue System

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •