1

我正在使用libwidevinecdm.sochrome 来处理受 DRM 保护的数据。我目前正在成功设置从许可证服务器获得的 Widevine 服务器证书。我还可以使用我试图解码的媒体的 pssh 框创建一个会话。到目前为止,一切都很成功(所有承诺都可以解决)。

(会话是这样创建的_cdm->CreateSessionAndGenerateRequest(promise_id, cdm::SessionType::kTemporary, cdm::InitDataType::kCenc, pssh_box.data(), static_cast<uint32_t>(pssh_box.size()));:)

然后我会收到一个类型的会话消息,kLicenseRequest我将其转发到相应的许可证服务器。许可证服务器以有效响应和与我在使用 Chrome 时在浏览器中看到的相同数量的数据进行响应。然后我将它传递给我的会话,如下所示:

        _cdm->UpdateSession(promise_id, session_id.data(), static_cast<uint32_t>(session_id.size()),
                            license_response.data(), static_cast<uint32_t>(license_response.size()));

现在的问题是这个承诺永远不会解决。它kLicenseRequest一遍又一遍地将消息发布到我的会话中,而从未返回。这是否意味着我的反应是错误的?或者这是别的什么?

亚尼克

4

1 回答 1

0

问题是由以下事实引起的,即所有内容CreateSessionAndGenerateRequest都是同步完成的 - 这意味着到CreateSessionAndGenerateRequest返回时,您的承诺将始终得到解决。

CDM 将发出kLicenseRequest内部CreateSessionAndGenerateRequest信号,它不会以“即发即弃”的方式这样做,但该函数会在那里等待,直到您从cdm::Host_10::OnSessionMessage. 由于我之前的实现OnSessionMessage是向许可证服务器创建同步 HTTP 请求 - 也是同步的 - 调用UpdateSession整个链最终被阻塞。

所以最终我UpdateSession还在里面打电话CreateSessionAndGenerateRequest,我假设 CDM 无法处理这个问题,并通过使用给定 ID 创建一个新会话并再次生成一个请求来做出反应,这当然触发了另一个UpdateSession等等。

最终,打破循环的最简单方法是使某些东西异步。我决定在接收时启动一个单独的线程kLicenseRequest,等待几毫秒以确保CreateSessionAndGenerateRequest有时间完成(不确定是否真的需要),然后向许可证服务器发出请求。

我必须做的唯一改变是添加周围的std::thread

    void WidevineSession::forward_license_request(const std::vector<uint8_t> &data) {
        std::thread{
                [=]() {
                    std::this_thread::sleep_for(std::chrono::milliseconds{100});

                    net::HttpRequest request{"POST", _license_server_url};
                    request.add_header("Authorization", fmt::format("Bearer {}", _access_token))
                            .byte_body(data);

                    const auto response = _client.execute(request);
                    if (response.status_code() != 200) {
                        log->error("Widevine license request not accepted by license server: {} {} ({})", response.status_code(), response.status_text(), utils::bytes_to_utf8(response.body()));
                        throw std::runtime_error{"Error requesting widevine license"};
                    }

                    log->info("Successfully requested widevine license from license server");
                    _adapter->update_session(this, _session_id, response.body());
                }
        }.detach();
    }
于 2020-01-11T07:53:01.563 回答