/* * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. * * Use of this source code is governed by a BSD-style license * that can be found in the LICENSE file in the root of the source * tree. An additional intellectual property rights grant can be found * in the file PATENTS. All contributing project authors may * be found in the AUTHORS file in the root of the source tree. */ /* * vie_channel_manager.cc */ #include "vie_channel_manager.h" #include "engine_configurations.h" #include "vie_defines.h" #include "critical_section_wrapper.h" #include "trace.h" #include "vie_channel.h" #include "vie_encoder.h" #include "process_thread.h" // VoiceEngine #include "voe_video_sync.h" namespace webrtc { ViEChannelManagerScoped::ViEChannelManagerScoped( const ViEChannelManager& vieChannelManager) : ViEManagerScopedBase(vieChannelManager) { } ViEChannel* ViEChannelManagerScoped::Channel(int vieChannelId) const { return static_cast (_vieManager)->ViEChannelPtr(vieChannelId); } ViEEncoder* ViEChannelManagerScoped::Encoder(int vieChannelId) const { return static_cast (_vieManager)->ViEEncoderPtr(vieChannelId); } bool ViEChannelManagerScoped::ChannelUsingViEEncoder(int channelId) const { return (static_cast (_vieManager))->ChannelUsingViEEncoder( channelId); } // ============================================================================ // VieChannelManager // ============================================================================ // ---------------------------------------------------------------------------- // Constructor // ---------------------------------------------------------------------------- ViEChannelManager::ViEChannelManager(int engineId, int numberOfCores, ViEPerformanceMonitor& viePerformanceMonitor) : _ptrChannelIdCritsect(CriticalSectionWrapper::CreateCriticalSection()), _engineId(engineId), _numberOfCores(numberOfCores), _viePerformanceMonitor(viePerformanceMonitor), _channelMap(), _freeChannelIds(new bool[kViEMaxNumberOfChannels]), _freeChannelIdsSize(kViEMaxNumberOfChannels), _vieEncoderMap(), _voiceSyncInterface(NULL), _voiceEngine(NULL), _moduleProcessThread(NULL) { WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(engineId), "ViEChannelManager::ViEChannelManager(engineId: %d) - Constructor", engineId); for (int idx = 0; idx < _freeChannelIdsSize; idx++) { _freeChannelIds[idx] = true; } } // ---------------------------------------------------------------------------- // SetModuleProcessThread // Initialize the thread context used by none time critical tasks in video channels. // ---------------------------------------------------------------------------- void ViEChannelManager::SetModuleProcessThread( ProcessThread& moduleProcessThread) { assert(!_moduleProcessThread); _moduleProcessThread = &moduleProcessThread; } // ---------------------------------------------------------------------------- // Destructor // ---------------------------------------------------------------------------- ViEChannelManager::~ViEChannelManager() { WEBRTC_TRACE(webrtc::kTraceMemory, webrtc::kTraceVideo, ViEId(_engineId), "ViEChannelManager Destructor, engineId: %d", _engineId); while (_channelMap.Size() != 0) { MapItem* item = _channelMap.First(); const int channelId = item->GetId(); item = NULL; DeleteChannel(channelId); } if (_voiceSyncInterface) _voiceSyncInterface->Release(); if (_ptrChannelIdCritsect) { delete _ptrChannelIdCritsect; _ptrChannelIdCritsect = NULL; } if (_freeChannelIds) { delete[] _freeChannelIds; _freeChannelIds = NULL; _freeChannelIdsSize = 0; } } // ---------------------------------------------------------------------------- // CreateChannel // // Creates a new channel. 'channelId' will be the id of the created channel // ---------------------------------------------------------------------------- int ViEChannelManager::CreateChannel(int& channelId) { CriticalSectionScoped cs(*_ptrChannelIdCritsect); // Get a free id for the new channel if (GetFreeChannelId(channelId) == false) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "Max number of channels reached: %d", _channelMap.Size()); return -1; } ViEChannel* vieChannel = new ViEChannel(channelId, _engineId, _numberOfCores, *_moduleProcessThread); if (vieChannel == NULL) { ReturnChannelId(channelId); return -1; } if (vieChannel->Init() != 0) { // Could not init channel WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "%s could not init channel", __FUNCTION__, channelId); ReturnChannelId(channelId); delete vieChannel; vieChannel = NULL; return -1; } // There is no ViEEncoder for this channel, create one with default settings ViEEncoder* vieEncoder = new ViEEncoder(_engineId, channelId, _numberOfCores, *_moduleProcessThread); if (vieEncoder == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "%s(videoChannelId: %d) - Could not create a new encoder", __FUNCTION__, channelId); delete vieChannel; return -1; } // Add to the map if (_vieEncoderMap.Insert(channelId, vieEncoder) != 0) { // Could not add to the map WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "%s: Could not add new encoder for video channel %d", __FUNCTION__, channelId); delete vieChannel; delete vieEncoder; return -1; } _channelMap.Insert(channelId, vieChannel); // Register the channel at the encoder RtpRtcp* ptrSendRtpRtcpModule = vieEncoder->SendRtpRtcpModule(); if (vieChannel->RegisterSendRtpRtcpModule(*ptrSendRtpRtcpModule) != 0) { assert(false); _vieEncoderMap.Erase(channelId); _channelMap.Erase(channelId); ReturnChannelId(channelId); delete vieChannel; WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, channelId), "%s: Could not register rtp module %d", __FUNCTION__, channelId); return -1; } return 0; } // ---------------------------------------------------------------------------- // CreateChannel // // Creates a channel and attaches to an already existing ViEEncoder // ---------------------------------------------------------------------------- int ViEChannelManager::CreateChannel(int& channelId, int originalChannel) { CriticalSectionScoped cs(*_ptrChannelIdCritsect); // Check that originalChannel already exists ViEEncoder* vieEncoder = ViEEncoderPtr(originalChannel); if (vieEncoder == NULL) { // The original channel doesn't exist WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "%s: Original channel doesn't exist", __FUNCTION__, originalChannel); return -1; } // Get a free id for the new channel if (GetFreeChannelId(channelId) == false) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "Max number of channels reached: %d", _channelMap.Size()); return -1; } ViEChannel* vieChannel = new ViEChannel(channelId, _engineId, _numberOfCores, *_moduleProcessThread); if (vieChannel == NULL) { ReturnChannelId(channelId); return -1; } if (vieChannel->Init() != 0) { // Could not init channel WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "%s could not init channel", __FUNCTION__, channelId); ReturnChannelId(channelId); delete vieChannel; vieChannel = NULL; return -1; } if (_vieEncoderMap.Insert(channelId, vieEncoder) != 0) { // Could not add to the map WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "%s: Could not add new encoder for video channel %d", __FUNCTION__, channelId); ReturnChannelId(channelId); delete vieChannel; return -1; } // Set the same encoder settings for the channel as used by the master channel. // Do this before attaching rtp module to ensure all rtp cihldren has the same codec type VideoCodec encoder; if (vieEncoder->GetEncoder(encoder) == 0) { vieChannel->SetSendCodec(encoder); } _channelMap.Insert(channelId, vieChannel); // Register the channel at the encoder RtpRtcp* ptrSendRtpRtcpModule = vieEncoder->SendRtpRtcpModule(); if (vieChannel->RegisterSendRtpRtcpModule(*ptrSendRtpRtcpModule) != 0) { assert(false); _vieEncoderMap.Erase(channelId); _channelMap.Erase(channelId); ReturnChannelId(channelId); delete vieChannel; WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, channelId), "%s: Could not register rtp module %d", __FUNCTION__, channelId); return -1; } return 0; } // ---------------------------------------------------------------------------- // DeleteChannel // ---------------------------------------------------------------------------- int ViEChannelManager::DeleteChannel(int channelId) { ViEChannel* vieChannel = NULL; ViEEncoder* vieEncoder = NULL; { // Write lock to make sure no one is using the channel ViEManagerWriteScoped wl(*this); // Protect the map CriticalSectionScoped cs(*_ptrChannelIdCritsect); MapItem* mapItem = _channelMap.Find(channelId); if (mapItem == NULL) { // No such channel WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "%s Channel doesn't exist: %d", __FUNCTION__, channelId); return -1; } vieChannel = reinterpret_cast (mapItem->GetItem()); _channelMap.Erase(mapItem); // Deregister the channel from the ViEEncoder to stop the media flow vieChannel->DeregisterSendRtpRtcpModule(); ReturnChannelId(channelId); // Find the encoder object mapItem = _vieEncoderMap.Find(channelId); if (mapItem == NULL) { assert(false); WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s ViEEncoder not found for channel %d", __FUNCTION__, channelId); return -1; } // Get the ViEEncoder item vieEncoder = reinterpret_cast (mapItem->GetItem()); // Check if other channels are using the same encoder if (ChannelUsingViEEncoder(channelId)) { // Don't delete the ViEEncoder, at least on other channel is using it. WEBRTC_TRACE( webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s ViEEncoder removed from map for channel %d, not deleted", __FUNCTION__, channelId); vieEncoder = NULL; } else { WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s ViEEncoder deleted for channel %d", __FUNCTION__, channelId); // Delete later when we've released the critsect } // We can't erase the item before we've checked for other channels using same ViEEncoder _vieEncoderMap.Erase(mapItem); } // Leave the write critsect before deleting the objects. // Deleting a channel can cause other objects, such as renderers, to be deleted and might take time if (vieEncoder) { delete vieEncoder; } delete vieChannel; WEBRTC_TRACE(webrtc::kTraceInfo, webrtc::kTraceVideo, ViEId(_engineId), "%s Channel %d deleted", __FUNCTION__, channelId); return 0; } // ---------------------------------------------------------------------------- // Channel // // Returns a pointer to the channel with id 'channelId' // ---------------------------------------------------------------------------- ViEChannel* ViEChannelManager::ViEChannelPtr(int channelId) const { CriticalSectionScoped cs(*_ptrChannelIdCritsect); MapItem* mapItem = _channelMap.Find(channelId); if (mapItem == NULL) { // No such channel WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "%s Channel doesn't exist: %d", __FUNCTION__, channelId); return NULL; } ViEChannel* vieChannel = reinterpret_cast (mapItem->GetItem()); return vieChannel; } // ---------------------------------------------------------------------------- // GetChannels // // Adds all channels to channelMap // ---------------------------------------------------------------------------- void ViEChannelManager::GetViEChannels(MapWrapper& channelMap) { CriticalSectionScoped cs(*_ptrChannelIdCritsect); if (channelMap.Size() == 0) { // No channels return; } // Add all items to 'channelMap' for (MapItem* item = _channelMap.First(); item != NULL; item = _channelMap.Next(item)) { channelMap.Insert(item->GetId(), item->GetItem()); } return; } // ---------------------------------------------------------------------------- // ViEEncoderPtr // // Gets the ViEEncoder used as input for videoChannelId // ---------------------------------------------------------------------------- ViEEncoder* ViEChannelManager::ViEEncoderPtr(int videoChannelId) const { CriticalSectionScoped cs(*_ptrChannelIdCritsect); MapItem* mapItem = _vieEncoderMap.Find(videoChannelId); if (mapItem == NULL) { // No ViEEncoder for this channel... return NULL; } ViEEncoder* vieEncoder = static_cast (mapItem->GetItem()); return vieEncoder; } // ---------------------------------------------------------------------------- // GetFreeChannelId // // Returns true if we found a new channel id, freeChannelId, false otherwise // ---------------------------------------------------------------------------- bool ViEChannelManager::GetFreeChannelId(int& freeChannelId) { CriticalSectionScoped cs(*_ptrChannelIdCritsect); int idx = 0; while (idx < _freeChannelIdsSize) { if (_freeChannelIds[idx] == true) { // We've found a free id, allocate it and return _freeChannelIds[idx] = false; freeChannelId = idx + kViEChannelIdBase; return true; } idx++; } // No free channel id freeChannelId = -1; return false; } // ---------------------------------------------------------------------------- // ReturnChannelID // // Returns a previously allocated channel id // ---------------------------------------------------------------------------- void ViEChannelManager::ReturnChannelId(int channelId) { CriticalSectionScoped cs(*_ptrChannelIdCritsect); assert(channelId < kViEMaxNumberOfChannels+kViEChannelIdBase && channelId>=kViEChannelIdBase); _freeChannelIds[channelId - kViEChannelIdBase] = true; } // ---------------------------------------------------------------------------- // ChannelUsingViEEncoder // // Returns true if at least one nother channel is using the same encoder // ---------------------------------------------------------------------------- bool ViEChannelManager::ChannelUsingViEEncoder(int channelId) const { CriticalSectionScoped cs(*_ptrChannelIdCritsect); MapItem* channelItem = _vieEncoderMap.Find(channelId); if (channelItem == NULL) { // No ViEEncoder for this channel... return false; } ViEEncoder* channelEncoder = static_cast (channelItem->GetItem()); // Loop through all other channels to see if anyone points at the same ViEEncoder MapItem* mapItem = _vieEncoderMap.First(); while (mapItem) { ViEEncoder* vieEncoder = static_cast (mapItem->GetItem()); if (mapItem->GetId() != channelId) { if (channelEncoder == static_cast (mapItem->GetItem())) { // We've found another channel using the same ViEEncoder return true; } } mapItem = _vieEncoderMap.Next(mapItem); } return false; } // ---------------------------------------------------------------------------- // SetVoiceEngine // // Set the voice engine instance to be used by all video channels. We are interested in the voice engine sync interfaces // ---------------------------------------------------------------------------- int ViEChannelManager::SetVoiceEngine(VoiceEngine* voiceEngine) { // Write lock to make sure no one is using the channel ViEManagerWriteScoped wl(*this); CriticalSectionScoped cs(*_ptrChannelIdCritsect); VoEVideoSync* syncInterface = NULL; if (voiceEngine) { // Get new sync interface; syncInterface = VoEVideoSync::GetInterface(voiceEngine); if (!syncInterface) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId), "%s Can't get audio sync interface from VoiceEngine.", __FUNCTION__); if (syncInterface) { syncInterface->Release(); } return -1; } } for (MapItem* item = _channelMap.First(); item != NULL; item = _channelMap.Next(item)) { ViEChannel* channel = static_cast (item->GetItem()); assert(channel); channel->SetVoiceChannel(-1, syncInterface); } if (_voiceSyncInterface) { _voiceSyncInterface->Release(); } _voiceEngine = voiceEngine; _voiceSyncInterface = syncInterface; return 0; } VoiceEngine* ViEChannelManager::GetVoiceEngine() { CriticalSectionScoped cs(*_ptrChannelIdCritsect); return _voiceEngine; } // ---------------------------------------------------------------------------- // ConnectVoiceChannel // // Enables lip sync of the channel. // ---------------------------------------------------------------------------- int ViEChannelManager::ConnectVoiceChannel(int channelId, int audioChannelId) { CriticalSectionScoped cs(*_ptrChannelIdCritsect); if (_voiceSyncInterface == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, channelId), "No VoE set"); return -1; } ViEChannel* channel = ViEChannelPtr(channelId); if (!channel) { return -1; } return channel->SetVoiceChannel(audioChannelId, _voiceSyncInterface); } // ---------------------------------------------------------------------------- // DisconnectVoiceChannel // // Disables lip sync of the channel. // ---------------------------------------------------------------------------- int ViEChannelManager::DisconnectVoiceChannel(int channelId) { CriticalSectionScoped cs(*_ptrChannelIdCritsect); ViEChannel* channel = ViEChannelPtr(channelId); if (channel) { channel->SetVoiceChannel(-1, NULL); return 0; } else { return -1; } } } // namespace webrtc