Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers icecast_client.c Source File

icecast_client.c

Go to the documentation of this file.
00001 /**
00002  * @file icecast_client.c
00003  * @brief Icecast client
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL ICECAST_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <stdlib.h>
00034 #include "icecast/icecast_client.h"
00035 #include "str.h"
00036 #include "debug.h"
00037 
00038 //Check TCP/IP stack configuration
00039 #if (ICECAST_CLIENT_SUPPORT == ENABLED)
00040 
00041 
00042 /**
00043  * @brief Initialize settings with default values
00044  * @param[out] settings Structure that contains Icecast client settings
00045  **/
00046 
00047 void icecastClientGetDefaultSettings(IcecastClientSettings *settings)
00048 {
00049    //Use default interface
00050    settings->interface = netGetDefaultInterface();
00051 
00052    //Icecast server name
00053    strcpy(settings->serverName, "");
00054    //Icecast server port
00055    settings->serverPort = 8000;
00056    //Requested resource
00057    strcpy(settings->resource, "/stream");
00058 
00059    //Streaming buffer size
00060    settings->bufferSize = 80000;
00061 }
00062 
00063 
00064 /**
00065  * @brief Icecast client initialization
00066  * @param[in] context Pointer to the Icecast client context
00067  * @param[in] settings Icecast client specific settings
00068  * @return Error code
00069  **/
00070 
00071 error_t icecastClientInit(IcecastClientContext *context,
00072    const IcecastClientSettings *settings)
00073 {
00074    error_t error;
00075 
00076    //Debug message
00077    TRACE_INFO("Initializing Icecast client...\r\n");
00078 
00079    //Ensure the parameters are valid
00080    if(!context || !settings)
00081       return ERROR_INVALID_PARAMETER;
00082 
00083    //Clear the Icecast client context
00084    memset(context, 0, sizeof(IcecastClientContext));
00085 
00086    //Save user settings
00087    context->settings = *settings;
00088    //Get the size of the circular buffer
00089    context->bufferSize = settings->bufferSize;
00090 
00091    //Start of exception handling block
00092    do
00093    {
00094       //Allocate a memory block to hold the circular buffer
00095       context->streamBuffer = osAllocMem(context->bufferSize);
00096       //Failed to allocate memory?
00097       if(!context->streamBuffer)
00098       {
00099          //Report an error to the calling function
00100          error = ERROR_OUT_OF_MEMORY;
00101          break;
00102       }
00103 
00104       //Create mutex object to protect critical sections
00105       if(!osCreateMutex(&context->mutex))
00106       {
00107          //Failed to create mutex
00108          error = ERROR_OUT_OF_RESOURCES;
00109          break;
00110       }
00111 
00112       //Create event to get notified when the buffer is writable
00113       if(!osCreateEvent(&context->writeEvent))
00114       {
00115          //Failed to create event object
00116          error = ERROR_OUT_OF_RESOURCES;
00117          break;
00118       }
00119 
00120       //The buffer is available for writing
00121       osSetEvent(&context->writeEvent);
00122 
00123       //Create event to get notified when the buffer is readable
00124       if(!osCreateEvent(&context->readEvent))
00125       {
00126          //Failed to create event object
00127          error = ERROR_OUT_OF_RESOURCES;
00128          break;
00129       }
00130 
00131       //Successful initialization
00132       error = NO_ERROR;
00133 
00134       //End of exception handling block
00135    } while(0);
00136 
00137    //Check whether an error occurred
00138    if(error)
00139    {
00140       //Clean up side effects...
00141       osFreeMem(context->streamBuffer);
00142       osDeleteMutex(&context->mutex);
00143       osDeleteEvent(&context->writeEvent);
00144       osDeleteEvent(&context->readEvent);
00145    }
00146 
00147    //Return status code
00148    return error;
00149 }
00150 
00151 
00152 /**
00153  * @brief Start Icecast client
00154  * @param[in] context Pointer to the Icecast client context
00155  * @return Error code
00156  **/
00157 
00158 error_t icecastClientStart(IcecastClientContext *context)
00159 {
00160    OsTask *task;
00161 
00162    //Debug message
00163    TRACE_INFO("Starting Icecast client...\r\n");
00164 
00165    //Create the Icecast client task
00166    task = osCreateTask("Icecast client", icecastClientTask,
00167       context, ICECAST_CLIENT_STACK_SIZE, ICECAST_CLIENT_PRIORITY);
00168 
00169    //Unable to create the task?
00170    if(task == OS_INVALID_HANDLE)
00171       return ERROR_OUT_OF_RESOURCES;
00172 
00173    //Successful processing
00174    return NO_ERROR;
00175 }
00176 
00177 
00178 /**
00179  * @brief Copy data from input stream
00180  * @param[in] context Pointer to the Icecast client context
00181  * @param[out] data Pointer to the user buffer
00182  * @param[in] size Maximum number of bytes that can be read
00183  * @param[out] length Number of bytes that have been read
00184  * @param[in] timeout Maximum time to wait before returning
00185  * @return Error code
00186  **/
00187 
00188 error_t icecastClientReadStream(IcecastClientContext *context,
00189    uint8_t *data, size_t size, size_t *length, systime_t timeout)
00190 {
00191    bool_t status;
00192 
00193    //Ensure the parameters are valid
00194    if(!context || !data)
00195       return ERROR_INVALID_PARAMETER;
00196 
00197    //Wait for the buffer to be available for reading
00198    status = osWaitForEvent(&context->readEvent, timeout);
00199    //Timeout error?
00200    if(!status)
00201       return ERROR_TIMEOUT;
00202 
00203    //Enter critical section
00204    osAcquireMutex(&context->mutex);
00205    //Compute the number of bytes to read at a time
00206    *length = MIN(size, context->bufferLength);
00207    //Leave critical section
00208    osReleaseMutex(&context->mutex);
00209 
00210    //Check whether the specified data crosses buffer boundaries
00211    if((context->readIndex + *length) <= context->bufferSize)
00212    {
00213       //Copy the data
00214       memcpy(data, context->streamBuffer + context->readIndex, *length);
00215    }
00216    else
00217    {
00218       //Copy the first part of the data
00219       memcpy(data, context->streamBuffer + context->readIndex,
00220          context->bufferSize - context->readIndex);
00221       //Wrap around to the beginning of the circular buffer
00222       memcpy(data + context->bufferSize - context->readIndex, context->streamBuffer,
00223          *length - context->bufferSize + context->readIndex);
00224    }
00225 
00226    //Enter critical section
00227    osAcquireMutex(&context->mutex);
00228 
00229    //Increment read index
00230    context->readIndex += *length;
00231    //Wrap around if necessary
00232    if(context->readIndex >= context->bufferSize)
00233       context->readIndex -= context->bufferSize;
00234 
00235    //Update buffer length
00236    context->bufferLength -= *length;
00237    //Check whether the buffer is available for writing
00238    if(context->bufferLength < context->bufferSize)
00239       osSetEvent(&context->writeEvent);
00240    //Check whether the buffer is available for reading
00241    if(context->bufferLength > 0)
00242       osSetEvent(&context->readEvent);
00243 
00244    //Leave critical section
00245    osReleaseMutex(&context->mutex);
00246 
00247    //Successful read operation
00248    return NO_ERROR;
00249 }
00250 
00251 
00252 /**
00253  * @brief Copy metadata from input stream
00254  * @param[in] context Pointer to the Icecast client context
00255  * @param[out] metadata Pointer to the user buffer
00256  * @param[in] size Maximum number of bytes that can be read
00257  * @param[out] length Number of bytes that have been read
00258  * @return Error code
00259  **/
00260 
00261 error_t icecastClientReadMetadata(IcecastClientContext *context,
00262    char_t *metadata, size_t size, size_t *length)
00263 {
00264    //Ensure the parameters are valid
00265    if(!context || !metadata)
00266       return ERROR_INVALID_PARAMETER;
00267 
00268    //Enter critical section
00269    osAcquireMutex(&context->mutex);
00270 
00271    //Limit the number of data to read
00272    *length = MIN(size, context->metadataLength);
00273    //Save metadata information
00274    memcpy(metadata, context->metadata, *length);
00275 
00276    //Leave critical section
00277    osReleaseMutex(&context->mutex);
00278 
00279    //Successful read operation
00280    return NO_ERROR;
00281 }
00282 
00283 
00284 /**
00285  * @brief Icecast client task
00286  * @param[in] param Pointer to the Icecast client context
00287  **/
00288 
00289 void icecastClientTask(void *param)
00290 {
00291    error_t error;
00292    bool_t end;
00293    size_t n;
00294    size_t length;
00295    size_t received;
00296    IcecastClientContext *context;
00297 
00298    //Retrieve the Icecast client context
00299    context = (IcecastClientContext *) param;
00300 
00301    //Main loop
00302    while(1)
00303    {
00304       //Debug message
00305       TRACE_INFO("Icecast client: Connecting to server %s port %" PRIu16 "\r\n",
00306          context->settings.serverName, context->settings.serverPort);
00307 
00308       //Initiate a connection to the Icecast server
00309       error = icecastClientConnect(context);
00310 
00311       //Connection to server failed?
00312       if(error)
00313       {
00314          //Debug message
00315          TRACE_ERROR("Icecast client: Connection to server failed!\r\n");
00316          //Recovery delay
00317          osDelayTask(ICECAST_RECOVERY_DELAY);
00318          //Try to reconnect...
00319          continue;
00320       }
00321 
00322       //Debug message
00323       TRACE_INFO("Block size = %" PRIuSIZE "\r\n", context->blockSize);
00324 
00325       //Check block size
00326       if(!context->blockSize)
00327       {
00328          //Close socket
00329          socketClose(context->socket);
00330          //Recovery delay
00331          osDelayTask(ICECAST_RECOVERY_DELAY);
00332          //Try to reconnect...
00333          continue;
00334       }
00335 
00336       //Initialize loop condition variable
00337       end = FALSE;
00338 
00339       //Read as much data as possible...
00340       while(!end)
00341       {
00342          //Process the stream block by block
00343          length = context->blockSize;
00344 
00345          //Read current block
00346          while(!end && length > 0)
00347          {
00348             //Wait for the buffer to be available for writing
00349             osWaitForEvent(&context->writeEvent, INFINITE_DELAY);
00350 
00351             //Enter critical section
00352             osAcquireMutex(&context->mutex);
00353             //Compute the number of bytes to read at a time
00354             n = MIN(length, context->bufferSize - context->bufferLength);
00355             //Leave critical section
00356             osReleaseMutex(&context->mutex);
00357 
00358             //Check whether the specified data crosses buffer boundaries
00359             if((context->writeIndex + n) > context->bufferSize)
00360                n = context->bufferSize - context->writeIndex;
00361 
00362             //Receive data
00363             error = socketReceive(context->socket, context->streamBuffer +
00364                context->writeIndex, n, &received, SOCKET_FLAG_WAIT_ALL);
00365 
00366             //Any error to report?
00367             if(error)
00368             {
00369                //Stop streaming data
00370                end = TRUE;
00371             }
00372             else
00373             {
00374                //Enter critical section
00375                osAcquireMutex(&context->mutex);
00376 
00377                //Increment write index
00378                context->writeIndex += n;
00379                //Wrap around if necessary
00380                if(context->writeIndex >= context->bufferSize)
00381                   context->writeIndex -= context->bufferSize;
00382 
00383                //Update buffer length
00384                context->bufferLength += n;
00385                //Check whether the buffer is available for writing
00386                if(context->bufferLength < context->bufferSize)
00387                   osSetEvent(&context->writeEvent);
00388                //Check whether the buffer is available for reading
00389                if(context->bufferLength > 0)
00390                   osSetEvent(&context->readEvent);
00391 
00392                //Leave critical section
00393                osReleaseMutex(&context->mutex);
00394 
00395                //Update the total number of bytes that have been received
00396                context->totalLength += n;
00397                //Number of remaining data to read
00398                length -= n;
00399             }
00400          }
00401 
00402          //Debug message
00403          TRACE_DEBUG("Icecast client: Total bytes received = %" PRIuSIZE "\r\n", context->totalLength);
00404 
00405          //Check whether the metadata block should be read
00406          if(!end)
00407          {
00408             //Process the metadata block
00409             error = icecastClientProcessMetadata(context);
00410             //Any error to report?
00411             if(error) end = TRUE;
00412          }
00413       }
00414 
00415       //Close connection
00416       socketClose(context->socket);
00417    }
00418 }
00419 
00420 
00421 /**
00422  * @brief Connect to the specified Icecast server
00423  * @param[in] context Pointer to the Icecast client context
00424  **/
00425 
00426 error_t icecastClientConnect(IcecastClientContext *context)
00427 {
00428    error_t error;
00429    size_t length;
00430    uint16_t serverPort;
00431    IpAddr serverIpAddr;
00432    NetInterface *interface;
00433 
00434    //Underlying network interface
00435    interface = context->settings.interface;
00436 
00437    //Force traffic to go through a proxy server?
00438    if(strcmp(interface->proxyName, ""))
00439    {
00440       //Icecast request template
00441       const char_t requestTemplate[] =
00442          "GET http://%s:%" PRIu16 "%s HTTP/1.1\r\n"
00443          "Host: %s:%" PRIu16 "\r\n"
00444          "User-agent: UserAgent\r\n"
00445          "Icy-MetaData: 1\r\n"
00446          "Connection: close\r\n"
00447          "\r\n";
00448 
00449       //Format Icecast request
00450       length = sprintf(context->buffer, requestTemplate,
00451          context->settings.serverName, context->settings.serverPort,
00452          context->settings.resource, context->settings.serverName,
00453          context->settings.serverPort);
00454 
00455       //The specified proxy server can be either an IP or a host name
00456       error = getHostByName(interface, interface->proxyName, &serverIpAddr, 0);
00457       //Unable to resolve server name?
00458       if(error)
00459          return error;
00460 
00461       //Proxy server port
00462       serverPort = interface->proxyPort;
00463    }
00464    else
00465    {
00466       //Icecast request template
00467       const char_t requestTemplate[] =
00468          "GET %s HTTP/1.1\r\n"
00469          "Host: %s\r\n"
00470          "User-agent: UserAgent\r\n"
00471          "Icy-MetaData: 1\r\n"
00472          "Connection: close\r\n"
00473          "\r\n";
00474 
00475       //Format Icecast request
00476       length = sprintf(context->buffer, requestTemplate,
00477          context->settings.resource, context->settings.serverName);
00478 
00479       //The specified Icecast server can be either an IP or a host name
00480       error = getHostByName(interface, context->settings.serverName, &serverIpAddr, 0);
00481       //Unable to resolve server name?
00482       if(error)
00483          return error;
00484 
00485       //Icecast server port
00486       serverPort = context->settings.serverPort;
00487    }
00488 
00489    //Open a TCP socket
00490    context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
00491    //Failed to open socket?
00492    if(!context->socket)
00493       return ERROR_OUT_OF_RESOURCES;
00494 
00495    //Start of exception handling block
00496    do
00497    {
00498       //Associate the socket with the relevant interface
00499       error = socketBindToInterface(context->socket, interface);
00500       //Unable to bind the socket to the desired interface?
00501       if(error)
00502          break;
00503 
00504       //Adjust receive timeout
00505       error = socketSetTimeout(context->socket, ICECAST_CLIENT_TIMEOUT);
00506       //Any error to report?
00507       if(error)
00508          break;
00509 
00510       //Connect to the server
00511       error = socketConnect(context->socket, &serverIpAddr, serverPort);
00512       //Connection with server failed?
00513       if(error)
00514          break;
00515 
00516       //Display Icecast request for debugging purpose
00517       TRACE_DEBUG(context->buffer);
00518 
00519       //Send request to the server
00520       error = socketSend(context->socket, context->buffer,
00521          length, NULL, SOCKET_FLAG_WAIT_ACK);
00522       //Failed to send the request?
00523       if(error)
00524          break;
00525 
00526       //Parse response header
00527       while(1)
00528       {
00529          char_t *separator;
00530          char_t *property;
00531          char_t *value;
00532 
00533          //Read a line from the response header
00534          error = socketReceive(context->socket, context->buffer,
00535             ICECAST_CLIENT_METADATA_MAX_SIZE, &length, SOCKET_FLAG_BREAK_CRLF);
00536          //Failed to read data?
00537          if(error)
00538             break;
00539 
00540          //Properly terminate the string with a NULL character
00541          context->buffer[length] = '\0';
00542 
00543          //The end of the header has been reached?
00544          if(!strcmp(context->buffer, "\r\n"))
00545             break;
00546 
00547          //Check whether a separator is present
00548          separator = strchr(context->buffer, ':');
00549 
00550          //Separator found?
00551          if(separator)
00552          {
00553             //Split the line
00554             *separator = '\0';
00555 
00556             //Get property name and value
00557             property = strTrimWhitespace(context->buffer);
00558             value = strTrimWhitespace(separator + 1);
00559 
00560             //Debug message
00561             TRACE_INFO("<%s>=<%s>\r\n", property, value);
00562 
00563             //Icy-Metaint property found?
00564             if(!strcasecmp(property, "Icy-Metaint"))
00565             {
00566                //Retrieve the block size used by the Icecast server
00567                context->blockSize = atoi(value);
00568             }
00569          }
00570       }
00571 
00572       //End of exception handling block
00573    } while(0);
00574 
00575    //Check whether an error occurred
00576    if(error)
00577    {
00578       //Clean up side effects
00579       socketClose(context->socket);
00580    }
00581 
00582    //Return status code
00583    return error;
00584 }
00585 
00586 
00587 /**
00588  * @brief Decode metadata block
00589  * @param[in] context Pointer to the Icecast client context
00590  **/
00591 
00592 error_t icecastClientProcessMetadata(IcecastClientContext *context)
00593 {
00594    error_t error;
00595    size_t n;
00596    size_t length;
00597    size_t metadataLength;
00598 
00599    //The metadata block begins with a single byte which indicates
00600    //how many 16-byte segments need to be read
00601    error = socketReceive(context->socket, context->buffer,
00602       sizeof(uint8_t), &length, SOCKET_FLAG_WAIT_ALL);
00603 
00604    //Any error to report?
00605    if(error)
00606       return error;
00607    //Make sure the expected number of bytes have been received
00608    if(length != sizeof(uint8_t))
00609       return ERROR_INVALID_METADATA;
00610 
00611    //Compute the length of the following metadata block
00612    metadataLength = context->buffer[0] * 16;
00613    //Limit the number of bytes to read
00614    n = MIN(metadataLength, ICECAST_CLIENT_METADATA_MAX_SIZE - 1);
00615 
00616    //Read the metadata information
00617    error = socketReceive(context->socket, context->buffer,
00618       n, &length, SOCKET_FLAG_WAIT_ALL);
00619 
00620    //Any error to report?
00621    if(error)
00622       return error;
00623    //Make sure the expected number of bytes have been received
00624    if(length != n)
00625       return ERROR_INVALID_METADATA;
00626 
00627    //Enter critical section
00628    osAcquireMutex(&context->mutex);
00629 
00630    //Save metadata information
00631    memcpy(context->metadata, context->buffer, n);
00632    //Terminate the string properly
00633    context->metadata[n] = '\0';
00634    //Record the length of the metadata
00635    context->metadataLength = n;
00636 
00637    //Leave critical section
00638    osReleaseMutex(&context->mutex);
00639 
00640    //Any metadata information received?
00641    if(n > 0)
00642    {
00643       //Debug message
00644       TRACE_DEBUG("Icecast client: Metadata = <%s>\r\n", context->metadata);
00645    }
00646 
00647    //Compute the number of bytes that have not been processed
00648    metadataLength -= n;
00649 
00650    //Read the complete metadata
00651    while(metadataLength > 0)
00652    {
00653       //Compute the number of data to read at a time
00654       n = MIN(metadataLength, ICECAST_CLIENT_METADATA_MAX_SIZE);
00655 
00656       //Drop incoming data...
00657       error = socketReceive(context->socket, context->buffer,
00658          n, &length, SOCKET_FLAG_WAIT_ALL);
00659 
00660       //Any error to report?
00661       if(error)
00662          return error;
00663       //Make sure the expected number of bytes have been received
00664       if(length != n)
00665          return ERROR_INVALID_METADATA;
00666 
00667       //Update byte counter
00668       metadataLength -= n;
00669    }
00670 
00671    //Successful processing
00672    return NO_ERROR;
00673 }
00674 
00675 #endif
00676 
00677