MHEG-5  19.3.0
MHEG-5 Documentation
stmr_msp.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright © 2014 The DTVKit Open Software Foundation Ltd (www.dtvkit.org)
3  * Copyright © 2010 Ocean Blue Software Ltd
4  *
5  * This file is part of a DTVKit Software Component
6  * You are permitted to copy, modify or distribute this file subject to the terms
7  * of the DTVKit 1.0 Licence which can be found in licence.txt or at www.dtvkit.org
8  *
9  * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
10  * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES
11  * OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * If you or your organisation is not a member of DTVKit then you have access
14  * to this source code outside of the terms of the licence agreement
15  * and you are expected to delete this and any associated files immediately.
16  * Further information on DTVKit, membership and terms can be found at www.dtvkit.org
17  *******************************************************************************/
25 /*---includes for this file--------------------------------------------------*/
26 #include <assert.h>
27 #include <string.h>
28 
29 #include "stb_os.h"
30 #include "http_interface.h"
31 #include "glue_memory.h"
32 #include "glue_queue.h"
33 
34 #include "mh5base.h"
35 #include "mh5profile.h"
36 #include "mh5streamer.h"
37 #include "stmr_msp.h"
38 #include "stmr_util.h"
39 #include "stmr_common.h"
40 
41 /*---constant definitions for this file--------------------------------------*/
42 
43 #define MAX_MEASURE_SIZE (0x7fffffff)
44 
45 
46 
47 #define USE_MAGIC
48 
49 #ifdef USE_MAGIC
50 #define GOOD_MAGIC 0xdeadbeef
51 #define BAD_MAGIC 0xfefefefe
52 #define SET_MAGIC(r) do { r->magic = GOOD_MAGIC; } while (0)
53 #define VERIFY_MAGIC(r) assert(r->magic == GOOD_MAGIC)
54 #define CLEAR_MAGIC(r) do { r->magic = BAD_MAGIC; } while (0)
55 #else
56 #define SET_MAGIC(r)
57 #define VERIFY_MAGIC(r)
58 #define CLEAR_MAGIC(r)
59 #endif
60 
61 #define DBG(x)
62 
63 
64 /*---local typedef structs for this file-------------------------------------*/
65 
66 typedef struct sMeasureRequest
67 {
68  /* Magic */
69  U32BIT magic;
70 
71  /* Download ID */
72  U32BIT downloadId;
73 
74  /* Request ID */
75  U32BIT requestId;
76 
77  /* HTTP handle */
78  HttpRequest_t handle;
79 
80  /* Response code and status */
81  S32BIT code;
82  E_HttpStatus status;
83 
84  /* Measurement */
85  U32BIT startTime;
86  U32BIT finishTime;
87  U64BIT receivedBytes;
88  U64BIT maxReceivedBytes;
89 
90  /* Next request */
91  struct sMeasureRequest *next;
93 
94 /*---local function definitions----------------------------------------------*/
95 
96 /*---global function definitions---------------------------------------------*/
97 
98 static MeasureRequest* FindRequestById(U32BIT requestId);
99 static BOOLEAN HeaderCallback(void *userdata, U32BIT downloadId,
100  HttpResponse_t *response);
101 static BOOLEAN ContentCallback(void *userdata, U32BIT downloadId,
102  HttpResponse_t *response);
103 static BOOLEAN HandleMeasureData(MeasureRequest *request, U32BIT bytes);
104 static BOOLEAN HandleMeasureEnd(MeasureRequest *request,
105  HttpResponse_t *response);
106 
107 /*---local (static) variable declarations for this file----------------------*/
108 
109 static MeasureRequest *measureRequestList = NULL;
110 
111 
119 U32BIT MHEG5CreateMeasureRequest(U32BIT requestId, char *url, S32BIT maxBytes)
120 {
121  char rangeBuffer[MHEG5_MAX_RANGE_BUFFER];
122  MeasureRequest *request;
123  U32BIT downloadId;
124 
125  downloadId = 0;
126  request = MHEG5getMem(sizeof *request);
127  if (request != NULL)
128  {
129  SET_MAGIC(request);
130 
131  /* Download ID is a unique ID */
132  request->downloadId = MHEG5GetUniqueId();
133 
134  request->requestId = requestId;
135 
136  request->handle = NULL;
137  request->code = 0;
138  request->status = HTTP_STATUS_OTHER_ERROR;
139 
140  request->startTime = 0;
141  request->finishTime = 0;
142 
143  request->next = measureRequestList;
144  measureRequestList = request;
145 
146  strcpy(rangeBuffer, "0-");
147  if (maxBytes > 0)
148  {
149  sprintf(&rangeBuffer[2], "%d", (int)maxBytes);
150  }
151  else
152  {
153  maxBytes = 0x7fffffff;
154  }
155 
156  ULL_Set32(request->receivedBytes, 0);
157  ULL_Set32(request->maxReceivedBytes, maxBytes);
158 
159  request->handle = httpCreateStreamRequest((U8BIT *)url,
160  (U8BIT *)rangeBuffer,
161  HeaderCallback,
162  ContentCallback,
163  request->downloadId,
164  request);
165  if (request->handle != NULL)
166  {
167  downloadId = request->downloadId;
168  }
169  else
170  {
171  /* Failed to create an HTTP request */
172  MHEG5freeMem(request);
173  request = NULL;
174  }
175  }
176 
177  return downloadId;
178 }
179 
185 void MHEG5StartMeasureRequest(U32BIT downloadId)
186 {
187  MeasureRequest *request;
188 
189  request = FindRequestById(downloadId);
190  if (request != NULL)
191  {
192  VERIFY_MAGIC(request);
193 
194  assert(request->handle != NULL);
195  request->startTime = STB_OSGetClockMilliseconds();
196  httpStartRequest(request->handle);
197  }
198 }
199 
205 S32BIT MHEG5GetMeasureResponseCode(U32BIT downloadId)
206 {
207  MeasureRequest *request;
208  S32BIT code = 0;
209 
210  request = FindRequestById(downloadId);
211  if (request != NULL)
212  {
213  VERIFY_MAGIC(request);
214 
215  code = request->code;
216  }
217 
218  return code;
219 }
220 
226 S32BIT MHEG5GetMeasureStatus(U32BIT downloadId)
227 {
228  MeasureRequest *request;
229  S32BIT status = HTTP_STATUS_OTHER_ERROR;
230 
231  request = FindRequestById(downloadId);
232  if (request != NULL)
233  {
234  VERIFY_MAGIC(request);
235 
236  status = request->status;
237  }
238 
239  return status;
240 }
241 
248 U8BIT* MHEG5GetMeasureRedirect(U32BIT downloadId)
249 {
250  MeasureRequest *request;
251  U8BIT *redirectUrl = NULL;
252 
253  request = FindRequestById(downloadId);
254  if (request != NULL)
255  {
256  VERIFY_MAGIC(request);
257 
258  redirectUrl = httpGetRequestRedirect(request->handle);
259  }
260 
261  return redirectUrl;
262 }
263 
269 void MHEG5ProcessMeasureRequest(U32BIT downloadId)
270 {
271  U64BIT numerator;
272  MeasureRequest *request;
273  U32BIT timeDiff, speed;
274 
275  request = FindRequestById(downloadId);
276  if (request != NULL)
277  {
278  /* Report speed in terms of bytes / second */
279  if (ULL_IsValid(request->receivedBytes))
280  {
281  timeDiff = request->finishTime - request->startTime;
282  if (timeDiff == 0)
283  {
284  /* Avoid the division by zero */
285  speed = -1;
286  }
287  else
288  {
289  /* speed = receivedBytes * 1000 / timeDiff */
290  numerator = request->receivedBytes;
291  ULL_Mul32(numerator, 1000);
292  ULL_Div32(numerator, timeDiff);
293  speed = ULL_Get32(numerator);
294  }
295  }
296  else
297  {
298  speed = -1;
299  }
300 
301  MHEG5StreamerNotifyStreamingPerformance(request->requestId, speed);
302  }
303 }
304 
310 void MHEG5StopMeasureRequest(U32BIT downloadId)
311 {
312  MeasureRequest *request;
313 
314  request = FindRequestById(downloadId);
315  if (request != NULL)
316  {
317  VERIFY_MAGIC(request);
318 
319  assert(request->handle != NULL);
320  httpStopRequest(request->handle);
321  }
322 }
323 
329 void MHEG5DestroyMeasureRequest(U32BIT downloadId)
330 {
331  MeasureRequest **pRequest, *request;
332 
333  pRequest = &measureRequestList;
334  while (*pRequest != NULL)
335  {
336  request = *pRequest;
337  if (request->downloadId == downloadId)
338  {
339  VERIFY_MAGIC(request);
340 
341  assert(request->handle != NULL);
342  httpDestroyRequest(request->handle);
343  request->handle = NULL;
344 
345  *pRequest = request->next;
346  MHEG5freeMem(request);
347 
348  break;
349  }
350  else
351  {
352  pRequest = &request->next;
353  }
354  }
355 }
356 
357 /*******************
358  * LOCAL FUNCTION *
359  ********************/
360 
361 
367 static MeasureRequest* FindRequestById(U32BIT downloadId)
368 {
369  MeasureRequest *request;
370 
371  request = measureRequestList;
372  while (request != NULL && request->downloadId != downloadId)
373  {
374  request = request->next;
375  }
376 
377  return request;
378 }
379 
387 static BOOLEAN HeaderCallback(void *userdata, U32BIT downloadId,
388  HttpResponse_t *response)
389 {
390  MeasureRequest *request = userdata;
391 
392  VERIFY_MAGIC(request);
393 
394  if (response->data_len <= 2)
395  {
396  /* End of headers */
397  request->code = response->code;
398  }
399 
400  return TRUE;
401 }
402 
410 static BOOLEAN ContentCallback(void *userdata, U32BIT downloadId,
411  HttpResponse_t *response)
412 {
413  MeasureRequest *request = userdata;
414  BOOLEAN more = TRUE;
415 
416  VERIFY_MAGIC(request);
417 
418  if (response->status == HTTP_STATUS_WAIT)
419  {
420  more = HandleMeasureData(request, response->data_len);
421  }
422  else
423  {
424  more = HandleMeasureEnd(request, response);
425  }
426 
427  return more;
428 }
429 
436 static BOOLEAN HandleMeasureData(MeasureRequest *request, U32BIT bytes)
437 {
438  MHEG5eventMessage_t event;
439  E_MhegErr cqu_err;
440  BOOLEAN more = TRUE;
441 
442  if (request->code == 200 || request->code == 206)
443  {
444  /* Update bytes received */
445  ULL_Add32(request->receivedBytes, bytes);
446 
447  if (ULL_Compare(request->receivedBytes,
448  request->maxReceivedBytes) >= 0)
449  {
450  /* Update finish time */
451  request->finishTime = STB_OSGetClockMilliseconds();
452  more = FALSE;
453  }
454  }
455 
456  if (!more)
457  {
458  /* Update status */
459  request->status = HTTP_STATUS_OK;
460 
461  /* HandleMeasureEnd will not be called, as more=FALSE. So the
462  * event must be sent here.
463  */
464  event.proc_msg_func = (F_MSG_PROCESS)MHEG5StreamerHandle;
465  event.data_type = DT_VALUE;
466  event.data.streamer.requestId = request->downloadId;
467  event.data.streamer.eventType = MHEG5_STREAMER_EVENT_MSP_DOWNLOAD_DONE;
468 
469  cqu_err = VQ_PutMsg(&event, PRTY_NORMAL);
470  if (cqu_err != MHERR_OK)
471  {
472  DBG(("HandleMeasureData: Cannot send MHEG5_STREAMER_EVENT_MSP_DOWNLOAD_DONE event\n"));
473  }
474  }
475 
476  return more;
477 }
478 
485 static BOOLEAN HandleMeasureEnd(MeasureRequest *request,
486  HttpResponse_t *response)
487 {
488  MHEG5eventMessage_t event;
489  E_MhegErr cqu_err;
490 
491  /* Perform the following only if the request hasn't finished yet */
492  if (request->finishTime == 0)
493  {
494  /* Update status */
495  request->status = response->status;
496 
497  /* Update finish time */
498  request->finishTime = STB_OSGetClockMilliseconds();
499 
500  event.proc_msg_func = (F_MSG_PROCESS)MHEG5StreamerHandle;
501  event.data_type = DT_VALUE;
502  event.data.streamer.requestId = request->downloadId;
503  event.data.streamer.eventType = MHEG5_STREAMER_EVENT_MSP_DOWNLOAD_DONE;
504 
505  cqu_err = VQ_PutMsg(&event, PRTY_NORMAL);
506  if (cqu_err != MHERR_OK)
507  {
508  DBG(("HandleMeasureEnd: Cannot send MHEG5_STREAMER_EVENT_MSP_DOWNLOAD_DONE event %d\n", cqu_err));
509  }
510  }
511  return TRUE;
512 }
513 
U32BIT STB_OSGetClockMilliseconds(void)
Get Current Computer Clock Time.
Basis MHEG5 data types.
E_MhegErr VQ_PutMsg(S_MhegMessage *pMsg, E_PRIORITY priority)
Post event or section message on queue. Copies data into queue.
Definition: glue_queue.c:248
void MHEG5StopMeasureRequest(U32BIT downloadId)
Stop HTTP streaming performance measurement request.
Definition: stmr_msp.c:310
Utilitiy functions for IC Streamer.
U32BIT MHEG5GetUniqueId(void)
Return a unique ID. The ID is a non-zero 32-bit value. It is guaranteed to be unique for the first 0x...
Definition: stmr_util.c:98
void httpStartRequest(HttpRequest_t request)
Start an HTTP request. Everything related to the request is passed through the callback that was regi...
Manages the interface between MHEG5 Engine and the HTTP component.
Common header internal to IC streamer.
MHEG5 queue.
S32BIT MHEG5GetMeasureStatus(U32BIT downloadId)
Return HTTP status of performance measurement request.
Definition: stmr_msp.c:226
void MHEG5StartMeasureRequest(U32BIT downloadId)
Start HTTP streaming performance measurement request.
Definition: stmr_msp.c:185
void(* F_MSG_PROCESS)(void *data)
Function to Process voyager message.
Definition: glue_queue.h:70
U8BIT * MHEG5GetMeasureRedirect(U32BIT downloadId)
Return the redirection URL for a request that was redirected (HTTP status 3xx).
Definition: stmr_msp.c:248
Memory functions.
API for IC streamer.
U8BIT * httpGetRequestRedirect(HttpRequest_t request)
Return the URL that the request is redirected to (valid only for response codes of 3xx)...
This file defines the profile for the MHEG engine.
S32BIT MHEG5GetMeasureResponseCode(U32BIT downloadId)
Return response code for performance measurement request.
Definition: stmr_msp.c:205
void MHEG5DestroyMeasureRequest(U32BIT downloadId)
Destroy HTTP streaming performance measurement request.
Definition: stmr_msp.c:329
void httpStopRequest(HttpRequest_t request)
Stop an HTTP request. This function does not destroy the request; this is done using httpDestroyReque...
U32BIT MHEG5CreateMeasureRequest(U32BIT requestId, char *url, S32BIT maxBytes)
Create HTTP streaming performance measurement request.
Definition: stmr_msp.c:119
void httpDestroyRequest(HttpRequest_t request)
Destroy an HTTP request.
IC Streamer performance measurement.
void MHEG5StreamerHandle(MHEG5StreamerEventParams_t *params)
Process an MHEG5StreamerEvent message The event is passed onto the streamer module for processing...
void MHEG5StreamerNotifyStreamingPerformance(U32BIT requestId, U32BIT speed)
Notify measured streaming performance (speed).
HttpRequest_t httpCreateStreamRequest(U8BIT *url, U8BIT *range, HttpCallback_t header_callback, HttpCallback_t callback, U32BIT request_id, void *userdata)
Create an HTTP request for stream media.
void MHEG5ProcessMeasureRequest(U32BIT downloadId)
Process HTTP streaming performance measurement request.
Definition: stmr_msp.c:269
Header file - Function prototypes for operating system.