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