This program plays an internet radio audio stream like Shoutcast.
Dependencies: EthernetNetIf mbed HTTPClient
main.cpp@0:37da71b87d96, 2011-03-01 (annotated)
- Committer:
- parik
- Date:
- Tue Mar 01 06:22:50 2011 +0000
- Revision:
- 0:37da71b87d96
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
parik | 0:37da71b87d96 | 1 | |
parik | 0:37da71b87d96 | 2 | #include "mbed.h" |
parik | 0:37da71b87d96 | 3 | #include "VS1002.h" |
parik | 0:37da71b87d96 | 4 | #include "EthernetNetIf.h" |
parik | 0:37da71b87d96 | 5 | #include "HTTPClient.h" |
parik | 0:37da71b87d96 | 6 | #include "TCPSocket.h" |
parik | 0:37da71b87d96 | 7 | #include "MSCFileSystem.h" |
parik | 0:37da71b87d96 | 8 | |
parik | 0:37da71b87d96 | 9 | #define SBUFSIZE (1024*4) |
parik | 0:37da71b87d96 | 10 | //Select the time to play 1000 k of data in this case |
parik | 0:37da71b87d96 | 11 | #define MAXSIZE (250*1000) |
parik | 0:37da71b87d96 | 12 | |
parik | 0:37da71b87d96 | 13 | // PinName mosi, PinName miso, PinName sck, PinName cs, PinName rst, |
parik | 0:37da71b87d96 | 14 | // PinName dreq, PinName dcs, PinName vol) |
parik | 0:37da71b87d96 | 15 | VS1002 mp3(p11, p12, p13, p14, p15,p16, p17, p20); |
parik | 0:37da71b87d96 | 16 | |
parik | 0:37da71b87d96 | 17 | //Print or debug on the serail port/hyperterminal |
parik | 0:37da71b87d96 | 18 | Serial pc(USBTX,USBRX); |
parik | 0:37da71b87d96 | 19 | EthernetNetIf eth; |
parik | 0:37da71b87d96 | 20 | |
parik | 0:37da71b87d96 | 21 | //TCP socket to connectto server,receive data |
parik | 0:37da71b87d96 | 22 | TCPSocket sock; |
parik | 0:37da71b87d96 | 23 | |
parik | 0:37da71b87d96 | 24 | |
parik | 0:37da71b87d96 | 25 | char sResponse[800]; // keeps Stream Response |
parik | 0:37da71b87d96 | 26 | char sMetadata[200]; // keeps Stream Metadata |
parik | 0:37da71b87d96 | 27 | char sPrevMetadata[200]; // keeps Previous Stream Metadata |
parik | 0:37da71b87d96 | 28 | int metaint=0; // metadate interval |
parik | 0:37da71b87d96 | 29 | |
parik | 0:37da71b87d96 | 30 | // client state |
parik | 0:37da71b87d96 | 31 | enum wSTATE{NOP,PUT_HEADER} WriteState; |
parik | 0:37da71b87d96 | 32 | enum rSTATE{GET_RESPONSE,GET_STREAM} ReadState; |
parik | 0:37da71b87d96 | 33 | |
parik | 0:37da71b87d96 | 34 | char inbuf[2048]; // IP input buffer |
parik | 0:37da71b87d96 | 35 | char* cp; |
parik | 0:37da71b87d96 | 36 | // stream |
parik | 0:37da71b87d96 | 37 | int slen; // stream length |
parik | 0:37da71b87d96 | 38 | unsigned long int tlen=0; // total lenth of downloaded file |
parik | 0:37da71b87d96 | 39 | |
parik | 0:37da71b87d96 | 40 | |
parik | 0:37da71b87d96 | 41 | //Buffer the data to a file on flash drive |
parik | 0:37da71b87d96 | 42 | FILE *fp; |
parik | 0:37da71b87d96 | 43 | MSCFileSystem msc("msc"); |
parik | 0:37da71b87d96 | 44 | |
parik | 0:37da71b87d96 | 45 | //Create a file on the flash drive for writing |
parik | 0:37da71b87d96 | 46 | void CreateFile () |
parik | 0:37da71b87d96 | 47 | { |
parik | 0:37da71b87d96 | 48 | fp = fopen("/msc/stream.mp3", "wb"); |
parik | 0:37da71b87d96 | 49 | } |
parik | 0:37da71b87d96 | 50 | |
parik | 0:37da71b87d96 | 51 | //Write the mp3 data to the file created |
parik | 0:37da71b87d96 | 52 | void WriteFile(unsigned char sbyte) |
parik | 0:37da71b87d96 | 53 | { |
parik | 0:37da71b87d96 | 54 | unsigned char wc=sbyte; |
parik | 0:37da71b87d96 | 55 | fwrite(&wc,1,1,fp); |
parik | 0:37da71b87d96 | 56 | tlen++; |
parik | 0:37da71b87d96 | 57 | if (tlen==MAXSIZE) |
parik | 0:37da71b87d96 | 58 | { |
parik | 0:37da71b87d96 | 59 | fclose(fp); |
parik | 0:37da71b87d96 | 60 | //Play the file |
parik | 0:37da71b87d96 | 61 | mp3.play_song(); |
parik | 0:37da71b87d96 | 62 | //Loop and read the next stream of data |
parik | 0:37da71b87d96 | 63 | tlen=0; |
parik | 0:37da71b87d96 | 64 | CreateFile(); |
parik | 0:37da71b87d96 | 65 | } |
parik | 0:37da71b87d96 | 66 | } |
parik | 0:37da71b87d96 | 67 | |
parik | 0:37da71b87d96 | 68 | class RingBuffer |
parik | 0:37da71b87d96 | 69 | { |
parik | 0:37da71b87d96 | 70 | protected: |
parik | 0:37da71b87d96 | 71 | unsigned char *buffer; |
parik | 0:37da71b87d96 | 72 | int buffersize; |
parik | 0:37da71b87d96 | 73 | int rp; // read index |
parik | 0:37da71b87d96 | 74 | int wp; // write index |
parik | 0:37da71b87d96 | 75 | |
parik | 0:37da71b87d96 | 76 | |
parik | 0:37da71b87d96 | 77 | public: |
parik | 0:37da71b87d96 | 78 | RingBuffer(int bufsiz) |
parik | 0:37da71b87d96 | 79 | { |
parik | 0:37da71b87d96 | 80 | buffersize = bufsiz; |
parik | 0:37da71b87d96 | 81 | |
parik | 0:37da71b87d96 | 82 | buffer = new unsigned char[buffersize]; |
parik | 0:37da71b87d96 | 83 | // memset(buffer, 0, sizeof(char) * buffersize); |
parik | 0:37da71b87d96 | 84 | // reset pointer to make empty |
parik | 0:37da71b87d96 | 85 | rp = 0; |
parik | 0:37da71b87d96 | 86 | wp = 0; |
parik | 0:37da71b87d96 | 87 | }; |
parik | 0:37da71b87d96 | 88 | |
parik | 0:37da71b87d96 | 89 | ~RingBuffer(void) |
parik | 0:37da71b87d96 | 90 | { |
parik | 0:37da71b87d96 | 91 | delete[] buffer; |
parik | 0:37da71b87d96 | 92 | }; |
parik | 0:37da71b87d96 | 93 | |
parik | 0:37da71b87d96 | 94 | int GetByte(unsigned char *cp); |
parik | 0:37da71b87d96 | 95 | int PutByte(unsigned char c); |
parik | 0:37da71b87d96 | 96 | int IsEmpty(void); |
parik | 0:37da71b87d96 | 97 | }; |
parik | 0:37da71b87d96 | 98 | |
parik | 0:37da71b87d96 | 99 | |
parik | 0:37da71b87d96 | 100 | int RingBuffer::GetByte(unsigned char *cp ) |
parik | 0:37da71b87d96 | 101 | { |
parik | 0:37da71b87d96 | 102 | if( rp != wp ) { // not empty |
parik | 0:37da71b87d96 | 103 | *cp = buffer[rp]; |
parik | 0:37da71b87d96 | 104 | rp = (rp + 1) % buffersize; |
parik | 0:37da71b87d96 | 105 | return 0; |
parik | 0:37da71b87d96 | 106 | } else { // empty |
parik | 0:37da71b87d96 | 107 | return -1; |
parik | 0:37da71b87d96 | 108 | } |
parik | 0:37da71b87d96 | 109 | } |
parik | 0:37da71b87d96 | 110 | |
parik | 0:37da71b87d96 | 111 | int RingBuffer::PutByte(unsigned char c ) |
parik | 0:37da71b87d96 | 112 | { |
parik | 0:37da71b87d96 | 113 | int next = (wp + 1) % buffersize; |
parik | 0:37da71b87d96 | 114 | if( next == rp ) { |
parik | 0:37da71b87d96 | 115 | pc.printf("*** Buffer Full ***\r\n" ); |
parik | 0:37da71b87d96 | 116 | // printf("*");//debug |
parik | 0:37da71b87d96 | 117 | return -1; |
parik | 0:37da71b87d96 | 118 | } |
parik | 0:37da71b87d96 | 119 | buffer[wp] = c; |
parik | 0:37da71b87d96 | 120 | wp = next; |
parik | 0:37da71b87d96 | 121 | return 0; |
parik | 0:37da71b87d96 | 122 | } |
parik | 0:37da71b87d96 | 123 | |
parik | 0:37da71b87d96 | 124 | int RingBuffer::IsEmpty(void) |
parik | 0:37da71b87d96 | 125 | { |
parik | 0:37da71b87d96 | 126 | return (rp==wp)?(true):(false); |
parik | 0:37da71b87d96 | 127 | } |
parik | 0:37da71b87d96 | 128 | |
parik | 0:37da71b87d96 | 129 | RingBuffer sbuf(SBUFSIZE); |
parik | 0:37da71b87d96 | 130 | |
parik | 0:37da71b87d96 | 131 | |
parik | 0:37da71b87d96 | 132 | //Check for appropriate event by polling network stack and handle |
parik | 0:37da71b87d96 | 133 | void onTCPSocketEvent(TCPSocketEvent e) |
parik | 0:37da71b87d96 | 134 | { |
parik | 0:37da71b87d96 | 135 | int i,len; |
parik | 0:37da71b87d96 | 136 | switch (e) |
parik | 0:37da71b87d96 | 137 | { |
parik | 0:37da71b87d96 | 138 | case TCPSOCKET_CONNECTED: |
parik | 0:37da71b87d96 | 139 | pc.printf("TCP Socket Connected\r\n"); // this printf disturb socket work correctly |
parik | 0:37da71b87d96 | 140 | // break; // we must comment out ? |
parik | 0:37da71b87d96 | 141 | case TCPSOCKET_WRITEABLE: |
parik | 0:37da71b87d96 | 142 | switch (WriteState) |
parik | 0:37da71b87d96 | 143 | { |
parik | 0:37da71b87d96 | 144 | case PUT_HEADER: |
parik | 0:37da71b87d96 | 145 | //Can now write some data... |
parik | 0:37da71b87d96 | 146 | const char* str = |
parik | 0:37da71b87d96 | 147 | "GET /stream/1074 HTTP/1.0\r\n" |
parik | 0:37da71b87d96 | 148 | "Host: gw\r\n" |
parik | 0:37da71b87d96 | 149 | "Accept: */*\r\n" |
parik | 0:37da71b87d96 | 150 | "User-Agent: mbed\r\n" |
parik | 0:37da71b87d96 | 151 | #ifdef METADATA |
parik | 0:37da71b87d96 | 152 | "Icy-MetaData: 1\r\n" // send this if you want Metadata |
parik | 0:37da71b87d96 | 153 | #endif |
parik | 0:37da71b87d96 | 154 | //"Connection: close\r\n" |
parik | 0:37da71b87d96 | 155 | "\r\n" |
parik | 0:37da71b87d96 | 156 | ; |
parik | 0:37da71b87d96 | 157 | sock.send(str, strlen(str)); |
parik | 0:37da71b87d96 | 158 | pc.printf("\r\nHEADER:\r\n%s\r\n", str); // display PUT_HEADER |
parik | 0:37da71b87d96 | 159 | WriteState=NOP; |
parik | 0:37da71b87d96 | 160 | ReadState=GET_RESPONSE; |
parik | 0:37da71b87d96 | 161 | break; |
parik | 0:37da71b87d96 | 162 | case NOP: |
parik | 0:37da71b87d96 | 163 | break; |
parik | 0:37da71b87d96 | 164 | } |
parik | 0:37da71b87d96 | 165 | break; |
parik | 0:37da71b87d96 | 166 | case TCPSOCKET_READABLE: |
parik | 0:37da71b87d96 | 167 | //Can now read some data... |
parik | 0:37da71b87d96 | 168 | switch(ReadState) |
parik | 0:37da71b87d96 | 169 | { |
parik | 0:37da71b87d96 | 170 | case GET_RESPONSE: |
parik | 0:37da71b87d96 | 171 | len=sock.recv(inbuf, sizeof inbuf); |
parik | 0:37da71b87d96 | 172 | cp=strstr(inbuf,"\r\n\r\n"); |
parik | 0:37da71b87d96 | 173 | if (cp==NULL) |
parik | 0:37da71b87d96 | 174 | { |
parik | 0:37da71b87d96 | 175 | inbuf[len]=0; |
parik | 0:37da71b87d96 | 176 | // printf("%s",inbuf); // debug |
parik | 0:37da71b87d96 | 177 | sprintf(sResponse,"%s",inbuf); |
parik | 0:37da71b87d96 | 178 | return; // still read response again |
parik | 0:37da71b87d96 | 179 | } |
parik | 0:37da71b87d96 | 180 | // |
parik | 0:37da71b87d96 | 181 | *cp=0; |
parik | 0:37da71b87d96 | 182 | sprintf(sResponse+strlen(sResponse),"%s\r\n\r\n",inbuf); |
parik | 0:37da71b87d96 | 183 | pc.printf("RESPONSE:\r\n%s",sResponse); |
parik | 0:37da71b87d96 | 184 | // get metaint value |
parik | 0:37da71b87d96 | 185 | cp=strstr(sResponse,"icy-metaint:"); |
parik | 0:37da71b87d96 | 186 | if (cp==NULL) metaint=0; else sscanf(cp+strlen("icy-metaint:"),"%d",&metaint); |
parik | 0:37da71b87d96 | 187 | pc.printf("\r\nmetaint: %d\r\n\r\n",metaint); //debug |
parik | 0:37da71b87d96 | 188 | // |
parik | 0:37da71b87d96 | 189 | i=strlen(inbuf)+4; // bump bitstream right after response |
parik | 0:37da71b87d96 | 190 | ReadState=GET_STREAM; |
parik | 0:37da71b87d96 | 191 | CreateFile(); |
parik | 0:37da71b87d96 | 192 | |
parik | 0:37da71b87d96 | 193 | // |
parik | 0:37da71b87d96 | 194 | while(i<len) { |
parik | 0:37da71b87d96 | 195 | // write one bye |
parik | 0:37da71b87d96 | 196 | sbuf.PutByte(inbuf[i]);i++; |
parik | 0:37da71b87d96 | 197 | }; |
parik | 0:37da71b87d96 | 198 | return; |
parik | 0:37da71b87d96 | 199 | break; |
parik | 0:37da71b87d96 | 200 | |
parik | 0:37da71b87d96 | 201 | case GET_STREAM: |
parik | 0:37da71b87d96 | 202 | // receive data ****repeatedly**** |
parik | 0:37da71b87d96 | 203 | //pc.printf("Stream receiving\n"); |
parik | 0:37da71b87d96 | 204 | while(len=sock.recv(inbuf, sizeof inbuf)) { |
parik | 0:37da71b87d96 | 205 | i=0; |
parik | 0:37da71b87d96 | 206 | // save len bytes |
parik | 0:37da71b87d96 | 207 | while (i<len) { |
parik | 0:37da71b87d96 | 208 | |
parik | 0:37da71b87d96 | 209 | WriteFile(inbuf[i]); |
parik | 0:37da71b87d96 | 210 | i++; |
parik | 0:37da71b87d96 | 211 | } |
parik | 0:37da71b87d96 | 212 | |
parik | 0:37da71b87d96 | 213 | //pc.printf("%s\n",inbuf); |
parik | 0:37da71b87d96 | 214 | |
parik | 0:37da71b87d96 | 215 | } // while (len=sock...) |
parik | 0:37da71b87d96 | 216 | return; // get more stream |
parik | 0:37da71b87d96 | 217 | break; |
parik | 0:37da71b87d96 | 218 | // |
parik | 0:37da71b87d96 | 219 | } // switch (ReadState) |
parik | 0:37da71b87d96 | 220 | break;// |
parik | 0:37da71b87d96 | 221 | case TCPSOCKET_CONTIMEOUT: |
parik | 0:37da71b87d96 | 222 | pc.printf("TCP Socket Timeout\r\n"); |
parik | 0:37da71b87d96 | 223 | break; |
parik | 0:37da71b87d96 | 224 | case TCPSOCKET_CONRST: |
parik | 0:37da71b87d96 | 225 | pc.printf("TCP Socket CONRST\r\n"); |
parik | 0:37da71b87d96 | 226 | break; |
parik | 0:37da71b87d96 | 227 | case TCPSOCKET_CONABRT: |
parik | 0:37da71b87d96 | 228 | pc.printf("TCP Socket CONABRT\r\n"); |
parik | 0:37da71b87d96 | 229 | pc.printf("Maybe Server Down...\r\n"); |
parik | 0:37da71b87d96 | 230 | break; |
parik | 0:37da71b87d96 | 231 | case TCPSOCKET_ERROR: |
parik | 0:37da71b87d96 | 232 | pc.printf("TCP Socket Error\r\n"); |
parik | 0:37da71b87d96 | 233 | break; |
parik | 0:37da71b87d96 | 234 | case TCPSOCKET_DISCONNECTED: |
parik | 0:37da71b87d96 | 235 | //Close socket... |
parik | 0:37da71b87d96 | 236 | pc.printf("TCP Socket Disconnected\r\n"); |
parik | 0:37da71b87d96 | 237 | sock.close(); |
parik | 0:37da71b87d96 | 238 | break; |
parik | 0:37da71b87d96 | 239 | }// switch(e) |
parik | 0:37da71b87d96 | 240 | } |
parik | 0:37da71b87d96 | 241 | |
parik | 0:37da71b87d96 | 242 | |
parik | 0:37da71b87d96 | 243 | |
parik | 0:37da71b87d96 | 244 | int main () { |
parik | 0:37da71b87d96 | 245 | |
parik | 0:37da71b87d96 | 246 | |
parik | 0:37da71b87d96 | 247 | /*============================================================ |
parik | 0:37da71b87d96 | 248 | * MP3 Initialising |
parik | 0:37da71b87d96 | 249 | *==========================================================*/ |
parik | 0:37da71b87d96 | 250 | #ifndef FS_ONLY |
parik | 0:37da71b87d96 | 251 | mp3._RST = 1; |
parik | 0:37da71b87d96 | 252 | mp3.cs_high(); //chip disabled |
parik | 0:37da71b87d96 | 253 | mp3.sci_initialise(); //initialise MBED |
parik | 0:37da71b87d96 | 254 | mp3.sci_write(0x00,(SM_SDINEW+SM_STREAM+SM_DIFF)); |
parik | 0:37da71b87d96 | 255 | mp3.sci_write(0x03, 0x9800); |
parik | 0:37da71b87d96 | 256 | mp3.sdi_initialise(); |
parik | 0:37da71b87d96 | 257 | #endif |
parik | 0:37da71b87d96 | 258 | |
parik | 0:37da71b87d96 | 259 | /*================================================================ |
parik | 0:37da71b87d96 | 260 | Networking setup |
parik | 0:37da71b87d96 | 261 | ==================================================================*/ |
parik | 0:37da71b87d96 | 262 | |
parik | 0:37da71b87d96 | 263 | pc.printf("Start\n"); |
parik | 0:37da71b87d96 | 264 | |
parik | 0:37da71b87d96 | 265 | pc.printf("Setting up...\n"); |
parik | 0:37da71b87d96 | 266 | EthernetErr ethErr = eth.setup(); |
parik | 0:37da71b87d96 | 267 | if(ethErr) |
parik | 0:37da71b87d96 | 268 | { |
parik | 0:37da71b87d96 | 269 | pc.printf("Error %d in setup.\n", ethErr); |
parik | 0:37da71b87d96 | 270 | return -1; |
parik | 0:37da71b87d96 | 271 | } |
parik | 0:37da71b87d96 | 272 | pc.printf("Setup OK\n"); |
parik | 0:37da71b87d96 | 273 | |
parik | 0:37da71b87d96 | 274 | sprintf(sMetadata,"StreamTitle='Currently, Unknown';"); |
parik | 0:37da71b87d96 | 275 | sprintf(sPrevMetadata,""); |
parik | 0:37da71b87d96 | 276 | |
parik | 0:37da71b87d96 | 277 | // Init State for Read/Write |
parik | 0:37da71b87d96 | 278 | ReadState=GET_RESPONSE; |
parik | 0:37da71b87d96 | 279 | WriteState=PUT_HEADER; |
parik | 0:37da71b87d96 | 280 | |
parik | 0:37da71b87d96 | 281 | //Host server(IpAddr(208,80,55,219), 10012); |
parik | 0:37da71b87d96 | 282 | //208.80.55.219 |
parik | 0:37da71b87d96 | 283 | |
parik | 0:37da71b87d96 | 284 | Host server(IpAddr(205,188,234,1),80); //IP 205.188.234.1 ,Port 80 |
parik | 0:37da71b87d96 | 285 | //http://scfire-dtc-aa01.stream.aol.com:80/stream/1074 (205,188,234,1) |
parik | 0:37da71b87d96 | 286 | |
parik | 0:37da71b87d96 | 287 | |
parik | 0:37da71b87d96 | 288 | // display IP address and port# of server |
parik | 0:37da71b87d96 | 289 | IpAddr serverIp = server.getIp(); |
parik | 0:37da71b87d96 | 290 | int port = server.getPort(); |
parik | 0:37da71b87d96 | 291 | |
parik | 0:37da71b87d96 | 292 | pc.printf("Connecting... %d.%d.%d.%d:%d\r\n", serverIp[0],serverIp[1],serverIp[2],serverIp[3],port); |
parik | 0:37da71b87d96 | 293 | TCPSocketErr bindErr = sock.connect(server); |
parik | 0:37da71b87d96 | 294 | pc.printf("Connected\n"); |
parik | 0:37da71b87d96 | 295 | sock.setOnEvent(&onTCPSocketEvent); |
parik | 0:37da71b87d96 | 296 | |
parik | 0:37da71b87d96 | 297 | |
parik | 0:37da71b87d96 | 298 | //Poll the networking stack |
parik | 0:37da71b87d96 | 299 | while (true) |
parik | 0:37da71b87d96 | 300 | { |
parik | 0:37da71b87d96 | 301 | Net::poll(); |
parik | 0:37da71b87d96 | 302 | |
parik | 0:37da71b87d96 | 303 | } |
parik | 0:37da71b87d96 | 304 | |
parik | 0:37da71b87d96 | 305 | } |