Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 17:10:13 by
