Add ios bindings for PeerConnectionState.

This change makes it possible for ios apps to use the new standards-compliant PeerConnectionState.

Originally reviewed as https://webrtc-review.googlesource.com/c/110502, with an added check to prevent calling unimplemented optional method.

Bug: webrtc:9977
Change-Id: Iebac8ce58d435e38450add51b8915575d0ffd934
Reviewed-on: https://webrtc-review.googlesource.com/c/111084
Reviewed-by: Kári Helgason <kthelgason@webrtc.org>
Commit-Queue: Jonas Olsson <jonasolsson@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25727}
diff --git a/examples/objc/AppRTCMobile/ARDAppClient.m b/examples/objc/AppRTCMobile/ARDAppClient.m
index b033a98..8b3d105 100644
--- a/examples/objc/AppRTCMobile/ARDAppClient.m
+++ b/examples/objc/AppRTCMobile/ARDAppClient.m
@@ -405,6 +405,11 @@
 }
 
 - (void)peerConnection:(RTCPeerConnection *)peerConnection
+    didChangeConnectionState:(RTCPeerConnectionState)newState {
+  RTCLog(@"ICE+DTLS state changed: %ld", (long)newState);
+}
+
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
     didChangeIceGatheringState:(RTCIceGatheringState)newState {
   RTCLog(@"ICE gathering state changed: %ld", (long)newState);
 }
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h b/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h
index b6440cd..d26eb2e 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection+Private.h
@@ -39,6 +39,8 @@
 
   void OnIceConnectionChange(PeerConnectionInterface::IceConnectionState new_state) override;
 
+  void OnConnectionChange(PeerConnectionInterface::PeerConnectionState new_state) override;
+
   void OnIceGatheringChange(PeerConnectionInterface::IceGatheringState new_state) override;
 
   void OnIceCandidate(const IceCandidateInterface *candidate) override;
@@ -85,11 +87,19 @@
 + (webrtc::PeerConnectionInterface::IceConnectionState)nativeIceConnectionStateForState:
         (RTCIceConnectionState)state;
 
++ (webrtc::PeerConnectionInterface::PeerConnectionState)nativeConnectionStateForState:
+        (RTCPeerConnectionState)state;
+
 + (RTCIceConnectionState)iceConnectionStateForNativeState:
         (webrtc::PeerConnectionInterface::IceConnectionState)nativeState;
 
++ (RTCPeerConnectionState)connectionStateForNativeState:
+        (webrtc::PeerConnectionInterface::PeerConnectionState)nativeState;
+
 + (NSString *)stringForIceConnectionState:(RTCIceConnectionState)state;
 
++ (NSString *)stringForConnectionState:(RTCPeerConnectionState)state;
+
 + (webrtc::PeerConnectionInterface::IceGatheringState)nativeIceGatheringStateForState:
         (RTCIceGatheringState)state;
 
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.h b/sdk/objc/api/peerconnection/RTCPeerConnection.h
index 0179ec0..393a50b 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnection.h
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection.h
@@ -57,6 +57,16 @@
   RTCIceConnectionStateCount,
 };
 
+/** Represents the combined ice+dtls connection state of the peer connection. */
+typedef NS_ENUM(NSInteger, RTCPeerConnectionState) {
+  RTCPeerConnectionStateNew,
+  RTCPeerConnectionStateConnecting,
+  RTCPeerConnectionStateConnected,
+  RTCPeerConnectionStateDisconnected,
+  RTCPeerConnectionStateFailed,
+  RTCPeerConnectionStateClosed,
+};
+
 /** Represents the ice gathering state of the peer connection. */
 typedef NS_ENUM(NSInteger, RTCIceGatheringState) {
   RTCIceGatheringStateNew,
@@ -115,11 +125,14 @@
  *  This is only called with RTCSdpSemanticsUnifiedPlan specified.
  */
 @optional
+/** Called any time the PeerConnectionState changes. */
+- (void)peerConnection:(RTCPeerConnection *)peerConnection
+    didChangeConnectionState:(RTCPeerConnectionState)newState;
+
 - (void)peerConnection:(RTCPeerConnection *)peerConnection
     didStartReceivingOnTransceiver:(RTCRtpTransceiver *)transceiver;
 
 /** Called when a receiver and its track are created. */
-@optional
 - (void)peerConnection:(RTCPeerConnection *)peerConnection
         didAddReceiver:(RTCRtpReceiver *)rtpReceiver
                streams:(NSArray<RTCMediaStream *> *)mediaStreams;
@@ -145,6 +158,7 @@
 @property(nonatomic, readonly, nullable) RTCSessionDescription *remoteDescription;
 @property(nonatomic, readonly) RTCSignalingState signalingState;
 @property(nonatomic, readonly) RTCIceConnectionState iceConnectionState;
+@property(nonatomic, readonly) RTCPeerConnectionState connectionState;
 @property(nonatomic, readonly) RTCIceGatheringState iceGatheringState;
 @property(nonatomic, readonly, copy) RTCConfiguration *configuration;
 
diff --git a/sdk/objc/api/peerconnection/RTCPeerConnection.mm b/sdk/objc/api/peerconnection/RTCPeerConnection.mm
index 1ac076b..b59dafe 100644
--- a/sdk/objc/api/peerconnection/RTCPeerConnection.mm
+++ b/sdk/objc/api/peerconnection/RTCPeerConnection.mm
@@ -175,11 +175,17 @@
 
 void PeerConnectionDelegateAdapter::OnIceConnectionChange(
     PeerConnectionInterface::IceConnectionState new_state) {
-  RTCIceConnectionState state =
-      [[RTCPeerConnection class] iceConnectionStateForNativeState:new_state];
-  RTCPeerConnection *peer_connection = peer_connection_;
-  [peer_connection.delegate peerConnection:peer_connection
-               didChangeIceConnectionState:state];
+  RTCIceConnectionState state = [RTCPeerConnection iceConnectionStateForNativeState:new_state];
+  [peer_connection_.delegate peerConnection:peer_connection_ didChangeIceConnectionState:state];
+}
+
+void PeerConnectionDelegateAdapter::OnConnectionChange(
+    PeerConnectionInterface::PeerConnectionState new_state) {
+  if ([peer_connection_.delegate
+          respondsToSelector:@selector(peerConnection:didChangeConnectionState:)]) {
+    RTCPeerConnectionState state = [RTCPeerConnection connectionStateForNativeState:new_state];
+    [peer_connection_.delegate peerConnection:peer_connection_ didChangeConnectionState:state];
+  }
 }
 
 void PeerConnectionDelegateAdapter::OnIceGatheringChange(
@@ -322,6 +328,10 @@
       _peerConnection->ice_connection_state()];
 }
 
+- (RTCPeerConnectionState)connectionState {
+  return [[self class] connectionStateForNativeState:_peerConnection->peer_connection_state()];
+}
+
 - (RTCIceGatheringState)iceGatheringState {
   return [[self class] iceGatheringStateForNativeState:
       _peerConnection->ice_gathering_state()];
@@ -632,6 +642,59 @@
   }
 }
 
++ (webrtc::PeerConnectionInterface::PeerConnectionState)nativeConnectionStateForState:
+        (RTCPeerConnectionState)state {
+  switch (state) {
+    case RTCPeerConnectionStateNew:
+      return webrtc::PeerConnectionInterface::PeerConnectionState::kNew;
+    case RTCPeerConnectionStateConnecting:
+      return webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting;
+    case RTCPeerConnectionStateConnected:
+      return webrtc::PeerConnectionInterface::PeerConnectionState::kConnected;
+    case RTCPeerConnectionStateFailed:
+      return webrtc::PeerConnectionInterface::PeerConnectionState::kFailed;
+    case RTCPeerConnectionStateDisconnected:
+      return webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected;
+    case RTCPeerConnectionStateClosed:
+      return webrtc::PeerConnectionInterface::PeerConnectionState::kClosed;
+  }
+}
+
++ (RTCPeerConnectionState)connectionStateForNativeState:
+        (webrtc::PeerConnectionInterface::PeerConnectionState)nativeState {
+  switch (nativeState) {
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kNew:
+      return RTCPeerConnectionStateNew;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kConnecting:
+      return RTCPeerConnectionStateConnecting;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kConnected:
+      return RTCPeerConnectionStateConnected;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kFailed:
+      return RTCPeerConnectionStateFailed;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kDisconnected:
+      return RTCPeerConnectionStateDisconnected;
+    case webrtc::PeerConnectionInterface::PeerConnectionState::kClosed:
+      return RTCPeerConnectionStateClosed;
+  }
+}
+
++ (NSString *)stringForConnectionState:(RTCPeerConnectionState)state {
+  switch (state) {
+    case RTCPeerConnectionStateNew:
+      return @"NEW";
+    case RTCPeerConnectionStateConnecting:
+      return @"CONNECTING";
+    case RTCPeerConnectionStateConnected:
+      return @"CONNECTED";
+    case RTCPeerConnectionStateFailed:
+      return @"FAILED";
+    case RTCPeerConnectionStateDisconnected:
+      return @"DISCONNECTED";
+    case RTCPeerConnectionStateClosed:
+      return @"CLOSED";
+  }
+}
+
 + (webrtc::PeerConnectionInterface::IceConnectionState)
     nativeIceConnectionStateForState:(RTCIceConnectionState)state {
   switch (state) {