线程启动:platform_thread.cc
void PlatformThread::Run() {
if (!name_.empty())
rtc::SetCurrentThreadName(name_.c_str());
do {
// The interface contract of Start/Stop is that for a successful call to
// Start, there should be at least one call to the run function. So we
// call the function before checking |stop_|.
if (!run_function_(obj_))
break;
#if defined(WEBRTC_WIN)
// Alertable sleep to permit RaiseFlag to run and update |stop_|.
SleepEx(0, true);
} while (!stop_);
#else
} while (!stop_event_.Wait(0));
#endif // defined(WEBRTC_WIN)
}
发送音频是有一个线程一直在循环发送:
process_thread_impl.cc
// static
bool ProcessThreadImpl::Run(void* obj) {
return static_cast<ProcessThreadImpl*>(obj)->Process();
}
bool ProcessThreadImpl::Process() {
int64_t now = rtc::TimeMillis();
int64_t next_checkpoint = now + (1000 * 60);
{
rtc::CritScope lock(&lock_);
if (stop_)
return false;
for (ModuleCallback& m : modules_) {
// TODO(tommi): Would be good to measure the time TimeUntilNextProcess
// takes and dcheck if it takes too long (e.g. >=10ms). Ideally this
// operation should not require taking a lock, so querying all modules
// should run in a matter of nanoseconds.
if (m.next_callback == 0)
m.next_callback = GetNextCallbackTime(m.module, now);
if (m.next_callback <= now ||
m.next_callback == kCallProcessImmediately) {
m.module->Process();//线程
// Use a new 'now' reference to calculate when the next callback
// should occur. We'll continue to use 'now' above for the baseline
// of calculating how long we should wait, to reduce variance.
int64_t new_now = rtc::TimeMillis();
m.next_callback = GetNextCallbackTime(m.module, new_now);
}
if (m.next_callback < next_checkpoint)
next_checkpoint = m.next_callback;
}
while (!queue_.empty()) {
rtc::QueuedTask* task = queue_.front();
queue_.pop();
lock_.Leave();
task->Run();
delete task;
lock_.Enter();
}
}
int64_t time_to_wait = next_checkpoint - rtc::TimeMillis();
if (time_to_wait > 0)
wake_up_->Wait(static_cast<unsigned long>(time_to_wait));
return true;
}
paced_sender.cc
void PacedSender::Process() {
while (!packets_->Empty()) {
if (media_budget_->bytes_remaining() == 0 && !is_probing)
return;
// Since we need to release the lock in order to send, we first pop the
// element from the priority queue but keep it in storage, so that we can
// reinsert it if send fails.
const paced_sender::Packet& packet = packets_->BeginPop();
if (SendPacket(packet, probe_cluster_id)) { //发送
// Send succeeded, remove it from the queue.
packets_->FinalizePop(packet);
if (is_probing)
return;
} else {
// Send failed, put it back into the queue.
packets_->CancelPop(packet);
return;
}
}
}
bool PacedSender::SendPacket(const paced_sender::Packet& packet,
int probe_cluster_id) {
// TODO(holmer): Because of this bug issue 5307 we have to send audio
// packets even when the pacer is paused. Here we assume audio packets are
// always high priority and that they are the only high priority packets.
if (paused_ && packet.priority != kHighPriority)
return false;
critsect_->Leave();
const bool success = packet_sender_->TimeToSendPacket(
packet.ssrc, packet.sequence_number, packet.capture_time_ms,
packet.retransmission, probe_cluster_id);
critsect_->Enter();
if (success) {
prober_->PacketSent(clock_->TimeInMilliseconds(), packet.bytes);
// TODO(holmer): High priority packets should only be accounted for if we
// are allocating bandwidth for audio.
if (packet.priority != kHighPriority) {
// Update media bytes sent.
media_budget_->UseBudget(packet.bytes);
padding_budget_->UseBudget(packet.bytes);
}
}
return success;
}
rtp_sender.cc
// Called from pacer when we can send the packet.
bool RTPSender::TimeToSendPacket(uint16_t sequence_number,
int64_t capture_time_ms,
bool retransmission,
int probe_cluster_id) {
size_t length = IP_PACKET_SIZE;
uint8_t data_buffer[IP_PACKET_SIZE];
int64_t stored_time_ms;
if (!packet_history_.GetPacketAndSetSendTime(sequence_number,
0,
retransmission,
data_buffer,
&length,
&stored_time_ms)) {
// Packet cannot be found. Allow sending to continue.
return true;
}
int rtx;
{
rtc::CritScope lock(&send_critsect_);
rtx = rtx_;
}
return PrepareAndSendPacket(data_buffer, length, capture_time_ms,
retransmission && (rtx & kRtxRetransmitted) > 0,
retransmission, probe_cluster_id);
}
bool RTPSender::PrepareAndSendPacket(uint8_t* buffer,
size_t length,
int64_t capture_time_ms,
bool send_over_rtx,
bool is_retransmit,
int probe_cluster_id) {
uint8_t* buffer_to_send_ptr = buffer;
RtpUtility::RtpHeaderParser rtp_parser(buffer, length);
RTPHeader rtp_header;
rtp_parser.Parse(&rtp_header);
if (!is_retransmit && rtp_header.markerBit) {
TRACE_EVENT_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "PacedSend",
capture_time_ms);
}
TRACE_EVENT_INSTANT2(
TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "PrepareAndSendPacket",
"timestamp", rtp_header.timestamp, "seqnum", rtp_header.sequenceNumber);
uint8_t data_buffer_rtx[IP_PACKET_SIZE];
if (send_over_rtx) {
BuildRtxPacket(buffer, &length, data_buffer_rtx);
buffer_to_send_ptr = data_buffer_rtx;
}
int64_t now_ms = clock_->TimeInMilliseconds();
int64_t diff_ms = now_ms - capture_time_ms;
UpdateTransmissionTimeOffset(buffer_to_send_ptr, length, rtp_header,
diff_ms);
UpdateAbsoluteSendTime(buffer_to_send_ptr, length, rtp_header, now_ms);
PacketOptions options;
if (AllocateTransportSequenceNumber(&options.packet_id)) {
if (UpdateTransportSequenceNumber(options.packet_id, buffer_to_send_ptr,
length, rtp_header)) {
if (transport_feedback_observer_)
transport_feedback_observer_->AddPacket(options.packet_id, length,
probe_cluster_id);
}
}
if (!is_retransmit && !send_over_rtx) {
UpdateDelayStatistics(capture_time_ms, now_ms);
UpdateOnSendPacket(options.packet_id, capture_time_ms, rtp_header.ssrc);
}
bool ret = SendPacketToNetwork(buffer_to_send_ptr, length, options);
if (ret) {
rtc::CritScope lock(&send_critsect_);
media_has_been_sent_ = true;
}
UpdateRtpStats(buffer_to_send_ptr, length, rtp_header, send_over_rtx,
is_retransmit);
return ret;
}
bool RTPSender::SendPacketToNetwork(const uint8_t* packet,
size_t size,
const PacketOptions& options) {
int bytes_sent = -1;
if (transport_) {
//发送rtp
bytes_sent = transport_->SendRtp(packet, size, options)
? static_cast<int>(size)
: -1;
if (event_log_ && bytes_sent > 0) {
event_log_->LogRtpHeader(kOutgoingPacket, MediaType::ANY, packet, size);
}
}
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
"RTPSender::SendPacketToNetwork", "size", size, "sent",
bytes_sent);
// TODO(pwestin): Add a separate bitrate for sent bitrate after pacer.
if (bytes_sent <= 0) {
LOG(LS_WARNING) << "Transport failed to send packet";
return false;
}
return true;
}
channel.cc
bool Channel::SendRtp(const uint8_t* data,
size_t len,
const PacketOptions& options) {
WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId, _channelId),
"Channel::SendPacket(channel=%d, len=%" PRIuS ")", len);
rtc::CritScope cs(&_callbackCritSect);
if (_transportPtr == NULL) {
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
"Channel::SendPacket() failed to send RTP packet due to"
" invalid transport object");
return false;
}
uint8_t* bufferToSendPtr = (uint8_t*)data;
size_t bufferLength = len;
//发送rtp
if (!_transportPtr->SendRtp(bufferToSendPtr, bufferLength, options)) {
std::string transport_name =
_externalTransport ? "external transport" : "WebRtc sockets";
WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId, _channelId),
"Channel::SendPacket() RTP transmission using %s failed",
transport_name.c_str());
return false;
}
return true;
}
webrtcvoiceengine.h
bool SendRtp(const uint8_t* data,
size_t len,
const webrtc::PacketOptions& options) override {
rtc::CopyOnWriteBuffer packet(data, len, kMaxRtpPacketLen);
rtc::PacketOptions rtc_options;
rtc_options.packet_id = options.packet_id;
return VoiceMediaChannel::SendPacket(&packet, rtc_options);//发送
}
mediachannel.h
// Base method to send packet using NetworkInterface.
bool SendPacket(rtc::CopyOnWriteBuffer* packet,
const rtc::PacketOptions& options) {
return DoSendPacket(packet, false, options);
}
bool DoSendPacket(rtc::CopyOnWriteBuffer* packet,
bool rtcp,
const rtc::PacketOptions& options) {
rtc::CritScope cs(&network_interface_crit_);
if (!network_interface_)
return false;
return (!rtcp) ? network_interface_->SendPacket(packet, options)
: network_interface_->SendRtcp(packet, options);
}
channel.cpp
bool BaseChannel::SendPacket(bool rtcp,
rtc::CopyOnWriteBuffer* packet,
const rtc::PacketOptions& options) {
// SendPacket gets called from MediaEngine, on a pacer or an encoder thread.
// If the thread is not our network thread, we will post to our network
// so that the real work happens on our network. This avoids us having to
// synchronize access to all the pieces of the send path, including
// SRTP and the inner workings of the transport channels.
// The only downside is that we can't return a proper failure code if
// needed. Since UDP is unreliable anyway, this should be a non-issue.
if (!network_thread_->IsCurrent()) {
// Avoid a copy by transferring the ownership of the packet data.
int message_id = rtcp ? MSG_SEND_RTCP_PACKET : MSG_SEND_RTP_PACKET;
SendPacketMessageData* data = new SendPacketMessageData;
data->packet = std::move(*packet);
data->options = options;
network_thread_->Post(RTC_FROM_HERE, this, message_id, data);//
return true;
}