Проблема вызвана тем фактом, что все в CreateSessionAndGenerateRequest
выполняется синхронно - это означает, что к тому времени, когда CreateSessionAndGenerateRequest
вернет ваше обещание, оно будет всегда разрешено.
МЧР выпустит kLicenseRequest
внутри CreateSessionAndGenerateRequest
, и он не делает это в режиме "запусти и забудь", но функция ждет там, пока ты не вернешься из cdm::Host_10::OnSessionMessage
. Поскольку моя реализация OnSessionMessage
создавала синхронный HTTP-запрос к серверу лицензий до - также синхронно - вызова UpdateSession
, вся цепочка оказалась блокированной.
Так что в конечном итоге я звонил UpdateSession
все еще находясь внутри CreateSessionAndGenerateRequest
, и я предполагаю, что CDM не может справиться с этим и реагирует, создавая новый сеанс с данным ID и снова генерируя запрос, который, конечно, вызвал еще один UpdateSession
и т. д.
В конечном счете, самым простым способом разорвать цикл было сделать что-то асинхронное. Я решил запустить отдельный поток при получении kLicenseRequest
, подождать несколько миллисекунд, чтобы убедиться, что CreateSessionAndGenerateRequest
успевает завершить sh (не уверен, действительно ли это требуется), а затем отправить запрос на сервер лицензий. .
Единственное изменение, которое я должен был сделать, это добавить окружение 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();
}