Webserver+3d print

Dependents:   Nucleo

Committer:
Sergunb
Date:
Sat Feb 04 18:15:49 2017 +0000
Revision:
0:8918a71cdbe9
nothing else

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sergunb 0:8918a71cdbe9 1 /**
Sergunb 0:8918a71cdbe9 2 * @file icecast_client.c
Sergunb 0:8918a71cdbe9 3 * @brief Icecast client
Sergunb 0:8918a71cdbe9 4 *
Sergunb 0:8918a71cdbe9 5 * @section License
Sergunb 0:8918a71cdbe9 6 *
Sergunb 0:8918a71cdbe9 7 * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
Sergunb 0:8918a71cdbe9 8 *
Sergunb 0:8918a71cdbe9 9 * This file is part of CycloneTCP Open.
Sergunb 0:8918a71cdbe9 10 *
Sergunb 0:8918a71cdbe9 11 * This program is free software; you can redistribute it and/or
Sergunb 0:8918a71cdbe9 12 * modify it under the terms of the GNU General Public License
Sergunb 0:8918a71cdbe9 13 * as published by the Free Software Foundation; either version 2
Sergunb 0:8918a71cdbe9 14 * of the License, or (at your option) any later version.
Sergunb 0:8918a71cdbe9 15 *
Sergunb 0:8918a71cdbe9 16 * This program is distributed in the hope that it will be useful,
Sergunb 0:8918a71cdbe9 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Sergunb 0:8918a71cdbe9 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Sergunb 0:8918a71cdbe9 19 * GNU General Public License for more details.
Sergunb 0:8918a71cdbe9 20 *
Sergunb 0:8918a71cdbe9 21 * You should have received a copy of the GNU General Public License
Sergunb 0:8918a71cdbe9 22 * along with this program; if not, write to the Free Software Foundation,
Sergunb 0:8918a71cdbe9 23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Sergunb 0:8918a71cdbe9 24 *
Sergunb 0:8918a71cdbe9 25 * @author Oryx Embedded SARL (www.oryx-embedded.com)
Sergunb 0:8918a71cdbe9 26 * @version 1.7.6
Sergunb 0:8918a71cdbe9 27 **/
Sergunb 0:8918a71cdbe9 28
Sergunb 0:8918a71cdbe9 29 //Switch to the appropriate trace level
Sergunb 0:8918a71cdbe9 30 #define TRACE_LEVEL ICECAST_TRACE_LEVEL
Sergunb 0:8918a71cdbe9 31
Sergunb 0:8918a71cdbe9 32 //Dependencies
Sergunb 0:8918a71cdbe9 33 #include <stdlib.h>
Sergunb 0:8918a71cdbe9 34 #include "icecast/icecast_client.h"
Sergunb 0:8918a71cdbe9 35 #include "str.h"
Sergunb 0:8918a71cdbe9 36 #include "debug.h"
Sergunb 0:8918a71cdbe9 37
Sergunb 0:8918a71cdbe9 38 //Check TCP/IP stack configuration
Sergunb 0:8918a71cdbe9 39 #if (ICECAST_CLIENT_SUPPORT == ENABLED)
Sergunb 0:8918a71cdbe9 40
Sergunb 0:8918a71cdbe9 41
Sergunb 0:8918a71cdbe9 42 /**
Sergunb 0:8918a71cdbe9 43 * @brief Initialize settings with default values
Sergunb 0:8918a71cdbe9 44 * @param[out] settings Structure that contains Icecast client settings
Sergunb 0:8918a71cdbe9 45 **/
Sergunb 0:8918a71cdbe9 46
Sergunb 0:8918a71cdbe9 47 void icecastClientGetDefaultSettings(IcecastClientSettings *settings)
Sergunb 0:8918a71cdbe9 48 {
Sergunb 0:8918a71cdbe9 49 //Use default interface
Sergunb 0:8918a71cdbe9 50 settings->interface = netGetDefaultInterface();
Sergunb 0:8918a71cdbe9 51
Sergunb 0:8918a71cdbe9 52 //Icecast server name
Sergunb 0:8918a71cdbe9 53 strcpy(settings->serverName, "");
Sergunb 0:8918a71cdbe9 54 //Icecast server port
Sergunb 0:8918a71cdbe9 55 settings->serverPort = 8000;
Sergunb 0:8918a71cdbe9 56 //Requested resource
Sergunb 0:8918a71cdbe9 57 strcpy(settings->resource, "/stream");
Sergunb 0:8918a71cdbe9 58
Sergunb 0:8918a71cdbe9 59 //Streaming buffer size
Sergunb 0:8918a71cdbe9 60 settings->bufferSize = 80000;
Sergunb 0:8918a71cdbe9 61 }
Sergunb 0:8918a71cdbe9 62
Sergunb 0:8918a71cdbe9 63
Sergunb 0:8918a71cdbe9 64 /**
Sergunb 0:8918a71cdbe9 65 * @brief Icecast client initialization
Sergunb 0:8918a71cdbe9 66 * @param[in] context Pointer to the Icecast client context
Sergunb 0:8918a71cdbe9 67 * @param[in] settings Icecast client specific settings
Sergunb 0:8918a71cdbe9 68 * @return Error code
Sergunb 0:8918a71cdbe9 69 **/
Sergunb 0:8918a71cdbe9 70
Sergunb 0:8918a71cdbe9 71 error_t icecastClientInit(IcecastClientContext *context,
Sergunb 0:8918a71cdbe9 72 const IcecastClientSettings *settings)
Sergunb 0:8918a71cdbe9 73 {
Sergunb 0:8918a71cdbe9 74 error_t error;
Sergunb 0:8918a71cdbe9 75
Sergunb 0:8918a71cdbe9 76 //Debug message
Sergunb 0:8918a71cdbe9 77 TRACE_INFO("Initializing Icecast client...\r\n");
Sergunb 0:8918a71cdbe9 78
Sergunb 0:8918a71cdbe9 79 //Ensure the parameters are valid
Sergunb 0:8918a71cdbe9 80 if(!context || !settings)
Sergunb 0:8918a71cdbe9 81 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 82
Sergunb 0:8918a71cdbe9 83 //Clear the Icecast client context
Sergunb 0:8918a71cdbe9 84 memset(context, 0, sizeof(IcecastClientContext));
Sergunb 0:8918a71cdbe9 85
Sergunb 0:8918a71cdbe9 86 //Save user settings
Sergunb 0:8918a71cdbe9 87 context->settings = *settings;
Sergunb 0:8918a71cdbe9 88 //Get the size of the circular buffer
Sergunb 0:8918a71cdbe9 89 context->bufferSize = settings->bufferSize;
Sergunb 0:8918a71cdbe9 90
Sergunb 0:8918a71cdbe9 91 //Start of exception handling block
Sergunb 0:8918a71cdbe9 92 do
Sergunb 0:8918a71cdbe9 93 {
Sergunb 0:8918a71cdbe9 94 //Allocate a memory block to hold the circular buffer
Sergunb 0:8918a71cdbe9 95 context->streamBuffer = osAllocMem(context->bufferSize);
Sergunb 0:8918a71cdbe9 96 //Failed to allocate memory?
Sergunb 0:8918a71cdbe9 97 if(!context->streamBuffer)
Sergunb 0:8918a71cdbe9 98 {
Sergunb 0:8918a71cdbe9 99 //Report an error to the calling function
Sergunb 0:8918a71cdbe9 100 error = ERROR_OUT_OF_MEMORY;
Sergunb 0:8918a71cdbe9 101 break;
Sergunb 0:8918a71cdbe9 102 }
Sergunb 0:8918a71cdbe9 103
Sergunb 0:8918a71cdbe9 104 //Create mutex object to protect critical sections
Sergunb 0:8918a71cdbe9 105 if(!osCreateMutex(&context->mutex))
Sergunb 0:8918a71cdbe9 106 {
Sergunb 0:8918a71cdbe9 107 //Failed to create mutex
Sergunb 0:8918a71cdbe9 108 error = ERROR_OUT_OF_RESOURCES;
Sergunb 0:8918a71cdbe9 109 break;
Sergunb 0:8918a71cdbe9 110 }
Sergunb 0:8918a71cdbe9 111
Sergunb 0:8918a71cdbe9 112 //Create event to get notified when the buffer is writable
Sergunb 0:8918a71cdbe9 113 if(!osCreateEvent(&context->writeEvent))
Sergunb 0:8918a71cdbe9 114 {
Sergunb 0:8918a71cdbe9 115 //Failed to create event object
Sergunb 0:8918a71cdbe9 116 error = ERROR_OUT_OF_RESOURCES;
Sergunb 0:8918a71cdbe9 117 break;
Sergunb 0:8918a71cdbe9 118 }
Sergunb 0:8918a71cdbe9 119
Sergunb 0:8918a71cdbe9 120 //The buffer is available for writing
Sergunb 0:8918a71cdbe9 121 osSetEvent(&context->writeEvent);
Sergunb 0:8918a71cdbe9 122
Sergunb 0:8918a71cdbe9 123 //Create event to get notified when the buffer is readable
Sergunb 0:8918a71cdbe9 124 if(!osCreateEvent(&context->readEvent))
Sergunb 0:8918a71cdbe9 125 {
Sergunb 0:8918a71cdbe9 126 //Failed to create event object
Sergunb 0:8918a71cdbe9 127 error = ERROR_OUT_OF_RESOURCES;
Sergunb 0:8918a71cdbe9 128 break;
Sergunb 0:8918a71cdbe9 129 }
Sergunb 0:8918a71cdbe9 130
Sergunb 0:8918a71cdbe9 131 //Successful initialization
Sergunb 0:8918a71cdbe9 132 error = NO_ERROR;
Sergunb 0:8918a71cdbe9 133
Sergunb 0:8918a71cdbe9 134 //End of exception handling block
Sergunb 0:8918a71cdbe9 135 } while(0);
Sergunb 0:8918a71cdbe9 136
Sergunb 0:8918a71cdbe9 137 //Check whether an error occurred
Sergunb 0:8918a71cdbe9 138 if(error)
Sergunb 0:8918a71cdbe9 139 {
Sergunb 0:8918a71cdbe9 140 //Clean up side effects...
Sergunb 0:8918a71cdbe9 141 osFreeMem(context->streamBuffer);
Sergunb 0:8918a71cdbe9 142 osDeleteMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 143 osDeleteEvent(&context->writeEvent);
Sergunb 0:8918a71cdbe9 144 osDeleteEvent(&context->readEvent);
Sergunb 0:8918a71cdbe9 145 }
Sergunb 0:8918a71cdbe9 146
Sergunb 0:8918a71cdbe9 147 //Return status code
Sergunb 0:8918a71cdbe9 148 return error;
Sergunb 0:8918a71cdbe9 149 }
Sergunb 0:8918a71cdbe9 150
Sergunb 0:8918a71cdbe9 151
Sergunb 0:8918a71cdbe9 152 /**
Sergunb 0:8918a71cdbe9 153 * @brief Start Icecast client
Sergunb 0:8918a71cdbe9 154 * @param[in] context Pointer to the Icecast client context
Sergunb 0:8918a71cdbe9 155 * @return Error code
Sergunb 0:8918a71cdbe9 156 **/
Sergunb 0:8918a71cdbe9 157
Sergunb 0:8918a71cdbe9 158 error_t icecastClientStart(IcecastClientContext *context)
Sergunb 0:8918a71cdbe9 159 {
Sergunb 0:8918a71cdbe9 160 OsTask *task;
Sergunb 0:8918a71cdbe9 161
Sergunb 0:8918a71cdbe9 162 //Debug message
Sergunb 0:8918a71cdbe9 163 TRACE_INFO("Starting Icecast client...\r\n");
Sergunb 0:8918a71cdbe9 164
Sergunb 0:8918a71cdbe9 165 //Create the Icecast client task
Sergunb 0:8918a71cdbe9 166 task = osCreateTask("Icecast client", icecastClientTask,
Sergunb 0:8918a71cdbe9 167 context, ICECAST_CLIENT_STACK_SIZE, ICECAST_CLIENT_PRIORITY);
Sergunb 0:8918a71cdbe9 168
Sergunb 0:8918a71cdbe9 169 //Unable to create the task?
Sergunb 0:8918a71cdbe9 170 if(task == OS_INVALID_HANDLE)
Sergunb 0:8918a71cdbe9 171 return ERROR_OUT_OF_RESOURCES;
Sergunb 0:8918a71cdbe9 172
Sergunb 0:8918a71cdbe9 173 //Successful processing
Sergunb 0:8918a71cdbe9 174 return NO_ERROR;
Sergunb 0:8918a71cdbe9 175 }
Sergunb 0:8918a71cdbe9 176
Sergunb 0:8918a71cdbe9 177
Sergunb 0:8918a71cdbe9 178 /**
Sergunb 0:8918a71cdbe9 179 * @brief Copy data from input stream
Sergunb 0:8918a71cdbe9 180 * @param[in] context Pointer to the Icecast client context
Sergunb 0:8918a71cdbe9 181 * @param[out] data Pointer to the user buffer
Sergunb 0:8918a71cdbe9 182 * @param[in] size Maximum number of bytes that can be read
Sergunb 0:8918a71cdbe9 183 * @param[out] length Number of bytes that have been read
Sergunb 0:8918a71cdbe9 184 * @param[in] timeout Maximum time to wait before returning
Sergunb 0:8918a71cdbe9 185 * @return Error code
Sergunb 0:8918a71cdbe9 186 **/
Sergunb 0:8918a71cdbe9 187
Sergunb 0:8918a71cdbe9 188 error_t icecastClientReadStream(IcecastClientContext *context,
Sergunb 0:8918a71cdbe9 189 uint8_t *data, size_t size, size_t *length, systime_t timeout)
Sergunb 0:8918a71cdbe9 190 {
Sergunb 0:8918a71cdbe9 191 bool_t status;
Sergunb 0:8918a71cdbe9 192
Sergunb 0:8918a71cdbe9 193 //Ensure the parameters are valid
Sergunb 0:8918a71cdbe9 194 if(!context || !data)
Sergunb 0:8918a71cdbe9 195 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 196
Sergunb 0:8918a71cdbe9 197 //Wait for the buffer to be available for reading
Sergunb 0:8918a71cdbe9 198 status = osWaitForEvent(&context->readEvent, timeout);
Sergunb 0:8918a71cdbe9 199 //Timeout error?
Sergunb 0:8918a71cdbe9 200 if(!status)
Sergunb 0:8918a71cdbe9 201 return ERROR_TIMEOUT;
Sergunb 0:8918a71cdbe9 202
Sergunb 0:8918a71cdbe9 203 //Enter critical section
Sergunb 0:8918a71cdbe9 204 osAcquireMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 205 //Compute the number of bytes to read at a time
Sergunb 0:8918a71cdbe9 206 *length = MIN(size, context->bufferLength);
Sergunb 0:8918a71cdbe9 207 //Leave critical section
Sergunb 0:8918a71cdbe9 208 osReleaseMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 209
Sergunb 0:8918a71cdbe9 210 //Check whether the specified data crosses buffer boundaries
Sergunb 0:8918a71cdbe9 211 if((context->readIndex + *length) <= context->bufferSize)
Sergunb 0:8918a71cdbe9 212 {
Sergunb 0:8918a71cdbe9 213 //Copy the data
Sergunb 0:8918a71cdbe9 214 memcpy(data, context->streamBuffer + context->readIndex, *length);
Sergunb 0:8918a71cdbe9 215 }
Sergunb 0:8918a71cdbe9 216 else
Sergunb 0:8918a71cdbe9 217 {
Sergunb 0:8918a71cdbe9 218 //Copy the first part of the data
Sergunb 0:8918a71cdbe9 219 memcpy(data, context->streamBuffer + context->readIndex,
Sergunb 0:8918a71cdbe9 220 context->bufferSize - context->readIndex);
Sergunb 0:8918a71cdbe9 221 //Wrap around to the beginning of the circular buffer
Sergunb 0:8918a71cdbe9 222 memcpy(data + context->bufferSize - context->readIndex, context->streamBuffer,
Sergunb 0:8918a71cdbe9 223 *length - context->bufferSize + context->readIndex);
Sergunb 0:8918a71cdbe9 224 }
Sergunb 0:8918a71cdbe9 225
Sergunb 0:8918a71cdbe9 226 //Enter critical section
Sergunb 0:8918a71cdbe9 227 osAcquireMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 228
Sergunb 0:8918a71cdbe9 229 //Increment read index
Sergunb 0:8918a71cdbe9 230 context->readIndex += *length;
Sergunb 0:8918a71cdbe9 231 //Wrap around if necessary
Sergunb 0:8918a71cdbe9 232 if(context->readIndex >= context->bufferSize)
Sergunb 0:8918a71cdbe9 233 context->readIndex -= context->bufferSize;
Sergunb 0:8918a71cdbe9 234
Sergunb 0:8918a71cdbe9 235 //Update buffer length
Sergunb 0:8918a71cdbe9 236 context->bufferLength -= *length;
Sergunb 0:8918a71cdbe9 237 //Check whether the buffer is available for writing
Sergunb 0:8918a71cdbe9 238 if(context->bufferLength < context->bufferSize)
Sergunb 0:8918a71cdbe9 239 osSetEvent(&context->writeEvent);
Sergunb 0:8918a71cdbe9 240 //Check whether the buffer is available for reading
Sergunb 0:8918a71cdbe9 241 if(context->bufferLength > 0)
Sergunb 0:8918a71cdbe9 242 osSetEvent(&context->readEvent);
Sergunb 0:8918a71cdbe9 243
Sergunb 0:8918a71cdbe9 244 //Leave critical section
Sergunb 0:8918a71cdbe9 245 osReleaseMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 246
Sergunb 0:8918a71cdbe9 247 //Successful read operation
Sergunb 0:8918a71cdbe9 248 return NO_ERROR;
Sergunb 0:8918a71cdbe9 249 }
Sergunb 0:8918a71cdbe9 250
Sergunb 0:8918a71cdbe9 251
Sergunb 0:8918a71cdbe9 252 /**
Sergunb 0:8918a71cdbe9 253 * @brief Copy metadata from input stream
Sergunb 0:8918a71cdbe9 254 * @param[in] context Pointer to the Icecast client context
Sergunb 0:8918a71cdbe9 255 * @param[out] metadata Pointer to the user buffer
Sergunb 0:8918a71cdbe9 256 * @param[in] size Maximum number of bytes that can be read
Sergunb 0:8918a71cdbe9 257 * @param[out] length Number of bytes that have been read
Sergunb 0:8918a71cdbe9 258 * @return Error code
Sergunb 0:8918a71cdbe9 259 **/
Sergunb 0:8918a71cdbe9 260
Sergunb 0:8918a71cdbe9 261 error_t icecastClientReadMetadata(IcecastClientContext *context,
Sergunb 0:8918a71cdbe9 262 char_t *metadata, size_t size, size_t *length)
Sergunb 0:8918a71cdbe9 263 {
Sergunb 0:8918a71cdbe9 264 //Ensure the parameters are valid
Sergunb 0:8918a71cdbe9 265 if(!context || !metadata)
Sergunb 0:8918a71cdbe9 266 return ERROR_INVALID_PARAMETER;
Sergunb 0:8918a71cdbe9 267
Sergunb 0:8918a71cdbe9 268 //Enter critical section
Sergunb 0:8918a71cdbe9 269 osAcquireMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 270
Sergunb 0:8918a71cdbe9 271 //Limit the number of data to read
Sergunb 0:8918a71cdbe9 272 *length = MIN(size, context->metadataLength);
Sergunb 0:8918a71cdbe9 273 //Save metadata information
Sergunb 0:8918a71cdbe9 274 memcpy(metadata, context->metadata, *length);
Sergunb 0:8918a71cdbe9 275
Sergunb 0:8918a71cdbe9 276 //Leave critical section
Sergunb 0:8918a71cdbe9 277 osReleaseMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 278
Sergunb 0:8918a71cdbe9 279 //Successful read operation
Sergunb 0:8918a71cdbe9 280 return NO_ERROR;
Sergunb 0:8918a71cdbe9 281 }
Sergunb 0:8918a71cdbe9 282
Sergunb 0:8918a71cdbe9 283
Sergunb 0:8918a71cdbe9 284 /**
Sergunb 0:8918a71cdbe9 285 * @brief Icecast client task
Sergunb 0:8918a71cdbe9 286 * @param[in] param Pointer to the Icecast client context
Sergunb 0:8918a71cdbe9 287 **/
Sergunb 0:8918a71cdbe9 288
Sergunb 0:8918a71cdbe9 289 void icecastClientTask(void *param)
Sergunb 0:8918a71cdbe9 290 {
Sergunb 0:8918a71cdbe9 291 error_t error;
Sergunb 0:8918a71cdbe9 292 bool_t end;
Sergunb 0:8918a71cdbe9 293 size_t n;
Sergunb 0:8918a71cdbe9 294 size_t length;
Sergunb 0:8918a71cdbe9 295 size_t received;
Sergunb 0:8918a71cdbe9 296 IcecastClientContext *context;
Sergunb 0:8918a71cdbe9 297
Sergunb 0:8918a71cdbe9 298 //Retrieve the Icecast client context
Sergunb 0:8918a71cdbe9 299 context = (IcecastClientContext *) param;
Sergunb 0:8918a71cdbe9 300
Sergunb 0:8918a71cdbe9 301 //Main loop
Sergunb 0:8918a71cdbe9 302 while(1)
Sergunb 0:8918a71cdbe9 303 {
Sergunb 0:8918a71cdbe9 304 //Debug message
Sergunb 0:8918a71cdbe9 305 TRACE_INFO("Icecast client: Connecting to server %s port %" PRIu16 "\r\n",
Sergunb 0:8918a71cdbe9 306 context->settings.serverName, context->settings.serverPort);
Sergunb 0:8918a71cdbe9 307
Sergunb 0:8918a71cdbe9 308 //Initiate a connection to the Icecast server
Sergunb 0:8918a71cdbe9 309 error = icecastClientConnect(context);
Sergunb 0:8918a71cdbe9 310
Sergunb 0:8918a71cdbe9 311 //Connection to server failed?
Sergunb 0:8918a71cdbe9 312 if(error)
Sergunb 0:8918a71cdbe9 313 {
Sergunb 0:8918a71cdbe9 314 //Debug message
Sergunb 0:8918a71cdbe9 315 TRACE_ERROR("Icecast client: Connection to server failed!\r\n");
Sergunb 0:8918a71cdbe9 316 //Recovery delay
Sergunb 0:8918a71cdbe9 317 osDelayTask(ICECAST_RECOVERY_DELAY);
Sergunb 0:8918a71cdbe9 318 //Try to reconnect...
Sergunb 0:8918a71cdbe9 319 continue;
Sergunb 0:8918a71cdbe9 320 }
Sergunb 0:8918a71cdbe9 321
Sergunb 0:8918a71cdbe9 322 //Debug message
Sergunb 0:8918a71cdbe9 323 TRACE_INFO("Block size = %" PRIuSIZE "\r\n", context->blockSize);
Sergunb 0:8918a71cdbe9 324
Sergunb 0:8918a71cdbe9 325 //Check block size
Sergunb 0:8918a71cdbe9 326 if(!context->blockSize)
Sergunb 0:8918a71cdbe9 327 {
Sergunb 0:8918a71cdbe9 328 //Close socket
Sergunb 0:8918a71cdbe9 329 socketClose(context->socket);
Sergunb 0:8918a71cdbe9 330 //Recovery delay
Sergunb 0:8918a71cdbe9 331 osDelayTask(ICECAST_RECOVERY_DELAY);
Sergunb 0:8918a71cdbe9 332 //Try to reconnect...
Sergunb 0:8918a71cdbe9 333 continue;
Sergunb 0:8918a71cdbe9 334 }
Sergunb 0:8918a71cdbe9 335
Sergunb 0:8918a71cdbe9 336 //Initialize loop condition variable
Sergunb 0:8918a71cdbe9 337 end = FALSE;
Sergunb 0:8918a71cdbe9 338
Sergunb 0:8918a71cdbe9 339 //Read as much data as possible...
Sergunb 0:8918a71cdbe9 340 while(!end)
Sergunb 0:8918a71cdbe9 341 {
Sergunb 0:8918a71cdbe9 342 //Process the stream block by block
Sergunb 0:8918a71cdbe9 343 length = context->blockSize;
Sergunb 0:8918a71cdbe9 344
Sergunb 0:8918a71cdbe9 345 //Read current block
Sergunb 0:8918a71cdbe9 346 while(!end && length > 0)
Sergunb 0:8918a71cdbe9 347 {
Sergunb 0:8918a71cdbe9 348 //Wait for the buffer to be available for writing
Sergunb 0:8918a71cdbe9 349 osWaitForEvent(&context->writeEvent, INFINITE_DELAY);
Sergunb 0:8918a71cdbe9 350
Sergunb 0:8918a71cdbe9 351 //Enter critical section
Sergunb 0:8918a71cdbe9 352 osAcquireMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 353 //Compute the number of bytes to read at a time
Sergunb 0:8918a71cdbe9 354 n = MIN(length, context->bufferSize - context->bufferLength);
Sergunb 0:8918a71cdbe9 355 //Leave critical section
Sergunb 0:8918a71cdbe9 356 osReleaseMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 357
Sergunb 0:8918a71cdbe9 358 //Check whether the specified data crosses buffer boundaries
Sergunb 0:8918a71cdbe9 359 if((context->writeIndex + n) > context->bufferSize)
Sergunb 0:8918a71cdbe9 360 n = context->bufferSize - context->writeIndex;
Sergunb 0:8918a71cdbe9 361
Sergunb 0:8918a71cdbe9 362 //Receive data
Sergunb 0:8918a71cdbe9 363 error = socketReceive(context->socket, context->streamBuffer +
Sergunb 0:8918a71cdbe9 364 context->writeIndex, n, &received, SOCKET_FLAG_WAIT_ALL);
Sergunb 0:8918a71cdbe9 365
Sergunb 0:8918a71cdbe9 366 //Any error to report?
Sergunb 0:8918a71cdbe9 367 if(error)
Sergunb 0:8918a71cdbe9 368 {
Sergunb 0:8918a71cdbe9 369 //Stop streaming data
Sergunb 0:8918a71cdbe9 370 end = TRUE;
Sergunb 0:8918a71cdbe9 371 }
Sergunb 0:8918a71cdbe9 372 else
Sergunb 0:8918a71cdbe9 373 {
Sergunb 0:8918a71cdbe9 374 //Enter critical section
Sergunb 0:8918a71cdbe9 375 osAcquireMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 376
Sergunb 0:8918a71cdbe9 377 //Increment write index
Sergunb 0:8918a71cdbe9 378 context->writeIndex += n;
Sergunb 0:8918a71cdbe9 379 //Wrap around if necessary
Sergunb 0:8918a71cdbe9 380 if(context->writeIndex >= context->bufferSize)
Sergunb 0:8918a71cdbe9 381 context->writeIndex -= context->bufferSize;
Sergunb 0:8918a71cdbe9 382
Sergunb 0:8918a71cdbe9 383 //Update buffer length
Sergunb 0:8918a71cdbe9 384 context->bufferLength += n;
Sergunb 0:8918a71cdbe9 385 //Check whether the buffer is available for writing
Sergunb 0:8918a71cdbe9 386 if(context->bufferLength < context->bufferSize)
Sergunb 0:8918a71cdbe9 387 osSetEvent(&context->writeEvent);
Sergunb 0:8918a71cdbe9 388 //Check whether the buffer is available for reading
Sergunb 0:8918a71cdbe9 389 if(context->bufferLength > 0)
Sergunb 0:8918a71cdbe9 390 osSetEvent(&context->readEvent);
Sergunb 0:8918a71cdbe9 391
Sergunb 0:8918a71cdbe9 392 //Leave critical section
Sergunb 0:8918a71cdbe9 393 osReleaseMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 394
Sergunb 0:8918a71cdbe9 395 //Update the total number of bytes that have been received
Sergunb 0:8918a71cdbe9 396 context->totalLength += n;
Sergunb 0:8918a71cdbe9 397 //Number of remaining data to read
Sergunb 0:8918a71cdbe9 398 length -= n;
Sergunb 0:8918a71cdbe9 399 }
Sergunb 0:8918a71cdbe9 400 }
Sergunb 0:8918a71cdbe9 401
Sergunb 0:8918a71cdbe9 402 //Debug message
Sergunb 0:8918a71cdbe9 403 TRACE_DEBUG("Icecast client: Total bytes received = %" PRIuSIZE "\r\n", context->totalLength);
Sergunb 0:8918a71cdbe9 404
Sergunb 0:8918a71cdbe9 405 //Check whether the metadata block should be read
Sergunb 0:8918a71cdbe9 406 if(!end)
Sergunb 0:8918a71cdbe9 407 {
Sergunb 0:8918a71cdbe9 408 //Process the metadata block
Sergunb 0:8918a71cdbe9 409 error = icecastClientProcessMetadata(context);
Sergunb 0:8918a71cdbe9 410 //Any error to report?
Sergunb 0:8918a71cdbe9 411 if(error) end = TRUE;
Sergunb 0:8918a71cdbe9 412 }
Sergunb 0:8918a71cdbe9 413 }
Sergunb 0:8918a71cdbe9 414
Sergunb 0:8918a71cdbe9 415 //Close connection
Sergunb 0:8918a71cdbe9 416 socketClose(context->socket);
Sergunb 0:8918a71cdbe9 417 }
Sergunb 0:8918a71cdbe9 418 }
Sergunb 0:8918a71cdbe9 419
Sergunb 0:8918a71cdbe9 420
Sergunb 0:8918a71cdbe9 421 /**
Sergunb 0:8918a71cdbe9 422 * @brief Connect to the specified Icecast server
Sergunb 0:8918a71cdbe9 423 * @param[in] context Pointer to the Icecast client context
Sergunb 0:8918a71cdbe9 424 **/
Sergunb 0:8918a71cdbe9 425
Sergunb 0:8918a71cdbe9 426 error_t icecastClientConnect(IcecastClientContext *context)
Sergunb 0:8918a71cdbe9 427 {
Sergunb 0:8918a71cdbe9 428 error_t error;
Sergunb 0:8918a71cdbe9 429 size_t length;
Sergunb 0:8918a71cdbe9 430 uint16_t serverPort;
Sergunb 0:8918a71cdbe9 431 IpAddr serverIpAddr;
Sergunb 0:8918a71cdbe9 432 NetInterface *interface;
Sergunb 0:8918a71cdbe9 433
Sergunb 0:8918a71cdbe9 434 //Underlying network interface
Sergunb 0:8918a71cdbe9 435 interface = context->settings.interface;
Sergunb 0:8918a71cdbe9 436
Sergunb 0:8918a71cdbe9 437 //Force traffic to go through a proxy server?
Sergunb 0:8918a71cdbe9 438 if(strcmp(interface->proxyName, ""))
Sergunb 0:8918a71cdbe9 439 {
Sergunb 0:8918a71cdbe9 440 //Icecast request template
Sergunb 0:8918a71cdbe9 441 const char_t requestTemplate[] =
Sergunb 0:8918a71cdbe9 442 "GET http://%s:%" PRIu16 "%s HTTP/1.1\r\n"
Sergunb 0:8918a71cdbe9 443 "Host: %s:%" PRIu16 "\r\n"
Sergunb 0:8918a71cdbe9 444 "User-agent: UserAgent\r\n"
Sergunb 0:8918a71cdbe9 445 "Icy-MetaData: 1\r\n"
Sergunb 0:8918a71cdbe9 446 "Connection: close\r\n"
Sergunb 0:8918a71cdbe9 447 "\r\n";
Sergunb 0:8918a71cdbe9 448
Sergunb 0:8918a71cdbe9 449 //Format Icecast request
Sergunb 0:8918a71cdbe9 450 length = sprintf(context->buffer, requestTemplate,
Sergunb 0:8918a71cdbe9 451 context->settings.serverName, context->settings.serverPort,
Sergunb 0:8918a71cdbe9 452 context->settings.resource, context->settings.serverName,
Sergunb 0:8918a71cdbe9 453 context->settings.serverPort);
Sergunb 0:8918a71cdbe9 454
Sergunb 0:8918a71cdbe9 455 //The specified proxy server can be either an IP or a host name
Sergunb 0:8918a71cdbe9 456 error = getHostByName(interface, interface->proxyName, &serverIpAddr, 0);
Sergunb 0:8918a71cdbe9 457 //Unable to resolve server name?
Sergunb 0:8918a71cdbe9 458 if(error)
Sergunb 0:8918a71cdbe9 459 return error;
Sergunb 0:8918a71cdbe9 460
Sergunb 0:8918a71cdbe9 461 //Proxy server port
Sergunb 0:8918a71cdbe9 462 serverPort = interface->proxyPort;
Sergunb 0:8918a71cdbe9 463 }
Sergunb 0:8918a71cdbe9 464 else
Sergunb 0:8918a71cdbe9 465 {
Sergunb 0:8918a71cdbe9 466 //Icecast request template
Sergunb 0:8918a71cdbe9 467 const char_t requestTemplate[] =
Sergunb 0:8918a71cdbe9 468 "GET %s HTTP/1.1\r\n"
Sergunb 0:8918a71cdbe9 469 "Host: %s\r\n"
Sergunb 0:8918a71cdbe9 470 "User-agent: UserAgent\r\n"
Sergunb 0:8918a71cdbe9 471 "Icy-MetaData: 1\r\n"
Sergunb 0:8918a71cdbe9 472 "Connection: close\r\n"
Sergunb 0:8918a71cdbe9 473 "\r\n";
Sergunb 0:8918a71cdbe9 474
Sergunb 0:8918a71cdbe9 475 //Format Icecast request
Sergunb 0:8918a71cdbe9 476 length = sprintf(context->buffer, requestTemplate,
Sergunb 0:8918a71cdbe9 477 context->settings.resource, context->settings.serverName);
Sergunb 0:8918a71cdbe9 478
Sergunb 0:8918a71cdbe9 479 //The specified Icecast server can be either an IP or a host name
Sergunb 0:8918a71cdbe9 480 error = getHostByName(interface, context->settings.serverName, &serverIpAddr, 0);
Sergunb 0:8918a71cdbe9 481 //Unable to resolve server name?
Sergunb 0:8918a71cdbe9 482 if(error)
Sergunb 0:8918a71cdbe9 483 return error;
Sergunb 0:8918a71cdbe9 484
Sergunb 0:8918a71cdbe9 485 //Icecast server port
Sergunb 0:8918a71cdbe9 486 serverPort = context->settings.serverPort;
Sergunb 0:8918a71cdbe9 487 }
Sergunb 0:8918a71cdbe9 488
Sergunb 0:8918a71cdbe9 489 //Open a TCP socket
Sergunb 0:8918a71cdbe9 490 context->socket = socketOpen(SOCKET_TYPE_STREAM, SOCKET_IP_PROTO_TCP);
Sergunb 0:8918a71cdbe9 491 //Failed to open socket?
Sergunb 0:8918a71cdbe9 492 if(!context->socket)
Sergunb 0:8918a71cdbe9 493 return ERROR_OUT_OF_RESOURCES;
Sergunb 0:8918a71cdbe9 494
Sergunb 0:8918a71cdbe9 495 //Start of exception handling block
Sergunb 0:8918a71cdbe9 496 do
Sergunb 0:8918a71cdbe9 497 {
Sergunb 0:8918a71cdbe9 498 //Associate the socket with the relevant interface
Sergunb 0:8918a71cdbe9 499 error = socketBindToInterface(context->socket, interface);
Sergunb 0:8918a71cdbe9 500 //Unable to bind the socket to the desired interface?
Sergunb 0:8918a71cdbe9 501 if(error)
Sergunb 0:8918a71cdbe9 502 break;
Sergunb 0:8918a71cdbe9 503
Sergunb 0:8918a71cdbe9 504 //Adjust receive timeout
Sergunb 0:8918a71cdbe9 505 error = socketSetTimeout(context->socket, ICECAST_CLIENT_TIMEOUT);
Sergunb 0:8918a71cdbe9 506 //Any error to report?
Sergunb 0:8918a71cdbe9 507 if(error)
Sergunb 0:8918a71cdbe9 508 break;
Sergunb 0:8918a71cdbe9 509
Sergunb 0:8918a71cdbe9 510 //Connect to the server
Sergunb 0:8918a71cdbe9 511 error = socketConnect(context->socket, &serverIpAddr, serverPort);
Sergunb 0:8918a71cdbe9 512 //Connection with server failed?
Sergunb 0:8918a71cdbe9 513 if(error)
Sergunb 0:8918a71cdbe9 514 break;
Sergunb 0:8918a71cdbe9 515
Sergunb 0:8918a71cdbe9 516 //Display Icecast request for debugging purpose
Sergunb 0:8918a71cdbe9 517 TRACE_DEBUG(context->buffer);
Sergunb 0:8918a71cdbe9 518
Sergunb 0:8918a71cdbe9 519 //Send request to the server
Sergunb 0:8918a71cdbe9 520 error = socketSend(context->socket, context->buffer,
Sergunb 0:8918a71cdbe9 521 length, NULL, SOCKET_FLAG_WAIT_ACK);
Sergunb 0:8918a71cdbe9 522 //Failed to send the request?
Sergunb 0:8918a71cdbe9 523 if(error)
Sergunb 0:8918a71cdbe9 524 break;
Sergunb 0:8918a71cdbe9 525
Sergunb 0:8918a71cdbe9 526 //Parse response header
Sergunb 0:8918a71cdbe9 527 while(1)
Sergunb 0:8918a71cdbe9 528 {
Sergunb 0:8918a71cdbe9 529 char_t *separator;
Sergunb 0:8918a71cdbe9 530 char_t *property;
Sergunb 0:8918a71cdbe9 531 char_t *value;
Sergunb 0:8918a71cdbe9 532
Sergunb 0:8918a71cdbe9 533 //Read a line from the response header
Sergunb 0:8918a71cdbe9 534 error = socketReceive(context->socket, context->buffer,
Sergunb 0:8918a71cdbe9 535 ICECAST_CLIENT_METADATA_MAX_SIZE, &length, SOCKET_FLAG_BREAK_CRLF);
Sergunb 0:8918a71cdbe9 536 //Failed to read data?
Sergunb 0:8918a71cdbe9 537 if(error)
Sergunb 0:8918a71cdbe9 538 break;
Sergunb 0:8918a71cdbe9 539
Sergunb 0:8918a71cdbe9 540 //Properly terminate the string with a NULL character
Sergunb 0:8918a71cdbe9 541 context->buffer[length] = '\0';
Sergunb 0:8918a71cdbe9 542
Sergunb 0:8918a71cdbe9 543 //The end of the header has been reached?
Sergunb 0:8918a71cdbe9 544 if(!strcmp(context->buffer, "\r\n"))
Sergunb 0:8918a71cdbe9 545 break;
Sergunb 0:8918a71cdbe9 546
Sergunb 0:8918a71cdbe9 547 //Check whether a separator is present
Sergunb 0:8918a71cdbe9 548 separator = strchr(context->buffer, ':');
Sergunb 0:8918a71cdbe9 549
Sergunb 0:8918a71cdbe9 550 //Separator found?
Sergunb 0:8918a71cdbe9 551 if(separator)
Sergunb 0:8918a71cdbe9 552 {
Sergunb 0:8918a71cdbe9 553 //Split the line
Sergunb 0:8918a71cdbe9 554 *separator = '\0';
Sergunb 0:8918a71cdbe9 555
Sergunb 0:8918a71cdbe9 556 //Get property name and value
Sergunb 0:8918a71cdbe9 557 property = strTrimWhitespace(context->buffer);
Sergunb 0:8918a71cdbe9 558 value = strTrimWhitespace(separator + 1);
Sergunb 0:8918a71cdbe9 559
Sergunb 0:8918a71cdbe9 560 //Debug message
Sergunb 0:8918a71cdbe9 561 TRACE_INFO("<%s>=<%s>\r\n", property, value);
Sergunb 0:8918a71cdbe9 562
Sergunb 0:8918a71cdbe9 563 //Icy-Metaint property found?
Sergunb 0:8918a71cdbe9 564 if(!strcasecmp(property, "Icy-Metaint"))
Sergunb 0:8918a71cdbe9 565 {
Sergunb 0:8918a71cdbe9 566 //Retrieve the block size used by the Icecast server
Sergunb 0:8918a71cdbe9 567 context->blockSize = atoi(value);
Sergunb 0:8918a71cdbe9 568 }
Sergunb 0:8918a71cdbe9 569 }
Sergunb 0:8918a71cdbe9 570 }
Sergunb 0:8918a71cdbe9 571
Sergunb 0:8918a71cdbe9 572 //End of exception handling block
Sergunb 0:8918a71cdbe9 573 } while(0);
Sergunb 0:8918a71cdbe9 574
Sergunb 0:8918a71cdbe9 575 //Check whether an error occurred
Sergunb 0:8918a71cdbe9 576 if(error)
Sergunb 0:8918a71cdbe9 577 {
Sergunb 0:8918a71cdbe9 578 //Clean up side effects
Sergunb 0:8918a71cdbe9 579 socketClose(context->socket);
Sergunb 0:8918a71cdbe9 580 }
Sergunb 0:8918a71cdbe9 581
Sergunb 0:8918a71cdbe9 582 //Return status code
Sergunb 0:8918a71cdbe9 583 return error;
Sergunb 0:8918a71cdbe9 584 }
Sergunb 0:8918a71cdbe9 585
Sergunb 0:8918a71cdbe9 586
Sergunb 0:8918a71cdbe9 587 /**
Sergunb 0:8918a71cdbe9 588 * @brief Decode metadata block
Sergunb 0:8918a71cdbe9 589 * @param[in] context Pointer to the Icecast client context
Sergunb 0:8918a71cdbe9 590 **/
Sergunb 0:8918a71cdbe9 591
Sergunb 0:8918a71cdbe9 592 error_t icecastClientProcessMetadata(IcecastClientContext *context)
Sergunb 0:8918a71cdbe9 593 {
Sergunb 0:8918a71cdbe9 594 error_t error;
Sergunb 0:8918a71cdbe9 595 size_t n;
Sergunb 0:8918a71cdbe9 596 size_t length;
Sergunb 0:8918a71cdbe9 597 size_t metadataLength;
Sergunb 0:8918a71cdbe9 598
Sergunb 0:8918a71cdbe9 599 //The metadata block begins with a single byte which indicates
Sergunb 0:8918a71cdbe9 600 //how many 16-byte segments need to be read
Sergunb 0:8918a71cdbe9 601 error = socketReceive(context->socket, context->buffer,
Sergunb 0:8918a71cdbe9 602 sizeof(uint8_t), &length, SOCKET_FLAG_WAIT_ALL);
Sergunb 0:8918a71cdbe9 603
Sergunb 0:8918a71cdbe9 604 //Any error to report?
Sergunb 0:8918a71cdbe9 605 if(error)
Sergunb 0:8918a71cdbe9 606 return error;
Sergunb 0:8918a71cdbe9 607 //Make sure the expected number of bytes have been received
Sergunb 0:8918a71cdbe9 608 if(length != sizeof(uint8_t))
Sergunb 0:8918a71cdbe9 609 return ERROR_INVALID_METADATA;
Sergunb 0:8918a71cdbe9 610
Sergunb 0:8918a71cdbe9 611 //Compute the length of the following metadata block
Sergunb 0:8918a71cdbe9 612 metadataLength = context->buffer[0] * 16;
Sergunb 0:8918a71cdbe9 613 //Limit the number of bytes to read
Sergunb 0:8918a71cdbe9 614 n = MIN(metadataLength, ICECAST_CLIENT_METADATA_MAX_SIZE - 1);
Sergunb 0:8918a71cdbe9 615
Sergunb 0:8918a71cdbe9 616 //Read the metadata information
Sergunb 0:8918a71cdbe9 617 error = socketReceive(context->socket, context->buffer,
Sergunb 0:8918a71cdbe9 618 n, &length, SOCKET_FLAG_WAIT_ALL);
Sergunb 0:8918a71cdbe9 619
Sergunb 0:8918a71cdbe9 620 //Any error to report?
Sergunb 0:8918a71cdbe9 621 if(error)
Sergunb 0:8918a71cdbe9 622 return error;
Sergunb 0:8918a71cdbe9 623 //Make sure the expected number of bytes have been received
Sergunb 0:8918a71cdbe9 624 if(length != n)
Sergunb 0:8918a71cdbe9 625 return ERROR_INVALID_METADATA;
Sergunb 0:8918a71cdbe9 626
Sergunb 0:8918a71cdbe9 627 //Enter critical section
Sergunb 0:8918a71cdbe9 628 osAcquireMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 629
Sergunb 0:8918a71cdbe9 630 //Save metadata information
Sergunb 0:8918a71cdbe9 631 memcpy(context->metadata, context->buffer, n);
Sergunb 0:8918a71cdbe9 632 //Terminate the string properly
Sergunb 0:8918a71cdbe9 633 context->metadata[n] = '\0';
Sergunb 0:8918a71cdbe9 634 //Record the length of the metadata
Sergunb 0:8918a71cdbe9 635 context->metadataLength = n;
Sergunb 0:8918a71cdbe9 636
Sergunb 0:8918a71cdbe9 637 //Leave critical section
Sergunb 0:8918a71cdbe9 638 osReleaseMutex(&context->mutex);
Sergunb 0:8918a71cdbe9 639
Sergunb 0:8918a71cdbe9 640 //Any metadata information received?
Sergunb 0:8918a71cdbe9 641 if(n > 0)
Sergunb 0:8918a71cdbe9 642 {
Sergunb 0:8918a71cdbe9 643 //Debug message
Sergunb 0:8918a71cdbe9 644 TRACE_DEBUG("Icecast client: Metadata = <%s>\r\n", context->metadata);
Sergunb 0:8918a71cdbe9 645 }
Sergunb 0:8918a71cdbe9 646
Sergunb 0:8918a71cdbe9 647 //Compute the number of bytes that have not been processed
Sergunb 0:8918a71cdbe9 648 metadataLength -= n;
Sergunb 0:8918a71cdbe9 649
Sergunb 0:8918a71cdbe9 650 //Read the complete metadata
Sergunb 0:8918a71cdbe9 651 while(metadataLength > 0)
Sergunb 0:8918a71cdbe9 652 {
Sergunb 0:8918a71cdbe9 653 //Compute the number of data to read at a time
Sergunb 0:8918a71cdbe9 654 n = MIN(metadataLength, ICECAST_CLIENT_METADATA_MAX_SIZE);
Sergunb 0:8918a71cdbe9 655
Sergunb 0:8918a71cdbe9 656 //Drop incoming data...
Sergunb 0:8918a71cdbe9 657 error = socketReceive(context->socket, context->buffer,
Sergunb 0:8918a71cdbe9 658 n, &length, SOCKET_FLAG_WAIT_ALL);
Sergunb 0:8918a71cdbe9 659
Sergunb 0:8918a71cdbe9 660 //Any error to report?
Sergunb 0:8918a71cdbe9 661 if(error)
Sergunb 0:8918a71cdbe9 662 return error;
Sergunb 0:8918a71cdbe9 663 //Make sure the expected number of bytes have been received
Sergunb 0:8918a71cdbe9 664 if(length != n)
Sergunb 0:8918a71cdbe9 665 return ERROR_INVALID_METADATA;
Sergunb 0:8918a71cdbe9 666
Sergunb 0:8918a71cdbe9 667 //Update byte counter
Sergunb 0:8918a71cdbe9 668 metadataLength -= n;
Sergunb 0:8918a71cdbe9 669 }
Sergunb 0:8918a71cdbe9 670
Sergunb 0:8918a71cdbe9 671 //Successful processing
Sergunb 0:8918a71cdbe9 672 return NO_ERROR;
Sergunb 0:8918a71cdbe9 673 }
Sergunb 0:8918a71cdbe9 674
Sergunb 0:8918a71cdbe9 675 #endif
Sergunb 0:8918a71cdbe9 676
Sergunb 0:8918a71cdbe9 677