Compare commits
4 Commits
dc8cf6a12c
...
7f638a5aef
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f638a5aef | |||
| 25e30a6ba7 | |||
| 3d455732ea | |||
| 0e48bed9c1 |
@@ -189,6 +189,7 @@ void AgentImpl::processConfig(JsonCpp::Value &d, JsonCpp::Value &answer)
|
|||||||
|
|
||||||
config()[CONFIG_MULTIPLEXING] = true;
|
config()[CONFIG_MULTIPLEXING] = true;
|
||||||
config()[CONFIG_DISPLAYNAME] = "Voip quality tester";
|
config()[CONFIG_DISPLAYNAME] = "Voip quality tester";
|
||||||
|
config()[CONFIG_USERAGENT] = d["useragent"].asString();
|
||||||
|
|
||||||
mUseNativeAudio = d["nativeaudio"].asBool();
|
mUseNativeAudio = d["nativeaudio"].asBool();
|
||||||
config()[CONFIG_OWN_DNS] = d["dns_servers"].asString();
|
config()[CONFIG_OWN_DNS] = d["dns_servers"].asString();
|
||||||
|
|||||||
@@ -66,10 +66,13 @@ size_t SpeexResampler::processBuffer(const void* src, size_t sourceLength, size_
|
|||||||
|
|
||||||
if (mDestRate == mSourceRate)
|
if (mDestRate == mSourceRate)
|
||||||
{
|
{
|
||||||
|
// Pass-through, but never write past the caller's buffer: clamp to its
|
||||||
|
// capacity instead of trusting sourceLength (which is caller/file driven).
|
||||||
assert(destCapacity >= sourceLength);
|
assert(destCapacity >= sourceLength);
|
||||||
memcpy(dest, src, sourceLength);
|
size_t copied = std::min(sourceLength, destCapacity);
|
||||||
sourceProcessed = sourceLength;
|
memcpy(dest, src, copied);
|
||||||
return sourceLength;
|
sourceProcessed = copied;
|
||||||
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mContext)
|
if (!mContext)
|
||||||
|
|||||||
@@ -150,6 +150,14 @@ bool WavFileReader::open(const std::filesystem::path& p)
|
|||||||
if (mBits != 16)
|
if (mBits != 16)
|
||||||
THROW_READERROR;
|
THROW_READERROR;
|
||||||
|
|
||||||
|
// The read path is mono-only: it divides byte counts by AUDIO_CHANNELS
|
||||||
|
// and starts the resampler with AUDIO_CHANNELS. Reject anything else -
|
||||||
|
// a multi-channel file would make read() copy more source bytes than the
|
||||||
|
// caller's (mono-sized) output buffer can hold. Also reject a zero rate,
|
||||||
|
// which would divide by zero in readRaw() / poison the resampler ratio.
|
||||||
|
if (mChannels != AUDIO_CHANNELS || mSamplerate == 0)
|
||||||
|
THROW_READERROR;
|
||||||
|
|
||||||
// Look for the chunk 'data'
|
// Look for the chunk 'data'
|
||||||
mInput->seekg(fmtStart + std::streampos(fmtSize));
|
mInput->seekg(fmtStart + std::streampos(fmtSize));
|
||||||
|
|
||||||
|
|||||||
@@ -94,8 +94,20 @@ static AmrPayload parseAmrPayload(AmrPayloadInfo& input, size_t& cngCounter)
|
|||||||
// Table of contents
|
// Table of contents
|
||||||
uint8_t F, FT, Q;
|
uint8_t F, FT, Q;
|
||||||
|
|
||||||
|
// Bits consumed by a single ToC entry: F(1) + FT(4) + Q(1), plus 2 padding
|
||||||
|
// bits in octet-aligned mode.
|
||||||
|
const size_t tocEntryBits = input.mOctetAligned ? 8 : 6;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
// Stop when the payload no longer holds a full ToC entry. BitReader
|
||||||
|
// saturates at end-of-stream (re-reads the last bit) instead of
|
||||||
|
// signalling EOF, so trusting the F continuation bit alone would loop
|
||||||
|
// forever - and append AmrFrames unbounded - on a truncated or crafted
|
||||||
|
// payload whose final bit is 1.
|
||||||
|
if (bit_reader.position() + tocEntryBits > bit_reader.count())
|
||||||
|
break;
|
||||||
|
|
||||||
// Read TOC. It is still relates to RTP part of AMR frames packing; not the AMR frame itself.
|
// Read TOC. It is still relates to RTP part of AMR frames packing; not the AMR frame itself.
|
||||||
// F (1 bit): If set to 1, indicates that this frame is followed by
|
// F (1 bit): If set to 1, indicates that this frame is followed by
|
||||||
// another speech frame in this payload; if set to 0, indicates that
|
// another speech frame in this payload; if set to 0, indicates that
|
||||||
|
|||||||
@@ -37,11 +37,14 @@ void SingleAudioStream::copyPcmTo(Audio::DataWindow& output, int needed)
|
|||||||
// Number of bytes to fill on this step
|
// Number of bytes to fill on this step
|
||||||
auto requested = needed - output.filled();
|
auto requested = needed - output.filled();
|
||||||
|
|
||||||
|
// requested is in bytes: 16-bit samples at AUDIO_SAMPLERATE/AUDIO_CHANNELS
|
||||||
|
constexpr int bytesPerMs = AUDIO_SAMPLERATE / 1000 * sizeof(int16_t) * AUDIO_CHANNELS;
|
||||||
|
|
||||||
auto options = AudioReceiver::DecodeOptions{
|
auto options = AudioReceiver::DecodeOptions{
|
||||||
.mRealtimeProcessing = true,
|
.mRealtimeProcessing = true,
|
||||||
.mResampleToMainRate = true,
|
.mResampleToMainRate = true,
|
||||||
.mSkipDecode = false,
|
.mSkipDecode = false,
|
||||||
.mElapsed = std::chrono::milliseconds(requested / (AUDIO_SAMPLERATE / 1000))
|
.mElapsed = std::chrono::milliseconds(requested / bytesPerMs)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Try to get the data from receiver / decoder
|
// Try to get the data from receiver / decoder
|
||||||
|
|||||||
@@ -497,12 +497,12 @@ size_t BufferReader::count() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
// -------------- BufferWriter ----------------------
|
// -------------- BufferWriter ----------------------
|
||||||
BufferWriter::BufferWriter(ByteBuffer &buffer)
|
BufferWriter::BufferWriter(ByteBuffer &buffer, size_t startOffset)
|
||||||
:mData(buffer.mutableData()), mIndex(0)
|
:mBuffer(&buffer), mData(buffer.mutableData() + startOffset), mBase(startOffset), mIndex(0), mCapacity(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
BufferWriter::BufferWriter(void *output)
|
BufferWriter::BufferWriter(void *output, size_t capacity)
|
||||||
:mData(reinterpret_cast<uint8_t*>(output)), mIndex(0)
|
:mBuffer(nullptr), mData(reinterpret_cast<uint8_t*>(output)), mBase(0), mIndex(0), mCapacity(capacity)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
@@ -545,6 +545,30 @@ void BufferWriter::writeIp(const NetworkAddress& ip)
|
|||||||
|
|
||||||
void BufferWriter::writeBuffer(const void* dataPtr, size_t dataSize)
|
void BufferWriter::writeBuffer(const void* dataPtr, size_t dataSize)
|
||||||
{
|
{
|
||||||
|
if (dataSize == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mBuffer)
|
||||||
|
{
|
||||||
|
// Growable mode: ensure the backing buffer is large enough, then refresh
|
||||||
|
// the cached pointer in case resize() reallocated the storage.
|
||||||
|
size_t needed = mBase + mIndex + dataSize;
|
||||||
|
if (needed > mBuffer->size())
|
||||||
|
mBuffer->resize(needed);
|
||||||
|
mData = mBuffer->mutableData() + mBase;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Bounded mode: never write past the caller-supplied capacity.
|
||||||
|
if (mIndex + dataSize > mCapacity)
|
||||||
|
{
|
||||||
|
assert(0 && "BufferWriter capacity exceeded");
|
||||||
|
dataSize = mIndex < mCapacity ? mCapacity - mIndex : 0;
|
||||||
|
if (dataSize == 0)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
memmove(mData + mIndex, dataPtr, dataSize);
|
memmove(mData + mIndex, dataPtr, dataSize);
|
||||||
mIndex += dataSize;
|
mIndex += dataSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,12 +172,17 @@ namespace ice
|
|||||||
class BufferWriter
|
class BufferWriter
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
uint8_t* mData;
|
ByteBuffer* mBuffer; // Non-null => growable: writes resize this buffer to fit
|
||||||
size_t mIndex;
|
uint8_t* mData; // Cached write pointer (refreshed on growth in growable mode)
|
||||||
|
size_t mBase; // Start offset within mBuffer (growable mode)
|
||||||
|
size_t mIndex; // Bytes written since mBase
|
||||||
|
size_t mCapacity; // Usable capacity from mData (raw/bounded mode)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BufferWriter(void* output);
|
// Bounded writer over caller-owned memory. Writes past 'capacity' are refused.
|
||||||
BufferWriter(ByteBuffer& buffer);
|
BufferWriter(void* output, size_t capacity);
|
||||||
|
// Growable writer: the backing buffer is resized as needed so writes never overflow.
|
||||||
|
BufferWriter(ByteBuffer& buffer, size_t startOffset = 0);
|
||||||
|
|
||||||
void writeUInt(uint32_t value);
|
void writeUInt(uint32_t value);
|
||||||
void writeUShort(uint16_t value);
|
void writeUShort(uint16_t value);
|
||||||
|
|||||||
@@ -216,8 +216,10 @@ void StunMessage::buildPacket(ByteBuffer& buffer, const std::string& password)
|
|||||||
for (size_t i=0; i<4; i++)
|
for (size_t i=0; i<4; i++)
|
||||||
bitstream.writeBit(bit(msgtype, 3-i));
|
bitstream.writeBit(bit(msgtype, 3-i));
|
||||||
|
|
||||||
// Enqueue 2 bytes of length - now it is zero
|
// Enqueue 2 bytes of length - now it is zero.
|
||||||
BufferWriter stream(buffer.mutableData() + bitstream.count() / 8);
|
// Growable writer starting right after the bits already emitted; it resizes
|
||||||
|
// 'buffer' as attributes are appended so an oversized message cannot overflow.
|
||||||
|
BufferWriter stream(buffer, bitstream.count() / 8);
|
||||||
stream.writeUShort(0);
|
stream.writeUShort(0);
|
||||||
|
|
||||||
// Enqueue magic cookie value
|
// Enqueue magic cookie value
|
||||||
|
|||||||
Reference in New Issue
Block a user