webrtc/video_engine/main/source/vie_channel_manager.cc

595 lines
20 KiB
C++

/*
* 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<const ViEChannelManager*>
(_vieManager)->ViEChannelPtr(vieChannelId);
}
ViEEncoder* ViEChannelManagerScoped::Encoder(int vieChannelId) const
{
return static_cast<const ViEChannelManager*>
(_vieManager)->ViEEncoderPtr(vieChannelId);
}
bool ViEChannelManagerScoped::ChannelUsingViEEncoder(int channelId) const
{
return (static_cast<const ViEChannelManager*>
(_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<ViEChannel*> (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<ViEEncoder*> (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<ViEChannel*> (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<ViEEncoder*> (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<ViEEncoder*> (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<ViEEncoder*> (mapItem->GetItem());
if (mapItem->GetId() != channelId)
{
if (channelEncoder == static_cast<ViEEncoder*> (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<ViEChannel*> (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