diff --git a/src/Session.cpp b/src/Session.cpp index 09660ebf4..16c3ec7a4 100644 --- a/src/Session.cpp +++ b/src/Session.cpp @@ -1263,6 +1263,36 @@ void CSession::OnStreamChange(adaptive::AdaptiveStream* adStream) } } +bool SESSION::CSession::OnGetStream(int streamid, kodi::addon::InputstreamInfo& info) +{ + CStream* stream(GetStream(streamid - GetPeriodId() * 1000)); + + if (stream) + { + const uint16_t psshSetPos = stream->m_adStream.getRepresentation()->m_psshSetPos; + if (psshSetPos != PSSHSET_POS_DEFAULT || + stream->m_adStream.getPeriod()->GetEncryptionState() == EncryptionState::NOT_SUPPORTED) + { + if (!GetSingleSampleDecryptor(psshSetPos)) + { + // If the stream is protected with a unsupported DRM, we have to stop the playback, + // since there are no ways to stop playback when Kodi request streams + // we are forced to delete all CStream's here, so that when demux reader will starts + // will have no data to process, and so stop the playback + // (other streams may have been requested/opened before this one) + LOG::Log(LOGERROR, "GetStream(%d): Decrypter for the stream not found"); + DeleteStreams(); + return false; + } + } + + info = stream->m_info; + return true; + } + + return false; +} + std::shared_ptr CSession::GetSingleSampleDecrypter(std::string sessionId) { for (std::vector::iterator b(m_cdmSessions.begin() + 1), e(m_cdmSessions.end()); diff --git a/src/Session.h b/src/Session.h index ebf435404..05dedf034 100644 --- a/src/Session.h +++ b/src/Session.h @@ -318,6 +318,14 @@ class ATTR_DLL_LOCAL CSession : public adaptive::AdaptiveStreamObserver */ void OnStreamChange(adaptive::AdaptiveStream* adStream) override; + /*! + * \brief Callback from CInputStreamAdaptive::GetStream. + * \param streamid The requested stream id + * \param info The stream info object (can be updated) + * \return True to allow Kodi core to load the stream, otherwise false + */ + bool OnGetStream(int streamid, kodi::addon::InputstreamInfo& info); + protected: /*! \brief Check for and load decrypter module matching the supplied key system * \param key_system [OUT] Will be assigned to if a decrypter is found matching diff --git a/src/main.cpp b/src/main.cpp index a6ec67eea..ea35b4048 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -127,38 +127,13 @@ void CInputStreamAdaptive::GetCapabilities(kodi::addon::InputstreamCapabilities& bool CInputStreamAdaptive::GetStream(int streamid, kodi::addon::InputstreamInfo& info) { + // GetStream is called by Kodi twice times, before and after OpenStream. LOG::Log(LOGDEBUG, "GetStream(%d)", streamid); - CStream* stream(m_session->GetStream(streamid - m_session->GetPeriodId() * 1000)); - - if (stream) - { - // If the stream is encrypted, verify if the decrypter has been initialized - // this is important for HLS because the DRM it is initialized at later time - // so on the OpenStream, instead of CSession::Initialize->InitializePeriod->InitializeDRM - // Since kodi initialize one single stream at time, can happens that or another stream - // has been opened before this one, or another stream will be opened after this one (e.g. unencrypted) - // so if you dont delete all streams, the kodi demux reader still starts - // and a corrupted playback will starts. - // NOTE: GetStream is called by Kodi twice times, before and after OpenStream, on HLS - // the first time all streams are unencrypted because child manifest has not been downloaded - const uint16_t psshSetPos = stream->m_adStream.getRepresentation()->m_psshSetPos; - if (psshSetPos != PSSHSET_POS_DEFAULT || - stream->m_adStream.getPeriod()->GetEncryptionState() == EncryptionState::NOT_SUPPORTED) - { - if (!m_session->GetSingleSampleDecryptor(psshSetPos)) - { - LOG::Log(LOGERROR, "GetStream(%d): Decrypter for the stream not found"); - m_session->DeleteStreams(); - return false; - } - } - - info = stream->m_info; - return true; - } - - return false; + // Return false prevents this stream from loading, but does not stop playback, + // Kodi core will continue to request another stream of same type (a/v) + // as long as one is successful + return m_session->OnGetStream(streamid, info); } void CInputStreamAdaptive::UnlinkIncludedStreams(CStream* stream)