Introduce CreateDataChannelOrError

Deprecate CreateDataChannel, and make it a simple wrapper function.

Bug: webrtc:12796
Change-Id: I053d75a264596ba87ca734a29df9241de93a80c3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/219784
Reviewed-by: Xavier Lepaul‎ <xalep@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Harald Alvestrand <hta@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#34130}
diff --git a/api/peer_connection_interface.h b/api/peer_connection_interface.h
index 75c4d3c..e815f19 100644
--- a/api/peer_connection_interface.h
+++ b/api/peer_connection_interface.h
@@ -920,9 +920,24 @@
   // Also, calling CreateDataChannel is the only way to get a data "m=" section
   // in SDP, so it should be done before CreateOffer is called, if the
   // application plans to use data channels.
+  virtual RTCErrorOr<rtc::scoped_refptr<DataChannelInterface>>
+  CreateDataChannelOrError(const std::string& label,
+                           const DataChannelInit* config) {
+    return RTCError(RTCErrorType::INTERNAL_ERROR, "dummy function called");
+  }
+  // TODO(crbug.com/788659): Remove "virtual" below and default implementation
+  // above once mock in Chrome is fixed.
+  ABSL_DEPRECATED("Use CreateDataChannelOrError")
   virtual rtc::scoped_refptr<DataChannelInterface> CreateDataChannel(
       const std::string& label,
-      const DataChannelInit* config) = 0;
+      const DataChannelInit* config) {
+    auto result = CreateDataChannelOrError(label, config);
+    if (!result.ok()) {
+      return nullptr;
+    } else {
+      return result.MoveValue();
+    }
+  }
 
   // NOTE: For the following 6 methods, it's only safe to dereference the
   // SessionDescriptionInterface on signaling_thread() (for example, calling
diff --git a/api/peer_connection_proxy.h b/api/peer_connection_proxy.h
index cc9df10..de7664f 100644
--- a/api/peer_connection_proxy.h
+++ b/api/peer_connection_proxy.h
@@ -76,8 +76,8 @@
               rtc::scoped_refptr<RtpReceiverInterface>,
               rtc::scoped_refptr<RTCStatsCollectorCallback>)
 PROXY_METHOD0(void, ClearStatsCache)
-PROXY_METHOD2(rtc::scoped_refptr<DataChannelInterface>,
-              CreateDataChannel,
+PROXY_METHOD2(RTCErrorOr<rtc::scoped_refptr<DataChannelInterface>>,
+              CreateDataChannelOrError,
               const std::string&,
               const DataChannelInit*)
 PROXY_CONSTMETHOD0(const SessionDescriptionInterface*, local_description)
diff --git a/api/test/dummy_peer_connection.h b/api/test/dummy_peer_connection.h
index 4d17aed..80ae20c 100644
--- a/api/test/dummy_peer_connection.h
+++ b/api/test/dummy_peer_connection.h
@@ -114,10 +114,10 @@
   }
   void ClearStatsCache() override {}
 
-  rtc::scoped_refptr<DataChannelInterface> CreateDataChannel(
+  RTCErrorOr<rtc::scoped_refptr<DataChannelInterface>> CreateDataChannelOrError(
       const std::string& label,
       const DataChannelInit* config) override {
-    return nullptr;
+    return RTCError(RTCErrorType::INTERNAL_ERROR, "Dummy function called");
   }
 
   const SessionDescriptionInterface* local_description() const override {
diff --git a/api/test/mock_peerconnectioninterface.h b/api/test/mock_peerconnectioninterface.h
index be34df0..b5d9423 100644
--- a/api/test/mock_peerconnectioninterface.h
+++ b/api/test/mock_peerconnectioninterface.h
@@ -100,8 +100,8 @@
               GetSctpTransport,
               (),
               (const override));
-  MOCK_METHOD(rtc::scoped_refptr<DataChannelInterface>,
-              CreateDataChannel,
+  MOCK_METHOD(RTCErrorOr<rtc::scoped_refptr<DataChannelInterface>>,
+              CreateDataChannelOrError,
               (const std::string&, const DataChannelInit*),
               (override));
   MOCK_METHOD(const SessionDescriptionInterface*,
diff --git a/examples/unityplugin/simple_peer_connection.cc b/examples/unityplugin/simple_peer_connection.cc
index 128ca76..c7e5185 100644
--- a/examples/unityplugin/simple_peer_connection.cc
+++ b/examples/unityplugin/simple_peer_connection.cc
@@ -497,8 +497,9 @@
   struct webrtc::DataChannelInit init;
   init.ordered = true;
   init.reliable = true;
-  data_channel_ = peer_connection_->CreateDataChannel("Hello", &init);
-  if (data_channel_.get()) {
+  auto result = peer_connection_->CreateDataChannelOrError("Hello", &init);
+  if (result.ok()) {
+    data_channel_ = result.MoveValue();
     data_channel_->RegisterObserver(this);
     RTC_LOG(LS_INFO) << "Succeeds to create data channel";
     return true;
diff --git a/pc/peer_connection.cc b/pc/peer_connection.cc
index e2b3b61..0939f59 100644
--- a/pc/peer_connection.cc
+++ b/pc/peer_connection.cc
@@ -1279,9 +1279,9 @@
       "trickle");
 }
 
-rtc::scoped_refptr<DataChannelInterface> PeerConnection::CreateDataChannel(
-    const std::string& label,
-    const DataChannelInit* config) {
+RTCErrorOr<rtc::scoped_refptr<DataChannelInterface>>
+PeerConnection::CreateDataChannelOrError(const std::string& label,
+                                         const DataChannelInit* config) {
   RTC_DCHECK_RUN_ON(signaling_thread());
   TRACE_EVENT0("webrtc", "PeerConnection::CreateDataChannel");
 
@@ -1291,11 +1291,13 @@
   if (config) {
     internal_config.reset(new InternalDataChannelInit(*config));
   }
+  // TODO(bugs.webrtc.org/12796): Return a more specific error.
   rtc::scoped_refptr<DataChannelInterface> channel(
       data_channel_controller_.InternalCreateDataChannelWithProxy(
           label, internal_config.get()));
   if (!channel.get()) {
-    return nullptr;
+    return RTCError(RTCErrorType::INTERNAL_ERROR,
+                    "Data channel creation failed");
   }
 
   // Trigger the onRenegotiationNeeded event for
diff --git a/pc/peer_connection.h b/pc/peer_connection.h
index 7be137a..4476c5d 100644
--- a/pc/peer_connection.h
+++ b/pc/peer_connection.h
@@ -167,7 +167,7 @@
   std::vector<rtc::scoped_refptr<RtpTransceiverInterface>> GetTransceivers()
       const override;
 
-  rtc::scoped_refptr<DataChannelInterface> CreateDataChannel(
+  RTCErrorOr<rtc::scoped_refptr<DataChannelInterface>> CreateDataChannelOrError(
       const std::string& label,
       const DataChannelInit* config) override;
   // WARNING: LEGACY. See peerconnectioninterface.h
diff --git a/pc/peer_connection_wrapper.cc b/pc/peer_connection_wrapper.cc
index 6aed8f1..3b4d28f 100644
--- a/pc/peer_connection_wrapper.cc
+++ b/pc/peer_connection_wrapper.cc
@@ -306,7 +306,14 @@
 
 rtc::scoped_refptr<DataChannelInterface>
 PeerConnectionWrapper::CreateDataChannel(const std::string& label) {
-  return pc()->CreateDataChannel(label, nullptr);
+  auto result = pc()->CreateDataChannelOrError(label, nullptr);
+  if (!result.ok()) {
+    RTC_LOG(LS_ERROR) << "CreateDataChannel failed: "
+                      << ToString(result.error().type()) << " "
+                      << result.error().message();
+    return nullptr;
+  }
+  return result.MoveValue();
 }
 
 PeerConnectionInterface::SignalingState
diff --git a/pc/test/fake_peer_connection_base.h b/pc/test/fake_peer_connection_base.h
index 1acf86f..7970dd0 100644
--- a/pc/test/fake_peer_connection_base.h
+++ b/pc/test/fake_peer_connection_base.h
@@ -120,10 +120,11 @@
     return nullptr;
   }
 
-  rtc::scoped_refptr<DataChannelInterface> CreateDataChannel(
+  RTCErrorOr<rtc::scoped_refptr<DataChannelInterface>> CreateDataChannelOrError(
       const std::string& label,
       const DataChannelInit* config) override {
-    return nullptr;
+    return RTCError(RTCErrorType::UNSUPPORTED_OPERATION,
+                    "Fake function called");
   }
 
   const SessionDescriptionInterface* local_description() const override {
diff --git a/pc/test/peer_connection_test_wrapper.cc b/pc/test/peer_connection_test_wrapper.cc
index 56e81ec..8fdfb1b 100644
--- a/pc/test/peer_connection_test_wrapper.cc
+++ b/pc/test/peer_connection_test_wrapper.cc
@@ -140,7 +140,14 @@
 PeerConnectionTestWrapper::CreateDataChannel(
     const std::string& label,
     const webrtc::DataChannelInit& init) {
-  return peer_connection_->CreateDataChannel(label, &init);
+  auto result = peer_connection_->CreateDataChannelOrError(label, &init);
+  if (!result.ok()) {
+    RTC_LOG(LS_ERROR) << "CreateDataChannel failed: "
+                      << ToString(result.error().type()) << " "
+                      << result.error().message();
+    return nullptr;
+  }
+  return result.MoveValue();
 }
 
 void PeerConnectionTestWrapper::WaitForNegotiation() {
diff --git a/sdk/android/src/jni/pc/peer_connection.cc b/sdk/android/src/jni/pc/peer_connection.cc
index 93c6eb3..cee7a58 100644
--- a/sdk/android/src/jni/pc/peer_connection.cc
+++ b/sdk/android/src/jni/pc/peer_connection.cc
@@ -538,10 +538,12 @@
     const JavaParamRef<jstring>& j_label,
     const JavaParamRef<jobject>& j_init) {
   DataChannelInit init = JavaToNativeDataChannelInit(jni, j_init);
-  rtc::scoped_refptr<DataChannelInterface> channel(
-      ExtractNativePC(jni, j_pc)->CreateDataChannel(
-          JavaToNativeString(jni, j_label), &init));
-  return WrapNativeDataChannel(jni, channel);
+  auto result = ExtractNativePC(jni, j_pc)->CreateDataChannelOrError(
+      JavaToNativeString(jni, j_label), &init);
+  if (!result.ok()) {
+    return WrapNativeDataChannel(jni, nullptr);
+  }
+  return WrapNativeDataChannel(jni, result.MoveValue());
 }
 
 static void JNI_PeerConnection_CreateOffer(
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+DataChannel.mm b/sdk/objc/api/peerconnection/RTCPeerConnection+DataChannel.mm
index 1ded45d..cb75f06 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnection+DataChannel.mm
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection+DataChannel.mm
@@ -23,14 +23,12 @@
   std::string labelString = [NSString stdStringForString:label];
   const webrtc::DataChannelInit nativeInit =
       configuration.nativeDataChannelInit;
-  rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel =
-      self.nativePeerConnection->CreateDataChannel(labelString,
-                                                   &nativeInit);
-  if (!dataChannel) {
+  auto result = self.nativePeerConnection->CreateDataChannelOrError(labelString, &nativeInit);
+  if (!result.ok()) {
     return nil;
   }
   return [[RTC_OBJC_TYPE(RTCDataChannel) alloc] initWithFactory:self.factory
-                                              nativeDataChannel:dataChannel];
+                                              nativeDataChannel:result.MoveValue()];
 }
 
 @end