Add webrtc::AudioSendStream and methods on webrtc::Call to create and delete AudioSendStreams.
AudioSendStream will be replacing the send side of VoiceEngine channels and associated APIs. Hence, they will be used transform recorded audio into RTP/RTCP packets that can be transmitted to another party, according to given parameters.
BUG=webrtc:4690
Review URL: https://codereview.webrtc.org/1397123003
Cr-Commit-Position: refs/heads/master@{#10307}
diff --git a/webrtc/audio/BUILD.gn b/webrtc/audio/BUILD.gn
index db0791f..c6f4b6b 100644
--- a/webrtc/audio/BUILD.gn
+++ b/webrtc/audio/BUILD.gn
@@ -12,6 +12,8 @@
sources = [
"audio_receive_stream.cc",
"audio_receive_stream.h",
+ "audio_send_stream.cc",
+ "audio_send_stream.h",
]
configs += [ "..:common_config" ]
diff --git a/webrtc/audio/audio_send_stream.cc b/webrtc/audio/audio_send_stream.cc
new file mode 100644
index 0000000..0d0c072
--- /dev/null
+++ b/webrtc/audio/audio_send_stream.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2015 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.
+ */
+
+#include "webrtc/audio/audio_send_stream.h"
+
+#include <string>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/logging.h"
+
+namespace webrtc {
+std::string AudioSendStream::Config::Rtp::ToString() const {
+ std::stringstream ss;
+ ss << "{ssrc: " << ssrc;
+ ss << ", extensions: [";
+ for (size_t i = 0; i < extensions.size(); ++i) {
+ ss << extensions[i].ToString();
+ if (i != extensions.size() - 1)
+ ss << ", ";
+ }
+ ss << ']';
+ ss << '}';
+ return ss.str();
+}
+
+std::string AudioSendStream::Config::ToString() const {
+ std::stringstream ss;
+ ss << "{rtp: " << rtp.ToString();
+ ss << ", voe_channel_id: " << voe_channel_id;
+ // TODO(solenberg): Encoder config.
+ ss << ", cng_payload_type: " << cng_payload_type;
+ ss << ", red_payload_type: " << red_payload_type;
+ ss << '}';
+ return ss.str();
+}
+
+namespace internal {
+AudioSendStream::AudioSendStream(const webrtc::AudioSendStream::Config& config)
+ : config_(config) {
+ LOG(LS_INFO) << "AudioSendStream: " << config_.ToString();
+ RTC_DCHECK(config.voe_channel_id != -1);
+}
+
+AudioSendStream::~AudioSendStream() {
+ LOG(LS_INFO) << "~AudioSendStream: " << config_.ToString();
+}
+
+webrtc::AudioSendStream::Stats AudioSendStream::GetStats() const {
+ return webrtc::AudioSendStream::Stats();
+}
+
+void AudioSendStream::Start() {
+}
+
+void AudioSendStream::Stop() {
+}
+
+void AudioSendStream::SignalNetworkState(NetworkState state) {
+}
+
+bool AudioSendStream::DeliverRtcp(const uint8_t* packet, size_t length) {
+ return false;
+}
+} // namespace internal
+} // namespace webrtc
diff --git a/webrtc/audio/audio_send_stream.h b/webrtc/audio/audio_send_stream.h
new file mode 100644
index 0000000..54046fc
--- /dev/null
+++ b/webrtc/audio/audio_send_stream.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2015 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.
+ */
+
+#ifndef WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
+#define WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
+
+#include "webrtc/audio_send_stream.h"
+
+namespace webrtc {
+namespace internal {
+
+class AudioSendStream : public webrtc::AudioSendStream {
+ public:
+ explicit AudioSendStream(const webrtc::AudioSendStream::Config& config);
+ ~AudioSendStream() override;
+
+ // webrtc::SendStream implementation.
+ void Start() override;
+ void Stop() override;
+ void SignalNetworkState(NetworkState state) override;
+ bool DeliverRtcp(const uint8_t* packet, size_t length) override;
+
+ // webrtc::AudioSendStream implementation.
+ webrtc::AudioSendStream::Stats GetStats() const override;
+
+ const webrtc::AudioSendStream::Config& config() const {
+ return config_;
+ }
+
+ private:
+ const webrtc::AudioSendStream::Config config_;
+};
+} // namespace internal
+} // namespace webrtc
+
+#endif // WEBRTC_AUDIO_AUDIO_SEND_STREAM_H_
diff --git a/webrtc/audio/audio_send_stream_unittest.cc b/webrtc/audio/audio_send_stream_unittest.cc
new file mode 100644
index 0000000..e5d73ff
--- /dev/null
+++ b/webrtc/audio/audio_send_stream_unittest.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015 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.
+ */
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/audio/audio_send_stream.h"
+
+namespace webrtc {
+
+TEST(AudioSendStreamTest, ConfigToString) {
+ const int kAbsSendTimeId = 3;
+ AudioSendStream::Config config(nullptr);
+ config.rtp.ssrc = 1234;
+ config.rtp.extensions.push_back(
+ RtpExtension(RtpExtension::kAbsSendTime, kAbsSendTimeId));
+ config.voe_channel_id = 1;
+ config.cng_payload_type = 42;
+ config.red_payload_type = 17;
+ EXPECT_GT(config.ToString().size(), 0u);
+}
+
+TEST(AudioSendStreamTest, ConstructDestruct) {
+ AudioSendStream::Config config(nullptr);
+ config.voe_channel_id = 1;
+ internal::AudioSendStream send_stream(config);
+}
+} // namespace webrtc
diff --git a/webrtc/audio/webrtc_audio.gypi b/webrtc/audio/webrtc_audio.gypi
index 42f91ac..40ccff6 100644
--- a/webrtc/audio/webrtc_audio.gypi
+++ b/webrtc/audio/webrtc_audio.gypi
@@ -16,6 +16,8 @@
'webrtc_audio_sources': [
'audio/audio_receive_stream.cc',
'audio/audio_receive_stream.h',
+ 'audio/audio_send_stream.cc',
+ 'audio/audio_send_stream.h',
],
},
}
diff --git a/webrtc/audio_send_stream.h b/webrtc/audio_send_stream.h
index 2fb288f..b96a8ef 100644
--- a/webrtc/audio_send_stream.h
+++ b/webrtc/audio_send_stream.h
@@ -45,7 +45,8 @@
std::vector<RtpExtension> extensions;
} rtp;
- // Transport for outgoing packets.
+ // Transport for outgoing packets. The transport is expected to exist for
+ // the entire life of the AudioSendStream and is owned by the API client.
Transport* send_transport = nullptr;
// Underlying VoiceEngine handle, used to map AudioSendStream to lower-level
@@ -54,7 +55,10 @@
// of Call.
int voe_channel_id = -1;
- rtc::scoped_ptr<AudioEncoder> encoder;
+ // Ownership of the encoder object is transferred to Call when the config is
+ // passed to Call::CreateAudioSendStream().
+ // TODO(solenberg): Implement, once we configure codecs through the new API.
+ // rtc::scoped_ptr<AudioEncoder> encoder;
int cng_payload_type = -1; // pt, or -1 to disable Comfort Noise Generator.
int red_payload_type = -1; // pt, or -1 to disable REDundant coding.
};
diff --git a/webrtc/call/call.cc b/webrtc/call/call.cc
index a32a823..6d9bf40 100644
--- a/webrtc/call/call.cc
+++ b/webrtc/call/call.cc
@@ -14,6 +14,7 @@
#include <vector>
#include "webrtc/audio/audio_receive_stream.h"
+#include "webrtc/audio/audio_send_stream.h"
#include "webrtc/base/checks.h"
#include "webrtc/base/scoped_ptr.h"
#include "webrtc/base/thread_annotations.h"
@@ -103,6 +104,7 @@
bool network_enabled_ GUARDED_BY(network_enabled_crit_);
rtc::scoped_ptr<RWLockWrapper> receive_crit_;
+ // Audio and Video receive streams are owned by the client that creates them.
std::map<uint32_t, AudioReceiveStream*> audio_receive_ssrcs_
GUARDED_BY(receive_crit_);
std::map<uint32_t, VideoReceiveStream*> video_receive_ssrcs_
@@ -113,6 +115,8 @@
GUARDED_BY(receive_crit_);
rtc::scoped_ptr<RWLockWrapper> send_crit_;
+ // Audio and Video send streams are owned by the client that creates them.
+ std::map<uint32_t, AudioSendStream*> audio_send_ssrcs_ GUARDED_BY(send_crit_);
std::map<uint32_t, VideoSendStream*> video_send_ssrcs_ GUARDED_BY(send_crit_);
std::set<VideoSendStream*> video_send_streams_ GUARDED_BY(send_crit_);
@@ -164,11 +168,12 @@
}
Call::~Call() {
- RTC_CHECK_EQ(0u, video_send_ssrcs_.size());
- RTC_CHECK_EQ(0u, video_send_streams_.size());
- RTC_CHECK_EQ(0u, audio_receive_ssrcs_.size());
- RTC_CHECK_EQ(0u, video_receive_ssrcs_.size());
- RTC_CHECK_EQ(0u, video_receive_streams_.size());
+ RTC_CHECK(audio_send_ssrcs_.empty());
+ RTC_CHECK(video_send_ssrcs_.empty());
+ RTC_CHECK(video_send_streams_.empty());
+ RTC_CHECK(audio_receive_ssrcs_.empty());
+ RTC_CHECK(video_receive_ssrcs_.empty());
+ RTC_CHECK(video_receive_streams_.empty());
module_process_thread_->Stop();
Trace::ReturnTrace();
@@ -178,14 +183,36 @@
webrtc::AudioSendStream* Call::CreateAudioSendStream(
const webrtc::AudioSendStream::Config& config) {
- // TODO(pbos): When adding AudioSendStream, add both TRACE_EVENT0 and config
- // logging to AudioSendStream constructor.
- return nullptr;
+ TRACE_EVENT0("webrtc", "Call::CreateAudioSendStream");
+ AudioSendStream* send_stream = new AudioSendStream(config);
+ {
+ rtc::CritScope lock(&network_enabled_crit_);
+ WriteLockScoped write_lock(*send_crit_);
+ RTC_DCHECK(audio_send_ssrcs_.find(config.rtp.ssrc) ==
+ audio_send_ssrcs_.end());
+ audio_send_ssrcs_[config.rtp.ssrc] = send_stream;
+
+ if (!network_enabled_)
+ send_stream->SignalNetworkState(kNetworkDown);
+ }
+ return send_stream;
}
void Call::DestroyAudioSendStream(webrtc::AudioSendStream* send_stream) {
- // TODO(pbos): When adding AudioSendStream, add both TRACE_EVENT0 and config
- // logging to AudioSendStream destructor.
+ TRACE_EVENT0("webrtc", "Call::DestroyAudioSendStream");
+ RTC_DCHECK(send_stream != nullptr);
+
+ send_stream->Stop();
+
+ webrtc::internal::AudioSendStream* audio_send_stream =
+ static_cast<webrtc::internal::AudioSendStream*>(send_stream);
+ {
+ WriteLockScoped write_lock(*send_crit_);
+ size_t num_deleted = audio_send_ssrcs_.erase(
+ audio_send_stream->config().rtp.ssrc);
+ RTC_DCHECK(num_deleted == 1);
+ }
+ delete audio_send_stream;
}
webrtc::AudioReceiveStream* Call::CreateAudioReceiveStream(
@@ -207,8 +234,8 @@
webrtc::AudioReceiveStream* receive_stream) {
TRACE_EVENT0("webrtc", "Call::DestroyAudioReceiveStream");
RTC_DCHECK(receive_stream != nullptr);
- AudioReceiveStream* audio_receive_stream =
- static_cast<AudioReceiveStream*>(receive_stream);
+ webrtc::internal::AudioReceiveStream* audio_receive_stream =
+ static_cast<webrtc::internal::AudioReceiveStream*>(receive_stream);
{
WriteLockScoped write_lock(*receive_crit_);
size_t num_deleted = audio_receive_ssrcs_.erase(
@@ -362,6 +389,7 @@
stats.pacer_delay_ms = channel_group_->GetPacerQueuingDelayMs();
{
ReadLockScoped read_lock(*send_crit_);
+ // TODO(solenberg): Add audio send streams.
for (const auto& kv : video_send_ssrcs_) {
int rtt_ms = kv.second->GetRtt();
if (rtt_ms > 0)
@@ -401,6 +429,9 @@
channel_group_->SignalNetworkState(state);
{
ReadLockScoped write_lock(*send_crit_);
+ for (auto& kv : audio_send_ssrcs_) {
+ kv.second->SignalNetworkState(state);
+ }
for (auto& kv : video_send_ssrcs_) {
kv.second->SignalNetworkState(state);
}
diff --git a/webrtc/call/call_unittest.cc b/webrtc/call/call_unittest.cc
new file mode 100644
index 0000000..9adecc3
--- /dev/null
+++ b/webrtc/call/call_unittest.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015 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.
+ */
+
+#include <list>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/call.h"
+
+namespace {
+
+struct CallHelper {
+ CallHelper() {
+ webrtc::Call::Config config;
+ // TODO(solenberg): Fill in with VoiceEngine* etc.
+ call_.reset(webrtc::Call::Create(config));
+ }
+
+ webrtc::Call* operator->() { return call_.get(); }
+
+ private:
+ rtc::scoped_ptr<webrtc::Call> call_;
+};
+} // namespace
+
+namespace webrtc {
+
+TEST(CallTest, ConstructDestruct) {
+ CallHelper call;
+}
+
+TEST(CallTest, CreateDestroy_AudioSendStream) {
+ CallHelper call;
+ AudioSendStream::Config config(nullptr);
+ config.rtp.ssrc = 42;
+ config.voe_channel_id = 123;
+ AudioSendStream* stream = call->CreateAudioSendStream(config);
+ EXPECT_NE(stream, nullptr);
+ call->DestroyAudioSendStream(stream);
+}
+
+TEST(CallTest, CreateDestroy_AudioReceiveStream) {
+ CallHelper call;
+ AudioReceiveStream::Config config;
+ config.rtp.remote_ssrc = 42;
+ config.voe_channel_id = 123;
+ AudioReceiveStream* stream = call->CreateAudioReceiveStream(config);
+ EXPECT_NE(stream, nullptr);
+ call->DestroyAudioReceiveStream(stream);
+}
+
+TEST(CallTest, CreateDestroy_AudioSendStreams) {
+ CallHelper call;
+ AudioSendStream::Config config(nullptr);
+ config.voe_channel_id = 123;
+ std::list<AudioSendStream*> streams;
+ for (int i = 0; i < 2; ++i) {
+ for (uint32_t ssrc = 0; ssrc < 1234567; ssrc += 34567) {
+ config.rtp.ssrc = ssrc;
+ AudioSendStream* stream = call->CreateAudioSendStream(config);
+ EXPECT_NE(stream, nullptr);
+ if (ssrc & 1) {
+ streams.push_back(stream);
+ } else {
+ streams.push_front(stream);
+ }
+ }
+ for (auto s : streams) {
+ call->DestroyAudioSendStream(s);
+ }
+ streams.clear();
+ }
+}
+
+TEST(CallTest, CreateDestroy_AudioReceiveStreams) {
+ CallHelper call;
+ AudioReceiveStream::Config config;
+ config.voe_channel_id = 123;
+ std::list<AudioReceiveStream*> streams;
+ for (int i = 0; i < 2; ++i) {
+ for (uint32_t ssrc = 0; ssrc < 1234567; ssrc += 34567) {
+ config.rtp.remote_ssrc = ssrc;
+ AudioReceiveStream* stream = call->CreateAudioReceiveStream(config);
+ EXPECT_NE(stream, nullptr);
+ if (ssrc & 1) {
+ streams.push_back(stream);
+ } else {
+ streams.push_front(stream);
+ }
+ }
+ for (auto s : streams) {
+ call->DestroyAudioReceiveStream(s);
+ }
+ streams.clear();
+ }
+}
+} // namespace webrtc
diff --git a/webrtc/webrtc_tests.gypi b/webrtc/webrtc_tests.gypi
index 0823500..0e245c5 100644
--- a/webrtc/webrtc_tests.gypi
+++ b/webrtc/webrtc_tests.gypi
@@ -146,12 +146,14 @@
],
},
{
- # TODO(pbos): Add separate target webrtc_audio_tests and move files there.
+ # TODO(solenberg): Rename to webrtc_call_tests.
'target_name': 'video_engine_tests',
'type': '<(gtest_target_type)',
'sources': [
'audio/audio_receive_stream_unittest.cc',
+ 'audio/audio_send_stream_unittest.cc',
'call/bitrate_estimator_tests.cc',
+ 'call/call_unittest.cc',
'call/packet_injection_tests.cc',
'test/common_unittest.cc',
'test/testsupport/metrics/video_metrics_unittest.cc',