IOS支持音频流断点续传

2022-08-24 19:17:23 浏览数 (1)

导语:

使用c 实现音频流过程中遇到的问题和解决过程

步骤一 :

在使用cgi编写输出音频流接口,前端同事无法拖动播放,于是查阅资料找到了一个关键词:断点续传 断点续传的解释: 断点续传:指的是在上传/下载时,将任务(一个文件或压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传/下载,如果碰到网络故障,可以从已经上传/下载的部分开始继续上传/下载未完成的部分,而没有必要从头开始上传/下载。可以节省时间,提高速度。 断点续传的用途: 有时用户上传/下载文件需要历时数小时,万一线路中断,不具备断点续传的 HTTP/FTP 服务器或下载软件就只能从头重传,比较好的 HTTP/FTP 服务器或下载软件具有断点续传能力,允许用户从上传/下载断线的地方继续传送,这样大大减少了用户的烦恼。 常见的支持断点续传的上传/下载软件:QQ 旋风、迅雷、快车、电驴、酷6、土豆、优酷、百度视频、新浪视频、腾讯视频、百度云等。 HTTP1.1 协议(RFC2616)开始支持获取文件的部分内容,这为并行下载以及断点续传提供了技术支持。它通过在 Header 里两个参数实现的,客户端发请求时对应的是 Range ,服务器端响应时对应的是 Content-Range。 解决方案: 在返回标头中新增两个参数 printf("Content-Length: %ldn", file_size); printf("Content-Range: bytes 0-%ld/%ldn", file_size - 1, file_size); 这里我将文件长度和范围都返回给前端,实现了拖动播放。

步骤二:

发现chrome和android机器都可以实现拖动,但iOS和safari中无法拖动播放,一度以为是前端同学播放组件有问题,后面发现,其实不然! 查阅资料: 通过比较Chrome和Safari的请求我们发现,Chrome请求头中range字段的值是bytes=0-,而Safari请求头中range字段的值是bytes=0-1。从此得知,浏览器请求音频时是使用的范围请求,Chrome是用一个HTTP请求请求了整个音频,即请求音频的第0个字节到最后一个字节,Chrome不强制要求服务端支持范围请求,服务端响应200或206,Chrome都能支持。但是Safari要求服务端必须支持范围请求,Safari会先请求音频的第0个字节到第1个字节,来测试服务端是否支持范围请求,如果服务端支持范围请求,则响应状态码206,响应头中有正确的Content-Range字段,响应体是音频的第一个字节,此时,Safari才会继续请求音频的其他字节,否则Safari会放弃该音频的请求。我们音频的服务端不支持范围请求,响应的是整个音频,状态码200,所以导致无法在Safari播放。 解决方案: 当收到请求表头有range的时候,返回部分文件流,否则返回全部。

参考代码:

代码语言:javascript复制
       // 文件校验
        size_t file_size;
        string filename = file_path   audio;
        SysLog(INFO, "PID[%d] FILENAME: %s", PID, filename.c_str());
        ifstream in(filename, ios::in | ios::binary | ios::ate);
        in.seekg(0, std::ios::end);
        file_size = in.tellg();
        
        SysLog(INFO, "PID[%d] FILE_SIZE: %ld", PID, file_size);
        if ((int)file_size < 0)
        {
            in.close();
            SysLog(ERROR, "PID[%d] file error", PID);
            write_msg_json(-4, "read file error", NULL, NULL);
            return 0;
        }

        CallLibcurl libcurl;
        verifyUrl(audioUrl);
        string header = "";
        int start = 0;
        int end = file_size - 1;

        char *HTTP_RANGE = getenv("HTTP_RANGE");
        SysLog(INFO, "PID[%d] REQ_ENV: HTTP_RANGE:%s", PID, HTTP_RANGE);

        //ios特殊处理 需要支持断点续传
        if (HTTP_RANGE != NULL)
        {
            string HTTP_RANGE_STRING = HTTP_RANGE;
            HTTP_RANGE_STRING = HTTP_RANGE_STRING.substr(6);

            vector<string> list1;
            list1 = split(HTTP_RANGE_STRING, "-");
            start = atoi(list1[0].c_str());
            if (list1.size() > 1)
            {
                end = atoi(list1[1].c_str());
            }
            else
            {
                end = start   99999999;
                end = end > file_size - 1 ? file_size - 1 : end;
            }
            printf("Status:206n");
            printf("Content-Length: %ldn", (end - start)   1);
            printf("Content-Range: bytes %ld-%ld/%ldn", start, end, file_size);
        }
        else
        {
            printf("Status:200n");
            printf("Content-Length: %ldn", file_size);
            printf("Content-Range: bytes 0-%ld/%ldn", file_size - 1, file_size);
        }
        printf("Accept-Ranges: bytesn");
        printf("Content-Type: audio/mpegnn");

        int content_length = 0;
        char *val;
        in.seekg(start);
        content_length = end - start   1;
        char *buf = new char[content_length];
        in.read(buf, content_length);
        for(size_t i = 0; i < content_length;i  ){
            char temp = buf[i];
            Content  = temp;
        }
        in.close();
        SysLog(INFO, "PID[%d] LEN: %ld", PID, content_length);
        cout.write(Content.c_str(), content_length);

0 人点赞