diff --git a/README.md b/README.md index da63f3d141..d879e38057 100644 --- a/README.md +++ b/README.md @@ -134,11 +134,11 @@ Video roadmap and changelog is available [here](https://github.com/GetStream/pro - [X] Android SDK development.md cleanup (Jaewoong) - [X] Upgrade to more recent versions of webrtc (Jaewoong/Kanat) - [X] Review foreground service vs backend for audio rooms etc. (Aleks) +- [X] Enable SFU switching - [ ] Logging is too verbose (rtc is very noisy), clean it up to focus on the essential for info and higher (Daniel) ### 0.5.0 milestone -- [ ] Enable SFU switching - [ ] H264 workaround on Samsung 23? (see https://github.com/livekit/client-sdk-android/blob/main/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/SimulcastVideoEncoderFactoryWrapper.kt#L34 and - https://github.com/react-native-webrtc/react-native-webrtc/issues/983#issuecomment-975624906) - [ ] Test coverage diff --git a/stream-video-android-core/api/stream-video-android-core.api b/stream-video-android-core/api/stream-video-android-core.api index 58ed4ae39c..c43136aba8 100644 --- a/stream-video-android-core/api/stream-video-android-core.api +++ b/stream-video-android-core/api/stream-video-android-core.api @@ -26,6 +26,7 @@ public final class io/getstream/video/android/core/Call { public final fun goLive (ZZZLkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun goLive$default (Lio/getstream/video/android/core/Call;ZZZLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; public final fun grantPermissions (Ljava/lang/String;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun handleEvent (Lorg/openapitools/client/models/VideoEvent;)V public final fun initRenderer (Lio/getstream/webrtc/android/ui/VideoTextureViewRenderer;Ljava/lang/String;Lstream/video/sfu/models/TrackType;Lkotlin/jvm/functions/Function1;)V public static synthetic fun initRenderer$default (Lio/getstream/video/android/core/Call;Lio/getstream/webrtc/android/ui/VideoTextureViewRenderer;Ljava/lang/String;Lstream/video/sfu/models/TrackType;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V public final fun join (ZLio/getstream/video/android/core/CreateCallOptions;ZZLkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -42,7 +43,7 @@ public final class io/getstream/video/android/core/Call { public final fun processAudioSample (Lorg/webrtc/audio/JavaAudioDeviceModule$AudioSamples;)V public final fun queryMembers (Ljava/util/Map;Ljava/util/List;ILjava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun queryMembers$default (Lio/getstream/video/android/core/Call;Ljava/util/Map;Ljava/util/List;ILjava/lang/String;Ljava/lang/String;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; - public final fun reconnectOrSwitchSfu (ZLkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun reconnect (ZLkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun reject (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun removeMembers (Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun requestPermissions ([Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; @@ -64,8 +65,7 @@ public final class io/getstream/video/android/core/Call { public final fun stopScreenSharing ()V public final fun subscribe (Lio/getstream/video/android/core/events/VideoEventListener;)Lio/getstream/video/android/core/EventSubscription; public final fun subscribeFor ([Ljava/lang/Class;Lio/getstream/video/android/core/events/VideoEventListener;)Lio/getstream/video/android/core/EventSubscription; - public final fun switchSfu (ZLkotlin/coroutines/Continuation;)Ljava/lang/Object; - public static synthetic fun switchSfu$default (Lio/getstream/video/android/core/Call;ZLkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; + public final fun switchSfu (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun takeScreenshot (Lio/getstream/video/android/core/model/VideoTrack;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun update (Ljava/util/Map;Lorg/openapitools/client/models/CallSettingsRequest;Lorg/threeten/bp/OffsetDateTime;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public static synthetic fun update$default (Lio/getstream/video/android/core/Call;Ljava/util/Map;Lorg/openapitools/client/models/CallSettingsRequest;Lorg/threeten/bp/OffsetDateTime;Lkotlin/coroutines/Continuation;ILjava/lang/Object;)Ljava/lang/Object; @@ -610,6 +610,13 @@ public final class io/getstream/video/android/core/RealtimeConnection$Joined : i public fun toString ()Ljava/lang/String; } +public final class io/getstream/video/android/core/RealtimeConnection$Migrating : io/getstream/video/android/core/RealtimeConnection { + public static final field INSTANCE Lio/getstream/video/android/core/RealtimeConnection$Migrating; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/video/android/core/RealtimeConnection$PreJoin : io/getstream/video/android/core/RealtimeConnection { public static final field INSTANCE Lio/getstream/video/android/core/RealtimeConnection$PreJoin; public fun equals (Ljava/lang/Object;)Z @@ -883,6 +890,7 @@ public final class io/getstream/video/android/core/call/RtcSession { public final fun createPublisher ()Lio/getstream/video/android/core/call/connection/StreamPeerConnection; public final fun createSubscriber ()Lio/getstream/video/android/core/call/connection/StreamPeerConnection; public final fun getPublisherStats (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun getSfuSocketState ()Lkotlinx/coroutines/flow/StateFlow; public final fun getSubscriber ()Lio/getstream/video/android/core/call/connection/StreamPeerConnection; public final fun getSubscriberStats (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun getTrackDimensions ()Lkotlinx/coroutines/flow/MutableStateFlow; @@ -891,14 +899,13 @@ public final class io/getstream/video/android/core/call/RtcSession { public final fun handleEvent (Lorg/openapitools/client/models/VideoEvent;)V public final fun handleIceTrickle (Lio/getstream/video/android/core/events/ICETrickleEvent;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun handleSubscriberOffer (Lio/getstream/video/android/core/events/SubscriberOfferEvent;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; - public final fun mangleSdp (Lorg/webrtc/SessionDescription;)Lorg/webrtc/SessionDescription; public final fun onNegotiationNeeded (Lio/getstream/video/android/core/call/connection/StreamPeerConnection;Lio/getstream/video/android/core/model/StreamPeerType;)V public final fun reconnect (ZLkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun requestSubscriberIceRestart (Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun setScreenShareTrack ()V public final fun setSubscriber (Lio/getstream/video/android/core/call/connection/StreamPeerConnection;)V public final fun setTracks (Ljava/util/Map;)V - public final fun switchSfu (Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun switchSfu (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/util/List;Lkotlin/jvm/functions/Function0;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public final fun updateTrackDimensions (Ljava/lang/String;Lstream/video/sfu/models/TrackType;ZLstream/video/sfu/models/VideoDimension;)V public static synthetic fun updateTrackDimensions$default (Lio/getstream/video/android/core/call/RtcSession;Ljava/lang/String;Lstream/video/sfu/models/TrackType;ZLstream/video/sfu/models/VideoDimension;ILjava/lang/Object;)V } @@ -2930,6 +2937,17 @@ public final class io/getstream/video/android/core/events/ErrorEvent : io/getstr public fun toString ()Ljava/lang/String; } +public final class io/getstream/video/android/core/events/GoAwayEvent : io/getstream/video/android/core/events/SfuDataEvent { + public fun (Lstream/video/sfu/models/GoAwayReason;)V + public final fun component1 ()Lstream/video/sfu/models/GoAwayReason; + public final fun copy (Lstream/video/sfu/models/GoAwayReason;)Lio/getstream/video/android/core/events/GoAwayEvent; + public static synthetic fun copy$default (Lio/getstream/video/android/core/events/GoAwayEvent;Lstream/video/sfu/models/GoAwayReason;ILjava/lang/Object;)Lio/getstream/video/android/core/events/GoAwayEvent; + public fun equals (Ljava/lang/Object;)Z + public final fun getReason ()Lstream/video/sfu/models/GoAwayReason; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/video/android/core/events/ICETrickleEvent : io/getstream/video/android/core/events/SfuDataEvent { public fun (Ljava/lang/String;Lstream/video/sfu/models/PeerType;)V public final fun component1 ()Ljava/lang/String; @@ -4175,6 +4193,7 @@ public final class io/getstream/video/android/core/socket/SfuSocket : io/getstre public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lkotlin/jvm/functions/Function1;Lkotlinx/coroutines/CoroutineScope;Lokhttp3/OkHttpClient;Lio/getstream/video/android/core/internal/network/NetworkStateProvider;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun authenticate ()V public fun connect (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; + public final fun connectMigrating (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; public fun onMessage (Lokhttp3/WebSocket;Lokio/ByteString;)V } @@ -4352,6 +4371,1221 @@ public final class io/getstream/video/android/core/utils/RtpMapAttribute { public fun toString ()Ljava/lang/String; } +public final class io/getstream/video/android/core/utils/SdpBandwidth { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBandwidth; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpBandwidth;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpBandwidth; + public fun equals (Ljava/lang/Object;)Z + public final fun getLimit ()Ljava/lang/String; + public final fun getType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpBfcpconfid { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBfcpconfid; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpBfcpconfid;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpBfcpconfid; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpBfcpfloorctrl { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBfcpfloorctrl; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpBfcpfloorctrl;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpBfcpfloorctrl; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpBfcpfloorid { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBfcpfloorid; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpBfcpfloorid;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpBfcpfloorid; + public fun equals (Ljava/lang/Object;)Z + public final fun getId ()Ljava/lang/String; + public final fun getMStream ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpBfcpuserid { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBfcpuserid; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpBfcpuserid;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpBfcpuserid; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpBundleonly { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBundleonly; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpBundleonly;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpBundleonly; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpCandidates { + public fun (Ljava/lang/String;JLjava/lang/String;JLjava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;)V + public final fun component1 ()Ljava/lang/String; + public final fun component10 ()Ljava/lang/String; + public final fun component11 ()Ljava/lang/Long; + public final fun component12 ()Ljava/lang/Long; + public final fun component13 ()Ljava/lang/Long; + public final fun component2 ()J + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()J + public final fun component5 ()Ljava/lang/String; + public final fun component6 ()J + public final fun component7 ()Ljava/lang/String; + public final fun component8 ()Ljava/lang/String; + public final fun component9 ()Ljava/lang/Long; + public final fun copy (Ljava/lang/String;JLjava/lang/String;JLjava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;)Lio/getstream/video/android/core/utils/SdpCandidates; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpCandidates;Ljava/lang/String;JLjava/lang/String;JLjava/lang/String;JLjava/lang/String;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/String;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/Long;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpCandidates; + public fun equals (Ljava/lang/Object;)Z + public final fun getComponent ()J + public final fun getFoundation ()Ljava/lang/String; + public final fun getGeneration ()Ljava/lang/Long; + public final fun getIp ()Ljava/lang/String; + public final fun getNetworkCost ()Ljava/lang/Long; + public final fun getNetworkId ()Ljava/lang/Long; + public final fun getPort ()J + public final fun getPriority ()J + public final fun getRaddr ()Ljava/lang/String; + public final fun getRport ()Ljava/lang/Long; + public final fun getTcptype ()Ljava/lang/String; + public final fun getTransport ()Ljava/lang/String; + public final fun getType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpConnection { + public fun (JLjava/lang/String;)V + public final fun component1 ()J + public final fun component2 ()Ljava/lang/String; + public final fun copy (JLjava/lang/String;)Lio/getstream/video/android/core/utils/SdpConnection; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpConnection;JLjava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpConnection; + public fun equals (Ljava/lang/Object;)Z + public final fun getIp ()Ljava/lang/String; + public final fun getVersion ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpConnectiontype { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpConnectiontype; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpConnectiontype;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpConnectiontype; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpContent { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpContent; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpContent;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpContent; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpControl { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpControl; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpControl;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpControl; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpCrypto { + public fun (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()J + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpCrypto; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpCrypto;JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpCrypto; + public fun equals (Ljava/lang/Object;)Z + public final fun getConfig ()Ljava/lang/String; + public final fun getId ()J + public final fun getSessionConfig ()Ljava/lang/String; + public final fun getSuite ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpDescription { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpDescription; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpDescription;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpDescription; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpDirection { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpDirection; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpDirection;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpDirection; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpEmail { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpEmail; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpEmail;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpEmail; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpEndofcandidates { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpEndofcandidates; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpEndofcandidates;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpEndofcandidates; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpExt { + public fun (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()J + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun copy (JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpExt; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpExt;JLjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpExt; + public fun equals (Ljava/lang/Object;)Z + public final fun getConfig ()Ljava/lang/String; + public final fun getDirection ()Ljava/lang/String; + public final fun getEncryptUri ()Ljava/lang/String; + public final fun getUri ()Ljava/lang/String; + public final fun getValue ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpExtmapallowmixed { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpExtmapallowmixed; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpExtmapallowmixed;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpExtmapallowmixed; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpFingerprint { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpFingerprint; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpFingerprint;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpFingerprint; + public fun equals (Ljava/lang/Object;)Z + public final fun getHash ()Ljava/lang/String; + public final fun getType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpFmtp { + public fun (JLjava/lang/String;)V + public final fun component1 ()J + public final fun component2 ()Ljava/lang/String; + public final fun copy (JLjava/lang/String;)Lio/getstream/video/android/core/utils/SdpFmtp; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpFmtp;JLjava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpFmtp; + public fun equals (Ljava/lang/Object;)Z + public final fun getConfig ()Ljava/lang/String; + public final fun getPayload ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpFramerate { + public fun (J)V + public final fun component1 ()J + public final fun copy (J)Lio/getstream/video/android/core/utils/SdpFramerate; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpFramerate;JILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpFramerate; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpGrammar { + public static final field INSTANCE Lio/getstream/video/android/core/utils/SdpGrammar; + public final fun tryParseBandwidth (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBandwidth; + public final fun tryParseBfcpconfid (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBfcpconfid; + public final fun tryParseBfcpfloorctrl (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBfcpfloorctrl; + public final fun tryParseBfcpfloorid (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBfcpfloorid; + public final fun tryParseBfcpuserid (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBfcpuserid; + public final fun tryParseBundleonly (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpBundleonly; + public final fun tryParseCandidates (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpCandidates; + public final fun tryParseConnection (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpConnection; + public final fun tryParseConnectiontype (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpConnectiontype; + public final fun tryParseContent (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpContent; + public final fun tryParseControl (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpControl; + public final fun tryParseCrypto (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpCrypto; + public final fun tryParseDescription (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpDescription; + public final fun tryParseDirection (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpDirection; + public final fun tryParseEmail (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpEmail; + public final fun tryParseEndofcandidates (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpEndofcandidates; + public final fun tryParseExt (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpExt; + public final fun tryParseExtmapallowmixed (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpExtmapallowmixed; + public final fun tryParseFingerprint (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpFingerprint; + public final fun tryParseFmtp (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpFmtp; + public final fun tryParseFramerate (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpFramerate; + public final fun tryParseGroups (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpGroups; + public final fun tryParseIcelite (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpIcelite; + public final fun tryParseIceoptions (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpIceoptions; + public final fun tryParseIcepwd (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpIcepwd; + public final fun tryParseIceufrag (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpIceufrag; + public final fun tryParseImageattrs (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpImageattrs; + public final fun tryParseInvalid (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpInvalid; + public final fun tryParseKeywords (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpKeywords; + public final fun tryParseLabel (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpLabel; + public final fun tryParseMaxmessagesize (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMaxmessagesize; + public final fun tryParseMaxptime (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMaxptime; + public final fun tryParseMediaclk (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMediaclk; + public final fun tryParseMid (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMid; + public final fun tryParseMline (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMline; + public final fun tryParseMsid (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMsid; + public final fun tryParseMsidsemantic (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMsidsemantic; + public final fun tryParseName (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpName; + public final fun tryParseOrigin (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpOrigin; + public final fun tryParsePhone (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpPhone; + public final fun tryParsePtime (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpPtime; + public final fun tryParseRemotecandidates (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRemotecandidates; + public final fun tryParseRepeats (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRepeats; + public final fun tryParseRids (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRids; + public final fun tryParseRtcp (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtcp; + public final fun tryParseRtcpfb (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtcpfb; + public final fun tryParseRtcpfbtrrint (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtcpfbtrrint; + public final fun tryParseRtcpmux (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtcpmux; + public final fun tryParseRtcprsize (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtcprsize; + public final fun tryParseRtp (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtp; + public final fun tryParseSctpmap (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSctpmap; + public final fun tryParseSctpport (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSctpport; + public final fun tryParseSetup (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSetup; + public final fun tryParseSimulcast (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSimulcast; + public final fun tryParseSimulcast03 (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSimulcast03; + public final fun tryParseSourcefilter (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSourcefilter; + public final fun tryParseSsrcgroups (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSsrcgroups; + public final fun tryParseSsrcs (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSsrcs; + public final fun tryParseTimezones (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpTimezones; + public final fun tryParseTiming (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpTiming; + public final fun tryParseTsrefclocks (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpTsrefclocks; + public final fun tryParseUri (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpUri; + public final fun tryParseVersion (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpVersion; + public final fun tryParseXgoogleflag (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpXgoogleflag; + public final fun writeBandwidth (Lio/getstream/video/android/core/utils/SdpBandwidth;)Ljava/lang/String; + public final fun writeBfcpconfid (Lio/getstream/video/android/core/utils/SdpBfcpconfid;)Ljava/lang/String; + public final fun writeBfcpfloorctrl (Lio/getstream/video/android/core/utils/SdpBfcpfloorctrl;)Ljava/lang/String; + public final fun writeBfcpfloorid (Lio/getstream/video/android/core/utils/SdpBfcpfloorid;)Ljava/lang/String; + public final fun writeBfcpuserid (Lio/getstream/video/android/core/utils/SdpBfcpuserid;)Ljava/lang/String; + public final fun writeBundleonly (Lio/getstream/video/android/core/utils/SdpBundleonly;)Ljava/lang/String; + public final fun writeCandidates (Lio/getstream/video/android/core/utils/SdpCandidates;)Ljava/lang/String; + public final fun writeConnection (Lio/getstream/video/android/core/utils/SdpConnection;)Ljava/lang/String; + public final fun writeConnectiontype (Lio/getstream/video/android/core/utils/SdpConnectiontype;)Ljava/lang/String; + public final fun writeContent (Lio/getstream/video/android/core/utils/SdpContent;)Ljava/lang/String; + public final fun writeControl (Lio/getstream/video/android/core/utils/SdpControl;)Ljava/lang/String; + public final fun writeCrypto (Lio/getstream/video/android/core/utils/SdpCrypto;)Ljava/lang/String; + public final fun writeDescription (Lio/getstream/video/android/core/utils/SdpDescription;)Ljava/lang/String; + public final fun writeDirection (Lio/getstream/video/android/core/utils/SdpDirection;)Ljava/lang/String; + public final fun writeEmail (Lio/getstream/video/android/core/utils/SdpEmail;)Ljava/lang/String; + public final fun writeEndofcandidates (Lio/getstream/video/android/core/utils/SdpEndofcandidates;)Ljava/lang/String; + public final fun writeExt (Lio/getstream/video/android/core/utils/SdpExt;)Ljava/lang/String; + public final fun writeExtmapallowmixed (Lio/getstream/video/android/core/utils/SdpExtmapallowmixed;)Ljava/lang/String; + public final fun writeFingerprint (Lio/getstream/video/android/core/utils/SdpFingerprint;)Ljava/lang/String; + public final fun writeFmtp (Lio/getstream/video/android/core/utils/SdpFmtp;)Ljava/lang/String; + public final fun writeFramerate (Lio/getstream/video/android/core/utils/SdpFramerate;)Ljava/lang/String; + public final fun writeGroups (Lio/getstream/video/android/core/utils/SdpGroups;)Ljava/lang/String; + public final fun writeIcelite (Lio/getstream/video/android/core/utils/SdpIcelite;)Ljava/lang/String; + public final fun writeIceoptions (Lio/getstream/video/android/core/utils/SdpIceoptions;)Ljava/lang/String; + public final fun writeIcepwd (Lio/getstream/video/android/core/utils/SdpIcepwd;)Ljava/lang/String; + public final fun writeIceufrag (Lio/getstream/video/android/core/utils/SdpIceufrag;)Ljava/lang/String; + public final fun writeImageattrs (Lio/getstream/video/android/core/utils/SdpImageattrs;)Ljava/lang/String; + public final fun writeInvalid (Lio/getstream/video/android/core/utils/SdpInvalid;)Ljava/lang/String; + public final fun writeKeywords (Lio/getstream/video/android/core/utils/SdpKeywords;)Ljava/lang/String; + public final fun writeLabel (Lio/getstream/video/android/core/utils/SdpLabel;)Ljava/lang/String; + public final fun writeMaxmessagesize (Lio/getstream/video/android/core/utils/SdpMaxmessagesize;)Ljava/lang/String; + public final fun writeMaxptime (Lio/getstream/video/android/core/utils/SdpMaxptime;)Ljava/lang/String; + public final fun writeMediaclk (Lio/getstream/video/android/core/utils/SdpMediaclk;)Ljava/lang/String; + public final fun writeMid (Lio/getstream/video/android/core/utils/SdpMid;)Ljava/lang/String; + public final fun writeMline (Lio/getstream/video/android/core/utils/SdpMline;)Ljava/lang/String; + public final fun writeMsid (Lio/getstream/video/android/core/utils/SdpMsid;)Ljava/lang/String; + public final fun writeMsidsemantic (Lio/getstream/video/android/core/utils/SdpMsidsemantic;)Ljava/lang/String; + public final fun writeName (Lio/getstream/video/android/core/utils/SdpName;)Ljava/lang/String; + public final fun writeOrigin (Lio/getstream/video/android/core/utils/SdpOrigin;)Ljava/lang/String; + public final fun writePhone (Lio/getstream/video/android/core/utils/SdpPhone;)Ljava/lang/String; + public final fun writePtime (Lio/getstream/video/android/core/utils/SdpPtime;)Ljava/lang/String; + public final fun writeRemotecandidates (Lio/getstream/video/android/core/utils/SdpRemotecandidates;)Ljava/lang/String; + public final fun writeRepeats (Lio/getstream/video/android/core/utils/SdpRepeats;)Ljava/lang/String; + public final fun writeRids (Lio/getstream/video/android/core/utils/SdpRids;)Ljava/lang/String; + public final fun writeRtcp (Lio/getstream/video/android/core/utils/SdpRtcp;)Ljava/lang/String; + public final fun writeRtcpfb (Lio/getstream/video/android/core/utils/SdpRtcpfb;)Ljava/lang/String; + public final fun writeRtcpfbtrrint (Lio/getstream/video/android/core/utils/SdpRtcpfbtrrint;)Ljava/lang/String; + public final fun writeRtcpmux (Lio/getstream/video/android/core/utils/SdpRtcpmux;)Ljava/lang/String; + public final fun writeRtcprsize (Lio/getstream/video/android/core/utils/SdpRtcprsize;)Ljava/lang/String; + public final fun writeRtp (Lio/getstream/video/android/core/utils/SdpRtp;)Ljava/lang/String; + public final fun writeSctpmap (Lio/getstream/video/android/core/utils/SdpSctpmap;)Ljava/lang/String; + public final fun writeSctpport (Lio/getstream/video/android/core/utils/SdpSctpport;)Ljava/lang/String; + public final fun writeSetup (Lio/getstream/video/android/core/utils/SdpSetup;)Ljava/lang/String; + public final fun writeSimulcast (Lio/getstream/video/android/core/utils/SdpSimulcast;)Ljava/lang/String; + public final fun writeSimulcast03 (Lio/getstream/video/android/core/utils/SdpSimulcast03;)Ljava/lang/String; + public final fun writeSourcefilter (Lio/getstream/video/android/core/utils/SdpSourcefilter;)Ljava/lang/String; + public final fun writeSsrcgroups (Lio/getstream/video/android/core/utils/SdpSsrcgroups;)Ljava/lang/String; + public final fun writeSsrcs (Lio/getstream/video/android/core/utils/SdpSsrcs;)Ljava/lang/String; + public final fun writeTimezones (Lio/getstream/video/android/core/utils/SdpTimezones;)Ljava/lang/String; + public final fun writeTiming (Lio/getstream/video/android/core/utils/SdpTiming;)Ljava/lang/String; + public final fun writeTsrefclocks (Lio/getstream/video/android/core/utils/SdpTsrefclocks;)Ljava/lang/String; + public final fun writeUri (Lio/getstream/video/android/core/utils/SdpUri;)Ljava/lang/String; + public final fun writeVersion (Lio/getstream/video/android/core/utils/SdpVersion;)Ljava/lang/String; + public final fun writeXgoogleflag (Lio/getstream/video/android/core/utils/SdpXgoogleflag;)Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpGroups { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpGroups; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpGroups;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpGroups; + public fun equals (Ljava/lang/Object;)Z + public final fun getMids ()Ljava/lang/String; + public final fun getType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpIcelite { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpIcelite; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpIcelite;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpIcelite; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpIceoptions { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpIceoptions; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpIceoptions;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpIceoptions; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpIcepwd { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpIcepwd; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpIcepwd;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpIcepwd; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpIceufrag { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpIceufrag; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpIceufrag;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpIceufrag; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpImageattrs { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpImageattrs; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpImageattrs;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpImageattrs; + public fun equals (Ljava/lang/Object;)Z + public final fun getPt ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpInvalid { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpInvalid; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpInvalid;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpInvalid; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpKeywords { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpKeywords; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpKeywords;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpKeywords; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpLabel { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpLabel; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpLabel;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpLabel; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpMaxmessagesize { + public fun (J)V + public final fun component1 ()J + public final fun copy (J)Lio/getstream/video/android/core/utils/SdpMaxmessagesize; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpMaxmessagesize;JILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpMaxmessagesize; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpMaxptime { + public fun (J)V + public final fun component1 ()J + public final fun copy (J)Lio/getstream/video/android/core/utils/SdpMaxptime; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpMaxptime;JILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpMaxptime; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpMedia { + public fun ()V + public fun equals (Ljava/lang/Object;)Z + public final fun getBandwidth ()Ljava/util/List; + public final fun getBfcpConfId ()Lio/getstream/video/android/core/utils/SdpBfcpconfid; + public final fun getBfcpFloorCtrl ()Lio/getstream/video/android/core/utils/SdpBfcpfloorctrl; + public final fun getBfcpFloorId ()Lio/getstream/video/android/core/utils/SdpBfcpfloorid; + public final fun getBfcpUserId ()Lio/getstream/video/android/core/utils/SdpBfcpuserid; + public final fun getBundleOnly ()Lio/getstream/video/android/core/utils/SdpBundleonly; + public final fun getCandidates ()Ljava/util/List; + public final fun getConnection ()Lio/getstream/video/android/core/utils/SdpConnection; + public final fun getConnectionType ()Lio/getstream/video/android/core/utils/SdpConnectiontype; + public final fun getContent ()Lio/getstream/video/android/core/utils/SdpContent; + public final fun getControl ()Lio/getstream/video/android/core/utils/SdpControl; + public final fun getCrypto ()Ljava/util/List; + public final fun getDescription ()Lio/getstream/video/android/core/utils/SdpDescription; + public final fun getDirection ()Lio/getstream/video/android/core/utils/SdpDirection; + public final fun getEmail ()Lio/getstream/video/android/core/utils/SdpEmail; + public final fun getEndOfCandidates ()Lio/getstream/video/android/core/utils/SdpEndofcandidates; + public final fun getExt ()Ljava/util/List; + public final fun getExtmapAllowMixed ()Lio/getstream/video/android/core/utils/SdpExtmapallowmixed; + public final fun getFingerprint ()Lio/getstream/video/android/core/utils/SdpFingerprint; + public final fun getFmtp ()Ljava/util/List; + public final fun getFramerate ()Lio/getstream/video/android/core/utils/SdpFramerate; + public final fun getGroups ()Ljava/util/List; + public final fun getIceOptions ()Lio/getstream/video/android/core/utils/SdpIceoptions; + public final fun getIcePwd ()Lio/getstream/video/android/core/utils/SdpIcepwd; + public final fun getIceUfrag ()Lio/getstream/video/android/core/utils/SdpIceufrag; + public final fun getIcelite ()Lio/getstream/video/android/core/utils/SdpIcelite; + public final fun getImageattrs ()Ljava/util/List; + public final fun getInvalid ()Ljava/util/List; + public final fun getKeywords ()Lio/getstream/video/android/core/utils/SdpKeywords; + public final fun getLabel ()Lio/getstream/video/android/core/utils/SdpLabel; + public final fun getMaxMessageSize ()Lio/getstream/video/android/core/utils/SdpMaxmessagesize; + public final fun getMaxptime ()Lio/getstream/video/android/core/utils/SdpMaxptime; + public final fun getMediaClk ()Lio/getstream/video/android/core/utils/SdpMediaclk; + public final fun getMid ()Lio/getstream/video/android/core/utils/SdpMid; + public final fun getMline ()Lio/getstream/video/android/core/utils/SdpMline; + public final fun getMsid ()Lio/getstream/video/android/core/utils/SdpMsid; + public final fun getMsidSemantic ()Lio/getstream/video/android/core/utils/SdpMsidsemantic; + public final fun getName ()Lio/getstream/video/android/core/utils/SdpName; + public final fun getOrigin ()Lio/getstream/video/android/core/utils/SdpOrigin; + public final fun getPhone ()Lio/getstream/video/android/core/utils/SdpPhone; + public final fun getPtime ()Lio/getstream/video/android/core/utils/SdpPtime; + public final fun getRemoteCandidates ()Lio/getstream/video/android/core/utils/SdpRemotecandidates; + public final fun getRepeats ()Lio/getstream/video/android/core/utils/SdpRepeats; + public final fun getRids ()Ljava/util/List; + public final fun getRtcp ()Lio/getstream/video/android/core/utils/SdpRtcp; + public final fun getRtcpFb ()Ljava/util/List; + public final fun getRtcpFbTrrInt ()Ljava/util/List; + public final fun getRtcpMux ()Lio/getstream/video/android/core/utils/SdpRtcpmux; + public final fun getRtcpRsize ()Lio/getstream/video/android/core/utils/SdpRtcprsize; + public final fun getRtp ()Ljava/util/List; + public final fun getSctpPort ()Lio/getstream/video/android/core/utils/SdpSctpport; + public final fun getSctpmap ()Lio/getstream/video/android/core/utils/SdpSctpmap; + public final fun getSetup ()Lio/getstream/video/android/core/utils/SdpSetup; + public final fun getSimulcast ()Lio/getstream/video/android/core/utils/SdpSimulcast; + public final fun getSimulcast03 ()Lio/getstream/video/android/core/utils/SdpSimulcast03; + public final fun getSourceFilter ()Lio/getstream/video/android/core/utils/SdpSourcefilter; + public final fun getSsrcGroups ()Ljava/util/List; + public final fun getSsrcs ()Ljava/util/List; + public final fun getTimezones ()Lio/getstream/video/android/core/utils/SdpTimezones; + public final fun getTiming ()Lio/getstream/video/android/core/utils/SdpTiming; + public final fun getTsRefClocks ()Ljava/util/List; + public final fun getUri ()Lio/getstream/video/android/core/utils/SdpUri; + public final fun getVersion ()Lio/getstream/video/android/core/utils/SdpVersion; + public final fun getXGoogleFlag ()Lio/getstream/video/android/core/utils/SdpXgoogleflag; + public final fun setBandwidth (Ljava/util/List;)V + public final fun setBfcpConfId (Lio/getstream/video/android/core/utils/SdpBfcpconfid;)V + public final fun setBfcpFloorCtrl (Lio/getstream/video/android/core/utils/SdpBfcpfloorctrl;)V + public final fun setBfcpFloorId (Lio/getstream/video/android/core/utils/SdpBfcpfloorid;)V + public final fun setBfcpUserId (Lio/getstream/video/android/core/utils/SdpBfcpuserid;)V + public final fun setBundleOnly (Lio/getstream/video/android/core/utils/SdpBundleonly;)V + public final fun setCandidates (Ljava/util/List;)V + public final fun setConnection (Lio/getstream/video/android/core/utils/SdpConnection;)V + public final fun setConnectionType (Lio/getstream/video/android/core/utils/SdpConnectiontype;)V + public final fun setContent (Lio/getstream/video/android/core/utils/SdpContent;)V + public final fun setControl (Lio/getstream/video/android/core/utils/SdpControl;)V + public final fun setCrypto (Ljava/util/List;)V + public final fun setDescription (Lio/getstream/video/android/core/utils/SdpDescription;)V + public final fun setDirection (Lio/getstream/video/android/core/utils/SdpDirection;)V + public final fun setEmail (Lio/getstream/video/android/core/utils/SdpEmail;)V + public final fun setEndOfCandidates (Lio/getstream/video/android/core/utils/SdpEndofcandidates;)V + public final fun setExt (Ljava/util/List;)V + public final fun setExtmapAllowMixed (Lio/getstream/video/android/core/utils/SdpExtmapallowmixed;)V + public final fun setFingerprint (Lio/getstream/video/android/core/utils/SdpFingerprint;)V + public final fun setFmtp (Ljava/util/List;)V + public final fun setFramerate (Lio/getstream/video/android/core/utils/SdpFramerate;)V + public final fun setGroups (Ljava/util/List;)V + public final fun setIceOptions (Lio/getstream/video/android/core/utils/SdpIceoptions;)V + public final fun setIcePwd (Lio/getstream/video/android/core/utils/SdpIcepwd;)V + public final fun setIceUfrag (Lio/getstream/video/android/core/utils/SdpIceufrag;)V + public final fun setIcelite (Lio/getstream/video/android/core/utils/SdpIcelite;)V + public final fun setImageattrs (Ljava/util/List;)V + public final fun setInvalid (Ljava/util/List;)V + public final fun setKeywords (Lio/getstream/video/android/core/utils/SdpKeywords;)V + public final fun setLabel (Lio/getstream/video/android/core/utils/SdpLabel;)V + public final fun setMaxMessageSize (Lio/getstream/video/android/core/utils/SdpMaxmessagesize;)V + public final fun setMaxptime (Lio/getstream/video/android/core/utils/SdpMaxptime;)V + public final fun setMediaClk (Lio/getstream/video/android/core/utils/SdpMediaclk;)V + public final fun setMid (Lio/getstream/video/android/core/utils/SdpMid;)V + public final fun setMline (Lio/getstream/video/android/core/utils/SdpMline;)V + public final fun setMsid (Lio/getstream/video/android/core/utils/SdpMsid;)V + public final fun setMsidSemantic (Lio/getstream/video/android/core/utils/SdpMsidsemantic;)V + public final fun setName (Lio/getstream/video/android/core/utils/SdpName;)V + public final fun setOrigin (Lio/getstream/video/android/core/utils/SdpOrigin;)V + public final fun setPhone (Lio/getstream/video/android/core/utils/SdpPhone;)V + public final fun setPtime (Lio/getstream/video/android/core/utils/SdpPtime;)V + public final fun setRemoteCandidates (Lio/getstream/video/android/core/utils/SdpRemotecandidates;)V + public final fun setRepeats (Lio/getstream/video/android/core/utils/SdpRepeats;)V + public final fun setRids (Ljava/util/List;)V + public final fun setRtcp (Lio/getstream/video/android/core/utils/SdpRtcp;)V + public final fun setRtcpFb (Ljava/util/List;)V + public final fun setRtcpFbTrrInt (Ljava/util/List;)V + public final fun setRtcpMux (Lio/getstream/video/android/core/utils/SdpRtcpmux;)V + public final fun setRtcpRsize (Lio/getstream/video/android/core/utils/SdpRtcprsize;)V + public final fun setRtp (Ljava/util/List;)V + public final fun setSctpPort (Lio/getstream/video/android/core/utils/SdpSctpport;)V + public final fun setSctpmap (Lio/getstream/video/android/core/utils/SdpSctpmap;)V + public final fun setSetup (Lio/getstream/video/android/core/utils/SdpSetup;)V + public final fun setSimulcast (Lio/getstream/video/android/core/utils/SdpSimulcast;)V + public final fun setSimulcast03 (Lio/getstream/video/android/core/utils/SdpSimulcast03;)V + public final fun setSourceFilter (Lio/getstream/video/android/core/utils/SdpSourcefilter;)V + public final fun setSsrcGroups (Ljava/util/List;)V + public final fun setSsrcs (Ljava/util/List;)V + public final fun setTimezones (Lio/getstream/video/android/core/utils/SdpTimezones;)V + public final fun setTiming (Lio/getstream/video/android/core/utils/SdpTiming;)V + public final fun setTsRefClocks (Ljava/util/List;)V + public final fun setUri (Lio/getstream/video/android/core/utils/SdpUri;)V + public final fun setVersion (Lio/getstream/video/android/core/utils/SdpVersion;)V + public final fun setXGoogleFlag (Lio/getstream/video/android/core/utils/SdpXgoogleflag;)V +} + +public final class io/getstream/video/android/core/utils/SdpMediaclk { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMediaclk; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpMediaclk;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpMediaclk; + public fun equals (Ljava/lang/Object;)Z + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpMid { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMid; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpMid;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpMid; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpMline { + public fun (Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()J + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMline; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpMline;Ljava/lang/String;JLjava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpMline; + public fun equals (Ljava/lang/Object;)Z + public final fun getPayloads ()Ljava/lang/String; + public final fun getPort ()J + public final fun getProtocol ()Ljava/lang/String; + public final fun getType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpMsid { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMsid; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpMsid;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpMsid; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpMsidsemantic { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpMsidsemantic; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpMsidsemantic;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpMsidsemantic; + public fun equals (Ljava/lang/Object;)Z + public final fun getSemantic ()Ljava/lang/String; + public final fun getToken ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpName { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpName; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpName;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpName; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpOrigin { + public fun (Ljava/lang/String;JJLjava/lang/String;JLjava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()J + public final fun component3 ()J + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()J + public final fun component6 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;JJLjava/lang/String;JLjava/lang/String;)Lio/getstream/video/android/core/utils/SdpOrigin; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpOrigin;Ljava/lang/String;JJLjava/lang/String;JLjava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpOrigin; + public fun equals (Ljava/lang/Object;)Z + public final fun getAddress ()Ljava/lang/String; + public final fun getIpVer ()J + public final fun getNetType ()Ljava/lang/String; + public final fun getSessionId ()J + public final fun getSessionVersion ()J + public final fun getUsername ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpPhone { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpPhone; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpPhone;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpPhone; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpPtime { + public fun (J)V + public final fun component1 ()J + public final fun copy (J)Lio/getstream/video/android/core/utils/SdpPtime; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpPtime;JILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpPtime; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpRemotecandidates { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRemotecandidates; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpRemotecandidates;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpRemotecandidates; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpRepeats { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRepeats; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpRepeats;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpRepeats; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpRids { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRids; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpRids;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpRids; + public fun equals (Ljava/lang/Object;)Z + public final fun getId ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpRtcp { + public fun (JLjava/lang/String;Ljava/lang/Long;Ljava/lang/String;)V + public final fun component1 ()J + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/Long; + public final fun component4 ()Ljava/lang/String; + public final fun copy (JLjava/lang/String;Ljava/lang/Long;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtcp; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpRtcp;JLjava/lang/String;Ljava/lang/Long;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpRtcp; + public fun equals (Ljava/lang/Object;)Z + public final fun getAddress ()Ljava/lang/String; + public final fun getIpVer ()Ljava/lang/Long; + public final fun getNetType ()Ljava/lang/String; + public final fun getPort ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpRtcpfb { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtcpfb; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpRtcpfb;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpRtcpfb; + public fun equals (Ljava/lang/Object;)Z + public final fun getPayload ()Ljava/lang/String; + public final fun getSubtype ()Ljava/lang/String; + public final fun getType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpRtcpfbtrrint { + public fun (Ljava/lang/String;J)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()J + public final fun copy (Ljava/lang/String;J)Lio/getstream/video/android/core/utils/SdpRtcpfbtrrint; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpRtcpfbtrrint;Ljava/lang/String;JILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpRtcpfbtrrint; + public fun equals (Ljava/lang/Object;)Z + public final fun getPayload ()Ljava/lang/String; + public final fun getValue ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpRtcpmux { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtcpmux; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpRtcpmux;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpRtcpmux; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpRtcprsize { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtcprsize; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpRtcprsize;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpRtcprsize; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpRtp { + public fun (JLjava/lang/String;Ljava/lang/Long;Ljava/lang/String;)V + public final fun component1 ()J + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/Long; + public final fun component4 ()Ljava/lang/String; + public final fun copy (JLjava/lang/String;Ljava/lang/Long;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpRtp; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpRtp;JLjava/lang/String;Ljava/lang/Long;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpRtp; + public fun equals (Ljava/lang/Object;)Z + public final fun getCodec ()Ljava/lang/String; + public final fun getEncoding ()Ljava/lang/String; + public final fun getPayload ()J + public final fun getRate ()Ljava/lang/Long; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpSctpmap { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSctpmap; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpSctpmap;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpSctpmap; + public fun equals (Ljava/lang/Object;)Z + public final fun getSctpmapNumber ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpSctpport { + public fun (J)V + public final fun component1 ()J + public final fun copy (J)Lio/getstream/video/android/core/utils/SdpSctpport; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpSctpport;JILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpSctpport; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpSession { + public fun ()V + public fun equals (Ljava/lang/Object;)Z + public final fun getBandwidth ()Ljava/util/List; + public final fun getBfcpConfId ()Lio/getstream/video/android/core/utils/SdpBfcpconfid; + public final fun getBfcpFloorCtrl ()Lio/getstream/video/android/core/utils/SdpBfcpfloorctrl; + public final fun getBfcpFloorId ()Lio/getstream/video/android/core/utils/SdpBfcpfloorid; + public final fun getBfcpUserId ()Lio/getstream/video/android/core/utils/SdpBfcpuserid; + public final fun getBundleOnly ()Lio/getstream/video/android/core/utils/SdpBundleonly; + public final fun getCandidates ()Ljava/util/List; + public final fun getConnection ()Lio/getstream/video/android/core/utils/SdpConnection; + public final fun getConnectionType ()Lio/getstream/video/android/core/utils/SdpConnectiontype; + public final fun getContent ()Lio/getstream/video/android/core/utils/SdpContent; + public final fun getControl ()Lio/getstream/video/android/core/utils/SdpControl; + public final fun getCrypto ()Ljava/util/List; + public final fun getDescription ()Lio/getstream/video/android/core/utils/SdpDescription; + public final fun getDirection ()Lio/getstream/video/android/core/utils/SdpDirection; + public final fun getEmail ()Lio/getstream/video/android/core/utils/SdpEmail; + public final fun getEndOfCandidates ()Lio/getstream/video/android/core/utils/SdpEndofcandidates; + public final fun getExt ()Ljava/util/List; + public final fun getExtmapAllowMixed ()Lio/getstream/video/android/core/utils/SdpExtmapallowmixed; + public final fun getFingerprint ()Lio/getstream/video/android/core/utils/SdpFingerprint; + public final fun getFmtp ()Ljava/util/List; + public final fun getFramerate ()Lio/getstream/video/android/core/utils/SdpFramerate; + public final fun getGroups ()Ljava/util/List; + public final fun getIceOptions ()Lio/getstream/video/android/core/utils/SdpIceoptions; + public final fun getIcePwd ()Lio/getstream/video/android/core/utils/SdpIcepwd; + public final fun getIceUfrag ()Lio/getstream/video/android/core/utils/SdpIceufrag; + public final fun getIcelite ()Lio/getstream/video/android/core/utils/SdpIcelite; + public final fun getImageattrs ()Ljava/util/List; + public final fun getInvalid ()Ljava/util/List; + public final fun getKeywords ()Lio/getstream/video/android/core/utils/SdpKeywords; + public final fun getLabel ()Lio/getstream/video/android/core/utils/SdpLabel; + public final fun getMaxMessageSize ()Lio/getstream/video/android/core/utils/SdpMaxmessagesize; + public final fun getMaxptime ()Lio/getstream/video/android/core/utils/SdpMaxptime; + public final fun getMedia ()Ljava/util/List; + public final fun getMediaClk ()Lio/getstream/video/android/core/utils/SdpMediaclk; + public final fun getMid ()Lio/getstream/video/android/core/utils/SdpMid; + public final fun getMline ()Lio/getstream/video/android/core/utils/SdpMline; + public final fun getMsid ()Lio/getstream/video/android/core/utils/SdpMsid; + public final fun getMsidSemantic ()Lio/getstream/video/android/core/utils/SdpMsidsemantic; + public final fun getName ()Lio/getstream/video/android/core/utils/SdpName; + public final fun getOrigin ()Lio/getstream/video/android/core/utils/SdpOrigin; + public final fun getPhone ()Lio/getstream/video/android/core/utils/SdpPhone; + public final fun getPtime ()Lio/getstream/video/android/core/utils/SdpPtime; + public final fun getRemoteCandidates ()Lio/getstream/video/android/core/utils/SdpRemotecandidates; + public final fun getRepeats ()Lio/getstream/video/android/core/utils/SdpRepeats; + public final fun getRids ()Ljava/util/List; + public final fun getRtcp ()Lio/getstream/video/android/core/utils/SdpRtcp; + public final fun getRtcpFb ()Ljava/util/List; + public final fun getRtcpFbTrrInt ()Ljava/util/List; + public final fun getRtcpMux ()Lio/getstream/video/android/core/utils/SdpRtcpmux; + public final fun getRtcpRsize ()Lio/getstream/video/android/core/utils/SdpRtcprsize; + public final fun getRtp ()Ljava/util/List; + public final fun getSctpPort ()Lio/getstream/video/android/core/utils/SdpSctpport; + public final fun getSctpmap ()Lio/getstream/video/android/core/utils/SdpSctpmap; + public final fun getSetup ()Lio/getstream/video/android/core/utils/SdpSetup; + public final fun getSimulcast ()Lio/getstream/video/android/core/utils/SdpSimulcast; + public final fun getSimulcast03 ()Lio/getstream/video/android/core/utils/SdpSimulcast03; + public final fun getSourceFilter ()Lio/getstream/video/android/core/utils/SdpSourcefilter; + public final fun getSsrcGroups ()Ljava/util/List; + public final fun getSsrcs ()Ljava/util/List; + public final fun getTimezones ()Lio/getstream/video/android/core/utils/SdpTimezones; + public final fun getTiming ()Lio/getstream/video/android/core/utils/SdpTiming; + public final fun getTsRefClocks ()Ljava/util/List; + public final fun getUri ()Lio/getstream/video/android/core/utils/SdpUri; + public final fun getVersion ()Lio/getstream/video/android/core/utils/SdpVersion; + public final fun getXGoogleFlag ()Lio/getstream/video/android/core/utils/SdpXgoogleflag; + public final fun parse (Ljava/lang/String;)V + public final fun setBandwidth (Ljava/util/List;)V + public final fun setBfcpConfId (Lio/getstream/video/android/core/utils/SdpBfcpconfid;)V + public final fun setBfcpFloorCtrl (Lio/getstream/video/android/core/utils/SdpBfcpfloorctrl;)V + public final fun setBfcpFloorId (Lio/getstream/video/android/core/utils/SdpBfcpfloorid;)V + public final fun setBfcpUserId (Lio/getstream/video/android/core/utils/SdpBfcpuserid;)V + public final fun setBundleOnly (Lio/getstream/video/android/core/utils/SdpBundleonly;)V + public final fun setCandidates (Ljava/util/List;)V + public final fun setConnection (Lio/getstream/video/android/core/utils/SdpConnection;)V + public final fun setConnectionType (Lio/getstream/video/android/core/utils/SdpConnectiontype;)V + public final fun setContent (Lio/getstream/video/android/core/utils/SdpContent;)V + public final fun setControl (Lio/getstream/video/android/core/utils/SdpControl;)V + public final fun setCrypto (Ljava/util/List;)V + public final fun setDescription (Lio/getstream/video/android/core/utils/SdpDescription;)V + public final fun setDirection (Lio/getstream/video/android/core/utils/SdpDirection;)V + public final fun setEmail (Lio/getstream/video/android/core/utils/SdpEmail;)V + public final fun setEndOfCandidates (Lio/getstream/video/android/core/utils/SdpEndofcandidates;)V + public final fun setExt (Ljava/util/List;)V + public final fun setExtmapAllowMixed (Lio/getstream/video/android/core/utils/SdpExtmapallowmixed;)V + public final fun setFingerprint (Lio/getstream/video/android/core/utils/SdpFingerprint;)V + public final fun setFmtp (Ljava/util/List;)V + public final fun setFramerate (Lio/getstream/video/android/core/utils/SdpFramerate;)V + public final fun setGroups (Ljava/util/List;)V + public final fun setIceOptions (Lio/getstream/video/android/core/utils/SdpIceoptions;)V + public final fun setIcePwd (Lio/getstream/video/android/core/utils/SdpIcepwd;)V + public final fun setIceUfrag (Lio/getstream/video/android/core/utils/SdpIceufrag;)V + public final fun setIcelite (Lio/getstream/video/android/core/utils/SdpIcelite;)V + public final fun setImageattrs (Ljava/util/List;)V + public final fun setInvalid (Ljava/util/List;)V + public final fun setKeywords (Lio/getstream/video/android/core/utils/SdpKeywords;)V + public final fun setLabel (Lio/getstream/video/android/core/utils/SdpLabel;)V + public final fun setMaxMessageSize (Lio/getstream/video/android/core/utils/SdpMaxmessagesize;)V + public final fun setMaxptime (Lio/getstream/video/android/core/utils/SdpMaxptime;)V + public final fun setMediaClk (Lio/getstream/video/android/core/utils/SdpMediaclk;)V + public final fun setMid (Lio/getstream/video/android/core/utils/SdpMid;)V + public final fun setMline (Lio/getstream/video/android/core/utils/SdpMline;)V + public final fun setMsid (Lio/getstream/video/android/core/utils/SdpMsid;)V + public final fun setMsidSemantic (Lio/getstream/video/android/core/utils/SdpMsidsemantic;)V + public final fun setName (Lio/getstream/video/android/core/utils/SdpName;)V + public final fun setOrigin (Lio/getstream/video/android/core/utils/SdpOrigin;)V + public final fun setPhone (Lio/getstream/video/android/core/utils/SdpPhone;)V + public final fun setPtime (Lio/getstream/video/android/core/utils/SdpPtime;)V + public final fun setRemoteCandidates (Lio/getstream/video/android/core/utils/SdpRemotecandidates;)V + public final fun setRepeats (Lio/getstream/video/android/core/utils/SdpRepeats;)V + public final fun setRids (Ljava/util/List;)V + public final fun setRtcp (Lio/getstream/video/android/core/utils/SdpRtcp;)V + public final fun setRtcpFb (Ljava/util/List;)V + public final fun setRtcpFbTrrInt (Ljava/util/List;)V + public final fun setRtcpMux (Lio/getstream/video/android/core/utils/SdpRtcpmux;)V + public final fun setRtcpRsize (Lio/getstream/video/android/core/utils/SdpRtcprsize;)V + public final fun setRtp (Ljava/util/List;)V + public final fun setSctpPort (Lio/getstream/video/android/core/utils/SdpSctpport;)V + public final fun setSctpmap (Lio/getstream/video/android/core/utils/SdpSctpmap;)V + public final fun setSetup (Lio/getstream/video/android/core/utils/SdpSetup;)V + public final fun setSimulcast (Lio/getstream/video/android/core/utils/SdpSimulcast;)V + public final fun setSimulcast03 (Lio/getstream/video/android/core/utils/SdpSimulcast03;)V + public final fun setSourceFilter (Lio/getstream/video/android/core/utils/SdpSourcefilter;)V + public final fun setSsrcGroups (Ljava/util/List;)V + public final fun setSsrcs (Ljava/util/List;)V + public final fun setTimezones (Lio/getstream/video/android/core/utils/SdpTimezones;)V + public final fun setTiming (Lio/getstream/video/android/core/utils/SdpTiming;)V + public final fun setTsRefClocks (Ljava/util/List;)V + public final fun setUri (Lio/getstream/video/android/core/utils/SdpUri;)V + public final fun setVersion (Lio/getstream/video/android/core/utils/SdpVersion;)V + public final fun setXGoogleFlag (Lio/getstream/video/android/core/utils/SdpXgoogleflag;)V + public final fun write ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpSetup { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSetup; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpSetup;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpSetup; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpSimulcast { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSimulcast; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpSimulcast;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpSimulcast; + public fun equals (Ljava/lang/Object;)Z + public final fun getDir1 ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpSimulcast03 { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSimulcast03; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpSimulcast03;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpSimulcast03; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpSourcefilter { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun component4 ()Ljava/lang/String; + public final fun component5 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSourcefilter; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpSourcefilter;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpSourcefilter; + public fun equals (Ljava/lang/Object;)Z + public final fun getAddressTypes ()Ljava/lang/String; + public final fun getDestAddress ()Ljava/lang/String; + public final fun getFilterMode ()Ljava/lang/String; + public final fun getNetType ()Ljava/lang/String; + public final fun getSrcList ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpSsrcgroups { + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSsrcgroups; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpSsrcgroups;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpSsrcgroups; + public fun equals (Ljava/lang/Object;)Z + public final fun getSemantics ()Ljava/lang/String; + public final fun getSsrcs ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpSsrcs { + public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun component3 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpSsrcs; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpSsrcs;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpSsrcs; + public fun equals (Ljava/lang/Object;)Z + public final fun getAttribute ()Ljava/lang/String; + public final fun getId ()Ljava/lang/String; + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpTimezones { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpTimezones; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpTimezones;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpTimezones; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpTiming { + public fun (JJ)V + public final fun component1 ()J + public final fun component2 ()J + public final fun copy (JJ)Lio/getstream/video/android/core/utils/SdpTiming; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpTiming;JJILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpTiming; + public fun equals (Ljava/lang/Object;)Z + public final fun getStart ()J + public final fun getStop ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpTsrefclocks { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpTsrefclocks; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpTsrefclocks;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpTsrefclocks; + public fun equals (Ljava/lang/Object;)Z + public final fun getClksrc ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpUri { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpUri; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpUri;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpUri; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpVersion { + public fun (J)V + public final fun component1 ()J + public final fun copy (J)Lio/getstream/video/android/core/utils/SdpVersion; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpVersion;JILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpVersion; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()J + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpVersionKt { + public static final fun component11 (Lkotlin/text/MatchResult$Destructured;)Ljava/lang/String; + public static final fun component12 (Lkotlin/text/MatchResult$Destructured;)Ljava/lang/String; + public static final fun component13 (Lkotlin/text/MatchResult$Destructured;)Ljava/lang/String; + public static final fun toOptionalLong (Ljava/lang/String;)Ljava/lang/Long; + public static final fun toOptionalString (Ljava/lang/String;)Ljava/lang/String; +} + +public final class io/getstream/video/android/core/utils/SdpXgoogleflag { + public fun (Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;)Lio/getstream/video/android/core/utils/SdpXgoogleflag; + public static synthetic fun copy$default (Lio/getstream/video/android/core/utils/SdpXgoogleflag;Ljava/lang/String;ILjava/lang/Object;)Lio/getstream/video/android/core/utils/SdpXgoogleflag; + public fun equals (Ljava/lang/Object;)Z + public final fun getValue ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class io/getstream/video/android/core/utils/StateFlowKt { public static final fun combineStates (Lkotlinx/coroutines/flow/StateFlow;Lkotlinx/coroutines/flow/StateFlow;Lkotlin/jvm/functions/Function2;)Lkotlinx/coroutines/flow/StateFlow; public static final fun mapState (Lkotlinx/coroutines/flow/StateFlow;Lkotlin/jvm/functions/Function1;)Lkotlinx/coroutines/flow/StateFlow; diff --git a/stream-video-android-core/build.gradle.kts b/stream-video-android-core/build.gradle.kts index fdd4d0c839..61ea173ef5 100644 --- a/stream-video-android-core/build.gradle.kts +++ b/stream-video-android-core/build.gradle.kts @@ -70,6 +70,10 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-proguard-rules.pro") buildConfigField("String", "STREAM_VIDEO_VERSION", "\"${Configuration.versionName}\"") + buildConfigField("Integer", "STREAM_VIDEO_VERSION_MAJOR", "${Configuration.majorVersion}") + buildConfigField("Integer", "STREAM_VIDEO_VERSION_MINOR", "${Configuration.minorVersion}") + buildConfigField("Integer", "STREAM_VIDEO_VERSION_PATCH", "${Configuration.patchVersion}") + } buildFeatures { diff --git a/stream-video-android-core/src/androidTest/kotlin/io/getstream/video/android/core/ReconnectTest.kt b/stream-video-android-core/src/androidTest/kotlin/io/getstream/video/android/core/ReconnectTest.kt index a27c18ec32..4a71e09997 100644 --- a/stream-video-android-core/src/androidTest/kotlin/io/getstream/video/android/core/ReconnectTest.kt +++ b/stream-video-android-core/src/androidTest/kotlin/io/getstream/video/android/core/ReconnectTest.kt @@ -139,7 +139,7 @@ class ReconnectTest : IntegrationTestBase(connectCoordinatorWS = false) { // the socket and rtc connection disconnect..., // or ice candidate don't arrive due to temporary network failure - call.session?.reconnect() + call.session?.reconnect(forceRestart = true) // leave and clean up a call call.leave() @@ -172,7 +172,7 @@ class ReconnectTest : IntegrationTestBase(connectCoordinatorWS = false) { // connect to the new socket // do an ice restart call.session?.let { - it.switchSfu(it.sfuUrl, it.sfuToken, it.remoteIceServers) + it.switchSfu(it.sfuUrl, it.sfuToken, it.sfuToken, it.remoteIceServers) } // assert the publisher is still connected diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt index ea302ad9dd..0c77e9443c 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/Call.kt @@ -29,6 +29,7 @@ import io.getstream.video.android.core.call.audio.AudioFilter import io.getstream.video.android.core.call.utils.SoundInputProcessor import io.getstream.video.android.core.call.video.VideoFilter import io.getstream.video.android.core.call.video.YuvFrame +import io.getstream.video.android.core.events.GoAwayEvent import io.getstream.video.android.core.events.VideoEventListener import io.getstream.video.android.core.internal.InternalStreamVideoApi import io.getstream.video.android.core.model.MuteUsersData @@ -377,25 +378,26 @@ public class Call( val iceServers = result.value.credentials.iceServers.map { it.toIceServer() } timer.split("join request completed") - if (session == null) { - session = if (testInstanceProvider.rtcSessionCreator != null) { - testInstanceProvider.rtcSessionCreator!!.invoke() - } else { - RtcSession( - client = client, - call = this, - sfuUrl = sfuUrl, - sfuToken = sfuToken, - connectionModule = (client as StreamVideoImpl).connectionModule, - remoteIceServers = iceServers, - ) - } + session = if (testInstanceProvider.rtcSessionCreator != null) { + testInstanceProvider.rtcSessionCreator!!.invoke() + } else { + RtcSession( + client = client, + call = this, + sfuUrl = sfuUrl, + sfuToken = sfuToken, + connectionModule = (client as StreamVideoImpl).connectionModule, + remoteIceServers = iceServers, + onMigrationCompleted = { + state._connection.value = RealtimeConnection.Connected + monitor.check() + }, + ) } session?.let { state._connection.value = RealtimeConnection.Joined(it) } - timer.split("rtc session init") session?.connect() @@ -438,7 +440,7 @@ public class Call( // listen to Signal WS scope.launch { session?.let { - it.sfuConnectionModule.sfuSocket.connectionState.collect { sfuSocketState -> + it.sfuSocketState.collect { sfuSocketState -> if (sfuSocketState is SocketState.DisconnectedPermanently) { handleSignalChannelDisconnect(isRetry = false) } @@ -455,6 +457,11 @@ public class Call( // Prevent multiple starts of the reconnect flow. For the start call // first check if sfuSocketReconnectionTime isn't already set - if yes // then we are already doing a full reconnect + if (state._connection.value == RealtimeConnection.Migrating) { + logger.d { "Skipping disconnected channel event - we are migrating" } + return + } + if (!isRetry && sfuSocketReconnectionTime != null) { logger.d { "[handleSignalChannelDisconnect] Already doing a full reconnect cycle - ignoring call" } return @@ -499,22 +506,35 @@ public class Call( return clientImpl.sendStats(type, id, data) } - suspend fun switchSfu(forceSwitch: Boolean = false) { + suspend fun switchSfu() { + state._connection.value = RealtimeConnection.Migrating + location?.let { - val joinResponse = joinRequest(location = it, currentSfu = session?.sfuUrl) - val shouldSwitch = false + val joinResponse = joinRequest(location = it, migratingFrom = session?.sfuUrl) - if ((shouldSwitch || forceSwitch) && joinResponse is Success) { + if (joinResponse is Success) { // switch to the new SFU val cred = joinResponse.value.credentials logger.i { "Switching SFU from ${session?.sfuUrl} to ${cred.server.url}" } val iceServers = cred.iceServers.map { it.toIceServer() } - session?.switchSfu(cred.server.url, cred.token, iceServers) + + session?.switchSfu(cred.server.edgeName, cred.server.url, cred.token, iceServers, failedToSwitch = { + logger.e { + "[switchSfu] Failed to connect to new SFU during migration. Reverting to full reconnect" + } + state._connection.value = RealtimeConnection.Reconnecting + }) + } else { + logger.e { + "[switchSfu] Failed to get a join response during " + + "migration - falling back to reconnect. Error ${joinResponse.errorOrNull()}" + } + state._connection.value = RealtimeConnection.Reconnecting } } } - suspend fun reconnectOrSwitchSfu(forceRestart: Boolean) { + suspend fun reconnect(forceRestart: Boolean) { // mark us as reconnecting val connectionState = state._connection.value @@ -528,10 +548,6 @@ public class Call( if (online) { // start by restarting ice connections session?.reconnect(forceRestart = forceRestart) - - // ask the coordinator if we should switch - // TODO: disabled since switching SFUs isn't 100% stable yet server side - // switchSfu() } } @@ -615,6 +631,22 @@ public class Call( session?.updateTrackDimensions(sessionId, trackType, visible) } + fun handleEvent(event: VideoEvent) { + logger.i { "[call handleEvent] #sfu; event: $event" } + + when (event) { + is GoAwayEvent -> + scope.launch { + handleSessionMigrationEvent() + } + } + } + + private suspend fun handleSessionMigrationEvent() { + logger.d { "[handleSessionMigrationEvent] Received goAway event - starting migration" } + switchSfu() + } + // TODO: review this /** * Perhaps it would be nicer to have an interface. Any UI elements that renders video should implement it @@ -891,7 +923,7 @@ public class Call( internal suspend fun joinRequest( create: CreateCallOptions? = null, location: String, - currentSfu: String? = null, + migratingFrom: String? = null, ring: Boolean = false, notify: Boolean = false, ): Result { @@ -906,6 +938,7 @@ public class Call( ring = ring, notify = notify, location = location, + migratingFrom = migratingFrom, ) result.onSuccess { state.updateFromResponse(it) @@ -987,7 +1020,7 @@ public class Call( public fun switchSfu() { call.scope.launch { - call.switchSfu(true) + call.switchSfu() } } } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallHealthMonitor.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallHealthMonitor.kt index 17bdabc4ae..cc3d22e486 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallHealthMonitor.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallHealthMonitor.kt @@ -105,6 +105,12 @@ public class CallHealthMonitor( */ @Synchronized fun check() { + // skip health checks if we are migrating + if (call.state._connection.value == RealtimeConnection.Migrating) { + logger.d { "Skipping health-check - we are migrating" } + return + } + val subscriberState = call.session?.subscriber?.state?.value val publisherState = call.session?.publisher?.state?.value val healthyPeerConnections = subscriberState in goodStates && publisherState in goodStates @@ -154,6 +160,11 @@ public class CallHealthMonitor( return } + if (call.state._connection.value == RealtimeConnection.Migrating) { + logger.d { "[reconnect] Skipping reconnect - already migrating" } + return + } + logger.i { "attempting to reconnect" } reconnectInProgress = true @@ -175,7 +186,7 @@ public class CallHealthMonitor( logger.d { "[reconnect] skipping reconnect - too often" } } else { lastReconnectAt = now - call.reconnectOrSwitchSfu(forceRestart = forceRestart) + call.reconnect(forceRestart = forceRestart) } reconnectInProgress = false diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt index 6a67a631cc..e143d57a82 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/CallState.kt @@ -151,7 +151,7 @@ public sealed interface RealtimeConnection { */ public data object Reconnecting : RealtimeConnection // reconnecting to recover from temporary issues - + public data object Migrating : RealtimeConnection public data class Failed(val error: Any) : RealtimeConnection // permanent failure public data object Disconnected : RealtimeConnection // normal disconnect by the app } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoImpl.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoImpl.kt index 52d5d17fde..e78390a95f 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoImpl.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/StreamVideoImpl.kt @@ -487,6 +487,7 @@ internal class StreamVideoImpl internal constructor( calls[selectedCid]?.let { it.state.handleEvent(event) it.session?.handleEvent(event) + it.handleEvent(event) } } @@ -641,6 +642,7 @@ internal class StreamVideoImpl internal constructor( ring: Boolean = false, notify: Boolean = false, location: String, + migratingFrom: String?, ): Result { val joinCallRequest = JoinCallRequest( create = create, @@ -654,6 +656,7 @@ internal class StreamVideoImpl internal constructor( ring = ring, notify = notify, location = location, + migratingFrom = migratingFrom, ) val result = wrapAPICall { diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt index 37ef9c2c7b..e740b699e4 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/RtcSession.kt @@ -51,6 +51,8 @@ import io.getstream.video.android.core.model.MediaTrack import io.getstream.video.android.core.model.StreamPeerType import io.getstream.video.android.core.model.VideoTrack import io.getstream.video.android.core.model.toPeerType +import io.getstream.video.android.core.socket.SocketState +import io.getstream.video.android.core.utils.SdpSession import io.getstream.video.android.core.utils.buildAudioConstraints import io.getstream.video.android.core.utils.buildConnectionConfiguration import io.getstream.video.android.core.utils.buildMediaConstraints @@ -61,9 +63,11 @@ import io.getstream.video.android.core.utils.stringify import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.cancel import kotlinx.coroutines.delay import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.catch import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.collectLatest @@ -85,10 +89,12 @@ import org.webrtc.MediaConstraints import org.webrtc.MediaStream import org.webrtc.MediaStreamTrack import org.webrtc.PeerConnection +import org.webrtc.PeerConnection.PeerConnectionState import org.webrtc.RTCStatsReport import org.webrtc.RtpTransceiver import org.webrtc.SessionDescription import retrofit2.HttpException +import stream.video.sfu.event.Migration import stream.video.sfu.models.ICETrickle import stream.video.sfu.models.Participant import stream.video.sfu.models.PeerType @@ -161,6 +167,7 @@ public class RtcSession internal constructor( internal var sfuUrl: String, internal var sfuToken: String, internal var remoteIceServers: List, + internal var onMigrationCompleted: () -> Unit, ) { internal val trackIdToParticipant: MutableStateFlow> = @@ -169,15 +176,17 @@ public class RtcSession internal constructor( private var syncPublisherJob: Job? = null private var subscriptionSyncJob: Job? = null private var muteStateSyncJob: Job? = null + private var sfuSocketStateJob: Job? = null + private var subscriberListenJob: Job? = null private var videoTransceiverInitialized: Boolean = false private var audioTransceiverInitialized: Boolean = false private var screenshareTransceiverInitialized: Boolean = false private var errorJob: Job? = null private var eventJob: Job? = null - internal val socket by lazy { sfuConnectionModule.sfuSocket } + internal val socket + get() = sfuConnectionModule.sfuSocket - private val context = client.context private val logger by taggedLogger("Call:RtcSession") private val dynascaleLogger by taggedLogger("Call:RtcSession:Dynascale") private val clientImpl = client as StreamVideoImpl @@ -263,9 +272,8 @@ public class RtcSession internal constructor( private var iceServers = buildRemoteIceServers(remoteIceServers) - private val connectionConfiguration: PeerConnection.RTCConfiguration by lazy { - buildConnectionConfiguration(iceServers) - } + private val connectionConfiguration: PeerConnection.RTCConfiguration + get() = buildConnectionConfiguration(iceServers) /** subscriber peer connection is used for subs */ public var subscriber: StreamPeerConnection? = null @@ -281,7 +289,16 @@ public class RtcSession internal constructor( buildAudioConstraints() } - internal var sfuConnectionModule: SfuConnectionModule + internal lateinit var sfuConnectionModule: SfuConnectionModule + + /** + * Used during a SFU migration as a temporary new SFU connection. Is null before and after + * the migration is finished. + */ + private var sfuConnectionMigrationModule: SfuConnectionModule? = null + + private val _sfuSocketState = MutableStateFlow(SocketState.NotConnected) + val sfuSocketState = _sfuSocketState.asStateFlow() private val sfuFastReconnectListener: () -> Unit = { // SFU socket has done a fast-reconnect. We need to an ICE restart immediately and not wait @@ -301,22 +318,22 @@ public class RtcSession internal constructor( // step 1 setup the peer connections subscriber = createSubscriber() - coroutineScope.launch { - // call update participant subscriptions debounced - subscriber?.let { - it.state.collect { - updatePeerState() - } - } - } + listenToSubscriberConnection() val session = this val getSdp = suspend { session.getSubscriberSdp().description } - sfuConnectionModule = - connectionModule.createSFUConnectionModule(sfuUrl, sessionId, sfuToken, getSdp, sfuFastReconnectListener) - listenToSocket() + val sfuConnectionModule = + connectionModule.createSFUConnectionModule( + sfuUrl, + sessionId, + sfuToken, + getSdp, + sfuFastReconnectListener, + ) + setSfuConnectionModule(sfuConnectionModule) + listenToSocketEventsAndErrors() coroutineScope.launch { // call update participant subscriptions debounced @@ -339,19 +356,19 @@ public class RtcSession internal constructor( } } - private fun listenToSocket() { + private fun listenToSocketEventsAndErrors() { // cancel any old socket monitoring if needed eventJob?.cancel() errorJob?.cancel() // listen to socket events and errors eventJob = coroutineScope.launch { - sfuConnectionModule.sfuSocket.events.collect() { + sfuConnectionModule.sfuSocket.events.collect { clientImpl.fireEvent(it, call.cid) } } errorJob = coroutineScope.launch { - sfuConnectionModule.sfuSocket.errors.collect() { + sfuConnectionModule.sfuSocket.errors.collect { logger.e(it) { "permanent failure on socket connection" } if (clientImpl.developmentMode) { throw it @@ -414,6 +431,22 @@ public class RtcSession internal constructor( } } + private fun setSfuConnectionModule(sfuConnectionModule: SfuConnectionModule) { + // This is used to switch from a current SFU connection to a new migrated SFU connection + this@RtcSession.sfuConnectionModule = sfuConnectionModule + + // Stop listening to connection state on the existing SFU connection + sfuSocketStateJob?.cancel() + sfuSocketStateJob = null + + // Start listening to connection state on new SFU connection + sfuSocketStateJob = coroutineScope.launch { + sfuConnectionModule.sfuSocket.connectionState.collect { sfuSocketState -> + _sfuSocketState.value = sfuSocketState + } + } + } + private fun initializeScreenshareTransceiver() { if (!screenshareTransceiverInitialized) { publisher?.let { @@ -671,6 +704,9 @@ public class RtcSession internal constructor( // disconnect the socket and clean it up sfuConnectionModule.sfuSocket.cleanup() + sfuConnectionMigrationModule?.sfuSocket?.cleanup() + sfuConnectionMigrationModule = null + // cleanup the publisher and subcriber peer connections subscriber?.connection?.close() publisher?.connection?.close() @@ -791,7 +827,7 @@ public class RtcSession internal constructor( } ?: throw Error("Couldn't create a generic SDP, subscriber isn't setup") } - fun mangleSdp(sdp: SessionDescription): SessionDescription { + private fun mangleSdp(sdp: SessionDescription): SessionDescription { val settings = call.state.settings.value val red = settings?.audio?.redundantCodingEnabled ?: true val opus = settings?.audio?.opusDtxEnabled ?: true @@ -1265,7 +1301,7 @@ public class RtcSession internal constructor( } // step 3 - create the list of tracks - val tracks = getPublisherTracks() + val tracks = getPublisherTracks(mangledSdp.description) val currentSfu = sfuUrl publisherSdpOffer.value = mangledSdp @@ -1283,6 +1319,7 @@ public class RtcSession internal constructor( session_id = sessionId, tracks = tracks, ) + val result = setPublisher(request) // step 5 - set the remote description @@ -1311,7 +1348,7 @@ public class RtcSession internal constructor( } } - private fun getPublisherTracks(): List { + private fun getPublisherTracks(sdp: String): List { val captureResolution = call.camera.resolution.value val screenShareTrack = getLocalTrack(TrackType.TRACK_TYPE_SCREEN_SHARE) @@ -1321,20 +1358,7 @@ public class RtcSession internal constructor( }.map { transceiver -> val track = transceiver.sender.track()!! - val trackType = when (track.kind()) { - "audio" -> TrackType.TRACK_TYPE_AUDIO - "screen" -> TrackType.TRACK_TYPE_SCREEN_SHARE - "video" -> { - // video tracks and screenshare tracks in webrtc are both video - // (the "screen" track type doesn't seem to be used). - if (screenShareTrack?.asVideoTrack()?.video?.id() == track.id()) { - TrackType.TRACK_TYPE_SCREEN_SHARE - } else { - TrackType.TRACK_TYPE_VIDEO - } - } - else -> TrackType.TRACK_TYPE_UNSPECIFIED - } + val trackType = convertKindToTrackType(track, screenShareTrack) val layers: List = if (trackType == TrackType.TRACK_TYPE_VIDEO) { checkNotNull(captureResolution) { @@ -1353,11 +1377,71 @@ public class RtcSession internal constructor( track_id = track.id(), track_type = trackType, layers = layers, + mid = transceiver.mid ?: extractMid(sdp, track, screenShareTrack, trackType, transceivers), ) } return tracks } + private fun convertKindToTrackType(track: MediaStreamTrack, screenShareTrack: MediaTrack?) = + when (track.kind()) { + "audio" -> TrackType.TRACK_TYPE_AUDIO + "screen" -> TrackType.TRACK_TYPE_SCREEN_SHARE + "video" -> { + // video tracks and screenshare tracks in webrtc are both video + // (the "screen" track type doesn't seem to be used). + if (screenShareTrack?.asVideoTrack()?.video?.id() == track.id()) { + TrackType.TRACK_TYPE_SCREEN_SHARE + } else { + TrackType.TRACK_TYPE_VIDEO + } + } + else -> TrackType.TRACK_TYPE_UNSPECIFIED + } + + private fun extractMid( + sdp: String?, + track: MediaStreamTrack, + screenShareTrack: MediaTrack?, + trackType: TrackType, + transceivers: List, + ): String { + if (sdp.isNullOrBlank()) { + logger.w { "[extractMid] No SDP found. Returning empty mid" } + return "" + } + + logger.d { + "[extractMid] No 'mid' found for track. Trying to find it from the Offer SDP" + } + + val sdpSession = SdpSession() + sdpSession.parse(sdp) + val media = sdpSession.media.find { m -> + m.mline?.type == track.kind() && + // if `msid` is not present, we assume that the track is the first one + (m.msid?.equals(track.id()) ?: true) + } + + if (media?.mid == null) { + logger.d { + "[extractMid] No mid found in SDP for track type ${track.kind()} and id ${track.id()}. Attempting to find a heuristic mid" + } + + val heuristicMid = transceivers.firstOrNull { + convertKindToTrackType(track, screenShareTrack) == trackType + } + if (heuristicMid != null) { + return heuristicMid.mid + } + + logger.d { "[extractMid] No heuristic mid found. Returning empty mid" } + return "" + } + + return media.mid.toString() + } + private fun createVideoLayers(transceiver: RtpTransceiver, captureResolution: CaptureFormat): List { // we tell the Sfu which resolutions we're sending return transceiver.sender.parameters.encodings.map { @@ -1564,28 +1648,143 @@ public class RtcSession internal constructor( trackDimensions.value = trackDimensionsMap } - suspend fun switchSfu(sfuUrl: String, sfuToken: String, remoteIceServers: List) { - logger.i { "switchSfu from ${this.sfuUrl} to $sfuUrl" } + private fun listenToSubscriberConnection() { + subscriberListenJob?.cancel() + subscriberListenJob = coroutineScope.launch { + // call update participant subscriptions debounced + subscriber?.let { + it.state.collect { + updatePeerState() + } + } + } + } + + suspend fun switchSfu(sfuName: String, sfuUrl: String, sfuToken: String, remoteIceServers: List, failedToSwitch: () -> Unit) { + logger.i { "[switchSfu] from ${this.sfuUrl} to $sfuUrl" } val timer = clientImpl.debugInfo.trackTime("call.switchSfu") - // update internal vars ot the new SFU - this.sfuUrl = sfuUrl - this.sfuToken = sfuToken - this.remoteIceServers = remoteIceServers - this.iceServers = buildRemoteIceServers(remoteIceServers) - // create the new socket + // Prepare SDP val getSdp = suspend { getSubscriberSdp().description } - // TODO: updating the turn server requires a new peer connection - sfuConnectionModule = - connectionModule.createSFUConnectionModule(sfuUrl, sessionId, sfuToken, getSdp, sfuFastReconnectListener) - listenToSocket() - sfuConnectionModule.sfuSocket.connect() - timer.split("socket connected") - // ice restart - reconnect(forceRestart = true) - timer.finish("ice restart in progress") + // Prepare migration object for SFU socket + val migration = suspend { + Migration( + from_sfu_id = sfuName, + announced_tracks = getPublisherTracks(getSdp.invoke()), + subscriptions = subscriptions.value, + ) + } + // Create a parallel SFU socket + sfuConnectionMigrationModule = + connectionModule.createSFUConnectionModule( + sfuUrl, + sessionId, + sfuToken, + getSdp, + sfuFastReconnectListener, + ) + + // Wait until the socket connects - if it fails to connect then return to "Reconnecting" + // state (to make sure that the full reconnect logic will kick in) + coroutineScope.launch { + sfuConnectionMigrationModule!!.sfuSocket.connectionState.collect { it -> + when (it) { + is SocketState.Connected -> { + logger.d { "[switchSfu] Migration SFU socket state changed to Connected" } + timer.split("SFU socket connected") + + // Disconnect the old SFU and stop listening to SFU stateflows + eventJob?.cancel() + errorJob?.cancel() + sfuConnectionModule.sfuSocket.cleanup() + + // Make the new SFU the currently used one + setSfuConnectionModule(sfuConnectionMigrationModule!!) + sfuConnectionMigrationModule = null + + // We are connected to the new SFU, change the RtcSession parameters to + // match the new SFU + this@RtcSession.sfuUrl = sfuUrl + this@RtcSession.sfuToken = sfuToken + this@RtcSession.remoteIceServers = remoteIceServers + this@RtcSession.iceServers = buildRemoteIceServers(remoteIceServers) + + // reconnect socket listeners + listenToSocketEventsAndErrors() + + var tempSubscriber = subscriber + + // step 1 setup the peer connections + subscriber = createSubscriber() + + // This makes sure that the new subscriber starts listening to the existing tracks + // Without this the peer connection state would stay in NEW + setVideoSubscriptions() + + // Start emiting the new subscriber connection state (used by CallHealthMonitor) + listenToSubscriberConnection() + + // Necessary after SFU migration. This will trigger onNegotiationNeeded + publisher?.connection?.restartIce() + + coroutineScope.launch { + subscriber?.state?.collect { + if (it == PeerConnectionState.CONNECTED) { + logger.d { "[switchSfu] Migration subscriber state changed to Connected" } + timer.split("Subscriber connected") + tempSubscriber?.let { tempSubscriberValue -> + tempSubscriberValue.connection.close() + tempSubscriber = null + } + + onMigrationCompleted.invoke() + + timer.finish() + cancel() + } else if (it == PeerConnectionState.CLOSED || + it == PeerConnectionState.DISCONNECTED || + it == PeerConnectionState.FAILED + ) { + logger.d { "[switchSfu] Failed to migrate - subscriber didn't connect ($it)" } + // Something when wrong with the new subscriber connection + // We give up the migration and wait for full reconnect + failedToSwitch() + cancel() + } + } + } + + updatePeerState() + + // Only listen for the connection event once + cancel() + } + + is SocketState.DisconnectedPermanently -> { + logger.d { "[switchSfu] Failed to migrate - SFU socket disconnected permanently ${it.error}" } + failedToSwitch() + cancel() + } + + is SocketState.DisconnectedTemporarily -> { + logger.d { "[switchSfu] Failed to migrate - SFU socket disconnected temporarily ${it.error}" } + // We don't wait for the socket to retry during migration + // In this case we will fall back to full-reconnect + failedToSwitch() + cancel() + } + + else -> { + // Wait + } + } + } + } + + // Connect to SFU socket + sfuConnectionMigrationModule!!.sfuSocket.connectMigrating(migration) {} } } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/signal/socket/RTCEventMapper.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/signal/socket/RTCEventMapper.kt index 29f1c708bc..49318ce6e5 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/signal/socket/RTCEventMapper.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/call/signal/socket/RTCEventMapper.kt @@ -23,6 +23,7 @@ import io.getstream.video.android.core.events.ChangePublishQualityEvent import io.getstream.video.android.core.events.ConnectionQualityChangeEvent import io.getstream.video.android.core.events.DominantSpeakerChangedEvent import io.getstream.video.android.core.events.ErrorEvent +import io.getstream.video.android.core.events.GoAwayEvent import io.getstream.video.android.core.events.ICETrickleEvent import io.getstream.video.android.core.events.JoinCallResponseEvent import io.getstream.video.android.core.events.ParticipantCount @@ -123,6 +124,8 @@ public object RTCEventMapper { event.call_grants_updated.message, ) + event.go_away != null -> GoAwayEvent(reason = event.go_away.reason) + else -> { logger.w { "Unknown event: $event" } UnknownEvent(event) diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/events/SfuDataEvent.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/events/SfuDataEvent.kt index 43f5bfb5b8..6f2e083204 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/events/SfuDataEvent.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/events/SfuDataEvent.kt @@ -23,6 +23,7 @@ import stream.video.sfu.event.ConnectionQualityInfo import stream.video.sfu.models.CallGrants import stream.video.sfu.models.CallState import stream.video.sfu.models.Error +import stream.video.sfu.models.GoAwayReason import stream.video.sfu.models.Participant import stream.video.sfu.models.PeerType import stream.video.sfu.models.TrackType @@ -37,6 +38,10 @@ public data class PublisherAnswerEvent( val sdp: String, ) : SfuDataEvent() +public data class GoAwayEvent( + val reason: GoAwayReason, +) : SfuDataEvent() + public data class CallGrantsUpdatedEvent( val current_grants: CallGrants?, val message: String = "", diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/internal/module/ConnectionModule.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/internal/module/ConnectionModule.kt index 15b2b6dc9d..cfa30e6bfe 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/internal/module/ConnectionModule.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/internal/module/ConnectionModule.kt @@ -180,7 +180,7 @@ internal class SfuConnectionModule( /** A token which gives you access to the sfu */ private val sfuToken: String, /** A token which gives you access to the sfu */ - val apiKey: String, + private val apiKey: String, /** Function that gives a fresh SDP */ getSubscriberSdp: suspend () -> String, private val loggingLevel: LoggingLevel = LoggingLevel(), @@ -228,6 +228,7 @@ internal class SfuConnectionModule( init { val socketUrl = "$updatedSignalUrl/ws".replace("https", "wss") + sfuSocket = SfuSocket( socketUrl, sessionId, diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/PersistentSocket.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/PersistentSocket.kt index 9a019e1dc0..628d95ebe8 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/PersistentSocket.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/PersistentSocket.kt @@ -306,6 +306,10 @@ public open class PersistentSocket( // onFailure, onClosed and the 2 onMessage can all generate errors // temporary errors should be logged and retried // permanent errors should be emitted so the app can decide how to handle it + if (destroyed) { + logger.d { "[handleError] Ignoring socket error - already closed $error" } + return + } val permanentError = isPermanentError(error) if (permanentError) { @@ -336,6 +340,12 @@ public open class PersistentSocket( */ override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { logger.d { "[onClosed] code: $code, reason: $reason" } + + if (destroyed) { + logger.d { "[onClosed] Ignoring onClosed - socket already closed" } + return + } + if (code != CODE_CLOSE_SOCKET_FROM_CLIENT) { handleError(IllegalStateException("socket closed by server, this shouldn't happen")) } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/SfuSocket.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/SfuSocket.kt index e128836984..d3dc66be9e 100644 --- a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/SfuSocket.kt +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/socket/SfuSocket.kt @@ -16,6 +16,7 @@ package io.getstream.video.android.core.socket +import android.os.Build import io.getstream.log.taggedLogger import io.getstream.video.android.core.BuildConfig import io.getstream.video.android.core.call.signal.socket.RTCEventMapper @@ -31,8 +32,14 @@ import okhttp3.OkHttpClient import okhttp3.WebSocket import okio.ByteString import stream.video.sfu.event.JoinRequest +import stream.video.sfu.event.Migration import stream.video.sfu.event.SfuEvent import stream.video.sfu.event.SfuRequest +import stream.video.sfu.models.ClientDetails +import stream.video.sfu.models.Device +import stream.video.sfu.models.OS +import stream.video.sfu.models.Sdk +import stream.video.sfu.models.SdkType /** * The SFU socket is slightly different from the coordinator socket @@ -63,6 +70,26 @@ public class SfuSocket( private val maxReconnectWindowTime = if (BuildConfig.DEBUG) { 10000L } else { 3000L } private var lastDisconnectTime: Long? = null + // Only set during SFU migration + private var migrationData: (suspend () -> Migration)? = null + + private val clientDetails + get() = ClientDetails( + os = OS( + name = "Android", + version = Build.VERSION.SDK_INT.toString(), + ), + device = Device( + name = "${Build.MANUFACTURER} : ${Build.MODEL}", + ), + sdk = Sdk( + type = SdkType.SDK_TYPE_ANDROID, + major = BuildConfig.STREAM_VIDEO_VERSION_MAJOR.toString(), + minor = BuildConfig.STREAM_VIDEO_VERSION_MINOR.toString(), + patch = BuildConfig.STREAM_VIDEO_VERSION_PATCH.toString(), + ), + ) + init { scope.launch { connectionState.collect { @@ -78,6 +105,11 @@ public class SfuSocket( } } + suspend fun connectMigrating(migration: (suspend () -> Migration), invocation: (CancellableContinuation) -> Unit): JoinCallResponseEvent? { + migrationData = migration + return connect(invocation) + } + override suspend fun connect(invocation: (CancellableContinuation) -> Unit): JoinCallResponseEvent? { val lastDisconnectTime = lastDisconnectTime // Check if too much time hasn't passed since last connect - if yes then a fast reconnect @@ -98,12 +130,29 @@ public class SfuSocket( if (socket != null) { val sdp = getSubscriberSdp() - val request = JoinRequest( - session_id = sessionId, - token = token, - subscriber_sdp = sdp, - fast_reconnect = reconnectionAttempts > 0, - ) + val migration = migrationData?.invoke() + // clear migration data - we only try to migrate once + migrationData = null + + val request = if (migration == null) { + JoinRequest( + session_id = sessionId, + token = token, + subscriber_sdp = sdp, + fast_reconnect = reconnectionAttempts > 0, + client_details = clientDetails, + ) + } else { + JoinRequest( + session_id = sessionId, + token = token, + subscriber_sdp = sdp, + fast_reconnect = false, + migration = migration, + client_details = clientDetails, + ) + } + socket?.send(SfuRequest(join_request = request).encodeByteString()) } } diff --git a/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/utils/SdpVersion.kt b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/utils/SdpVersion.kt new file mode 100644 index 0000000000..03ed7fc76a --- /dev/null +++ b/stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/utils/SdpVersion.kt @@ -0,0 +1,1714 @@ +/* + * Copyright (c) 2014-2023 Stream.io Inc. All rights reserved. + * + * Licensed under the Stream License; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://github.com/GetStream/stream-video-android/blob/main/LICENSE + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.getstream.video.android.core.utils + +/** + * This is a Kotlin port of the original (MIT licensed) located at + * https://github.com/clux/sdp-transform. This port is from: https://github.com/ggarber/sdpparser + */ + +data class SdpVersion(val value: Long) +data class SdpOrigin( + val username: String, + val sessionId: Long, + val sessionVersion: Long, + val netType: String, + val ipVer: Long, + val address: String, +) +data class SdpName(val value: String) +data class SdpDescription(val value: String) +data class SdpUri(val value: String) +data class SdpEmail(val value: String) +data class SdpPhone(val value: String) +data class SdpTimezones(val value: String) +data class SdpRepeats(val value: String) +data class SdpTiming(val start: Long, val stop: Long) +data class SdpConnection(val version: Long, val ip: String) +data class SdpBandwidth(val type: String, val limit: String) +data class SdpMline(val type: String, val port: Long, val protocol: String, val payloads: String) +data class SdpRtp(val payload: Long, val codec: String, val rate: Long?, val encoding: String?) +data class SdpFmtp(val payload: Long, val config: String) +data class SdpControl(val value: String) +data class SdpRtcp(val port: Long, val netType: String?, val ipVer: Long?, val address: String?) +data class SdpRtcpfbtrrint(val payload: String, val value: Long) +data class SdpRtcpfb(val payload: String, val type: String, val subtype: String?) +data class SdpExt( + val value: Long, + val direction: String?, + val encryptUri: String?, + val uri: String, + val config: String?, +) +data class SdpExtmapallowmixed(val value: String) +data class SdpCrypto( + val id: Long, + val suite: String, + val config: String, + val sessionConfig: String?, +) +data class SdpSetup(val value: String) +data class SdpConnectiontype(val value: String) +data class SdpMid(val value: String) +data class SdpMsid(val value: String) +data class SdpPtime(val value: Long) +data class SdpMaxptime(val value: Long) +data class SdpDirection(val value: String) +data class SdpIcelite(val value: String) +data class SdpIceufrag(val value: String) +data class SdpIcepwd(val value: String) +data class SdpFingerprint(val type: String, val hash: String) +data class SdpCandidates( + val foundation: String, + val component: Long, + val transport: String, + val priority: Long, + val ip: String, + val port: Long, + val type: String, + val raddr: String?, + val rport: Long?, + val tcptype: String?, + val generation: Long?, + val networkId: Long?, + val networkCost: Long?, +) +data class SdpEndofcandidates(val value: String) +data class SdpRemotecandidates(val value: String) +data class SdpIceoptions(val value: String) +data class SdpSsrcs(val id: String, val attribute: String?, val value: String?) +data class SdpSsrcgroups(val semantics: String, val ssrcs: String) +data class SdpMsidsemantic(val semantic: String, val token: String) +data class SdpGroups(val type: String, val mids: String) +data class SdpRtcpmux(val value: String) +data class SdpRtcprsize(val value: String) +data class SdpSctpmap(val sctpmapNumber: String) +data class SdpXgoogleflag(val value: String) +data class SdpRids(val id: String) +data class SdpImageattrs(val pt: String) +data class SdpSimulcast(val dir1: String) +data class SdpSimulcast03(val value: String) +data class SdpFramerate(val value: Long) +data class SdpSourcefilter( + val filterMode: String, + val netType: String, + val addressTypes: String, + val destAddress: String, + val srcList: String, +) +data class SdpBundleonly(val value: String) +data class SdpLabel(val value: String) +data class SdpSctpport(val value: Long) +data class SdpMaxmessagesize(val value: Long) +data class SdpTsrefclocks(val clksrc: String) +data class SdpMediaclk(val id: String) +data class SdpKeywords(val value: String) +data class SdpContent(val value: String) +data class SdpBfcpfloorctrl(val value: String) +data class SdpBfcpconfid(val value: String) +data class SdpBfcpuserid(val value: String) +data class SdpBfcpfloorid(val id: String, val mStream: String) +data class SdpInvalid(val value: String) + +fun toOptionalLong(str: String): Long? = if (str.isEmpty()) null else str.toLong() +fun toOptionalString(str: String): String? = str.ifEmpty { null } + +operator fun MatchResult.Destructured.component11(): String = match.groupValues[11] +operator fun MatchResult.Destructured.component12(): String = match.groupValues[12] +operator fun MatchResult.Destructured.component13(): String = match.groupValues[13] + +object SdpGrammar { + + private val VERSION = """(\d*)""".toRegex() + fun tryParseVersion(string: String): SdpVersion? { + val match = VERSION.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpVersion(value.toLong()) + } + fun writeVersion(item: SdpVersion): String { + return "${item.value}" + } + + private val ORIGIN = """(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)""".toRegex() + fun tryParseOrigin(string: String): SdpOrigin? { + val match = ORIGIN.matchEntire(string) ?: return null + val (username, sessionId, sessionVersion, netType, ipVer, address) = match.destructured + return SdpOrigin( + username, + sessionId.toLong(), + sessionVersion.toLong(), + netType, + ipVer.toLong(), + address, + ) + } + fun writeOrigin(item: SdpOrigin): String { + return "${item.username} ${item.sessionId} ${item.sessionVersion} ${item.netType} IP${item.ipVer} ${item.address}" + } + + private val NAME = """(.*)""".toRegex() + fun tryParseName(string: String): SdpName? { + val match = NAME.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpName(value) + } + fun writeName(item: SdpName): String { + return "${item.value}" + } + + private val DESCRIPTION = """(.*)""".toRegex() + fun tryParseDescription(string: String): SdpDescription? { + val match = DESCRIPTION.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpDescription(value) + } + fun writeDescription(item: SdpDescription): String { + return "${item.value}" + } + + private val URI = """(.*)""".toRegex() + fun tryParseUri(string: String): SdpUri? { + val match = URI.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpUri(value) + } + fun writeUri(item: SdpUri): String { + return "${item.value}" + } + + private val EMAIL = """(.*)""".toRegex() + fun tryParseEmail(string: String): SdpEmail? { + val match = EMAIL.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpEmail(value) + } + fun writeEmail(item: SdpEmail): String { + return "${item.value}" + } + + private val PHONE = """(.*)""".toRegex() + fun tryParsePhone(string: String): SdpPhone? { + val match = PHONE.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpPhone(value) + } + fun writePhone(item: SdpPhone): String { + return "${item.value}" + } + + private val TIMEZONES = """(.*)""".toRegex() + fun tryParseTimezones(string: String): SdpTimezones? { + val match = TIMEZONES.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpTimezones(value) + } + fun writeTimezones(item: SdpTimezones): String { + return "${item.value}" + } + + private val REPEATS = """(.*)""".toRegex() + fun tryParseRepeats(string: String): SdpRepeats? { + val match = REPEATS.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpRepeats(value) + } + fun writeRepeats(item: SdpRepeats): String { + return "${item.value}" + } + + private val TIMING = """(\d*) (\d*)""".toRegex() + fun tryParseTiming(string: String): SdpTiming? { + val match = TIMING.matchEntire(string) ?: return null + val (start, stop) = match.destructured + return SdpTiming(start.toLong(), stop.toLong()) + } + fun writeTiming(item: SdpTiming): String { + return "${item.start} ${item.stop}" + } + + private val CONNECTION = """IN IP(\d) (\S*)""".toRegex() + fun tryParseConnection(string: String): SdpConnection? { + val match = CONNECTION.matchEntire(string) ?: return null + val (version, ip) = match.destructured + return SdpConnection(version.toLong(), ip) + } + fun writeConnection(item: SdpConnection): String { + return "IN IP${item.version} ${item.ip}" + } + + private val BANDWIDTH = """(TIAS|AS|CT|RR|RS):(\d*)""".toRegex() + fun tryParseBandwidth(string: String): SdpBandwidth? { + val match = BANDWIDTH.matchEntire(string) ?: return null + val (type, limit) = match.destructured + return SdpBandwidth(type, limit) + } + fun writeBandwidth(item: SdpBandwidth): String { + return "${item.type}:${item.limit}" + } + + private val MLINE = """(\w*) (\d*) ([\w/]*)(?: (.*))?""".toRegex() + fun tryParseMline(string: String): SdpMline? { + val match = MLINE.matchEntire(string) ?: return null + val (type, port, protocol, payloads) = match.destructured + return SdpMline(type, port.toLong(), protocol, payloads) + } + fun writeMline(item: SdpMline): String { + return "${item.type} ${item.port} ${item.protocol} ${item.payloads}" + } + + private val RTP = """rtpmap:(\d*) ([\w\-.]*)(?:\s*/(\d*)(?:\s*/(\S*))?)?""".toRegex() + fun tryParseRtp(string: String): SdpRtp? { + val match = RTP.matchEntire(string) ?: return null + val (payload, codec, rate, encoding) = match.destructured + return SdpRtp(payload.toLong(), codec, toOptionalLong(rate), toOptionalString(encoding)) + } + fun writeRtp(item: SdpRtp): String { + return "rtpmap:${item.payload} ${item.codec}${if (item.rate != null) ("/" + item.rate) else ""}${if (item.encoding != null) ("/" + item.encoding) else ""}" + } + + private val FMTP = """fmtp:(\d*) ([\S| ]*)""".toRegex() + fun tryParseFmtp(string: String): SdpFmtp? { + val match = FMTP.matchEntire(string) ?: return null + val (payload, config) = match.destructured + return SdpFmtp(payload.toLong(), config) + } + fun writeFmtp(item: SdpFmtp): String { + return "fmtp:${item.payload} ${item.config}" + } + + private val CONTROL = """control:(.*)""".toRegex() + fun tryParseControl(string: String): SdpControl? { + val match = CONTROL.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpControl(value) + } + fun writeControl(item: SdpControl): String { + return "control:${item.value}" + } + + private val RTCP = """rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?""".toRegex() + fun tryParseRtcp(string: String): SdpRtcp? { + val match = RTCP.matchEntire(string) ?: return null + val (port, netType, ipVer, address) = match.destructured + return SdpRtcp( + port.toLong(), + toOptionalString(netType), + toOptionalLong(ipVer), + toOptionalString(address), + ) + } + fun writeRtcp(item: SdpRtcp): String { + return "rtcp:${item.port}${if (item.netType != null) (" " + item.netType) else ""}${if (item.ipVer != null) (" IP" + item.ipVer) else ""}${if (item.address != null) (" " + item.address) else ""}" + } + + private val RTCPFBTRRINT = """rtcp-fb:(\*|\d*) trr-int (\d*)""".toRegex() + fun tryParseRtcpfbtrrint(string: String): SdpRtcpfbtrrint? { + val match = RTCPFBTRRINT.matchEntire(string) ?: return null + val (payload, value) = match.destructured + return SdpRtcpfbtrrint(payload, value.toLong()) + } + fun writeRtcpfbtrrint(item: SdpRtcpfbtrrint): String { + return "rtcp-fb:${item.payload} trr-int ${item.value}" + } + + private val RTCPFB = """rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?""".toRegex() + fun tryParseRtcpfb(string: String): SdpRtcpfb? { + val match = RTCPFB.matchEntire(string) ?: return null + val (payload, type, subtype) = match.destructured + return SdpRtcpfb(payload, type, toOptionalString(subtype)) + } + fun writeRtcpfb(item: SdpRtcpfb): String { + return "rtcp-fb:${item.payload} ${item.type}${if (item.subtype != null) (" " + item.subtype) else ""}" + } + + private val EXT = """extmap:(\d+)(?:/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?""".toRegex() + fun tryParseExt(string: String): SdpExt? { + val match = EXT.matchEntire(string) ?: return null + val (value, direction, encryptUri, uri, config) = match.destructured + return SdpExt( + value.toLong(), + toOptionalString(direction), + toOptionalString(encryptUri), + uri, + toOptionalString(config), + ) + } + fun writeExt(item: SdpExt): String { + return "extmap:${item.value}${if (item.direction != null) ("/" + item.direction) else ""}${if (item.encryptUri != null) (" " + item.encryptUri) else ""} ${item.uri}${if (item.config != null) (" " + item.config) else ""}" + } + + private val EXTMAPALLOWMIXED = """(extmap-allow-mixed)""".toRegex() + fun tryParseExtmapallowmixed(string: String): SdpExtmapallowmixed? { + val match = EXTMAPALLOWMIXED.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpExtmapallowmixed(value) + } + fun writeExtmapallowmixed(item: SdpExtmapallowmixed): String { + return "${item.value}" + } + + private val CRYPTO = """crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?""".toRegex() + fun tryParseCrypto(string: String): SdpCrypto? { + val match = CRYPTO.matchEntire(string) ?: return null + val (id, suite, config, sessionConfig) = match.destructured + return SdpCrypto(id.toLong(), suite, config, toOptionalString(sessionConfig)) + } + fun writeCrypto(item: SdpCrypto): String { + return "crypto:${item.id} ${item.suite} ${item.config}${if (item.sessionConfig != null) (" " + item.sessionConfig) else ""}" + } + + private val SETUP = """setup:(\w*)""".toRegex() + fun tryParseSetup(string: String): SdpSetup? { + val match = SETUP.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpSetup(value) + } + fun writeSetup(item: SdpSetup): String { + return "setup:${item.value}" + } + + private val CONNECTIONTYPE = """connection:(new|existing)""".toRegex() + fun tryParseConnectiontype(string: String): SdpConnectiontype? { + val match = CONNECTIONTYPE.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpConnectiontype(value) + } + fun writeConnectiontype(item: SdpConnectiontype): String { + return "connection:${item.value}" + } + + private val MID = """mid:([^\s]*)""".toRegex() + fun tryParseMid(string: String): SdpMid? { + val match = MID.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpMid(value) + } + fun writeMid(item: SdpMid): String { + return "mid:${item.value}" + } + + private val MSID = """msid:(.*)""".toRegex() + fun tryParseMsid(string: String): SdpMsid? { + val match = MSID.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpMsid(value) + } + fun writeMsid(item: SdpMsid): String { + return "msid:${item.value}" + } + + private val PTIME = """ptime:(\d*(?:\.\d*)*)""".toRegex() + fun tryParsePtime(string: String): SdpPtime? { + val match = PTIME.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpPtime(value.toLong()) + } + fun writePtime(item: SdpPtime): String { + return "ptime:${item.value}" + } + + private val MAXPTIME = """maxptime:(\d*(?:\.\d*)*)""".toRegex() + fun tryParseMaxptime(string: String): SdpMaxptime? { + val match = MAXPTIME.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpMaxptime(value.toLong()) + } + fun writeMaxptime(item: SdpMaxptime): String { + return "maxptime:${item.value}" + } + + private val DIRECTION = """(sendrecv|recvonly|sendonly|inactive)""".toRegex() + fun tryParseDirection(string: String): SdpDirection? { + val match = DIRECTION.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpDirection(value) + } + fun writeDirection(item: SdpDirection): String { + return "${item.value}" + } + + private val ICELITE = """(ice-lite)""".toRegex() + fun tryParseIcelite(string: String): SdpIcelite? { + val match = ICELITE.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpIcelite(value) + } + fun writeIcelite(item: SdpIcelite): String { + return "${item.value}" + } + + private val ICEUFRAG = """ice-ufrag:(\S*)""".toRegex() + fun tryParseIceufrag(string: String): SdpIceufrag? { + val match = ICEUFRAG.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpIceufrag(value) + } + fun writeIceufrag(item: SdpIceufrag): String { + return "ice-ufrag:${item.value}" + } + + private val ICEPWD = """ice-pwd:(\S*)""".toRegex() + fun tryParseIcepwd(string: String): SdpIcepwd? { + val match = ICEPWD.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpIcepwd(value) + } + fun writeIcepwd(item: SdpIcepwd): String { + return "ice-pwd:${item.value}" + } + + private val FINGERPRINT = """fingerprint:(\S*) (\S*)""".toRegex() + fun tryParseFingerprint(string: String): SdpFingerprint? { + val match = FINGERPRINT.matchEntire(string) ?: return null + val (type, hash) = match.destructured + return SdpFingerprint(type, hash) + } + fun writeFingerprint(item: SdpFingerprint): String { + return "fingerprint:${item.type} ${item.hash}" + } + + private val CANDIDATES = """candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?(?: network-id (\d*))?(?: network-cost (\d*))?""".toRegex() + fun tryParseCandidates(string: String): SdpCandidates? { + val match = CANDIDATES.matchEntire(string) ?: return null + val (foundation, component, transport, priority, ip, port, type, raddr, rport, tcptype, generation, networkId, networkCost) = match.destructured + return SdpCandidates( + foundation, component.toLong(), transport, priority.toLong(), ip, port.toLong(), type, + toOptionalString( + raddr, + ), + toOptionalLong( + rport, + ), + toOptionalString( + tcptype, + ), + toOptionalLong(generation), toOptionalLong(networkId), toOptionalLong(networkCost), + ) + } + fun writeCandidates(item: SdpCandidates): String { + return "candidate:${item.foundation} ${item.component} ${item.transport} ${item.priority} ${item.ip} ${item.port} typ ${item.type}${if (item.raddr != null && item.rport != null) (" raddr " + item.raddr + " rport " + item.rport) else "" }${if (item.tcptype != null) (" tcptype " + item.tcptype) else "" }${if (item.generation != null) (" generation " + item.generation) else "" }${if (item.networkId != null) (" network-id " + item.networkId) else "" }${if (item.networkCost != null) (" network-cost " + item.networkCost) else "" }" + } + + private val ENDOFCANDIDATES = """(end-of-candidates)""".toRegex() + fun tryParseEndofcandidates(string: String): SdpEndofcandidates? { + val match = ENDOFCANDIDATES.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpEndofcandidates(value) + } + fun writeEndofcandidates(item: SdpEndofcandidates): String { + return "${item.value}" + } + + private val REMOTECANDIDATES = """remote-candidates:(.*)""".toRegex() + fun tryParseRemotecandidates(string: String): SdpRemotecandidates? { + val match = REMOTECANDIDATES.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpRemotecandidates(value) + } + fun writeRemotecandidates(item: SdpRemotecandidates): String { + return "remote-candidates:${item.value}" + } + + private val ICEOPTIONS = """ice-options:(\S*)""".toRegex() + fun tryParseIceoptions(string: String): SdpIceoptions? { + val match = ICEOPTIONS.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpIceoptions(value) + } + fun writeIceoptions(item: SdpIceoptions): String { + return "ice-options:${item.value}" + } + + private val SSRCS = """ssrc:(\d*) ([\w_-]*)(?::(.*))?""".toRegex() + fun tryParseSsrcs(string: String): SdpSsrcs? { + val match = SSRCS.matchEntire(string) ?: return null + val (id, attribute, value) = match.destructured + return SdpSsrcs(id, toOptionalString(attribute), toOptionalString(value)) + } + fun writeSsrcs(item: SdpSsrcs): String { + return "ssrc:${item.id}${if (item.attribute != null) (" " + item.attribute + (if (item.value != null) ":" + item.value else "")) else ""}" + } + + private val SSRCGROUPS = """ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\w]*) (.*)""".toRegex() + fun tryParseSsrcgroups(string: String): SdpSsrcgroups? { + val match = SSRCGROUPS.matchEntire(string) ?: return null + val (semantics, ssrcs) = match.destructured + return SdpSsrcgroups(semantics, ssrcs) + } + fun writeSsrcgroups(item: SdpSsrcgroups): String { + return "ssrc-group:${item.semantics} ${item.ssrcs}" + } + + private val MSIDSEMANTIC = """msid-semantic:\s?(\w*) (\S*)""".toRegex() + fun tryParseMsidsemantic(string: String): SdpMsidsemantic? { + val match = MSIDSEMANTIC.matchEntire(string) ?: return null + val (semantic, token) = match.destructured + return SdpMsidsemantic(semantic, token) + } + fun writeMsidsemantic(item: SdpMsidsemantic): String { + return "msid-semantic: ${item.semantic} ${item.token}" + } + + private val GROUPS = """group:(\w*) (.*)""".toRegex() + fun tryParseGroups(string: String): SdpGroups? { + val match = GROUPS.matchEntire(string) ?: return null + val (type, mids) = match.destructured + return SdpGroups(type, mids) + } + fun writeGroups(item: SdpGroups): String { + return "group:${item.type} ${item.mids}" + } + + private val RTCPMUX = """(rtcp-mux)""".toRegex() + fun tryParseRtcpmux(string: String): SdpRtcpmux? { + val match = RTCPMUX.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpRtcpmux(value) + } + fun writeRtcpmux(item: SdpRtcpmux): String { + return "${item.value}" + } + + private val RTCPRSIZE = """(rtcp-rsize)""".toRegex() + fun tryParseRtcprsize(string: String): SdpRtcprsize? { + val match = RTCPRSIZE.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpRtcprsize(value) + } + fun writeRtcprsize(item: SdpRtcprsize): String { + return "${item.value}" + } + + private val SCTPMAP = """sctpmap:([\w_/]*) (\S*)(?: (\S*))?""".toRegex() + fun tryParseSctpmap(string: String): SdpSctpmap? { + val match = SCTPMAP.matchEntire(string) ?: return null + val (sctpmapNumber) = match.destructured + return SdpSctpmap(sctpmapNumber) + } + fun writeSctpmap(item: SdpSctpmap): String { + return "sctpmap:${item.sctpmapNumber}" + } + + private val XGOOGLEFLAG = """x-google-flag:([^\s]*)""".toRegex() + fun tryParseXgoogleflag(string: String): SdpXgoogleflag? { + val match = XGOOGLEFLAG.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpXgoogleflag(value) + } + fun writeXgoogleflag(item: SdpXgoogleflag): String { + return "x-google-flag:${item.value}" + } + + private val RIDS = """rid:([\d\w]+) (\w+)(?: ([\S| ]*))?""".toRegex() + fun tryParseRids(string: String): SdpRids? { + val match = RIDS.matchEntire(string) ?: return null + val (id) = match.destructured + return SdpRids(id) + } + fun writeRids(item: SdpRids): String { + return "rid:${item.id}" + } + + private val IMAGEATTRS = """imageattr:(\d+|\*)[\s\t]+(send|recv)[\s\t]+(\*|[\S+](?:[\s\t]+[\S+])*)(?:[\s\t]+(recv|send)[\s\t]+(\*|[\S+](?:[\s\t]+[\S+])*))?""".toRegex() + fun tryParseImageattrs(string: String): SdpImageattrs? { + val match = IMAGEATTRS.matchEntire(string) ?: return null + val (pt) = match.destructured + return SdpImageattrs(pt) + } + fun writeImageattrs(item: SdpImageattrs): String { + return "imageattr:${item.pt}" + } + + private val SIMULCAST = """simulcast:(send|recv) ([a-zA-Z0-9\-_~;,]+)(?:\s?(send|recv) ([a-zA-Z0-9\-_~;,]+))?$""".toRegex() + fun tryParseSimulcast(string: String): SdpSimulcast? { + val match = SIMULCAST.matchEntire(string) ?: return null + val (dir1) = match.destructured + return SdpSimulcast(dir1) + } + fun writeSimulcast(item: SdpSimulcast): String { + return "simulcast:${item.dir1}" + } + + private val SIMULCAST03 = """simulcast:[\s\t]+([\S+\s\t]+)$""".toRegex() + fun tryParseSimulcast03(string: String): SdpSimulcast03? { + val match = SIMULCAST03.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpSimulcast03(value) + } + fun writeSimulcast03(item: SdpSimulcast03): String { + return "simulcast:${item.value}" + } + + private val FRAMERATE = """framerate:(\d+(?:$|\.\d+))""".toRegex() + fun tryParseFramerate(string: String): SdpFramerate? { + val match = FRAMERATE.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpFramerate(value.toLong()) + } + fun writeFramerate(item: SdpFramerate): String { + return "framerate:${item.value}" + } + + private val SOURCEFILTER = """source-filter: *(excl|incl) (\S*) (IP4|IP6|\*) (\S*) (.*)""".toRegex() + fun tryParseSourcefilter(string: String): SdpSourcefilter? { + val match = SOURCEFILTER.matchEntire(string) ?: return null + val (filterMode, netType, addressTypes, destAddress, srcList) = match.destructured + return SdpSourcefilter(filterMode, netType, addressTypes, destAddress, srcList) + } + fun writeSourcefilter(item: SdpSourcefilter): String { + return "source-filter: ${item.filterMode} ${item.netType} ${item.addressTypes} ${item.destAddress} ${item.srcList}" + } + + private val BUNDLEONLY = """(bundle-only)""".toRegex() + fun tryParseBundleonly(string: String): SdpBundleonly? { + val match = BUNDLEONLY.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpBundleonly(value) + } + fun writeBundleonly(item: SdpBundleonly): String { + return "${item.value}" + } + + private val LABEL = """label:(.+)""".toRegex() + fun tryParseLabel(string: String): SdpLabel? { + val match = LABEL.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpLabel(value) + } + fun writeLabel(item: SdpLabel): String { + return "label:${item.value}" + } + + private val SCTPPORT = """sctp-port:(\d+)$""".toRegex() + fun tryParseSctpport(string: String): SdpSctpport? { + val match = SCTPPORT.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpSctpport(value.toLong()) + } + fun writeSctpport(item: SdpSctpport): String { + return "sctp-port:${item.value}" + } + + private val MAXMESSAGESIZE = """max-message-size:(\d+)$""".toRegex() + fun tryParseMaxmessagesize(string: String): SdpMaxmessagesize? { + val match = MAXMESSAGESIZE.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpMaxmessagesize(value.toLong()) + } + fun writeMaxmessagesize(item: SdpMaxmessagesize): String { + return "max-message-size:${item.value}" + } + + private val TSREFCLOCKS = """ts-refclk:([^\s=]*)(?:=(\S*))?""".toRegex() + fun tryParseTsrefclocks(string: String): SdpTsrefclocks? { + val match = TSREFCLOCKS.matchEntire(string) ?: return null + val (clksrc) = match.destructured + return SdpTsrefclocks(clksrc) + } + fun writeTsrefclocks(item: SdpTsrefclocks): String { + return "ts-refclk:${item.clksrc}" + } + + private val MEDIACLK = """mediaclk:(?:id=(\S*))? *([^\s=]*)(?:=(\S*))?(?: *rate=(\d+)/(\d+))?""".toRegex() + fun tryParseMediaclk(string: String): SdpMediaclk? { + val match = MEDIACLK.matchEntire(string) ?: return null + val (id) = match.destructured + return SdpMediaclk(id) + } + fun writeMediaclk(item: SdpMediaclk): String { + return "mediaclk:${item.id}" + } + + private val KEYWORDS = """keywds:(.+)$""".toRegex() + fun tryParseKeywords(string: String): SdpKeywords? { + val match = KEYWORDS.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpKeywords(value) + } + fun writeKeywords(item: SdpKeywords): String { + return "keywds:${item.value}" + } + + private val CONTENT = """content:(.+)""".toRegex() + fun tryParseContent(string: String): SdpContent? { + val match = CONTENT.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpContent(value) + } + fun writeContent(item: SdpContent): String { + return "content:${item.value}" + } + + private val BFCPFLOORCTRL = """floorctrl:(c-only|s-only|c-s)""".toRegex() + fun tryParseBfcpfloorctrl(string: String): SdpBfcpfloorctrl? { + val match = BFCPFLOORCTRL.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpBfcpfloorctrl(value) + } + fun writeBfcpfloorctrl(item: SdpBfcpfloorctrl): String { + return "${item.value}" + } + + private val BFCPCONFID = """confid:(\d+)""".toRegex() + fun tryParseBfcpconfid(string: String): SdpBfcpconfid? { + val match = BFCPCONFID.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpBfcpconfid(value) + } + fun writeBfcpconfid(item: SdpBfcpconfid): String { + return "${item.value}" + } + + private val BFCPUSERID = """userid:(\d+)""".toRegex() + fun tryParseBfcpuserid(string: String): SdpBfcpuserid? { + val match = BFCPUSERID.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpBfcpuserid(value) + } + fun writeBfcpuserid(item: SdpBfcpuserid): String { + return "${item.value}" + } + + private val BFCPFLOORID = """floorid:(.+) (?:m-stream|mstrm):(.+)""".toRegex() + fun tryParseBfcpfloorid(string: String): SdpBfcpfloorid? { + val match = BFCPFLOORID.matchEntire(string) ?: return null + val (id, mStream) = match.destructured + return SdpBfcpfloorid(id, mStream) + } + fun writeBfcpfloorid(item: SdpBfcpfloorid): String { + return "floorid:${item.id} mstrm:${item.mStream}" + } + + private val INVALID = """(.*)""".toRegex() + fun tryParseInvalid(string: String): SdpInvalid? { + val match = INVALID.matchEntire(string) ?: return null + val (value) = match.destructured + return SdpInvalid(value) + } + fun writeInvalid(item: SdpInvalid): String { + return "${item.value}" + } +} + +class SdpMedia { + var version: SdpVersion? = null + var origin: SdpOrigin? = null + var name: SdpName? = null + var description: SdpDescription? = null + var uri: SdpUri? = null + var email: SdpEmail? = null + var phone: SdpPhone? = null + var timezones: SdpTimezones? = null + var repeats: SdpRepeats? = null + var timing: SdpTiming? = null + var connection: SdpConnection? = null + var bandwidth = mutableListOf() + var mline: SdpMline? = null + var rtp = mutableListOf() + var fmtp = mutableListOf() + var control: SdpControl? = null + var rtcp: SdpRtcp? = null + var rtcpFbTrrInt = mutableListOf() + var rtcpFb = mutableListOf() + var ext = mutableListOf() + var extmapAllowMixed: SdpExtmapallowmixed? = null + var crypto = mutableListOf() + var setup: SdpSetup? = null + var connectionType: SdpConnectiontype? = null + var mid: SdpMid? = null + var msid: SdpMsid? = null + var ptime: SdpPtime? = null + var maxptime: SdpMaxptime? = null + var direction: SdpDirection? = null + var icelite: SdpIcelite? = null + var iceUfrag: SdpIceufrag? = null + var icePwd: SdpIcepwd? = null + var fingerprint: SdpFingerprint? = null + var candidates = mutableListOf() + var endOfCandidates: SdpEndofcandidates? = null + var remoteCandidates: SdpRemotecandidates? = null + var iceOptions: SdpIceoptions? = null + var ssrcs = mutableListOf() + var ssrcGroups = mutableListOf() + var msidSemantic: SdpMsidsemantic? = null + var groups = mutableListOf() + var rtcpMux: SdpRtcpmux? = null + var rtcpRsize: SdpRtcprsize? = null + var sctpmap: SdpSctpmap? = null + var xGoogleFlag: SdpXgoogleflag? = null + var rids = mutableListOf() + var imageattrs = mutableListOf() + var simulcast: SdpSimulcast? = null + var simulcast03: SdpSimulcast03? = null + var framerate: SdpFramerate? = null + var sourceFilter: SdpSourcefilter? = null + var bundleOnly: SdpBundleonly? = null + var label: SdpLabel? = null + var sctpPort: SdpSctpport? = null + var maxMessageSize: SdpMaxmessagesize? = null + var tsRefClocks = mutableListOf() + var mediaClk: SdpMediaclk? = null + var keywords: SdpKeywords? = null + var content: SdpContent? = null + var bfcpFloorCtrl: SdpBfcpfloorctrl? = null + var bfcpConfId: SdpBfcpconfid? = null + var bfcpUserId: SdpBfcpuserid? = null + var bfcpFloorId: SdpBfcpfloorid? = null + var invalid = mutableListOf() + + override fun equals(other: Any?) = (other is SdpMedia) && + version == other.version && + origin == other.origin && + name == other.name && + description == other.description && + uri == other.uri && + email == other.email && + phone == other.phone && + timezones == other.timezones && + repeats == other.repeats && + timing == other.timing && + connection == other.connection && + bandwidth == other.bandwidth && + mline == other.mline && + rtp == other.rtp && + fmtp == other.fmtp && + control == other.control && + rtcp == other.rtcp && + rtcpFbTrrInt == other.rtcpFbTrrInt && + rtcpFb == other.rtcpFb && + ext == other.ext && + extmapAllowMixed == other.extmapAllowMixed && + crypto == other.crypto && + setup == other.setup && + connectionType == other.connectionType && + mid == other.mid && + msid == other.msid && + ptime == other.ptime && + maxptime == other.maxptime && + direction == other.direction && + icelite == other.icelite && + iceUfrag == other.iceUfrag && + icePwd == other.icePwd && + fingerprint == other.fingerprint && + candidates == other.candidates && + endOfCandidates == other.endOfCandidates && + remoteCandidates == other.remoteCandidates && + iceOptions == other.iceOptions && + ssrcs == other.ssrcs && + ssrcGroups == other.ssrcGroups && + msidSemantic == other.msidSemantic && + groups == other.groups && + rtcpMux == other.rtcpMux && + rtcpRsize == other.rtcpRsize && + sctpmap == other.sctpmap && + xGoogleFlag == other.xGoogleFlag && + rids == other.rids && + imageattrs == other.imageattrs && + simulcast == other.simulcast && + simulcast03 == other.simulcast03 && + framerate == other.framerate && + sourceFilter == other.sourceFilter && + bundleOnly == other.bundleOnly && + label == other.label && + sctpPort == other.sctpPort && + maxMessageSize == other.maxMessageSize && + tsRefClocks == other.tsRefClocks && + mediaClk == other.mediaClk && + keywords == other.keywords && + content == other.content && + bfcpFloorCtrl == other.bfcpFloorCtrl && + bfcpConfId == other.bfcpConfId && + bfcpUserId == other.bfcpUserId && + bfcpFloorId == other.bfcpFloorId && + invalid == other.invalid +} + +class SdpSession { + var version: SdpVersion? = null + var origin: SdpOrigin? = null + var name: SdpName? = null + var description: SdpDescription? = null + var uri: SdpUri? = null + var email: SdpEmail? = null + var phone: SdpPhone? = null + var timezones: SdpTimezones? = null + var repeats: SdpRepeats? = null + var timing: SdpTiming? = null + var connection: SdpConnection? = null + var bandwidth = mutableListOf() + var mline: SdpMline? = null + var rtp = mutableListOf() + var fmtp = mutableListOf() + var control: SdpControl? = null + var rtcp: SdpRtcp? = null + var rtcpFbTrrInt = mutableListOf() + var rtcpFb = mutableListOf() + var ext = mutableListOf() + var extmapAllowMixed: SdpExtmapallowmixed? = null + var crypto = mutableListOf() + var setup: SdpSetup? = null + var connectionType: SdpConnectiontype? = null + var mid: SdpMid? = null + var msid: SdpMsid? = null + var ptime: SdpPtime? = null + var maxptime: SdpMaxptime? = null + var direction: SdpDirection? = null + var icelite: SdpIcelite? = null + var iceUfrag: SdpIceufrag? = null + var icePwd: SdpIcepwd? = null + var fingerprint: SdpFingerprint? = null + var candidates = mutableListOf() + var endOfCandidates: SdpEndofcandidates? = null + var remoteCandidates: SdpRemotecandidates? = null + var iceOptions: SdpIceoptions? = null + var ssrcs = mutableListOf() + var ssrcGroups = mutableListOf() + var msidSemantic: SdpMsidsemantic? = null + var groups = mutableListOf() + var rtcpMux: SdpRtcpmux? = null + var rtcpRsize: SdpRtcprsize? = null + var sctpmap: SdpSctpmap? = null + var xGoogleFlag: SdpXgoogleflag? = null + var rids = mutableListOf() + var imageattrs = mutableListOf() + var simulcast: SdpSimulcast? = null + var simulcast03: SdpSimulcast03? = null + var framerate: SdpFramerate? = null + var sourceFilter: SdpSourcefilter? = null + var bundleOnly: SdpBundleonly? = null + var label: SdpLabel? = null + var sctpPort: SdpSctpport? = null + var maxMessageSize: SdpMaxmessagesize? = null + var tsRefClocks = mutableListOf() + var mediaClk: SdpMediaclk? = null + var keywords: SdpKeywords? = null + var content: SdpContent? = null + var bfcpFloorCtrl: SdpBfcpfloorctrl? = null + var bfcpConfId: SdpBfcpconfid? = null + var bfcpUserId: SdpBfcpuserid? = null + var bfcpFloorId: SdpBfcpfloorid? = null + var invalid = mutableListOf() + val media = mutableListOf() + + init { + version = SdpVersion(0) + } + + fun parse(sdp: String) { + val lines = sdp.split("\r\n").filter { line -> line.isNotEmpty() } + if (lines.isEmpty()) { + throw IllegalArgumentException("Invalid empty SDP") + } + lines.forEach { line -> parseLine(line) } + } + + fun write(): String { + val lines = mutableListOf() + if (version != null) lines.add("v=" + SdpGrammar.writeVersion(version!!)) + if (origin != null) lines.add("o=" + SdpGrammar.writeOrigin(origin!!)) + if (name != null) lines.add("s=" + SdpGrammar.writeName(name!!)) + if (description != null) lines.add("i=" + SdpGrammar.writeDescription(description!!)) + if (uri != null) lines.add("u=" + SdpGrammar.writeUri(uri!!)) + if (email != null) lines.add("e=" + SdpGrammar.writeEmail(email!!)) + if (phone != null) lines.add("p=" + SdpGrammar.writePhone(phone!!)) + if (timezones != null) lines.add("z=" + SdpGrammar.writeTimezones(timezones!!)) + if (repeats != null) lines.add("r=" + SdpGrammar.writeRepeats(repeats!!)) + if (timing != null) lines.add("t=" + SdpGrammar.writeTiming(timing!!)) + if (connection != null) lines.add("c=" + SdpGrammar.writeConnection(connection!!)) + bandwidth.forEach { item -> lines.add("b=" + SdpGrammar.writeBandwidth(item)) } + if (mline != null) lines.add("m=" + SdpGrammar.writeMline(mline!!)) + rtp.forEach { item -> lines.add("a=" + SdpGrammar.writeRtp(item)) } + fmtp.forEach { item -> lines.add("a=" + SdpGrammar.writeFmtp(item)) } + if (control != null) lines.add("a=" + SdpGrammar.writeControl(control!!)) + if (rtcp != null) lines.add("a=" + SdpGrammar.writeRtcp(rtcp!!)) + rtcpFbTrrInt.forEach { item -> lines.add("a=" + SdpGrammar.writeRtcpfbtrrint(item)) } + rtcpFb.forEach { item -> lines.add("a=" + SdpGrammar.writeRtcpfb(item)) } + ext.forEach { item -> lines.add("a=" + SdpGrammar.writeExt(item)) } + if (extmapAllowMixed != null) { + lines.add( + "a=" + SdpGrammar.writeExtmapallowmixed(extmapAllowMixed!!), + ) + } + crypto.forEach { item -> lines.add("a=" + SdpGrammar.writeCrypto(item)) } + if (setup != null) lines.add("a=" + SdpGrammar.writeSetup(setup!!)) + if (connectionType != null) { + lines.add( + "a=" + SdpGrammar.writeConnectiontype(connectionType!!), + ) + } + if (mid != null) lines.add("a=" + SdpGrammar.writeMid(mid!!)) + if (msid != null) lines.add("a=" + SdpGrammar.writeMsid(msid!!)) + if (ptime != null) lines.add("a=" + SdpGrammar.writePtime(ptime!!)) + if (maxptime != null) lines.add("a=" + SdpGrammar.writeMaxptime(maxptime!!)) + if (direction != null) lines.add("a=" + SdpGrammar.writeDirection(direction!!)) + if (icelite != null) lines.add("a=" + SdpGrammar.writeIcelite(icelite!!)) + if (iceUfrag != null) lines.add("a=" + SdpGrammar.writeIceufrag(iceUfrag!!)) + if (icePwd != null) lines.add("a=" + SdpGrammar.writeIcepwd(icePwd!!)) + if (fingerprint != null) lines.add("a=" + SdpGrammar.writeFingerprint(fingerprint!!)) + candidates.forEach { item -> lines.add("a=" + SdpGrammar.writeCandidates(item)) } + if (endOfCandidates != null) { + lines.add( + "a=" + SdpGrammar.writeEndofcandidates(endOfCandidates!!), + ) + } + if (remoteCandidates != null) { + lines.add( + "a=" + SdpGrammar.writeRemotecandidates(remoteCandidates!!), + ) + } + if (iceOptions != null) lines.add("a=" + SdpGrammar.writeIceoptions(iceOptions!!)) + ssrcs.forEach { item -> lines.add("a=" + SdpGrammar.writeSsrcs(item)) } + ssrcGroups.forEach { item -> lines.add("a=" + SdpGrammar.writeSsrcgroups(item)) } + if (msidSemantic != null) lines.add("a=" + SdpGrammar.writeMsidsemantic(msidSemantic!!)) + groups.forEach { item -> lines.add("a=" + SdpGrammar.writeGroups(item)) } + if (rtcpMux != null) lines.add("a=" + SdpGrammar.writeRtcpmux(rtcpMux!!)) + if (rtcpRsize != null) lines.add("a=" + SdpGrammar.writeRtcprsize(rtcpRsize!!)) + if (sctpmap != null) lines.add("a=" + SdpGrammar.writeSctpmap(sctpmap!!)) + if (xGoogleFlag != null) lines.add("a=" + SdpGrammar.writeXgoogleflag(xGoogleFlag!!)) + rids.forEach { item -> lines.add("a=" + SdpGrammar.writeRids(item)) } + imageattrs.forEach { item -> lines.add("a=" + SdpGrammar.writeImageattrs(item)) } + if (simulcast != null) lines.add("a=" + SdpGrammar.writeSimulcast(simulcast!!)) + if (simulcast03 != null) lines.add("a=" + SdpGrammar.writeSimulcast03(simulcast03!!)) + if (framerate != null) lines.add("a=" + SdpGrammar.writeFramerate(framerate!!)) + if (sourceFilter != null) lines.add("a=" + SdpGrammar.writeSourcefilter(sourceFilter!!)) + if (bundleOnly != null) lines.add("a=" + SdpGrammar.writeBundleonly(bundleOnly!!)) + if (label != null) lines.add("a=" + SdpGrammar.writeLabel(label!!)) + if (sctpPort != null) lines.add("a=" + SdpGrammar.writeSctpport(sctpPort!!)) + if (maxMessageSize != null) { + lines.add( + "a=" + SdpGrammar.writeMaxmessagesize(maxMessageSize!!), + ) + } + tsRefClocks.forEach { item -> lines.add("a=" + SdpGrammar.writeTsrefclocks(item)) } + if (mediaClk != null) lines.add("a=" + SdpGrammar.writeMediaclk(mediaClk!!)) + if (keywords != null) lines.add("a=" + SdpGrammar.writeKeywords(keywords!!)) + if (content != null) lines.add("a=" + SdpGrammar.writeContent(content!!)) + if (bfcpFloorCtrl != null) lines.add("a=" + SdpGrammar.writeBfcpfloorctrl(bfcpFloorCtrl!!)) + if (bfcpConfId != null) lines.add("a=" + SdpGrammar.writeBfcpconfid(bfcpConfId!!)) + if (bfcpUserId != null) lines.add("a=" + SdpGrammar.writeBfcpuserid(bfcpUserId!!)) + if (bfcpFloorId != null) lines.add("a=" + SdpGrammar.writeBfcpfloorid(bfcpFloorId!!)) + invalid.forEach { item -> lines.add("a=" + SdpGrammar.writeInvalid(item)) } + for (m in media) { + lines.add("m=" + SdpGrammar.writeMline(m.mline!!)) + if (m.version != null) lines.add("v=" + SdpGrammar.writeVersion(m.version!!)) + if (m.origin != null) lines.add("o=" + SdpGrammar.writeOrigin(m.origin!!)) + if (m.name != null) lines.add("s=" + SdpGrammar.writeName(m.name!!)) + if (m.description != null) { + lines.add( + "i=" + SdpGrammar.writeDescription(m.description!!), + ) + } + if (m.uri != null) lines.add("u=" + SdpGrammar.writeUri(m.uri!!)) + if (m.email != null) lines.add("e=" + SdpGrammar.writeEmail(m.email!!)) + if (m.phone != null) lines.add("p=" + SdpGrammar.writePhone(m.phone!!)) + if (m.timezones != null) lines.add("z=" + SdpGrammar.writeTimezones(m.timezones!!)) + if (m.repeats != null) lines.add("r=" + SdpGrammar.writeRepeats(m.repeats!!)) + if (m.timing != null) lines.add("t=" + SdpGrammar.writeTiming(m.timing!!)) + if (m.connection != null) lines.add("c=" + SdpGrammar.writeConnection(m.connection!!)) + m.bandwidth.forEach { item -> lines.add("b=" + SdpGrammar.writeBandwidth(item)) } + m.rtp.forEach { item -> lines.add("a=" + SdpGrammar.writeRtp(item)) } + m.fmtp.forEach { item -> lines.add("a=" + SdpGrammar.writeFmtp(item)) } + if (m.control != null) lines.add("a=" + SdpGrammar.writeControl(m.control!!)) + if (m.rtcp != null) lines.add("a=" + SdpGrammar.writeRtcp(m.rtcp!!)) + m.rtcpFbTrrInt.forEach { item -> lines.add("a=" + SdpGrammar.writeRtcpfbtrrint(item)) } + m.rtcpFb.forEach { item -> lines.add("a=" + SdpGrammar.writeRtcpfb(item)) } + m.ext.forEach { item -> lines.add("a=" + SdpGrammar.writeExt(item)) } + if (m.extmapAllowMixed != null) { + lines.add( + "a=" + SdpGrammar.writeExtmapallowmixed(m.extmapAllowMixed!!), + ) + } + m.crypto.forEach { item -> lines.add("a=" + SdpGrammar.writeCrypto(item)) } + if (m.setup != null) lines.add("a=" + SdpGrammar.writeSetup(m.setup!!)) + if (m.connectionType != null) { + lines.add( + "a=" + SdpGrammar.writeConnectiontype(m.connectionType!!), + ) + } + if (m.mid != null) lines.add("a=" + SdpGrammar.writeMid(m.mid!!)) + if (m.msid != null) lines.add("a=" + SdpGrammar.writeMsid(m.msid!!)) + if (m.ptime != null) lines.add("a=" + SdpGrammar.writePtime(m.ptime!!)) + if (m.maxptime != null) lines.add("a=" + SdpGrammar.writeMaxptime(m.maxptime!!)) + if (m.direction != null) lines.add("a=" + SdpGrammar.writeDirection(m.direction!!)) + if (m.icelite != null) lines.add("a=" + SdpGrammar.writeIcelite(m.icelite!!)) + if (m.iceUfrag != null) lines.add("a=" + SdpGrammar.writeIceufrag(m.iceUfrag!!)) + if (m.icePwd != null) lines.add("a=" + SdpGrammar.writeIcepwd(m.icePwd!!)) + if (m.fingerprint != null) { + lines.add( + "a=" + SdpGrammar.writeFingerprint(m.fingerprint!!), + ) + } + m.candidates.forEach { item -> lines.add("a=" + SdpGrammar.writeCandidates(item)) } + if (m.endOfCandidates != null) { + lines.add( + "a=" + SdpGrammar.writeEndofcandidates(m.endOfCandidates!!), + ) + } + if (m.remoteCandidates != null) { + lines.add( + "a=" + SdpGrammar.writeRemotecandidates(m.remoteCandidates!!), + ) + } + if (m.iceOptions != null) lines.add("a=" + SdpGrammar.writeIceoptions(m.iceOptions!!)) + m.ssrcs.forEach { item -> lines.add("a=" + SdpGrammar.writeSsrcs(item)) } + m.ssrcGroups.forEach { item -> lines.add("a=" + SdpGrammar.writeSsrcgroups(item)) } + if (m.msidSemantic != null) { + lines.add( + "a=" + SdpGrammar.writeMsidsemantic(m.msidSemantic!!), + ) + } + m.groups.forEach { item -> lines.add("a=" + SdpGrammar.writeGroups(item)) } + if (m.rtcpMux != null) lines.add("a=" + SdpGrammar.writeRtcpmux(m.rtcpMux!!)) + if (m.rtcpRsize != null) lines.add("a=" + SdpGrammar.writeRtcprsize(m.rtcpRsize!!)) + if (m.sctpmap != null) lines.add("a=" + SdpGrammar.writeSctpmap(m.sctpmap!!)) + if (m.xGoogleFlag != null) { + lines.add( + "a=" + SdpGrammar.writeXgoogleflag(m.xGoogleFlag!!), + ) + } + m.rids.forEach { item -> lines.add("a=" + SdpGrammar.writeRids(item)) } + m.imageattrs.forEach { item -> lines.add("a=" + SdpGrammar.writeImageattrs(item)) } + if (m.simulcast != null) lines.add("a=" + SdpGrammar.writeSimulcast(m.simulcast!!)) + if (m.simulcast03 != null) { + lines.add( + "a=" + SdpGrammar.writeSimulcast03(m.simulcast03!!), + ) + } + if (m.framerate != null) lines.add("a=" + SdpGrammar.writeFramerate(m.framerate!!)) + if (m.sourceFilter != null) { + lines.add( + "a=" + SdpGrammar.writeSourcefilter(m.sourceFilter!!), + ) + } + if (m.bundleOnly != null) lines.add("a=" + SdpGrammar.writeBundleonly(m.bundleOnly!!)) + if (m.label != null) lines.add("a=" + SdpGrammar.writeLabel(m.label!!)) + if (m.sctpPort != null) lines.add("a=" + SdpGrammar.writeSctpport(m.sctpPort!!)) + if (m.maxMessageSize != null) { + lines.add( + "a=" + SdpGrammar.writeMaxmessagesize(m.maxMessageSize!!), + ) + } + m.tsRefClocks.forEach { item -> lines.add("a=" + SdpGrammar.writeTsrefclocks(item)) } + if (m.mediaClk != null) lines.add("a=" + SdpGrammar.writeMediaclk(m.mediaClk!!)) + if (m.keywords != null) lines.add("a=" + SdpGrammar.writeKeywords(m.keywords!!)) + if (m.content != null) lines.add("a=" + SdpGrammar.writeContent(m.content!!)) + if (m.bfcpFloorCtrl != null) { + lines.add( + "a=" + SdpGrammar.writeBfcpfloorctrl(m.bfcpFloorCtrl!!), + ) + } + if (m.bfcpConfId != null) lines.add("a=" + SdpGrammar.writeBfcpconfid(m.bfcpConfId!!)) + if (m.bfcpUserId != null) lines.add("a=" + SdpGrammar.writeBfcpuserid(m.bfcpUserId!!)) + if (m.bfcpFloorId != null) { + lines.add( + "a=" + SdpGrammar.writeBfcpfloorid(m.bfcpFloorId!!), + ) + } + m.invalid.forEach { item -> lines.add("a=" + SdpGrammar.writeInvalid(item)) } + } + + return lines.joinToString("\r\n", postfix = "\r\n") + } + + private fun parseLine(line: String) { + if (line.length < 2 || line[1] != '=') { + throw IllegalArgumentException("Invalid SDP line") + } + val type = line[0] + val value = line.substring(2) + var lastMedia = media.lastOrNull() + when (type) { + 'v' -> { + val tryVersion = SdpGrammar.tryParseVersion(value) + if (tryVersion != null) { + if (lastMedia != null) lastMedia.version = tryVersion else version = tryVersion + return + } + } + 'o' -> { + val tryOrigin = SdpGrammar.tryParseOrigin(value) + if (tryOrigin != null) { + if (lastMedia != null) lastMedia.origin = tryOrigin else origin = tryOrigin + return + } + } + 's' -> { + val tryName = SdpGrammar.tryParseName(value) + if (tryName != null) { + if (lastMedia != null) lastMedia.name = tryName else name = tryName + return + } + } + 'i' -> { + val tryDescription = SdpGrammar.tryParseDescription(value) + if (tryDescription != null) { + if (lastMedia != null) lastMedia.description = tryDescription else description = tryDescription + return + } + } + 'u' -> { + val tryUri = SdpGrammar.tryParseUri(value) + if (tryUri != null) { + if (lastMedia != null) lastMedia.uri = tryUri else uri = tryUri + return + } + } + 'e' -> { + val tryEmail = SdpGrammar.tryParseEmail(value) + if (tryEmail != null) { + if (lastMedia != null) lastMedia.email = tryEmail else email = tryEmail + return + } + } + 'p' -> { + val tryPhone = SdpGrammar.tryParsePhone(value) + if (tryPhone != null) { + if (lastMedia != null) lastMedia.phone = tryPhone else phone = tryPhone + return + } + } + 'z' -> { + val tryTimezones = SdpGrammar.tryParseTimezones(value) + if (tryTimezones != null) { + if (lastMedia != null) lastMedia.timezones = tryTimezones else timezones = tryTimezones + return + } + } + 'r' -> { + val tryRepeats = SdpGrammar.tryParseRepeats(value) + if (tryRepeats != null) { + if (lastMedia != null) lastMedia.repeats = tryRepeats else repeats = tryRepeats + return + } + } + 't' -> { + val tryTiming = SdpGrammar.tryParseTiming(value) + if (tryTiming != null) { + if (lastMedia != null) lastMedia.timing = tryTiming else timing = tryTiming + return + } + } + 'c' -> { + val tryConnection = SdpGrammar.tryParseConnection(value) + if (tryConnection != null) { + if (lastMedia != null) lastMedia.connection = tryConnection else connection = tryConnection + return + } + } + 'b' -> { + val tryBandwidth = SdpGrammar.tryParseBandwidth(value) + if (tryBandwidth != null) { + if (lastMedia != null) { + lastMedia.bandwidth.add( + tryBandwidth, + ) + } else { + bandwidth.add(tryBandwidth) + } + return + } + } + 'm' -> { + val tryMline = SdpGrammar.tryParseMline(value) + if (tryMline != null) { + lastMedia = SdpMedia() + lastMedia.mline = tryMline + media.add(lastMedia) + return + } + } + 'a' -> { + val tryRtp = SdpGrammar.tryParseRtp(value) + if (tryRtp != null) { + if (lastMedia != null) lastMedia.rtp.add(tryRtp) else rtp.add(tryRtp) + return + } + val tryFmtp = SdpGrammar.tryParseFmtp(value) + if (tryFmtp != null) { + if (lastMedia != null) lastMedia.fmtp.add(tryFmtp) else fmtp.add(tryFmtp) + return + } + val tryControl = SdpGrammar.tryParseControl(value) + if (tryControl != null) { + if (lastMedia != null) lastMedia.control = tryControl else control = tryControl + return + } + val tryRtcp = SdpGrammar.tryParseRtcp(value) + if (tryRtcp != null) { + if (lastMedia != null) lastMedia.rtcp = tryRtcp else rtcp = tryRtcp + return + } + val tryRtcpfbtrrint = SdpGrammar.tryParseRtcpfbtrrint(value) + if (tryRtcpfbtrrint != null) { + if (lastMedia != null) { + lastMedia.rtcpFbTrrInt.add( + tryRtcpfbtrrint, + ) + } else { + rtcpFbTrrInt.add(tryRtcpfbtrrint) + } + return + } + val tryRtcpfb = SdpGrammar.tryParseRtcpfb(value) + if (tryRtcpfb != null) { + if (lastMedia != null) { + lastMedia.rtcpFb.add( + tryRtcpfb, + ) + } else { + rtcpFb.add(tryRtcpfb) + } + return + } + val tryExt = SdpGrammar.tryParseExt(value) + if (tryExt != null) { + if (lastMedia != null) lastMedia.ext.add(tryExt) else ext.add(tryExt) + return + } + val tryExtmapallowmixed = SdpGrammar.tryParseExtmapallowmixed(value) + if (tryExtmapallowmixed != null) { + if (lastMedia != null) lastMedia.extmapAllowMixed = tryExtmapallowmixed else extmapAllowMixed = tryExtmapallowmixed + return + } + val tryCrypto = SdpGrammar.tryParseCrypto(value) + if (tryCrypto != null) { + if (lastMedia != null) { + lastMedia.crypto.add( + tryCrypto, + ) + } else { + crypto.add(tryCrypto) + } + return + } + val trySetup = SdpGrammar.tryParseSetup(value) + if (trySetup != null) { + if (lastMedia != null) lastMedia.setup = trySetup else setup = trySetup + return + } + val tryConnectiontype = SdpGrammar.tryParseConnectiontype(value) + if (tryConnectiontype != null) { + if (lastMedia != null) lastMedia.connectionType = tryConnectiontype else connectionType = tryConnectiontype + return + } + val tryMid = SdpGrammar.tryParseMid(value) + if (tryMid != null) { + if (lastMedia != null) lastMedia.mid = tryMid else mid = tryMid + return + } + val tryMsid = SdpGrammar.tryParseMsid(value) + if (tryMsid != null) { + if (lastMedia != null) lastMedia.msid = tryMsid else msid = tryMsid + return + } + val tryPtime = SdpGrammar.tryParsePtime(value) + if (tryPtime != null) { + if (lastMedia != null) lastMedia.ptime = tryPtime else ptime = tryPtime + return + } + val tryMaxptime = SdpGrammar.tryParseMaxptime(value) + if (tryMaxptime != null) { + if (lastMedia != null) lastMedia.maxptime = tryMaxptime else maxptime = tryMaxptime + return + } + val tryDirection = SdpGrammar.tryParseDirection(value) + if (tryDirection != null) { + if (lastMedia != null) lastMedia.direction = tryDirection else direction = tryDirection + return + } + val tryIcelite = SdpGrammar.tryParseIcelite(value) + if (tryIcelite != null) { + if (lastMedia != null) lastMedia.icelite = tryIcelite else icelite = tryIcelite + return + } + val tryIceufrag = SdpGrammar.tryParseIceufrag(value) + if (tryIceufrag != null) { + if (lastMedia != null) lastMedia.iceUfrag = tryIceufrag else iceUfrag = tryIceufrag + return + } + val tryIcepwd = SdpGrammar.tryParseIcepwd(value) + if (tryIcepwd != null) { + if (lastMedia != null) lastMedia.icePwd = tryIcepwd else icePwd = tryIcepwd + return + } + val tryFingerprint = SdpGrammar.tryParseFingerprint(value) + if (tryFingerprint != null) { + if (lastMedia != null) lastMedia.fingerprint = tryFingerprint else fingerprint = tryFingerprint + return + } + val tryCandidates = SdpGrammar.tryParseCandidates(value) + if (tryCandidates != null) { + if (lastMedia != null) { + lastMedia.candidates.add( + tryCandidates, + ) + } else { + candidates.add(tryCandidates) + } + return + } + val tryEndofcandidates = SdpGrammar.tryParseEndofcandidates(value) + if (tryEndofcandidates != null) { + if (lastMedia != null) lastMedia.endOfCandidates = tryEndofcandidates else endOfCandidates = tryEndofcandidates + return + } + val tryRemotecandidates = SdpGrammar.tryParseRemotecandidates(value) + if (tryRemotecandidates != null) { + if (lastMedia != null) lastMedia.remoteCandidates = tryRemotecandidates else remoteCandidates = tryRemotecandidates + return + } + val tryIceoptions = SdpGrammar.tryParseIceoptions(value) + if (tryIceoptions != null) { + if (lastMedia != null) lastMedia.iceOptions = tryIceoptions else iceOptions = tryIceoptions + return + } + val trySsrcs = SdpGrammar.tryParseSsrcs(value) + if (trySsrcs != null) { + if (lastMedia != null) lastMedia.ssrcs.add(trySsrcs) else ssrcs.add(trySsrcs) + return + } + val trySsrcgroups = SdpGrammar.tryParseSsrcgroups(value) + if (trySsrcgroups != null) { + if (lastMedia != null) { + lastMedia.ssrcGroups.add( + trySsrcgroups, + ) + } else { + ssrcGroups.add(trySsrcgroups) + } + return + } + val tryMsidsemantic = SdpGrammar.tryParseMsidsemantic(value) + if (tryMsidsemantic != null) { + if (lastMedia != null) lastMedia.msidSemantic = tryMsidsemantic else msidSemantic = tryMsidsemantic + return + } + val tryGroups = SdpGrammar.tryParseGroups(value) + if (tryGroups != null) { + if (lastMedia != null) { + lastMedia.groups.add( + tryGroups, + ) + } else { + groups.add(tryGroups) + } + return + } + val tryRtcpmux = SdpGrammar.tryParseRtcpmux(value) + if (tryRtcpmux != null) { + if (lastMedia != null) lastMedia.rtcpMux = tryRtcpmux else rtcpMux = tryRtcpmux + return + } + val tryRtcprsize = SdpGrammar.tryParseRtcprsize(value) + if (tryRtcprsize != null) { + if (lastMedia != null) lastMedia.rtcpRsize = tryRtcprsize else rtcpRsize = tryRtcprsize + return + } + val trySctpmap = SdpGrammar.tryParseSctpmap(value) + if (trySctpmap != null) { + if (lastMedia != null) lastMedia.sctpmap = trySctpmap else sctpmap = trySctpmap + return + } + val tryXgoogleflag = SdpGrammar.tryParseXgoogleflag(value) + if (tryXgoogleflag != null) { + if (lastMedia != null) lastMedia.xGoogleFlag = tryXgoogleflag else xGoogleFlag = tryXgoogleflag + return + } + val tryRids = SdpGrammar.tryParseRids(value) + if (tryRids != null) { + if (lastMedia != null) lastMedia.rids.add(tryRids) else rids.add(tryRids) + return + } + val tryImageattrs = SdpGrammar.tryParseImageattrs(value) + if (tryImageattrs != null) { + if (lastMedia != null) { + lastMedia.imageattrs.add( + tryImageattrs, + ) + } else { + imageattrs.add(tryImageattrs) + } + return + } + val trySimulcast = SdpGrammar.tryParseSimulcast(value) + if (trySimulcast != null) { + if (lastMedia != null) lastMedia.simulcast = trySimulcast else simulcast = trySimulcast + return + } + val trySimulcast03 = SdpGrammar.tryParseSimulcast03(value) + if (trySimulcast03 != null) { + if (lastMedia != null) lastMedia.simulcast03 = trySimulcast03 else simulcast03 = trySimulcast03 + return + } + val tryFramerate = SdpGrammar.tryParseFramerate(value) + if (tryFramerate != null) { + if (lastMedia != null) lastMedia.framerate = tryFramerate else framerate = tryFramerate + return + } + val trySourcefilter = SdpGrammar.tryParseSourcefilter(value) + if (trySourcefilter != null) { + if (lastMedia != null) lastMedia.sourceFilter = trySourcefilter else sourceFilter = trySourcefilter + return + } + val tryBundleonly = SdpGrammar.tryParseBundleonly(value) + if (tryBundleonly != null) { + if (lastMedia != null) lastMedia.bundleOnly = tryBundleonly else bundleOnly = tryBundleonly + return + } + val tryLabel = SdpGrammar.tryParseLabel(value) + if (tryLabel != null) { + if (lastMedia != null) lastMedia.label = tryLabel else label = tryLabel + return + } + val trySctpport = SdpGrammar.tryParseSctpport(value) + if (trySctpport != null) { + if (lastMedia != null) lastMedia.sctpPort = trySctpport else sctpPort = trySctpport + return + } + val tryMaxmessagesize = SdpGrammar.tryParseMaxmessagesize(value) + if (tryMaxmessagesize != null) { + if (lastMedia != null) lastMedia.maxMessageSize = tryMaxmessagesize else maxMessageSize = tryMaxmessagesize + return + } + val tryTsrefclocks = SdpGrammar.tryParseTsrefclocks(value) + if (tryTsrefclocks != null) { + if (lastMedia != null) { + lastMedia.tsRefClocks.add( + tryTsrefclocks, + ) + } else { + tsRefClocks.add(tryTsrefclocks) + } + return + } + val tryMediaclk = SdpGrammar.tryParseMediaclk(value) + if (tryMediaclk != null) { + if (lastMedia != null) lastMedia.mediaClk = tryMediaclk else mediaClk = tryMediaclk + return + } + val tryKeywords = SdpGrammar.tryParseKeywords(value) + if (tryKeywords != null) { + if (lastMedia != null) lastMedia.keywords = tryKeywords else keywords = tryKeywords + return + } + val tryContent = SdpGrammar.tryParseContent(value) + if (tryContent != null) { + if (lastMedia != null) lastMedia.content = tryContent else content = tryContent + return + } + val tryBfcpfloorctrl = SdpGrammar.tryParseBfcpfloorctrl(value) + if (tryBfcpfloorctrl != null) { + if (lastMedia != null) lastMedia.bfcpFloorCtrl = tryBfcpfloorctrl else bfcpFloorCtrl = tryBfcpfloorctrl + return + } + val tryBfcpconfid = SdpGrammar.tryParseBfcpconfid(value) + if (tryBfcpconfid != null) { + if (lastMedia != null) lastMedia.bfcpConfId = tryBfcpconfid else bfcpConfId = tryBfcpconfid + return + } + val tryBfcpuserid = SdpGrammar.tryParseBfcpuserid(value) + if (tryBfcpuserid != null) { + if (lastMedia != null) lastMedia.bfcpUserId = tryBfcpuserid else bfcpUserId = tryBfcpuserid + return + } + val tryBfcpfloorid = SdpGrammar.tryParseBfcpfloorid(value) + if (tryBfcpfloorid != null) { + if (lastMedia != null) lastMedia.bfcpFloorId = tryBfcpfloorid else bfcpFloorId = tryBfcpfloorid + return + } + val tryInvalid = SdpGrammar.tryParseInvalid(value) + if (tryInvalid != null) { + if (lastMedia != null) { + lastMedia.invalid.add( + tryInvalid, + ) + } else { + invalid.add(tryInvalid) + } + return + } + } + } + } + + override fun equals(other: Any?) = (other is SdpSession) && + media == other.media && + version == other.version && + origin == other.origin && + name == other.name && + description == other.description && + uri == other.uri && + email == other.email && + phone == other.phone && + timezones == other.timezones && + repeats == other.repeats && + timing == other.timing && + connection == other.connection && + bandwidth == other.bandwidth && + mline == other.mline && + rtp == other.rtp && + fmtp == other.fmtp && + control == other.control && + rtcp == other.rtcp && + rtcpFbTrrInt == other.rtcpFbTrrInt && + rtcpFb == other.rtcpFb && + ext == other.ext && + extmapAllowMixed == other.extmapAllowMixed && + crypto == other.crypto && + setup == other.setup && + connectionType == other.connectionType && + mid == other.mid && + msid == other.msid && + ptime == other.ptime && + maxptime == other.maxptime && + direction == other.direction && + icelite == other.icelite && + iceUfrag == other.iceUfrag && + icePwd == other.icePwd && + fingerprint == other.fingerprint && + candidates == other.candidates && + endOfCandidates == other.endOfCandidates && + remoteCandidates == other.remoteCandidates && + iceOptions == other.iceOptions && + ssrcs == other.ssrcs && + ssrcGroups == other.ssrcGroups && + msidSemantic == other.msidSemantic && + groups == other.groups && + rtcpMux == other.rtcpMux && + rtcpRsize == other.rtcpRsize && + sctpmap == other.sctpmap && + xGoogleFlag == other.xGoogleFlag && + rids == other.rids && + imageattrs == other.imageattrs && + simulcast == other.simulcast && + simulcast03 == other.simulcast03 && + framerate == other.framerate && + sourceFilter == other.sourceFilter && + bundleOnly == other.bundleOnly && + label == other.label && + sctpPort == other.sctpPort && + maxMessageSize == other.maxMessageSize && + tsRefClocks == other.tsRefClocks && + mediaClk == other.mediaClk && + keywords == other.keywords && + content == other.content && + bfcpFloorCtrl == other.bfcpFloorCtrl && + bfcpConfId == other.bfcpConfId && + bfcpUserId == other.bfcpUserId && + bfcpFloorId == other.bfcpFloorId && + invalid == other.invalid +}