148 lines
3.9 KiB
C++
148 lines
3.9 KiB
C++
//
|
|
// Copyright (c) 2013-2025 The SRS Authors
|
|
//
|
|
// SPDX-License-Identifier: MIT
|
|
//
|
|
|
|
#include <srs_app_stream_token.hpp>
|
|
|
|
#include <srs_app_config.hpp>
|
|
#include <srs_kernel_error.hpp>
|
|
#include <srs_kernel_log.hpp>
|
|
#include <srs_protocol_rtmp_stack.hpp>
|
|
#include <srs_protocol_st.hpp>
|
|
|
|
// Global instance
|
|
SrsStreamPublishTokenManager *_srs_stream_publish_tokens = NULL;
|
|
|
|
ISrsStreamPublishToken::ISrsStreamPublishToken()
|
|
{
|
|
}
|
|
|
|
ISrsStreamPublishToken::~ISrsStreamPublishToken()
|
|
{
|
|
}
|
|
|
|
SrsStreamPublishToken::SrsStreamPublishToken(const std::string &stream_url, ISrsStreamPublishTokenManager *manager)
|
|
{
|
|
stream_url_ = stream_url;
|
|
acquired_ = false;
|
|
manager_ = manager;
|
|
publisher_cid_ = SrsContextId();
|
|
}
|
|
|
|
SrsStreamPublishToken::~SrsStreamPublishToken()
|
|
{
|
|
// Automatically release the token when destroyed
|
|
if (acquired_ && manager_) {
|
|
manager_->release_token(stream_url_);
|
|
}
|
|
}
|
|
|
|
std::string SrsStreamPublishToken::stream_url()
|
|
{
|
|
return stream_url_;
|
|
}
|
|
|
|
bool SrsStreamPublishToken::is_acquired()
|
|
{
|
|
return acquired_;
|
|
}
|
|
|
|
void SrsStreamPublishToken::set_acquired(bool acquired)
|
|
{
|
|
acquired_ = acquired;
|
|
}
|
|
|
|
const SrsContextId &SrsStreamPublishToken::publisher_cid()
|
|
{
|
|
return publisher_cid_;
|
|
}
|
|
|
|
void SrsStreamPublishToken::set_publisher_cid(const SrsContextId &cid)
|
|
{
|
|
publisher_cid_ = cid;
|
|
}
|
|
|
|
ISrsStreamPublishTokenManager::ISrsStreamPublishTokenManager()
|
|
{
|
|
}
|
|
|
|
ISrsStreamPublishTokenManager::~ISrsStreamPublishTokenManager()
|
|
{
|
|
}
|
|
|
|
SrsStreamPublishTokenManager::SrsStreamPublishTokenManager()
|
|
{
|
|
mutex_ = srs_mutex_new();
|
|
}
|
|
|
|
SrsStreamPublishTokenManager::~SrsStreamPublishTokenManager()
|
|
{
|
|
// Clean up all remaining tokens. Each token's destructor automatically calls
|
|
// release_token() which removes it from tokens_ map, so we use while loop
|
|
// to avoid iterator invalidation issues.
|
|
while (!tokens_.empty()) {
|
|
SrsStreamPublishToken *token = tokens_.begin()->second;
|
|
|
|
// Token destructor will call release_token() and remove this entry from map
|
|
srs_freep(token);
|
|
}
|
|
|
|
srs_mutex_destroy(mutex_);
|
|
srs_trace("stream publish token manager destroyed");
|
|
}
|
|
|
|
srs_error_t SrsStreamPublishTokenManager::acquire_token(ISrsRequest *req, SrsStreamPublishToken *&token)
|
|
{
|
|
srs_error_t err = srs_success;
|
|
|
|
std::string stream_url = req->get_stream_url();
|
|
SrsContextId current_cid = _srs_context->get_id();
|
|
|
|
SrsLocker(&mutex_);
|
|
|
|
// Get or create token for this stream
|
|
SrsStreamPublishToken *stream_token = NULL;
|
|
|
|
std::map<std::string, SrsStreamPublishToken *>::iterator it = tokens_.find(stream_url);
|
|
if (it != tokens_.end()) {
|
|
stream_token = it->second;
|
|
} else {
|
|
stream_token = new SrsStreamPublishToken(stream_url, this);
|
|
tokens_[stream_url] = stream_token;
|
|
}
|
|
|
|
// Check if token is already acquired by another publisher
|
|
if (stream_token->is_acquired()) {
|
|
SrsContextId existing_cid = stream_token->publisher_cid();
|
|
return srs_error_new(ERROR_SYSTEM_STREAM_BUSY,
|
|
"stream %s is busy, acquired by cid=%s, current cid=%s",
|
|
stream_url.c_str(), existing_cid.c_str(), current_cid.c_str());
|
|
} else {
|
|
stream_token->set_acquired(true);
|
|
stream_token->set_publisher_cid(current_cid);
|
|
}
|
|
|
|
// Return the token from the map (caller will manage its lifetime)
|
|
token = stream_token;
|
|
|
|
return err;
|
|
}
|
|
|
|
void SrsStreamPublishTokenManager::release_token(const std::string &stream_url)
|
|
{
|
|
SrsLocker(&mutex_);
|
|
|
|
// Find and erase the token from the map
|
|
std::map<std::string, SrsStreamPublishToken *>::iterator it = tokens_.find(stream_url);
|
|
srs_assert(it != tokens_.end());
|
|
|
|
SrsStreamPublishToken *token = it->second;
|
|
token->set_acquired(false);
|
|
srs_trace("stream publish token released and deleted, url=%s", stream_url.c_str());
|
|
|
|
// Erase from map first, then delete the token
|
|
tokens_.erase(it);
|
|
}
|