| 972 | } |
| 973 | |
| 974 | bool RtmpContext::RemoveMessageStream(RtmpStreamBase* stream) { |
| 975 | if (stream == NULL) { |
| 976 | LOG(FATAL) << "Param[stream] is NULL"; |
| 977 | return false; |
| 978 | } |
| 979 | const uint32_t stream_id = stream->stream_id(); |
| 980 | if (stream_id == RTMP_CONTROL_MESSAGE_STREAM_ID) { |
| 981 | LOG(FATAL) << "stream_id=" << RTMP_CONTROL_MESSAGE_STREAM_ID |
| 982 | << " is reserved for control stream"; |
| 983 | return false; |
| 984 | } |
| 985 | // for deref the stream outside _stream_mutex. |
| 986 | butil::intrusive_ptr<RtmpStreamBase> deref_ptr; |
| 987 | { |
| 988 | std::unique_lock<butil::Mutex> mu(_stream_mutex); |
| 989 | MessageStreamInfo* info = _mstream_map.seek(stream_id); |
| 990 | if (info == NULL) { |
| 991 | mu.unlock(); |
| 992 | return false; |
| 993 | } |
| 994 | if (stream != info->stream) { |
| 995 | mu.unlock(); |
| 996 | LOG(FATAL) << "Unmatched " |
| 997 | << (stream->is_client_stream() ? "client" : "server") |
| 998 | << " stream of stream_id=" << stream_id; |
| 999 | return false; |
| 1000 | } |
| 1001 | if (stream->is_client_stream()) { |
| 1002 | DeallocateChunkStreamId(stream->_chunk_stream_id); |
| 1003 | } else { // server-side |
| 1004 | DeallocateMessageStreamId(stream_id); |
| 1005 | } |
| 1006 | deref_ptr.swap(info->stream); |
| 1007 | _mstream_map.erase(stream_id); |
| 1008 | } |
| 1009 | return true; |
| 1010 | } |
| 1011 | |
| 1012 | // The transactionID is for createStream and RPC-call in RTMP which is |
| 1013 | // infrequent in most cases, thus we just use a map protected with a mutex |
no test coverage detected