856 lines
28 KiB
C
856 lines
28 KiB
C
|
#include <string.h>
|
||
|
#include "esp_types.h"
|
||
|
#include "stdlib.h"
|
||
|
#include "stdio.h"
|
||
|
#include "freertos/FreeRTOS.h"
|
||
|
#include "freertos/task.h"
|
||
|
#include "freertos/semphr.h"
|
||
|
#include "freertos/queue.h"
|
||
|
|
||
|
#include "lwip/sockets.h"
|
||
|
#include "lwip/err.h"
|
||
|
#include "lwip/dns.h"
|
||
|
#include "lwip/netdb.h"
|
||
|
#include "lwip/sys.h"
|
||
|
#include "errno.h"
|
||
|
#include "audio_log.h"
|
||
|
#include "inc/DownloadTask.h"
|
||
|
#include "inc/M3u8.h"
|
||
|
#include "EspAudioCom.h"
|
||
|
#include "EspAudio.h"
|
||
|
|
||
|
#include "inc/MediaDecoderTask.h"
|
||
|
#include "Storage.h"
|
||
|
#include "MediaHal.h"
|
||
|
#include "Utility.h"
|
||
|
|
||
|
#define PRIO_DOWNLOAD 19
|
||
|
#define DEFAULT_AAC_SEQ 0xFFFFFFFF
|
||
|
#define REQUEST_BUF_LEN 1024
|
||
|
#define RECV_BUF_LEN 1500
|
||
|
|
||
|
|
||
|
#if 1
|
||
|
#define DEBUGHTTP printf
|
||
|
#else
|
||
|
#define DEBUGHTTP
|
||
|
#endif
|
||
|
|
||
|
|
||
|
uint32_t fileTaskState = 0;
|
||
|
uint32_t m3u8TaskState = 0;
|
||
|
void m3u8DownloadTask(void *pvParameters);
|
||
|
void fileDownloadTask(void *pvParameters);
|
||
|
|
||
|
typedef struct {
|
||
|
int status; // 1:downloading; 2:finished
|
||
|
char *reqBuf;
|
||
|
char *recvBuf;
|
||
|
int blockQuit;
|
||
|
int receivedSize;
|
||
|
uint32_t remaindSize;
|
||
|
uint32_t downloadedSize;
|
||
|
uint32_t contentTotalSize;
|
||
|
UriSrcAttr uri;
|
||
|
} HttpObj;
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
TaskState state;
|
||
|
pthread_t thread;
|
||
|
int threadQuit;
|
||
|
} DownloadInstance;
|
||
|
|
||
|
|
||
|
static HttpObj localHttp;
|
||
|
//static mutex_t downloadMutex;
|
||
|
static UrlInfo actLiveUrl;
|
||
|
|
||
|
DownloadInstance dlInstance = { 0 };
|
||
|
|
||
|
typedef void (*Callback_Recv)(HttpObj *obj);
|
||
|
|
||
|
int checkIsReqOk(char *buf)
|
||
|
{
|
||
|
char *l = strstr(buf, "HTTP/1.1 2");
|
||
|
if (NULL == l) {
|
||
|
l = strstr(buf, "HTTP/1.0 2");
|
||
|
if (NULL == l) {
|
||
|
l = strstr(buf, "HTTP/1.0 3");
|
||
|
if (NULL == l) {
|
||
|
return -1;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
int getLocation (const char *buf, char* dest)
|
||
|
{
|
||
|
// Location: http://119.90.25.49/live.xmcdn.com/192.168.3.134/live/38/24/161118_174054_588.aac
|
||
|
char *l = strstr(buf, "Location:");
|
||
|
if (NULL == l) {
|
||
|
LOGE("Can't find Location:%s", buf);
|
||
|
return -1;
|
||
|
}
|
||
|
l += 10;
|
||
|
int i1 = 0;
|
||
|
if (l != NULL) {
|
||
|
while (*l != '\r') {
|
||
|
dest[i1++] = *(l++);
|
||
|
if (i1 > ESP_URI_LEN) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
LOGE("Can't find Location:%s", buf);
|
||
|
return -1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
int getFileLength(char *buf)
|
||
|
{
|
||
|
char *l = strstr(buf, "Content-Length:");
|
||
|
if (NULL == l) {
|
||
|
LOGE("Can't find length:%s", buf);
|
||
|
return 0;
|
||
|
}
|
||
|
l += 16;
|
||
|
char len[32] = {0};
|
||
|
int i1 = 0;
|
||
|
if (l != NULL) {
|
||
|
while (*l != '\r') {
|
||
|
len[i1++] = *(l++);
|
||
|
}
|
||
|
} else {
|
||
|
LOGE("Can't find length:%s", buf);
|
||
|
return 0;
|
||
|
}
|
||
|
return atoi(len);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void ReqHead(char* outReqBuf, const char *url, char* host)
|
||
|
{
|
||
|
LOGD("http HEAD requst\r\n");
|
||
|
sprintf(outReqBuf, "HEAD %s HTTP/1.1\r\n"
|
||
|
"Accept:*/*\r\n"
|
||
|
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
|
||
|
"Host: %s\r\n"
|
||
|
"Connection:Keep-Alive\r\n"
|
||
|
"Cache-Control: no-cache\r\n"
|
||
|
"\r\n\r\n", url, host);
|
||
|
DEBUGHTTP(outReqBuf);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ReqGetM3u8(char* outReqBuf, const char *url, char* host)
|
||
|
{
|
||
|
LOGD("http GET requst:");
|
||
|
if ((NULL == url) || (NULL == host)) {
|
||
|
LOGE("NULL = url or NULL = host");
|
||
|
return;
|
||
|
}
|
||
|
sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
|
||
|
"Accept:*/*\r\n"
|
||
|
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
|
||
|
"Host: %s\r\n"
|
||
|
"Connection: Close\r\n" // Keep-Alive
|
||
|
"Cache-Control: no-cache\r\n"
|
||
|
"\r\n\r\n", url, host);
|
||
|
DEBUGHTTP(outReqBuf);
|
||
|
}
|
||
|
|
||
|
|
||
|
void ReqDataPre(char* outReqBuf, const char *url, char* host, uint32_t startLen, uint32_t endLen)
|
||
|
{
|
||
|
if (0 != endLen) {
|
||
|
sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
|
||
|
"Accept:*/*\r\n"
|
||
|
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
|
||
|
"Host: %s\r\n"
|
||
|
"Proxy-Connection: Keep-Alive\r\n"
|
||
|
"Cache-Control: no-cache\r\n"
|
||
|
"Range: bytes=%d-%d\r\n\r\n", url, host, startLen, endLen - 1);
|
||
|
} else {
|
||
|
sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
|
||
|
"Accept:*/*\r\n"
|
||
|
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
|
||
|
"Host: %s\r\n"
|
||
|
"Proxy-Connection: Keep-Alive\r\n"
|
||
|
"Cache-Control: no-cache\r\n\r\n", url, host);
|
||
|
}
|
||
|
|
||
|
LOGD("http GET requst-%d:", strlen(outReqBuf));
|
||
|
//DEBUGHTTP(outReqBuf);
|
||
|
}
|
||
|
|
||
|
int getIpForHost(const char *host, struct sockaddr_in *ip)
|
||
|
{
|
||
|
struct hostent *he;
|
||
|
struct in_addr **addr_list;
|
||
|
char str[200] ;
|
||
|
|
||
|
he = gethostbyname(host);
|
||
|
if (he == NULL) return 0;
|
||
|
addr_list = (struct in_addr **)he->h_addr_list;
|
||
|
if (addr_list[0] == NULL) return 0;
|
||
|
ip->sin_family = AF_INET;
|
||
|
memcpy(&ip->sin_addr, addr_list[0], sizeof(ip->sin_addr));
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
int splitHostUrl(const char* url, char* host, uint16_t *port, char **path)
|
||
|
{
|
||
|
if ((NULL == url) || (NULL == host)) {
|
||
|
LOGE("ERR:url=NULL or Host=NULL\n");
|
||
|
return -1;
|
||
|
}
|
||
|
char* temp1;
|
||
|
char* source = (char*)url;
|
||
|
char portBuf[10] = {0};
|
||
|
while (url) {
|
||
|
source = strstr(source, "//");
|
||
|
if (url == NULL) {
|
||
|
LOGE("ERR:strchr=NULL\n");
|
||
|
return -1;
|
||
|
}
|
||
|
source += 2;
|
||
|
temp1 = strchr(source, ':');
|
||
|
if (temp1 != NULL) {
|
||
|
// try to find '/'
|
||
|
strncpy(host, source, temp1 - source);
|
||
|
temp1 += 1;
|
||
|
source = strchr(source, '/');
|
||
|
if (source == NULL) {
|
||
|
LOGE("ERR:strchr=NULL\n");
|
||
|
return 0;
|
||
|
}
|
||
|
strncpy(portBuf, temp1, source - temp1);
|
||
|
*port = strtoul(portBuf, 0, 10);
|
||
|
*path = source;
|
||
|
LOGD("\nUsed Host[%s] Port[%d],Path:%s\n", host, *port, *path);
|
||
|
} else {
|
||
|
// try to find port
|
||
|
temp1 = strchr(source, '/');
|
||
|
if (temp1 == NULL) {
|
||
|
LOGE("ERR:strchr=NULL\n");
|
||
|
return -1;
|
||
|
}
|
||
|
strncpy(host, source, temp1 - source);
|
||
|
*port = 80;
|
||
|
*path = temp1;
|
||
|
LOGD("\nUsed Host[%s] Port[%d],Path:%s\n", host, *port, *path);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
int connectToServer(const char* actUrl, const char* hostName, uint16_t port, int timeOut)
|
||
|
{
|
||
|
struct sockaddr_in remote_ip;
|
||
|
int sock = -1;
|
||
|
int nNetTimeout = timeOut; // socket timeout 1 Sec
|
||
|
int retryCnt = 3;
|
||
|
while (retryCnt--) {
|
||
|
bzero(&remote_ip, sizeof(struct sockaddr_in));
|
||
|
if (1 != inet_aton(hostName, &remote_ip.sin_addr)) {
|
||
|
if (!getIpForHost(hostName, &remote_ip)) {
|
||
|
vTaskDelay(1000 / portTICK_RATE_MS);
|
||
|
LOGE("getIpForHost failed");
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
remote_ip.sin_family = AF_INET;
|
||
|
int sock = socket(PF_INET, SOCK_STREAM, 0);
|
||
|
if (sock == -1) {
|
||
|
LOGE("socket failed errno=%d", errno);
|
||
|
continue;
|
||
|
}
|
||
|
// setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int));
|
||
|
struct timeval tv_out;
|
||
|
tv_out.tv_sec = 20; //Wait 20 seconds.
|
||
|
tv_out.tv_usec = 0;
|
||
|
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&tv_out, sizeof(tv_out));
|
||
|
|
||
|
remote_ip.sin_port = htons(port);
|
||
|
LOGD("[sock=%d],connecting to server IP:%s,Port:%d...",
|
||
|
sock, ipaddr_ntoa((const ip_addr_t*)&remote_ip.sin_addr.s_addr), port);
|
||
|
if (connect(sock, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) != 0) {
|
||
|
close(sock);
|
||
|
LOGE("Conn err.\n");
|
||
|
vTaskDelay(1000 / portTICK_RATE_MS);
|
||
|
continue;
|
||
|
}
|
||
|
return sock;
|
||
|
}
|
||
|
LOGE("Lost host,connect and getIpForHost timeout");
|
||
|
return -2;
|
||
|
}
|
||
|
|
||
|
void resetDownloadAttr(char *src, uint32_t *type)
|
||
|
{
|
||
|
localHttp.status = 0;
|
||
|
if (localHttp.blockQuit < 0) {
|
||
|
localHttp.blockQuit = 0;
|
||
|
}
|
||
|
localHttp.receivedSize = 0;
|
||
|
localHttp.remaindSize = 0;
|
||
|
localHttp.downloadedSize = 0;
|
||
|
localHttp.uri.srcType = *type;
|
||
|
localHttp.contentTotalSize = 0;
|
||
|
memset(localHttp.uri.str, 0, ESP_URI_LEN);
|
||
|
strncpy(localHttp.uri.str, src, strlen(src));
|
||
|
}
|
||
|
|
||
|
void OnFileDataCB(HttpObj *obj)
|
||
|
{
|
||
|
int ret;
|
||
|
|
||
|
do {
|
||
|
ret = audioBufWrite(obj->reqBuf, obj->receivedSize, 100);
|
||
|
if (ret) {
|
||
|
obj->remaindSize -= obj->receivedSize;
|
||
|
obj->downloadedSize += obj->receivedSize;
|
||
|
// uint32_t rd, wr;
|
||
|
// audioBufPosGet(&rd, &wr);
|
||
|
// LOGD("rd:%x,wr:%x,downloaded=%d, remaind=%d, total=%d, recvSize=%d",
|
||
|
// rd,wr,obj->downloadedSize, obj->remaindSize, obj->contentTotalSize, obj->receivedSize);
|
||
|
break;
|
||
|
} else {
|
||
|
LOGE("audioBufWrite failed ret=%d. rcev=%d,remaind=%d, d=%d", ret,
|
||
|
obj->receivedSize, obj->remaindSize, obj->downloadedSize);
|
||
|
break;
|
||
|
}
|
||
|
} while (0 == obj->blockQuit);
|
||
|
}
|
||
|
|
||
|
void OnM3u8DataCB(HttpObj *obj)
|
||
|
{
|
||
|
obj->remaindSize -= obj->receivedSize;
|
||
|
obj->downloadedSize += obj->receivedSize;
|
||
|
// LOGD(":\n%s", obj->reqBuf);
|
||
|
}
|
||
|
|
||
|
char *GetValidUrl(M3u8Info *pActM3u8, M3u8Seq *actSeq)
|
||
|
{
|
||
|
char *retUrl = NULL;
|
||
|
if ((NULL == actSeq)
|
||
|
|| (NULL == pActM3u8)) {
|
||
|
LOGE("pActM3u8 or actSeq is NULL");
|
||
|
return retUrl;
|
||
|
}
|
||
|
int validM3u8 = -1;
|
||
|
for (uint8_t i = 0; i < 3; i++) {
|
||
|
// LOGD("M3u8 AAC URL,%dth,%s\n", i, pActM3u8->segList[i].url);
|
||
|
if ((actSeq->sub == DEFAULT_AAC_SEQ)
|
||
|
|| (1 == m3u8CheckValid(&pActM3u8->segList[i].seq, (const M3u8Seq*)actSeq))) {
|
||
|
validM3u8 = 1;
|
||
|
retUrl = pActM3u8->segList[i].url;
|
||
|
memcpy(actSeq, &pActM3u8->segList[i].seq, sizeof(pActM3u8->segList[i].seq));
|
||
|
pActM3u8->segList[i].seq.sub = 0;
|
||
|
LOGD("Get one valid AAC URL,%dth,seq=%x,%s\n", i, actSeq->sub, retUrl);
|
||
|
if ((0 == actSeq->sub)
|
||
|
|| (retUrl[0] == '\0')) {
|
||
|
retUrl = NULL;
|
||
|
}
|
||
|
return retUrl;
|
||
|
} else {
|
||
|
// LOGD("Get one valid AAC URL,%dth,seq=%x,%s\n", i, pActM3u8->segList[i].seq.sub, pActM3u8->segList[i].url);
|
||
|
pActM3u8->segList[i].seq.sub = 0;
|
||
|
}
|
||
|
}
|
||
|
if (validM3u8 != 1) {
|
||
|
LOGD("Can not found valid aac url, curtAacSeq=%x", actSeq->sub);
|
||
|
}
|
||
|
return retUrl;
|
||
|
|
||
|
}
|
||
|
|
||
|
int httpDownloading(HttpObj *obj, Callback_Recv recvCB)
|
||
|
{
|
||
|
if ((NULL == obj)
|
||
|
|| (NULL == obj->uri.str)
|
||
|
|| (NULL == obj->reqBuf)
|
||
|
|| (NULL == obj->recvBuf)
|
||
|
|| (0 == strlen(obj->uri.str))) {
|
||
|
LOGE("Pointer is NULL,obj:%x,URL:%x reqbuf:%x recvBuf:%x,len:%d,blockQuit:%d",
|
||
|
obj, obj->uri.str, obj->reqBuf, obj->recvBuf, strlen(obj->uri.str), obj->blockQuit);
|
||
|
return -1;
|
||
|
}
|
||
|
char hostName[32] = { 0 };
|
||
|
int actSocket = -1;
|
||
|
uint32_t contrlDat = 0;
|
||
|
uint8_t modifyProFlag = 0;
|
||
|
int cnt = 0;
|
||
|
int n = 0;
|
||
|
LOGD("\n>>>>>Downloading start:%s,0x%x,remaind=%d,downloaded=%d,total=%d,fill=%d",
|
||
|
obj->uri.str, obj->uri.str, obj->remaindSize, obj->downloadedSize, obj->contentTotalSize, audioBufFillGet());
|
||
|
obj->status = 1;
|
||
|
uint16_t ipPort = 80;
|
||
|
char *uriPath = NULL;
|
||
|
do {
|
||
|
// Here will check exit event;
|
||
|
|
||
|
Retry: LOGD("retry new url size=%d", obj->remaindSize);
|
||
|
memset(hostName, 0, sizeof(hostName));
|
||
|
if (0 != splitHostUrl(obj->uri.str, hostName, &ipPort, &uriPath)) {
|
||
|
LOGE("splitHostUrl failed:%s", obj->uri.str);
|
||
|
continue;
|
||
|
}
|
||
|
LOGD("Hostname:%s", hostName);
|
||
|
if ((actSocket = connectToServer((const char*)obj->uri.str, hostName, ipPort, 10000)) >= 0) {
|
||
|
char * datPos = NULL;
|
||
|
bzero(obj->reqBuf, REQUEST_BUF_LEN);
|
||
|
ReqDataPre(obj->reqBuf, uriPath, hostName, obj->downloadedSize, obj->contentTotalSize);
|
||
|
LOGD("Hostname:%s++++++++", hostName);
|
||
|
write(actSocket, obj->reqBuf, strlen(obj->reqBuf));
|
||
|
LOGD("Hostname:%s--------", hostName);
|
||
|
bzero(obj->recvBuf, RECV_BUF_LEN);
|
||
|
datPos = NULL;
|
||
|
cnt = 0;
|
||
|
do {
|
||
|
bzero(obj->reqBuf, REQUEST_BUF_LEN);
|
||
|
n = read(actSocket, obj->reqBuf, REQUEST_BUF_LEN);
|
||
|
if ((n > 0) && (cnt <= RECV_BUF_LEN)) {
|
||
|
// DEBUGHTTP("Head is: %s", obj->reqBuf);
|
||
|
memcpy(obj->recvBuf + cnt, obj->reqBuf, n);
|
||
|
datPos = strstr(obj->recvBuf, "\r\n""""\r\n");
|
||
|
if (datPos) {
|
||
|
//DEBUGHTTP("Find CRLF CRLF ok");
|
||
|
// LOGD("Head is: %s", obj->recvBuf);
|
||
|
} else {
|
||
|
LOGE("Find CRLF CRLF failed,wait more data");
|
||
|
}
|
||
|
}
|
||
|
cnt += n;
|
||
|
} while ((datPos == NULL) && (n > 0) && (cnt < RECV_BUF_LEN));
|
||
|
if (n < 0) {
|
||
|
close(actSocket);
|
||
|
continue;
|
||
|
}
|
||
|
if (NULL == datPos) {
|
||
|
// datPos == strstr(obj->recvBuf, "\r\n""""\r\n");
|
||
|
LOGD("Head is: %s", obj->recvBuf);
|
||
|
|
||
|
if (NULL == datPos) {
|
||
|
close(actSocket);
|
||
|
LOGE("Can't Find CRLF CRLF,it's bad response,try again");
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
int ret = checkIsReqOk(obj->recvBuf);
|
||
|
if (ret < 0) {
|
||
|
close(actSocket);
|
||
|
LOGE("Recv a bad resp:%s", obj->recvBuf);
|
||
|
continue;
|
||
|
} else if (ret == 1) {
|
||
|
close(actSocket);
|
||
|
LOGW("Recv a 3xx resp:%s", obj->recvBuf);
|
||
|
memset(obj->uri.str, 0, ESP_URI_LEN);
|
||
|
if (getLocation((const char*)obj->recvBuf, obj->uri.str) < 0) {
|
||
|
LOGE("Find 3xx URL error");
|
||
|
} else {
|
||
|
LOGW("Recv a 3xx resp:%s", obj->uri.str);
|
||
|
}
|
||
|
goto Retry;
|
||
|
}
|
||
|
if (0 == obj->contentTotalSize) obj->contentTotalSize = getFileLength(obj->recvBuf);
|
||
|
datPos += 4;
|
||
|
cnt = cnt - (datPos - obj->recvBuf);
|
||
|
if (0 == obj->remaindSize) {
|
||
|
obj->remaindSize = obj->contentTotalSize;
|
||
|
}
|
||
|
// Save the tail data
|
||
|
bzero(obj->reqBuf, REQUEST_BUF_LEN);
|
||
|
memcpy(obj->reqBuf, datPos, cnt);
|
||
|
|
||
|
LOGD("downloaded=%d, remaind=%d, total=%d, cnt=%d",
|
||
|
obj->downloadedSize, obj->remaindSize, obj->contentTotalSize, cnt);
|
||
|
int writeComplete = 0;
|
||
|
do {
|
||
|
if (writeComplete) {
|
||
|
bzero(obj->reqBuf, REQUEST_BUF_LEN);
|
||
|
n = read(actSocket, obj->reqBuf, REQUEST_BUF_LEN);
|
||
|
cnt = n;
|
||
|
// DEBUGHTTP("recv,cnt:%d\n", cnt);
|
||
|
}
|
||
|
if (n > 0) {
|
||
|
if (cnt > 0) {
|
||
|
obj->receivedSize = cnt;
|
||
|
recvCB(obj);
|
||
|
}
|
||
|
cnt = 0;
|
||
|
writeComplete = 1;
|
||
|
}
|
||
|
} while ((n > 0) && (obj->remaindSize > 0) && (0 == obj->blockQuit));
|
||
|
close(actSocket);
|
||
|
LOGD("Sock[%d] has closed,n=%d,blockQuit=%d", actSocket, n, obj->blockQuit);
|
||
|
} else {
|
||
|
LOGE("Connect is error.");
|
||
|
}
|
||
|
LOGD("Connect closed,file size remaind=%d", obj->remaindSize);
|
||
|
|
||
|
} while ((obj->remaindSize != 0) && (0 == obj->blockQuit));
|
||
|
if (0 == obj->remaindSize) {
|
||
|
obj->status = 2;
|
||
|
} else {
|
||
|
obj->status = 3;
|
||
|
}
|
||
|
LOGD("\n<<<<<Downloading finish:%s,remaind=%d,downloaded=%d,total=%d fill=%d status=%d\n",
|
||
|
obj->uri.str, obj->remaindSize, obj->downloadedSize, obj->contentTotalSize,
|
||
|
audioBufFillGet(), obj->status);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void fileDownloadTask(void *pvParameters)
|
||
|
{
|
||
|
int n, cnt;
|
||
|
DownloadInstance *downloadObj = (DownloadInstance *)pvParameters;
|
||
|
LOGI("%s is running.%x %x", __func__, pvParameters, downloadObj->threadQuit);
|
||
|
|
||
|
/////////////////////////////
|
||
|
M3u8Seq runningAacSeq = {0, 0, DEFAULT_AAC_SEQ};
|
||
|
M3u8Info *pUsingM3u8 = NULL;
|
||
|
uint32_t mediaSeq = DEFAULT_AAC_SEQ;
|
||
|
|
||
|
downloadObj->threadQuit = 0;
|
||
|
while (downloadObj->threadQuit == 0) {
|
||
|
switch (downloadObj->state) {
|
||
|
case TaskState_Ready:
|
||
|
if ((NULL == actLiveUrl.str)
|
||
|
|| (actLiveUrl.str[0] == '\0')
|
||
|
|| (NULL == localHttp.uri.str )) {
|
||
|
downloadObj->state = TaskState_Idle;
|
||
|
vTaskDelay(200 / portTICK_RATE_MS);
|
||
|
LOGI("Downloading URL is NULL,downloading task paused");
|
||
|
break;
|
||
|
} else {
|
||
|
LOGI("Download task is ready.%s type:%d", actLiveUrl.str, actLiveUrl.type);
|
||
|
}
|
||
|
if (InputSrcType_NetSpec == actLiveUrl.type) {
|
||
|
resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
|
||
|
downloadObj->state = TaskState_Running;
|
||
|
audioBufWrRest();
|
||
|
} else if (InputSrcType_NetLiving == actLiveUrl.type) {
|
||
|
resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
|
||
|
|
||
|
audioBufWrRest();
|
||
|
mediaSeq = DEFAULT_AAC_SEQ;
|
||
|
downloadObj->state = TaskState_Running;
|
||
|
runningAacSeq.sub = DEFAULT_AAC_SEQ;
|
||
|
if (pUsingM3u8) {
|
||
|
free(pUsingM3u8);
|
||
|
pUsingM3u8 = NULL;
|
||
|
}
|
||
|
pUsingM3u8 = calloc(1, sizeof(M3u8Info));
|
||
|
if (pUsingM3u8 == NULL) {
|
||
|
LOGE("recvBuf malloc error");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
LOGE("Http uri.srcType is not supported[%d]", localHttp.uri.srcType);
|
||
|
downloadObj->state = TaskState_Idle;
|
||
|
vTaskDelay(200 / portTICK_RATE_MS);
|
||
|
}
|
||
|
break;
|
||
|
case TaskState_Pause:
|
||
|
LOGI("TaskState_Pause,Total=%d, downloaded=%d,remaind=%d", localHttp.contentTotalSize,
|
||
|
localHttp.downloadedSize,
|
||
|
localHttp.remaindSize);
|
||
|
downloadObj->state = TaskState_Idle;
|
||
|
break;
|
||
|
case TaskState_Resume:
|
||
|
downloadObj->state = TaskState_Running;
|
||
|
LOGI("TaskState_Resume,Total=%d, downloaded=%d,remaind=%d", localHttp.contentTotalSize,
|
||
|
localHttp.downloadedSize,
|
||
|
localHttp.remaindSize);
|
||
|
break;
|
||
|
case TaskState_Running:
|
||
|
if (InputSrcType_NetSpec == localHttp.uri.srcType) {
|
||
|
LOGI("Excute URL:%s", localHttp.uri.str);
|
||
|
httpDownloading(&localHttp, OnFileDataCB);
|
||
|
if (2 == localHttp.status) {
|
||
|
downloadObj->state = TaskState_Idle;
|
||
|
LOGI("Excute URL over, task will be idle.remind[%d]", localHttp.remaindSize);
|
||
|
}
|
||
|
} else if (InputSrcType_NetLiving == localHttp.uri.srcType) {
|
||
|
resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
|
||
|
memset(localHttp.recvBuf, 0, RECV_BUF_LEN);
|
||
|
memset(localHttp.reqBuf, 0, REQUEST_BUF_LEN);
|
||
|
|
||
|
LOGD("Excute URL:%s, actLiveUrl.str=%x", localHttp.uri.str, actLiveUrl.str);
|
||
|
httpDownloading(&localHttp, OnM3u8DataCB);
|
||
|
|
||
|
M3u8Info *pActM3u8 = m3u8Parser(localHttp.reqBuf, pUsingM3u8);
|
||
|
if (NULL == pActM3u8) {
|
||
|
LOGE("Parser m3u8 is error");
|
||
|
vTaskDelay(1000 / portTICK_RATE_MS);
|
||
|
break;
|
||
|
}
|
||
|
if ((pActM3u8->mediaSeq <= mediaSeq) && (mediaSeq != DEFAULT_AAC_SEQ)) {
|
||
|
LOGD("mediaSeq has not update,used=%d,new=%d", mediaSeq, pActM3u8->mediaSeq);
|
||
|
vTaskDelay(1000 / portTICK_RATE_MS);
|
||
|
break;
|
||
|
}
|
||
|
char *validUrl = GetValidUrl(pActM3u8, &runningAacSeq);
|
||
|
|
||
|
LOGD("AAC URL,runningAacSeq:%x,%x,%x\n",
|
||
|
runningAacSeq.sub, runningAacSeq.main, runningAacSeq.date);
|
||
|
if (NULL == validUrl) {
|
||
|
vTaskDelay(100 / portTICK_RATE_MS);
|
||
|
LOGE("uri.str is NULL,state=%d", downloadObj->state);
|
||
|
break;
|
||
|
}
|
||
|
DecoderObj decoder;
|
||
|
mediaDecoderTaskInfoGet(&decoder);
|
||
|
decoder.musicType = checkMediaType(validUrl);
|
||
|
if (decoder.musicType >= EspAudioMeidaType_M3u) {
|
||
|
LOGE("%s,Music type[%d] is error", validUrl, decoder.musicType);
|
||
|
vTaskDelay(100 / portTICK_RATE_MS);
|
||
|
break;
|
||
|
} else {
|
||
|
mediaDecoderTaskInfoSet(&decoder);
|
||
|
}
|
||
|
do {
|
||
|
resetDownloadAttr(validUrl, &actLiveUrl.type);
|
||
|
memset(localHttp.recvBuf, 0, RECV_BUF_LEN);
|
||
|
memset(localHttp.reqBuf, 0, REQUEST_BUF_LEN);
|
||
|
|
||
|
httpDownloading(&localHttp, OnFileDataCB);
|
||
|
validUrl = GetValidUrl(pActM3u8, &runningAacSeq);
|
||
|
|
||
|
LOGD("AAC URL,runningAacSeq:%x,%x,%x\n", runningAacSeq.sub, runningAacSeq.main, runningAacSeq.date);
|
||
|
if (NULL == validUrl) {
|
||
|
LOGD("uri.str is NULL,state=%d", downloadObj->state);
|
||
|
break;
|
||
|
}
|
||
|
} while (validUrl != NULL);
|
||
|
mediaSeq = pActM3u8->mediaSeq;
|
||
|
} else {
|
||
|
LOGE("Http uri.srcType is not supported[%d]", localHttp.uri.srcType);
|
||
|
downloadObj->state = TaskState_Idle;
|
||
|
vTaskDelay(200 / portTICK_RATE_MS);
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
case TaskState_Stoped:
|
||
|
downloadObj->state = TaskState_Idle;
|
||
|
break;
|
||
|
case TaskState_Idle:
|
||
|
default:
|
||
|
vTaskDelay(250 / portTICK_RATE_MS);
|
||
|
// LOGD("blockQuit[%d] state[%d]", localHttp.blockQuit, downloadObj->state);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
downloadObj->threadQuit = -1;
|
||
|
downloadObj->thread = NULL;
|
||
|
downloadObj->state = TaskState_Stoped;
|
||
|
if (pUsingM3u8) {
|
||
|
free(pUsingM3u8);
|
||
|
pUsingM3u8 = NULL;
|
||
|
}
|
||
|
LOGD("%s is ended...", __func__);
|
||
|
vTaskDelete(NULL);
|
||
|
}
|
||
|
|
||
|
TaskState downloadTaskStateGet()
|
||
|
{
|
||
|
return dlInstance.state;
|
||
|
}
|
||
|
|
||
|
int downloadTaskHTTPStateGet()
|
||
|
{
|
||
|
return localHttp.status;
|
||
|
}
|
||
|
|
||
|
void downloadTaskDownloadSizeSet(int *size)
|
||
|
{
|
||
|
if (NULL == size) {
|
||
|
LOGE("Invalid para");
|
||
|
return ;
|
||
|
}
|
||
|
// localHttp.blockQuit = 1;
|
||
|
localHttp.downloadedSize = *size;
|
||
|
downloadTaskResume();
|
||
|
}
|
||
|
|
||
|
void downloadTaskContentSizeGet(uint32_t *size)
|
||
|
{
|
||
|
if (NULL == size) {
|
||
|
LOGE("Invalid para");
|
||
|
return ;
|
||
|
}
|
||
|
*size = localHttp.contentTotalSize;
|
||
|
}
|
||
|
|
||
|
void downloadTaskInfoSet(UriSrcAttr *uri)
|
||
|
{
|
||
|
if (NULL == uri) {
|
||
|
LOGE("Invalid para");
|
||
|
return ;
|
||
|
}
|
||
|
actLiveUrl.type = uri->srcType;
|
||
|
memset(actLiveUrl.str, 0 , ESP_URI_LEN);
|
||
|
strncpy(actLiveUrl.str, uri->str, strlen(uri->str));
|
||
|
localHttp.blockQuit = 0;
|
||
|
LOGD("Set url ok:%s", actLiveUrl.str);
|
||
|
}
|
||
|
|
||
|
void downloadTaskPause()
|
||
|
{
|
||
|
if (0 == dlInstance.thread) {
|
||
|
dlInstance.state = TaskState_Unknown;
|
||
|
LOGE("dlInstance.thread is NULL");
|
||
|
return;
|
||
|
}
|
||
|
if (TaskState_Running == dlInstance.state) {
|
||
|
localHttp.blockQuit = -1;
|
||
|
}
|
||
|
dlInstance.state = TaskState_Pause;
|
||
|
|
||
|
LOGD("download task state=%d", dlInstance.state);
|
||
|
}
|
||
|
|
||
|
void downloadTaskResume()
|
||
|
{
|
||
|
if (0 == dlInstance.thread) {
|
||
|
dlInstance.state = TaskState_Unknown;
|
||
|
LOGE("dlInstance.thread is NULL");
|
||
|
return;
|
||
|
}
|
||
|
if (TaskState_Pause == dlInstance.state) {
|
||
|
localHttp.blockQuit = 0;
|
||
|
}
|
||
|
dlInstance.state = TaskState_Resume;
|
||
|
LOGD("download task state=%d", dlInstance.state);
|
||
|
}
|
||
|
|
||
|
void downloadTaskCreate(int taskType)
|
||
|
{
|
||
|
if (localHttp.reqBuf) {
|
||
|
free(localHttp.reqBuf);
|
||
|
}
|
||
|
if (localHttp.recvBuf) {
|
||
|
free(localHttp.recvBuf);
|
||
|
}
|
||
|
if (localHttp.uri.str) {
|
||
|
free(localHttp.uri.str);
|
||
|
}
|
||
|
localHttp.reqBuf = calloc(1, REQUEST_BUF_LEN);
|
||
|
if (NULL == localHttp.reqBuf) {
|
||
|
LOGE("reqBuf malloc error");
|
||
|
return;
|
||
|
}
|
||
|
localHttp.recvBuf = calloc(1, RECV_BUF_LEN);
|
||
|
if (NULL == localHttp.recvBuf) {
|
||
|
LOGE("recvBuf malloc error");
|
||
|
free(localHttp.reqBuf);
|
||
|
return;
|
||
|
}
|
||
|
localHttp.uri.str = calloc(1, ESP_URI_LEN);
|
||
|
if (NULL == localHttp.uri.str) {
|
||
|
LOGE("uri.str malloc error");
|
||
|
free(localHttp.reqBuf);
|
||
|
free(localHttp.recvBuf);
|
||
|
return;
|
||
|
}
|
||
|
// mutex_init(&downloadMutex);
|
||
|
// configASSERT(downloadMutex);
|
||
|
xTaskCreate(fileDownloadTask, "fileDownloadTask", (6 * 1024), &dlInstance, PRIO_DOWNLOAD, &dlInstance.thread);
|
||
|
configASSERT(dlInstance.thread);
|
||
|
LOGD("download task state=%d", dlInstance.state);
|
||
|
}
|
||
|
|
||
|
int downloadTaskStart()
|
||
|
{
|
||
|
if (0 == dlInstance.thread) {
|
||
|
dlInstance.state = TaskState_Unknown;
|
||
|
LOGE("dlInstance.thread is NULL");
|
||
|
return -1;
|
||
|
}
|
||
|
if ((actLiveUrl.str == NULL)
|
||
|
|| (actLiveUrl.str[0] == '\0')) {
|
||
|
dlInstance.state = TaskState_Idle;
|
||
|
LOGE("uri.str task is NULL");
|
||
|
return -1;
|
||
|
}
|
||
|
dlInstance.state = TaskState_Ready;
|
||
|
LOGD("download task state=%d, %s, %d", dlInstance.state, actLiveUrl.str, localHttp.blockQuit);
|
||
|
audioBufWrRest();
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void downloadTaskStop(void *que)
|
||
|
{
|
||
|
if (0 == dlInstance.thread) {
|
||
|
dlInstance.state = TaskState_Unknown;
|
||
|
LOGE("dlInstance.thread is NULL");
|
||
|
return;
|
||
|
}
|
||
|
if (dlInstance.state == TaskState_Unknown) {
|
||
|
LOGW("dlInstance.state is TaskState_Unknown");
|
||
|
return;
|
||
|
}
|
||
|
localHttp.blockQuit = 1;
|
||
|
dlInstance.state = TaskState_Stoped;
|
||
|
configASSERT(que);
|
||
|
xQueueSend(que, &localHttp.blockQuit, 0);
|
||
|
|
||
|
LOGD("download task +++++ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
|
||
|
while ((TaskState_Finished != dlInstance.state)
|
||
|
&& (TaskState_Idle != dlInstance.state)) {
|
||
|
if ((TaskState_Idle == dlInstance.state)) {
|
||
|
localHttp.blockQuit = 0;
|
||
|
break;
|
||
|
}
|
||
|
vTaskDelay(10 / portTICK_RATE_MS);
|
||
|
}
|
||
|
audioBufWrRest();
|
||
|
xQueueReset(que);
|
||
|
LOGD("download task ------ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
|
||
|
}
|
||
|
|
||
|
void downloadTaskDestroy()
|
||
|
{
|
||
|
if (0 == dlInstance.thread) {
|
||
|
dlInstance.state = TaskState_Unknown;
|
||
|
LOGE("dlInstance.thread is NULL");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
LOGD("download task +++++ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
|
||
|
if (0 == dlInstance.threadQuit) {
|
||
|
localHttp.blockQuit = 1;
|
||
|
dlInstance.threadQuit = 1;
|
||
|
dlInstance.state = TaskState_Stoped;
|
||
|
while (1) {
|
||
|
if ((dlInstance.threadQuit == -1)) {
|
||
|
localHttp.blockQuit = 0;
|
||
|
break;
|
||
|
}
|
||
|
vTaskDelay(200 / portTICK_RATE_MS);
|
||
|
}
|
||
|
}
|
||
|
if (localHttp.reqBuf) free(localHttp.reqBuf);
|
||
|
if (localHttp.recvBuf) free(localHttp.recvBuf);
|
||
|
if (localHttp.uri.str) free(localHttp.uri.str);
|
||
|
|
||
|
memset(&localHttp, 0, sizeof(localHttp));
|
||
|
localHttp.reqBuf = NULL;
|
||
|
localHttp.recvBuf = NULL;
|
||
|
localHttp.uri.str = NULL;
|
||
|
dlInstance.state = TaskState_Unknown;
|
||
|
dlInstance.thread = NULL;
|
||
|
// mutex_destroy(&downloadMutex);
|
||
|
// downloadMutex = NULL;
|
||
|
LOGD("download task ------ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
|
||
|
}
|
||
|
|