Announcement

Collapse
No announcement yet.

Pipe Squeezelite to Icecast

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Pipe Squeezelite to Icecast

    Can anyone help?
    I’m looking for a way of piping Squeezelite output to an Icecast server.
    I can do it by using a player’s audio output into the input of the Icecast server via Liquidsoap but I’m looking for a method of doing it without going analogue at any stage.
    I can do it using Squeezelite and an encoder on a Windows PC so there must be a way in Linux (Centos 8) preferably not using any gui. Anyone?
    Jim



    VB2.4 storage QNAP TS419p (NFS)
    Living Room Joggler & Pi4/Khadas -> Onkyo TXNR686 -> Celestion F20s
    Office Joggler & Pi3 -> Denon RCD N8 -> Celestion F10s
    Dining Room SB Radio
    Bedroom (Bedside) Pi Zero+DAC ->ToppingTP21 ->AKG Headphones
    Bedroom (TV) & Bathroom SB Touch ->Denon AVR ->Mordaunt Short M10s + Kef ceiling speakers
    Guest Room Joggler > Topping Amp -> Wharfedale Modus Cubes

    #2
    Probably using pulseaudio and then using parec providing the source for icecast

    Comment


      #3
      Originally posted by bpa View Post
      Probably using pulseaudio and then using parec providing the source for icecast
      Thanks bpa. That’s somewhere to start.
      Jim



      VB2.4 storage QNAP TS419p (NFS)
      Living Room Joggler & Pi4/Khadas -> Onkyo TXNR686 -> Celestion F20s
      Office Joggler & Pi3 -> Denon RCD N8 -> Celestion F10s
      Dining Room SB Radio
      Bedroom (Bedside) Pi Zero+DAC ->ToppingTP21 ->AKG Headphones
      Bedroom (TV) & Bathroom SB Touch ->Denon AVR ->Mordaunt Short M10s + Kef ceiling speakers
      Guest Room Joggler > Topping Amp -> Wharfedale Modus Cubes

      Comment


        #4
        Originally posted by d6jg View Post
        Thanks bpa. That’s somewhere to start.
        Using pulseaudio - squeezelite cannot be run as a service unless pulseaudio is configured system wide. The normal and recommended config for pulseaudio is on a per user see https://www.freedesktop.org/wiki/Sof...ithSystemWide/

        Comment


          #5
          Originally posted by bpa View Post
          Using pulseaudio - squeezelite cannot be run as a service unless pulseaudio is configured system wide. The normal and recommended config for pulseaudio is on a per user see https://www.freedesktop.org/wiki/Sof...ithSystemWide/
          I have had a bit of a read and I see that pacrec can be configured to take input from STDIN. If I sent Squeezelite to STDOUT would that work I wonder.
          Thanks for the note about running as a service
          Jim



          VB2.4 storage QNAP TS419p (NFS)
          Living Room Joggler & Pi4/Khadas -> Onkyo TXNR686 -> Celestion F20s
          Office Joggler & Pi3 -> Denon RCD N8 -> Celestion F10s
          Dining Room SB Radio
          Bedroom (Bedside) Pi Zero+DAC ->ToppingTP21 ->AKG Headphones
          Bedroom (TV) & Bathroom SB Touch ->Denon AVR ->Mordaunt Short M10s + Kef ceiling speakers
          Guest Room Joggler > Topping Amp -> Wharfedale Modus Cubes

          Comment


            #6
            Originally posted by d6jg View Post
            I have had a bit of a read and I see that pacrec can be configured to take input from STDIN. If I sent Squeezelite to STDOUT would that work I wonder.
            Thanks for the note about running as a service
            IIRC if you try to pipe STDOUT from squeezelite - you get get problems - flow control, silence etc. Can't remember the detail but is has been tried before

            Do not use parec using STDIN is default - specify the pulseaudio input aka sink.

            Best to play squeezelite into a pulse audio device (i.e. sink) and then use parec with "-monitor-stream" (a sink) or "-d" to capture the audio from source.

            Command line "pactl list" will show what's available/happening or GUI "Pulseaudio Volume Control" to see the device being used. Look at before and after starting to play something on a a squeezelite (from a command line under same parent process e.g. from a command shell) user - you'll see the devices.

            An alternative to Pulseaudio would be to use ALSA loop devices - squeezelite play to an ALSA loop device and then record from matching source. Maybe simpler to use than pulseaudio once loop device is setup (e.g. snd-aloop) - not sure how to set stream particulars - probably force them from squeezelite . Other ALSA way - snoop on a real output device.
            Last edited by bpa; 2020-08-22, 18:10.

            Comment


              #7
              Originally posted by bpa View Post
              IIRC if you try to pipe STDOUT from squeezelite - you get get problems - flow control, silence etc. Can't remember the detail but is has been tried before

              Do not use parec using STDIN is default - specify the pulseaudio input aka sink.

              Best to play squeezelite into a pulse audio device (i.e. sink) and then use parec with "-monitor-stream" (a sink) or "-d" to capture the audio from source.

              Command line "pactl list" will show what's available/happening or GUI "Pulseaudio Volume Control" to see the device being used. Look at before and after starting to play something on a a squeezelite (from a command line under same parent process e.g. from a command shell) user - you'll see the devices.

              An alternative to Pulseaudio would be to use ALSA loop devices - squeezelite play to an ALSA loop device and then record from matching source. Maybe simpler to use than pulseaudio once loop device is setup (e.g. snd-aloop) - not sure how to set stream particulars - probably force them from squeezelite . Other ALSA way - snoop on a real output device.
              Thanks
              Jim



              VB2.4 storage QNAP TS419p (NFS)
              Living Room Joggler & Pi4/Khadas -> Onkyo TXNR686 -> Celestion F20s
              Office Joggler & Pi3 -> Denon RCD N8 -> Celestion F10s
              Dining Room SB Radio
              Bedroom (Bedside) Pi Zero+DAC ->ToppingTP21 ->AKG Headphones
              Bedroom (TV) & Bathroom SB Touch ->Denon AVR ->Mordaunt Short M10s + Kef ceiling speakers
              Guest Room Joggler > Topping Amp -> Wharfedale Modus Cubes

              Comment


                #8
                I went to try this and have it working on a x86 box with the following setup:

                Code:
                #Startup Pulseaudio
                pulseaudio --start
                
                #Create the Radio "sink"
                pactl load-module module-null-sink sink_name=Radio sink_properties="device.description='Radio'"
                
                #Run squeezelite, ensure that you have the pulse audio version
                squeezelite -o Radio
                
                #Run PAREC piped into ICES
                parec | ices ices-conf.xml
                Code:
                #ices.conf input section
                <input>
                  <module>stdinpcm</module>
                  <param name="rate">44100</param>
                  <param name="channels">2</param>
                </input>
                I don't have metadata running, was looking to grab the info from the json, but having some issues crafting up the correct messages, if anyone has this working, please let me know. I just want to extract current playing title/artist, and dump into a file.

                Hope this helps someone.

                Comment


                  #9
                  Originally posted by Matt Drown View Post
                  I went to try this and have it working on a x86 box with the following setup:

                  Code:
                  #Startup Pulseaudio
                  pulseaudio --start
                  
                  #Create the Radio "sink"
                  pactl load-module module-null-sink sink_name=Radio sink_properties="device.description='Radio'"
                  
                  #Run squeezelite, ensure that you have the pulse audio version
                  squeezelite -o Radio
                  
                  #Run PAREC piped into ICES
                  parec | ices ices-conf.xml
                  Code:
                  #ices.conf input section
                  <input>
                    <module>stdinpcm</module>
                    <param name="rate">44100</param>
                    <param name="channels">2</param>
                  </input>
                  I don't have metadata running, was looking to grab the info from the json, but having some issues crafting up the correct messages, if anyone has this working, please let me know. I just want to extract current playing title/artist, and dump into a file.

                  Hope this helps someone.
                  I have the json metadata working but not the Squeezelite piped to Icecast. Perhaps we could trade the two?
                  Jim



                  VB2.4 storage QNAP TS419p (NFS)
                  Living Room Joggler & Pi4/Khadas -> Onkyo TXNR686 -> Celestion F20s
                  Office Joggler & Pi3 -> Denon RCD N8 -> Celestion F10s
                  Dining Room SB Radio
                  Bedroom (Bedside) Pi Zero+DAC ->ToppingTP21 ->AKG Headphones
                  Bedroom (TV) & Bathroom SB Touch ->Denon AVR ->Mordaunt Short M10s + Kef ceiling speakers
                  Guest Room Joggler > Topping Amp -> Wharfedale Modus Cubes

                  Comment


                    #10
                    Originally posted by d6jg View Post
                    I have the json metadata working but not the Squeezelite piped to Icecast. Perhaps we could trade the two?
                    Paste in json docs, would love to see them.

                    Let me know if you have any issues with the above docs. This is all working on squeezelite on centos8-stream for me. Ran it for 24 hours without issue into streaming radio.

                    Comment


                      #11
                      Originally posted by Matt Drown View Post
                      Paste in json docs, would love to see them.

                      Let me know if you have any issues with the above docs. This is all working on squeezelite on centos8-stream for me. Ran it for 24 hours without issue into streaming radio.
                      It’s more complicated than that. In my implementation we use a reverse proxy and an instance of node.js. A detected track change triggers calls via node.js to the fully Proxied LMS and grabs all the metadata and triggers an MAI lookup for lyrics, review and bio.
                      Jim



                      VB2.4 storage QNAP TS419p (NFS)
                      Living Room Joggler & Pi4/Khadas -> Onkyo TXNR686 -> Celestion F20s
                      Office Joggler & Pi3 -> Denon RCD N8 -> Celestion F10s
                      Dining Room SB Radio
                      Bedroom (Bedside) Pi Zero+DAC ->ToppingTP21 ->AKG Headphones
                      Bedroom (TV) & Bathroom SB Touch ->Denon AVR ->Mordaunt Short M10s + Kef ceiling speakers
                      Guest Room Joggler > Topping Amp -> Wharfedale Modus Cubes

                      Comment


                        #12
                        For some reason my attempt at sending "macaddr title ?" in json wasn't working, while sending other commands are. I assume i'm mis-formatting something in my json, any pointers?

                        Comment


                          #13
                          Originally posted by Matt Drown View Post
                          I don't have metadata running, was looking to grab the info from the json, but having some issues crafting up the correct messages, if anyone has this working, please let me know. I just want to extract current playing title/artist, and dump into a file.

                          Hope this helps someone.
                          Here's something I hacked together a while back. Only requirement is cJSON, which is a very basic json parser in C. You'll need to change the Server IP, Port and Ethernet address...

                          current.c:
                          Code:
                          #include <stdio.h>
                          #include <stdlib.h>
                          #include <string.h>
                          #include <unistd.h>
                          #include <sys/socket.h> /* socket, connect */
                          #include <netinet/in.h> /* struct sockaddr_in, struct sockaddr */
                          #include <netdb.h> /* struct hostent, gethostbyname */
                          
                          #include "cJSON.h"
                          #include "lms.h"
                          
                          void error(const char *msg) { perror(msg); exit(0); }
                          
                          int post(char *host, int portno, char *q, char *buf, int buflen)
                          {
                              int i;
                          
                              struct hostent *server;
                              struct sockaddr_in serv_addr;
                              int sockfd, bytes, sent, received, total, message_size;
                              char *message;
                              char *response = buf;
                          
                              /* How big is the message? */
                              message_size=0;
                              message_size+=strlen("%s %s HTTP/1.0\r\nPOST /jsonrpc.js");
                              message_size+=strlen(q)+strlen("\r\n");
                              message_size+=strlen("Content-Length: %d\r\n")+10; /* content length */
                              message_size+=strlen("\r\n");                          /* blank line     */
                          
                              /* allocate space for the message */
                              message=malloc(message_size);
                          
                              /* fill in the parameters */
                              sprintf(message,"POST /jsonrpc.js HTTP/1.0\r\n");
                              sprintf(message+strlen(message),"Content-Length: %d\r\n",strlen(q));
                              strcat(message,"\r\n");                                /* blank line     */
                              strcat(message,q);
                              strcat(message,"\r\n");
                          
                              /* create the socket */
                              sockfd = socket(AF_INET, SOCK_STREAM, 0);
                              if (sockfd < 0) error("ERROR opening socket");
                          
                              /* lookup the ip address */
                              server = gethostbyname(host);
                              if (server == NULL) error("ERROR, no such host");
                          
                              /* fill in the structure */
                              memset(&serv_addr,0,sizeof(serv_addr));
                              serv_addr.sin_family = AF_INET;
                              serv_addr.sin_port = htons(portno);
                              memcpy(&serv_addr.sin_addr.s_addr,server->h_addr,server->h_length);
                          
                              /* connect the socket */
                              if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
                                  error("ERROR connecting");
                          
                              /* send the request */
                              total = strlen(message);
                              sent = 0;
                              do {
                                  bytes = write(sockfd,message+sent,total-sent);
                                  if (bytes < 0)
                                      error("ERROR writing message to socket");
                                  if (bytes == 0)
                                      break;
                                  sent+=bytes;
                              } while (sent < total);
                          
                              /* receive the response */
                              memset(response,0,buflen);
                              total = buflen-1;
                          
                              received = 0;
                              do {
                                  bytes = read(sockfd,response+received,total-received);
                                  if (bytes < 0)
                                      error("ERROR reading response from socket");
                                  if (bytes == 0)
                                      break;
                                  received+=bytes;
                              } while (received < total);
                          
                              /*
                               * if the number of received bytes is the total size of the
                               * array then we have run out of space to store the response
                               * and it hasn't all arrived yet - so that's a bad thing
                               */
                              if (received == total)
                                  error("ERROR storing complete response from socket");
                          
                              /* close the socket */
                              close(sockfd);
                          
                              free(message);
                              return 0;
                          }
                          
                          int main(void) {
                          
                              char query[2048];
                              char param[1024];
                              char decoded[2048];
                              char *q = query;
                              char *p = param;
                              char *d = decoded;
                              char *r;
                              int arraylen, i;
                              int status = 1;
                              cJSON *results = NULL;
                              cJSON *result = NULL;
                              cJSON *items = NULL;
                              cJSON *item = NULL;
                              cJSON *json = NULL;
                          
                              char *host = "192.168.68.121";
                              int port = 9000;
                          
                              q = "{ \"id\": 1, \"method\": \"slim.request\", \"params\": [\"4c:e1:73:42:26:0c\",[\"path\", \"?\"]]}";
                          
                          
                              post(host,port,q,decoded,2048);
                          
                              r = strstr(decoded,"{");
                              strcpy(decoded,r);
                              json = cJSON_Parse(decoded);
                          
                              if (json == NULL)
                              {
                                const char *error_ptr = cJSON_GetErrorPtr();
                                if (error_ptr != NULL)
                                {
                                    fprintf(stderr, "Error before %s\n", error_ptr);
                                }
                                status = 0;
                          
                              }
                          
                              results = cJSON_GetObjectItemCaseSensitive(json, "result");
                              cJSON_ArrayForEach(result, results) 
                              {
                                cJSON *path = cJSON_GetObjectItemCaseSensitive(result, "_path");
                                if (cJSON_IsString(result) && (result->valuestring != NULL))
                                {
                                    p = result->valuestring;
                                }
                                else {
                                    printf("Error getting path\n");
                                }
                              }
                          
                              query[0] = '\0';
                              sprintf(query,"{\"method\":\"slim.request\",\"params\":[\"4c:e1:73:42:26:0c\",[\"songinfo\",0,99,\"url:%s\"]]}",p);
                          
                              cJSON_Delete(json);
                              p = param;
                          
                              post(host,port,query,decoded,2048);
                              r = strstr(decoded,"{");
                              strcpy(decoded,r);
                          
                              json = cJSON_Parse(decoded);
                              if (json == NULL)
                              {
                                const char *error_ptr = cJSON_GetErrorPtr();
                                if (error_ptr != NULL)
                                {
                                    fprintf(stderr, "Error before %s\n", error_ptr);
                                }
                                status = 0;
                              }
                          
                              results = cJSON_GetObjectItem(json, "result");
                          
                              items = cJSON_GetObjectItem(results, "songinfo_loop");
                          
                              cJSON_ArrayForEach(item, items)
                              {
                                if (cJSON_IsString(item->child) && (item->child->valuestring != NULL))
                                {
                                  printf("%s=%s\n", item->child->string,item->child->valuestring);
                                } 
                              }
                              cJSON_Delete(json);
                          }
                          lms.h:
                          Code:
                          #include <stdio.h>
                          #include <stdlib.h>
                          #include <string.h>
                          
                          struct metadata {
                            char artist[1024];
                            char album[1024];
                            char title[1024];
                            char bitrate[30];
                            char type[30];
                            int new_title;
                            int new_album;
                            int new_artist;
                            int terminate;
                            int playing;
                          };
                          
                          struct memory {
                             char *response;
                             size_t size;
                          };
                          
                          int post(char *host, int portno, char *q, char *buf, int buflen);
                          
                          void remove_char(char *str, char garbage); 
                          
                          int lms_query(char *query, char *decoded); 
                          
                          void *get_metadata(void *m);
                          Compile:
                          gcc -o current current.c cJSON.c

                          Run:
                          ./current

                          id=-561724432
                          title=Jazz Record Requests - New discoveries and evergreen classics
                          artist=Alyn Shipton presents jazz records of all styles as requested by you, with music from Fats Waller, Anita O'Day and Miles Davis.
                          coverid=-561724432
                          duration=3540
                          coverart=0
                          type=BBCSounds
                          bitrate=96kbps CBR
                          year=0
                          channels=2
                          artwork_url=https://ichef.bbci.co.uk/images/ic/320x320/p09c8r13.jpg
                          remote_title=Play
                          samplerate=48000
                          piTouch™ w/JustBoom DigiHat -> RME ADI-2 DAC FS -> JBL 305P MkII monitors; LMS 8.2 on piCorePlayer/Pi 4; Material Skin.

                          Comment


                            #14
                            Originally posted by d6jg View Post
                            I have the json metadata working but not the Squeezelite piped to Icecast. Perhaps we could trade the two?
                            d6jg, maybe I'm misreading what you are working on, but in case it might be helpful, I messed around with snd-aloop (as bpa mentioned) some time ago in this thread. The fossil link I posted in that thread (which was supposed to be to my versioned source files) doesn't work, I took that stuff down but if you want me to verify if the below asound.conf (copied from the thread) was my final version I can do that.

                            I said in that thread:
                            I've tested everything again and it's all working well. I paired my headphones, my phone, and my wife's phone and was able to play prime music from my phone, youtube audio from my wife's phone, music from squeezelite all at the same time streamed to my bluetooth headset synchronized with the onboard audio. Not that you'd ever want to do that, but it worked.
                            I was mostly focused on bluetooth in that thread but the foundation was the alsa loopback which duplicated audio across 8 loop devices. I was using multiple instances of the alsaloop utility to then take the audio from a separate loop device and send it to separate output. But in your case I would think it would maybe be something like using one alsaloop instance to send to a real output for monitoring and then the icecast utility could just take it's input from another loop device directly.

                            Contents of /etc/asound.conf
                            Code:
                            # duplicate audio to all Loopback channels
                            pcm.!default plug:aloopx
                            
                            pcm.aloopx {
                              type route;
                              slave.pcm {
                                  type multi;
                                  slaves.a.pcm "aloop0";
                                  slaves.b.pcm "aloop1";
                                  slaves.c.pcm "aloop2";
                                  slaves.d.pcm "aloop3";
                                  slaves.e.pcm "aloop4";
                                  slaves.f.pcm "aloop5";
                                  slaves.g.pcm "aloop6";
                                  slaves.h.pcm "aloop7";
                                  slaves.a.channels 2;
                                  slaves.b.channels 2;
                                  slaves.c.channels 2;
                                  slaves.d.channels 2;
                                  slaves.e.channels 2;
                                  slaves.f.channels 2;
                                  slaves.g.channels 2;
                                  slaves.h.channels 2;
                                  bindings.0.slave a;
                                  bindings.0.channel 0;
                                  bindings.1.slave a;
                                  bindings.1.channel 1;
                            
                                  bindings.2.slave b;
                                  bindings.2.channel 0;
                                  bindings.3.slave b;
                                  bindings.3.channel 1;
                            
                                  bindings.4.slave c;
                                  bindings.4.channel 0;
                                  bindings.5.slave c;
                                  bindings.5.channel 1;
                            
                                  bindings.6.slave d;
                                  bindings.6.channel 0;
                                  bindings.7.slave d;
                                  bindings.7.channel 1;
                            
                                  bindings.8.slave e;
                                  bindings.8.channel 0;
                                  bindings.9.slave e;
                                  bindings.9.channel 1;
                            
                                  bindings.10.slave f;
                                  bindings.10.channel 0;
                                  bindings.11.slave f;
                                  bindings.11.channel 1;
                            
                                  bindings.12.slave g;
                                  bindings.12.channel 0;
                                  bindings.13.slave g;
                                  bindings.13.channel 1;
                            
                                  bindings.14.slave h;
                                  bindings.14.channel 0;
                                  bindings.15.slave h;
                                  bindings.15.channel 1;
                            
                              }
                            
                              ttable.0.0 1;
                              ttable.1.1 1;
                            
                              ttable.0.2 1;
                              ttable.1.3 1;
                            
                              ttable.0.4 1;
                              ttable.1.5 1;
                            
                              ttable.0.6 1;
                              ttable.1.7 1;
                            
                              ttable.0.8 1;
                              ttable.1.9 1;
                            
                              ttable.0.10 1;
                              ttable.1.11 1;
                            
                              ttable.0.12 1;
                              ttable.1.13 1;
                            
                              ttable.0.14 1;
                              ttable.1.15 1;
                            }
                            
                            pcm.aloop0 {
                               type dmix
                               ipc_key 1024
                               slave {
                                   pcm "hw:Loopback,0,0"
                                   rate 48000
                                   channels 2
                                   period_size 1024
                                   buffer_size 8192
                                }
                                bindings {
                                   0 0
                                   1 1
                                }
                            }
                            
                            pcm.aloop1 {
                               type dmix
                               ipc_key 2048
                               slave {
                                   pcm "hw:Loopback,0,1"
                                   rate 48000
                                   channels 2
                                   period_size 1024
                                   buffer_size 8192
                                }
                                bindings {
                                   0 0
                                   1 1
                                }
                            }
                            
                            pcm.aloop2 {
                               type dmix
                               ipc_key 4096
                               slave {
                                   pcm "hw:Loopback,0,2"
                                   rate 48000
                                   channels 2
                                   period_size 1024
                                   buffer_size 8192
                                }
                                bindings {
                                   0 0
                                   1 1
                                }
                            }
                            
                            pcm.aloop3 {
                               type dmix
                               ipc_key 8092
                               slave {
                                   pcm "hw:Loopback,0,3"
                                   rate 48000
                                   channels 2
                                   period_size 1024
                                   buffer_size 8192
                                }
                                bindings {
                                   0 0
                                   1 1
                                }
                            }
                            
                            pcm.aloop4 {
                               type dmix
                               ipc_key 16184
                               slave {
                                   pcm "hw:Loopback,0,4"
                                   rate 48000
                                   channels 2
                                   period_size 1024
                                   buffer_size 8192
                                }
                                bindings {
                                   0 0
                                   1 1
                                }
                            }
                            
                            pcm.aloop5 {
                               type dmix
                               ipc_key 32368
                               slave {
                                   pcm "hw:Loopback,0,5"
                                   rate 48000
                                   channels 2
                                   period_size 1024
                                   buffer_size 8192
                                }
                                bindings {
                                   0 0
                                   1 1
                                }
                            }
                            
                            pcm.aloop6 {
                               type dmix
                               ipc_key 64736
                               slave {
                                   pcm "hw:Loopback,0,6"
                                   rate 48000
                                   channels 2
                                   period_size 1024
                                   buffer_size 8192
                                }
                                bindings {
                                   0 0
                                   1 1
                                }
                            }
                            
                            pcm.aloop7 {
                               type dmix
                               ipc_key 129472
                               slave {
                                   pcm "hw:Loopback,0,7"
                                   rate 48000
                                   channels 2
                                   period_size 1024
                                   buffer_size 8192
                                }
                                bindings {
                                   0 0
                                   1 1
                                }
                            }
                            Last edited by sodface; 2022-02-12, 11:54.

                            Comment


                              #15
                              Updated

                              Here's what's working right now for me, including metadata updates to an Azuracast radio. It's slightly above "hack" status, but appears to be working. I get really small pops every now and again, and I haven't narrowed it down to metadata updates, or something with buffering, or just the inherent issues with flac->pcm->ogg->mp3 workflow here. You can listen at https://rad10x.com/

                              To get it working, configure your ices.conf with the delta below. Save the metadata-update-script.sh, make it executable, and just run it in the background, it doesn't output anything normally. Then setup the pulseaudio, squeezelite, and parec piped to ices. Queue music up and your should see things operating. The script to do the metadata does no error checking, so permissions, etc, may throw it off. But it should be pretty clear what it's doing. I didn't bother getting rid of the quotes in the Title/Artist, that's for the next iteration.

                              Any questions, feel free to ask.


                              ices-conf.xml file. You need to make sure your PID file matches the Metatdata update script below, and your input needs a file to read metadata from. This is not the complete config, just the items you need to ensure you have. Update the file names as needed.
                              Code:
                              <ices>
                                <pidfile>/home/jukebox/ices.pid</pidfile>
                                      <input>
                                          <module>stdinpcm</module>
                                          <param name="rate">44100</param>
                                          <param name="channels">2</param>
                                          <param name="metadata">1</param>
                                          <param name="metadatafilename">/home/jukebox/metadata.txt</param>
                                      </input>
                              </ices>
                              Metadata Update bash script.
                              MAC needs to updated to the MAC address of the squeezebox client (you can look at the LMS Settings->Information Tab to find it.
                              METATIME is how often to scan for metadata updates.
                              ICESPID is the pid file written, so we can send the USR1 signal to retransmit the metadata.
                              METAFILE needs to match the ICES.CONF file above.
                              METATEMP is just used for temporary caching, we only update metadata on song changes.

                              Code:
                              #!/bin/bash
                              LMSIP=127.0.0.1
                              MAC=10:bf:48:7b:36:c3
                              METATIME=5
                              ICESPID=/home/jukebox/ices.pid
                              METAFILE=/home/jukebox/metadata.txt
                              METATEMP=/home/jukebox/metatemp.txt
                              
                              while [ 1 ]
                              do
                              
                              command='{"id": 1, "method": "slim.request", "params":["'$MAC'", ["'artist'", "'?'"]]}'
                              artist=`eval "curl -q -s -X POST -d '"$command"' "$LMSIP":9000/jsonrpc.js"`
                              echo artist=`echo $artist |grep -Po '"_artist":".*?"' | cut -d: -f 2` >$METATEMP
                              
                              command='{"id": 2, "method": "slim.request", "params":["'$MAC'", ["'title'", "'?'"]]}'
                              title=`eval "curl -q -s -X POST -d '"$command"' "$LMSIP":9000/jsonrpc.js"`
                              echo title=`echo $title | grep -Po '"_title":".*?"' | cut -d: -f 2` >>$METATEMP
                              
                              diff -q ${METATEMP} ${METAFILE} >/dev/null
                              status=$?
                              
                              if [ $status -ne 0 ] ; then
                                  cp -f ${METATEMP} ${METAFILE}
                                  kill -USR1 `cat ${ICESPID}`
                                  #echo "Updating Track Info"
                              fi
                              
                              sleep $METATIME
                              done
                              Pulse Radio Setup - Squeezelite outputs audio to "Radio" channel, and PAREC pulls PCM from it:
                              Code:
                              #Startup Pulseaudio
                              pulseaudio --start
                              
                              #Create the Radio "sink"
                              pactl load-module module-null-sink sink_name=Radio sink_properties="device.description='Radio'"
                              
                              #Run squeezelite, ensure that you have the pulse audio version
                              squeezelite -o Radio
                              
                              #Run the metadata-update.sh script in the background  (the script above)./m
                              ./metadata-update.sh &
                              
                              #Run PAREC piped into ICES
                              parec | ices ices-conf.xml
                              Last edited by Matt Drown; 2022-02-12, 23:00. Reason: fixing typo in metadata script

                              Comment

                              Working...
                              X