Bug 822129: don't alloc/free on every packet send in MediaPipeline r=bwc

This commit is contained in:
Randell Jesup 2015-06-05 15:16:45 -04:00
parent b898fa537d
commit 2f96e4ab5b
4 changed files with 82 additions and 81 deletions

View File

@ -17,29 +17,54 @@ namespace mozilla {
class DataBuffer {
public:
DataBuffer() : data_(nullptr), len_(0) {}
DataBuffer() : data_(nullptr), len_(0), capacity_(0) {}
DataBuffer(const uint8_t *data, size_t len) {
Assign(data, len);
Assign(data, len, len);
}
DataBuffer(const uint8_t *data, size_t len, size_t capacity) {
Assign(data, len, capacity);
}
void Assign(const uint8_t *data, size_t len) {
Allocate(len);
// to ensure extra space for expansion
void Assign(const uint8_t *data, size_t len, size_t capacity) {
MOZ_RELEASE_ASSERT(len <= capacity);
Allocate(capacity);
memcpy(static_cast<void *>(data_.get()),
static_cast<const void *>(data), len);
len_ = len;
}
void Allocate(size_t len) {
data_.reset(new uint8_t[len ? len : 1]); // Don't depend on new [0].
void Allocate(size_t capacity) {
data_.reset(new uint8_t[capacity ? capacity : 1]); // Don't depend on new [0].
capacity_ = capacity;
}
void EnsureCapacity(size_t capacity) {
if (capacity_ < capacity) {
uint8_t *new_data = new uint8_t[ capacity ? capacity : 1];
memcpy(static_cast<void *>(new_data),
static_cast<const void *>(data_.get()), len_);
data_.reset(new_data); // after copying! Deletes old data
capacity_ = capacity;
}
}
// used when something writes to the buffer (having checked
// capacity() or used EnsureCapacity()) and increased the length.
void SetLength(size_t len) {
MOZ_RELEASE_ASSERT(len <= capacity_);
len_ = len;
}
const uint8_t *data() const { return data_.get(); }
uint8_t *data() { return data_.get(); }
size_t len() const { return len_; }
size_t capacity() const { return capacity_; }
private:
UniquePtr<uint8_t[]> data_;
size_t len_;
size_t capacity_;
DISALLOW_COPY_ASSIGN(DataBuffer);
};

View File

@ -750,109 +750,85 @@ nsresult MediaPipeline::PipelineTransport::SendRtpPacket(
const void *data, int len) {
nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
len));
len, len + SRTP_MAX_EXPANSION));
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtpPacket_s,
buf),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf, true),
NS_DISPATCH_NORMAL);
return NS_OK;
}
nsresult MediaPipeline::PipelineTransport::SendRtpPacket_s(
nsAutoPtr<DataBuffer> data) {
ASSERT_ON_THREAD(sts_thread_);
if (!pipeline_)
return NS_OK; // Detached
nsresult MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s(
nsAutoPtr<DataBuffer> data,
bool is_rtp) {
if (!pipeline_->rtp_.send_srtp_) {
MOZ_MTLOG(ML_DEBUG, "Couldn't write RTP packet; SRTP not set up yet");
ASSERT_ON_THREAD(sts_thread_);
if (!pipeline_) {
return NS_OK; // Detached
}
TransportInfo& transport = is_rtp ? pipeline_->rtp_ : pipeline_->rtcp_;
if (!transport.send_srtp_) {
MOZ_MTLOG(ML_DEBUG, "Couldn't write RTP/RTCP packet; SRTP not set up yet");
return NS_OK;
}
MOZ_ASSERT(pipeline_->rtp_.transport_);
NS_ENSURE_TRUE(pipeline_->rtp_.transport_, NS_ERROR_NULL_POINTER);
MOZ_ASSERT(transport.transport_);
NS_ENSURE_TRUE(transport.transport_, NS_ERROR_NULL_POINTER);
// libsrtp enciphers in place, so we need a new, big enough
// buffer.
// XXX. allocates and deletes one buffer per packet sent.
// Bug 822129
int max_len = data->len() + SRTP_MAX_EXPANSION;
ScopedDeletePtr<unsigned char> inner_data(
new unsigned char[max_len]);
memcpy(inner_data, data->data(), data->len());
// libsrtp enciphers in place, so we need a big enough buffer.
MOZ_ASSERT(data->capacity() >= data->len() + SRTP_MAX_EXPANSION);
int out_len;
nsresult res = pipeline_->rtp_.send_srtp_->ProtectRtp(inner_data,
data->len(),
max_len,
&out_len);
if (!NS_SUCCEEDED(res))
nsresult res;
if (is_rtp) {
res = transport.send_srtp_->ProtectRtp(data->data(),
data->len(),
data->capacity(),
&out_len);
} else {
res = transport.send_srtp_->ProtectRtcp(data->data(),
data->len(),
data->capacity(),
&out_len);
}
if (!NS_SUCCEEDED(res)) {
return res;
}
MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending RTP packet.");
pipeline_->increment_rtp_packets_sent(out_len);
return pipeline_->SendPacket(pipeline_->rtp_.transport_, inner_data,
out_len);
// paranoia; don't have uninitialized bytes included in data->len()
data->SetLength(out_len);
MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending " <<
(is_rtp ? "RTP" : "RTCP") << " packet");
if (is_rtp) {
pipeline_->increment_rtp_packets_sent(out_len);
} else {
pipeline_->increment_rtcp_packets_sent();
}
return pipeline_->SendPacket(transport.transport_, data->data(), out_len);
}
nsresult MediaPipeline::PipelineTransport::SendRtcpPacket(
const void *data, int len) {
nsAutoPtr<DataBuffer> buf(new DataBuffer(static_cast<const uint8_t *>(data),
len));
len, len + SRTP_MAX_EXPANSION));
RUN_ON_THREAD(sts_thread_,
WrapRunnable(
RefPtr<MediaPipeline::PipelineTransport>(this),
&MediaPipeline::PipelineTransport::SendRtcpPacket_s,
buf),
&MediaPipeline::PipelineTransport::SendRtpRtcpPacket_s,
buf, false),
NS_DISPATCH_NORMAL);
return NS_OK;
}
nsresult MediaPipeline::PipelineTransport::SendRtcpPacket_s(
nsAutoPtr<DataBuffer> data) {
ASSERT_ON_THREAD(sts_thread_);
if (!pipeline_)
return NS_OK; // Detached
if (!pipeline_->rtcp_.send_srtp_) {
MOZ_MTLOG(ML_DEBUG, "Couldn't write RTCP packet; SRTCP not set up yet");
return NS_OK;
}
MOZ_ASSERT(pipeline_->rtcp_.transport_);
NS_ENSURE_TRUE(pipeline_->rtcp_.transport_, NS_ERROR_NULL_POINTER);
// libsrtp enciphers in place, so we need a new, big enough
// buffer.
// XXX. allocates and deletes one buffer per packet sent.
// Bug 822129.
int max_len = data->len() + SRTP_MAX_EXPANSION;
ScopedDeletePtr<unsigned char> inner_data(
new unsigned char[max_len]);
memcpy(inner_data, data->data(), data->len());
int out_len;
nsresult res = pipeline_->rtcp_.send_srtp_->ProtectRtcp(inner_data,
data->len(),
max_len,
&out_len);
if (!NS_SUCCEEDED(res))
return res;
MOZ_MTLOG(ML_DEBUG, pipeline_->description_ << " sending RTCP packet.");
pipeline_->increment_rtcp_packets_sent();
return pipeline_->SendPacket(pipeline_->rtcp_.transport_, inner_data,
out_len);
}
void MediaPipelineTransmit::PipelineListener::
UnsetTrackId(MediaStreamGraphImpl* graph) {
#ifndef USE_FAKE_MEDIA_STREAMS

View File

@ -191,8 +191,8 @@ class MediaPipeline : public sigslot::has_slots<> {
virtual nsresult SendRtcpPacket(const void* data, int len);
private:
virtual nsresult SendRtpPacket_s(nsAutoPtr<DataBuffer> data);
virtual nsresult SendRtcpPacket_s(nsAutoPtr<DataBuffer> data);
nsresult SendRtpRtcpPacket_s(nsAutoPtr<DataBuffer> data,
bool is_rtp);
MediaPipeline *pipeline_; // Raw pointer to avoid cycles
nsCOMPtr<nsIEventTarget> sts_thread_;

View File

@ -22,9 +22,9 @@ namespace mozilla {
#define SRTP_MASTER_SALT_LENGTH 14
#define SRTP_TOTAL_KEY_LENGTH (SRTP_MASTER_KEY_LENGTH + SRTP_MASTER_SALT_LENGTH)
// For some reason libsrtp increases packet size by > 12 for RTCP even though
// the doc claims otherwise.
#define SRTP_MAX_EXPANSION 20
// SRTCP requires an auth tag *plus* a 4-byte index-plus-'E'-bit value (see
// RFC 3711)
#define SRTP_MAX_EXPANSION (SRTP_MAX_TRAILER_LEN+4)
class SrtpFlow {