📄 conference.cxx
字号:
const short * end = pcm + (amount / 2);
while (pcm != end) {
if (*pcm < 0)
sum -= *pcm++;
else
sum += *pcm++;
}
signalLevel = sum/(amount/2);
}
audioLevel = ((signalLevel * 2) + audioLevel) / 3;
if (lock.Wait()) {
if (conference != NULL)
conference->WriteMemberAudioLevel(this, audioLevel);
MemberListType::iterator r;
for (r = memberList.begin(); r != memberList.end(); ++r) {
if (r->second != NULL)
r->second->OnExternalSendAudio(id, (BYTE *)buffer, amount);
}
lock.Signal();
}
}
void ConferenceMember::OnExternalSendAudio(ConferenceMemberId source, const void * buffer, PINDEX amount)
{
if (lock.Wait()) {
ConnectionListType::iterator r = connectionList.find(source);
if (r != connectionList.end())
if (r->second != NULL)
r->second->Write((BYTE *)buffer, amount);
lock.Signal();
}
}
void ConferenceMember::ReadAudio(void * buffer, PINDEX amount)
{
// First, set the buffer to empty.
memset(buffer, 0, amount);
if (lock.Wait()) {
if (conference != NULL)
conference->ReadMemberAudio(this, buffer, amount);
lock.Signal();
}
}
void ConferenceMember::OnExternalSetAudioLevel(ConferenceMemberId id, unsigned audioLevel)
{
#if OPENMCU_VIDEO
if (lock.Wait()) {
videoMixer->SetAudioLevel(id, audioLevel);
lock.Signal();
}
#endif // OPENMCU_VIDEO
}
#if OPENMCU_VIDEO
// called whenever the connection needs a frame of video to send
void ConferenceMember::ReadVideo(void * buffer, int width, int height, PINDEX & amount)
{
++totalVideoFramesSent;
if (!firstFrameSendTime.IsValid())
firstFrameSendTime = PTime();
if (lock.Wait()) {
if (conference != NULL) {
if (conference->UseSameVideoForAllMembers())
conference->ReadMemberVideo(this, buffer, width, height, amount);
else if (videoMixer != NULL)
videoMixer->ReadFrame(*this, buffer, width, height, amount);
}
lock.Signal();
}
}
// called whenever the connection receives a frame of video
void ConferenceMember::WriteVideo(const void * buffer, int width, int height, PINDEX amount)
{
++totalVideoFramesReceived;
if (!firstFrameReceiveTime.IsValid())
firstFrameReceiveTime = PTime();
if (lock.Wait()) {
if (conference != NULL) {
if (!conference->WriteMemberVideo(this, buffer, width, height, amount)) {
PWaitAndSignal m(memberFrameStoreMutex);
VideoFrameStoreList::FrameStore & fs = memberFrameStores.GetFrameStore(width, height);
memcpy(fs.data.GetPointer(), buffer, amount);
memberFrameStores.InvalidateExcept(width, height);
}
}
lock.Signal();
}
}
void ConferenceMember::OnExternalSendVideo(ConferenceMemberId id, const void * buffer, int width, int height, PINDEX amount)
{
if (lock.Wait()) {
videoMixer->WriteFrame(id, buffer, width, height, amount);
lock.Signal();
}
}
void * ConferenceMember::OnExternalReadVideo(ConferenceMemberId id, int width, int height, PINDEX & bytesReturned)
{
if (!lock.Wait())
return NULL;
memberFrameStoreMutex.Wait();
BOOL found;
VideoFrameStoreList::FrameStore & nearestFs = memberFrameStores.GetNearestFrameStore(width, height, found);
// if no valid framestores, nothing we can do
if (!found) {
memberFrameStoreMutex.Signal();
lock.Signal();
return NULL;
}
// if the valid framestore is a perfect match, return it
if ((nearestFs.width == width) && (nearestFs.height == height))
return nearestFs.data.GetPointer();
// create a new destinationf framestore
VideoFrameStoreList::FrameStore & destFs = memberFrameStores.GetFrameStore(width, height);
// if src is qcif, and dest is cif, then do special case
if ((nearestFs.width == QCIF_WIDTH) &&
(nearestFs.height == QCIF_HEIGHT) &&
(width == CIF_WIDTH) &&
(height == CIF_HEIGHT)) {
MCUVideoMixer::ConvertQCIFToCIF(nearestFs.data.GetPointer(), destFs.data.GetPointer());
destFs.valid = TRUE;
}
// create an image that is the right size
else {
fsConverter->SetSrcFrameSize(nearestFs.width, nearestFs.height);
fsConverter->SetDstFrameSize(width, height, TRUE);
bytesReturned = width*height*3/2;
fsConverter->Convert(nearestFs.data.GetPointer(), destFs.data.GetPointer(), nearestFs.width * nearestFs.height * 3 / 2, &bytesReturned);
destFs.valid = TRUE;
}
return destFs.data.GetPointer();
}
void ConferenceMember::UnlockExternalVideo()
{
memberFrameStoreMutex.Signal();
lock.Signal();
}
BOOL ConferenceMember::AddVideoSource(ConferenceMemberId id)
{
PAssert(videoMixer != NULL, "attempt to add video source to NULL video mixer");
return videoMixer->AddVideoSource(id, *this);
}
void ConferenceMember::RemoveVideoSource(ConferenceMemberId id)
{
PAssert(videoMixer != NULL, "attempt to add video source to NULL video mixer");
videoMixer->AddVideoSource(id, *this);
}
BOOL ConferenceMember::OnOutgoingVideo(void * buffer, int width, int height, PINDEX & amount)
{
return FALSE;
}
BOOL ConferenceMember::OnIncomingVideo(const void * buffer, int width, int height, PINDEX amount)
{
return FALSE;
}
#endif
PString ConferenceMember::GetMonitorInfo(const PString & /*hdr*/)
{
return PString::Empty();
}
///////////////////////////////////////////////////////////////////////////
ConferenceConnection::ConferenceConnection(ConferenceMemberId _id)
: id(_id), bufferSize(PCM_BUFFER_SIZE)
{
buffer = new BYTE[bufferSize];
bufferStart = bufferLen = 0;
}
ConferenceConnection::~ConferenceConnection()
{
delete[] buffer;
}
void ConferenceConnection::Write(const BYTE * data, PINDEX amount)
{
if (amount == 0)
return;
PWaitAndSignal mutex(audioBufferMutex);
// if there is not enough room for the new data, make room
PINDEX newLen = bufferLen + amount;
if (newLen > bufferSize) {
PINDEX toRemove = newLen - bufferSize;
bufferStart = (bufferStart + toRemove) % bufferSize;
bufferLen -= toRemove;
}
// copy data to the end of the new data, up to the end of the buffer
PINDEX copyStart = (bufferStart + bufferLen) % bufferSize;
if ((copyStart + amount) > bufferSize) {
PINDEX toCopy = bufferSize - copyStart;
memcpy(buffer + copyStart, data, toCopy);
copyStart = 0;
data += toCopy;
amount -= toCopy;
bufferLen += toCopy;
}
// copy the rest of the data
if (amount > 0) {
memcpy(buffer + copyStart, data, amount);
bufferLen += amount;
}
}
void ConferenceConnection::ReadAudio(BYTE * data, PINDEX amount)
{
if (amount == 0)
return;
PWaitAndSignal mutex(audioBufferMutex);
if (bufferLen == 0) {
memset(data, 0, amount); // nothing in the buffer. return silence
return;
}
// fill output data block with silence if audiobuffer is
// almost empty.
if (amount > bufferLen)
memset(data + bufferLen, 0, amount - bufferLen);
// only copy up to the amount of data remaining
PINDEX copyLeft = PMIN(amount, bufferLen);
// if buffer is wrapping, get first part
if ((bufferStart + copyLeft) > bufferSize) {
PINDEX toCopy = bufferSize - bufferStart;
memcpy(data, buffer + bufferStart, toCopy);
data += toCopy;
bufferLen -= toCopy;
copyLeft -= toCopy;
bufferStart = 0;
}
// get the remainder of the buffer
if (copyLeft > 0) {
memcpy(data, buffer + bufferStart, copyLeft);
bufferLen -= copyLeft;
bufferStart = (bufferStart + copyLeft) % bufferSize;
}
}
void ConferenceConnection::ReadAndMixAudio(BYTE * data, PINDEX amount, PINDEX channels)
{
if (amount == 0) {
PTRACE(3, "Mixer\tNo data to read");
return;
}
PWaitAndSignal mutex(audioBufferMutex);
if (bufferLen == 0) {
// nothing in the buffer to mix.
return;
}
// only mix up to the amount of data remaining
PINDEX copyLeft = PMIN(amount, bufferLen);
// if buffer is wrapping, get first part
if ((bufferStart + copyLeft) > bufferSize) {
PINDEX toCopy = bufferSize - bufferStart;
Mix(data, buffer + bufferStart, toCopy, channels);
data += toCopy;
bufferLen -= toCopy;
copyLeft -= toCopy;
bufferStart = 0;
}
// get the remainder of the buffer
if (copyLeft > 0) {
Mix(data, buffer + bufferStart, copyLeft, channels);
bufferLen -= copyLeft;
bufferStart = (bufferStart + copyLeft) % bufferSize;
}
}
void ConferenceConnection::Mix(BYTE * dst, const BYTE * src, PINDEX count, PINDEX /*channels*/)
{
#if 0
memcpy(dst, src, count);
#else
PINDEX i;
for (i = 0; i < count; i += 2) {
int srcVal = *(short *)src;
int dstVal = *(short *)dst;
int newVal = dstVal;
#if 0 //The loudest person gains the channel.
#define mix_abs(x) ((x) >= 0 ? (x) : -(x))
if (mix_abs(newVal) > mix_abs(srcVal))
dstVal = newVal;
else
dstVal = srcVal;
#else //Just add up all the channels.
if ((newVal + srcVal) > 0x7fff)
dstVal = 0x7fff;
else
dstVal += srcVal;
#endif
*(short *)dst = (short)dstVal;
dst += 2;
src += 2;
}
#endif
}
///////////////////////////////////////////////////////////////
MCULock::MCULock()
{
closing = FALSE;
count = 0;
}
BOOL MCULock::Wait(BOOL hard)
{
mutex.Wait();
if (hard)
return TRUE;
BOOL ret = TRUE;
if (!closing)
count++;
else
ret = FALSE;
mutex.Signal();
return ret;
}
void MCULock::Signal(BOOL hard)
{
if (hard) {
mutex.Signal();
return;
}
mutex.Wait();
if (count > 0)
count--;
if (closing)
closeSync.Signal();
mutex.Signal();
}
void MCULock::WaitForClose()
{
mutex.Wait();
closing = TRUE;
BOOL wait = count > 0;
mutex.Signal();
while (wait) {
closeSync.Wait();
mutex.Wait();
wait = count > 0;
mutex.Signal();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -