diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java index 697ebe7e..29eddb06 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusConnection.java @@ -15,7 +15,7 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; -public class JanusConnection { +class JanusConnection { protected final PeerConnection peerConnection; protected final PeerConnectionFactory peerConnectionFactory; protected PmxKeyStore keyStore; @@ -23,7 +23,7 @@ public class JanusConnection { private long sessionId = -1L; private final PcObserver pcObserver; - public JanusConnection( + JanusConnection( PeerConnectionFactory pcFactory, PmxKeyStore keyStore, ConnectionType connectionType, diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusPublisher.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusPublisher.java index 2b8a353b..2bfca9c5 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusPublisher.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusPublisher.java @@ -1,11 +1,9 @@ package com.simplito.java.privmx_endpoint.modules.stream; -import androidx.annotation.Nullable; - import com.simplito.java.privmx_endpoint.model.AudioTrackInfo; import com.simplito.java.privmx_endpoint.model.ConnectionType; -import com.simplito.java.privmx_endpoint.model.stream.SdpWithTypeModel; import com.simplito.java.privmx_endpoint.model.VideoTrackInfo; +import com.simplito.java.privmx_endpoint.model.stream.SdpWithTypeModel; import org.webrtc.MediaConstraints; import org.webrtc.PeerConnection; @@ -15,7 +13,6 @@ import org.webrtc.PmxKeyStore; import org.webrtc.RtpSender; import org.webrtc.SessionDescription; -import org.webrtc.VideoCapturer; import java.util.HashMap; import java.util.Map; @@ -25,13 +22,13 @@ import java.util.function.BiConsumer; import java.util.function.Consumer; -public class JanusPublisher extends JanusConnection{ +class JanusPublisher extends JanusConnection { private final Map audioTracks = new HashMap<>(); private final Map videoTracks = new HashMap<>(); private final BiConsumer setNewOfferOnReconfigure; private final ExecutorService executorService = Executors.newSingleThreadExecutor(); - public JanusPublisher( + JanusPublisher( PeerConnectionFactory pcFactory, PmxKeyStore keyStore, TrackObserver observer, diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusSubscriber.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusSubscriber.java index 1a02683b..de712fd2 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusSubscriber.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/JanusSubscriber.java @@ -3,17 +3,15 @@ import com.simplito.java.privmx_endpoint.model.ConnectionType; import org.webrtc.MediaConstraints; -import org.webrtc.PeerConnection; import org.webrtc.PeerConnectionFactory; import org.webrtc.PmxKeyStore; import org.webrtc.SessionDescription; -import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.function.BiConsumer; -public class JanusSubscriber extends JanusConnection { - public JanusSubscriber( +class JanusSubscriber extends JanusConnection { + JanusSubscriber( PeerConnectionFactory pcFactory, PmxKeyStore keyStore, TrackObserver observer, diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/PcObserver.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/PcObserver.java index 8cd5fc88..ba901782 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/PcObserver.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/PcObserver.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -public class PcObserver implements PeerConnection.Observer { +class PcObserver implements PeerConnection.Observer { private final Map frameCryptorMap = new HashMap<>(); private final PmxKeyStore keyStore; private final PeerConnectionFactory peerConnectionFactory; @@ -31,7 +31,7 @@ public class PcObserver implements PeerConnection.Observer { private final Runnable onRenegotiationNeeded; private final Consumer onIceConnectionChange; - public PcObserver( + PcObserver( PeerConnectionFactory peerConnectionFactory, PmxKeyStore store, TrackObserver observer, diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/RoomJanusSession.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/RoomJanusSession.java index a4df35ed..bc5b38d4 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/RoomJanusSession.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/RoomJanusSession.java @@ -24,7 +24,7 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -public class RoomJanusSession { +class RoomJanusSession { @NonNull public final String roomID; @NonNull @@ -42,7 +42,7 @@ public class RoomJanusSession { private final BiConsumer setNewOfferOnReconfigure; //TODO: Add error listener for catch errors from webrtcInterface - public RoomJanusSession( + RoomJanusSession( @NonNull String roomId, @NonNull PeerConnectionFactory pcFactory, BiConsumer onTrickle, diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java index 62fa179f..5f95cca4 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/StreamApi.java @@ -5,10 +5,10 @@ import androidx.annotation.NonNull; -import com.simplito.java.privmx_endpoint.model.ConnectionType; import com.simplito.java.privmx_endpoint.model.ContainerPolicy; import com.simplito.java.privmx_endpoint.model.PagingList; import com.simplito.java.privmx_endpoint.model.UserWithPubKey; +import com.simplito.java.privmx_endpoint.model.stream.Settings; import com.simplito.java.privmx_endpoint.model.stream.StreamHandle; import com.simplito.java.privmx_endpoint.model.stream.StreamInfo; import com.simplito.java.privmx_endpoint.model.stream.StreamPublishResult; @@ -36,9 +36,18 @@ import java.util.function.Consumer; import java.util.stream.Collectors; -public class StreamApi implements AutoCloseable{ +/** + * High-level API for managing PrivMX StreamRooms and WebRTC media sessions on Android. + * {@code StreamApi} is a high-level wrapper over {@link StreamApiLow} and WebRTC, providing + * a simplified interface for working with StreamRooms. + */ +public class StreamApi implements AutoCloseable { private final StreamApiLow api; private final PeerConnectionManager pcManager; + + /** + * Factory which provides helpers for creating WebRTC media sources and tracks. + */ public final TrackFactory trackFactory; private static PeerConnectionFactory DefaultPeerConnectionFactory( @@ -73,6 +82,13 @@ private static PeerConnectionFactory DefaultPeerConnectionFactory( return factory; } + /** + * Creates a {@code StreamApi} instance. + * + * @param appContext Android application context + * @param rootEglBase {@link EglBase} context used for hardware-accelerated video encoding and decoding + * @param api initialised {@link StreamApiLow} instance + */ public StreamApi( @NonNull Context appContext, @NonNull EglBase rootEglBase, @@ -87,14 +103,27 @@ public StreamApi( this.api.trickle(sessionId, rtcConfiguration); } }, - (s,s2)->{ - this.api.setNewOfferOnReconfigure(s,s2); + (s, s2) -> { + this.api.setNewOfferOnReconfigure(s, s2); } ); trackFactory = new TrackFactory(pcManager); } + /** + * Creates a new StreamRoom within the speci fvfied Context. + * + * @param contextId ID of the Context to create the StreamRoom in + * @param users list of {@link UserWithPubKey} indicating which users will have + * access to the created StreamRoom + * @param managers list of {@link UserWithPubKey} indicating which users will have + * access and management rights to the created StreamRoom + * @param publicMeta public (unencrypted) metadata + * @param privateMeta private (encrypted) metadata + * @param policies additional container access policies, or {@code null} to use default settings + * @return ID of the created StreamRoom + */ public String createStreamRoom( String contextId, List users, @@ -106,6 +135,21 @@ public String createStreamRoom( return api.createStreamRoom(contextId, users, managers, publicMeta, privateMeta, policies); } + /** + * Updates an existing StreamRoom. + * + * @param streamRoomId ID of the StreamRoom to update + * @param users list of {@link UserWithPubKey} indicating which users will have + * access to the StreamRoom + * @param managers list of {@link UserWithPubKey} indicating which users will have + * access and management rights to the created StreamRoom + * @param publicMeta public (unencrypted) metadata + * @param privateMeta private (encrypted) metadata + * @param version current version of the updated StreamRoom + * @param force force update (without checking version) + * @param forceGenerateNewKey force to regenerate the encryption key for the StreamRoom + * @param policies additional container access policies, or {@code null} to restore defaults + */ public void updateStreamRoom( String streamRoomId, List users, @@ -120,6 +164,19 @@ public void updateStreamRoom( api.updateStreamRoom(streamRoomId, users, managers, publicMeta, privateMeta, version, force, forceGenerateNewKey, policies); } + /** + * Gets a list of StreamRooms in given Context. + * + * @param contextId ID of the Context to get StreamRooms from + * @param skip number of elements to skip from result + * @param limit limit of elements to return for query + * @param sortOrder order of elements in result ({@code "asc"} for ascending, + * {@code "desc"} for descending) + * @param lastId ID of the element from which query results should start + * @param sortBy field name to sort elements by + * @param queryAsJson stringified JSON object with a custom field to filter result + * @return list of StreamRooms + */ public PagingList listStreamRooms( String contextId, long skip, @@ -132,6 +189,18 @@ public PagingList listStreamRooms( return api.listStreamRooms(contextId, skip, limit, sortOrder, lastId, sortBy, queryAsJson); } + /** + * Gets a list of StreamRooms in given Context. + * + * @param contextId ID of the Context to get StreamRooms from + * @param skip number of elements to skip from result + * @param limit limit of elements to return for query + * @param sortOrder order of elements in result ({@code "asc"} for ascending, + * {@code "desc"} for descending) + * @param lastId ID of the element from which query results should start + * @param sortBy field name to sort elements by + * @return list of StreamRooms + */ public PagingList listStreamRooms( String contextId, long skip, @@ -143,6 +212,17 @@ public PagingList listStreamRooms( return listStreamRooms(contextId, skip, limit, sortOrder, lastId, sortBy, null); } + /** + * Gets a list of StreamRooms in given Context. + * + * @param contextId ID of the Context to get StreamRooms from + * @param skip number of elements to skip from result + * @param limit limit of elements to return for query + * @param sortOrder order of elements in result ({@code "asc"} for ascending, + * {@code "desc"} for descending) + * @param lastId ID of the element from which query results should start + * @return list of StreamRooms + */ public PagingList listStreamRooms( String contextId, long skip, @@ -153,6 +233,16 @@ public PagingList listStreamRooms( return listStreamRooms(contextId, skip, limit, sortOrder, lastId, null, null); } + /** + * Gets a list of StreamRooms in given Context. + * + * @param contextId ID of the Context to get StreamRooms from + * @param skip number of elements to skip from result + * @param limit limit of elements to return for query + * @param sortOrder order of elements in result ({@code "asc"} for ascending, + * {@code "desc"} for descending) + * @return list of StreamRooms + */ public PagingList listStreamRooms( String contextId, long skip, @@ -162,19 +252,43 @@ public PagingList listStreamRooms( return listStreamRooms(contextId, skip, limit, sortOrder, null, null, null); } - + /** + * Gets a single StreamRoom identified by given StreamRoom ID. + * + * @param streamRoomId ID of the StreamRoom to get + * @return {@link StreamRoom} containing information about the room + */ public StreamRoom getStreamRoom(String streamRoomId) { return api.getStreamRoom(streamRoomId); } + /** + * Deletes a StreamRoom identified by given StreamRoom ID. + * + * @param streamRoomId ID of the StreamRoom to delete + */ public void deleteStreamRoom(String streamRoomId) { api.deleteStreamRoom(streamRoomId); } + /** + * Gets a list of currently published streams in given StreamRoom. + * + * @param streamRoomId ID of the StreamRoom to list streams from + * @return list of {@link StreamInfo} describing currently published streams + */ public List listStreams(String streamRoomId) { return api.listStreams(streamRoomId); } + /** + * Joins a StreamRoom and prepares the session for WebRTC communication. + * Must be called before {@link #createStream(String)}, + * {@link #publishStream(StreamHandle)}, and any remote stream subscription calls + * for the given room. + * + * @param streamRoomId ID of the StreamRoom to join + */ public void joinStreamRoom( String streamRoomId ) { @@ -182,11 +296,23 @@ public void joinStreamRoom( api.joinStreamRoom(streamRoomId, session.webrtc); } + /** + * Leaves a StreamRoom and releases the associated WebRTC session. + * + * @param streamRoomId ID of the StreamRoom to leave + */ public void leaveStreamRoom(String streamRoomId) { pcManager.leaveStreamRoom(streamRoomId); api.leaveStreamRoom(streamRoomId); } + /** + * Creates a local stream handle for publishing media in given StreamRoom. + * {@link #joinStreamRoom(String)} must be called before this method. + * + * @param streamRoomId ID of the StreamRoom to create the stream in + * @return handle to the local stream instance + */ public StreamHandle createStream(String streamRoomId) { RoomJanusSession session = pcManager.getSession(streamRoomId); if (session == null) @@ -203,8 +329,11 @@ public StreamHandle createStream(String streamRoomId) { } /** - * @param streamHandle - * @param track + * Adds a local media track to a Stream handle. + * The track is staged locally and becomes visible to others after publishStream/updateStream. + * + * @param streamHandle handle returned by {@link #createStream(String)} + * @param track {@link VideoTrack} or {@link AudioTrack} to add * @throws IllegalStateException if call addTrack before call createStream */ public void addTrack( @@ -230,6 +359,16 @@ public void addTrack( } } + /** + * Registers a {@link TrackObserver} to receive callbacks when a remote media track + * become available for a specified stream in the given StreamRoom. + * Use this method to observe tracks only from a selected remote stream. + * + * @param roomId ID of the StreamRoom + * @param observer observer implementation receiving track callbacks + * @param streamId ID of a specific remote stream to observe, or {@code null} for all streams in the given StreamRoom. + * @throws IllegalStateException thrown when no active session exists for the given room. + */ public void setTrackObserver( @NonNull String roomId, TrackObserver observer, @@ -242,6 +381,28 @@ public void setTrackObserver( session.setTrackObserver(streamId, observer); } + /** + * Registers a {@link TrackObserver} to receive callbacks when a remote media track + * become available for all streams in the given StreamRoom. + * + * @param roomId ID of the StreamRoom + * @param observer observer implementation receiving track callbacks + * @throws IllegalStateException thrown when no active session exists for the given room. + */ + public void setTrackObserver( + @NonNull String roomId, + TrackObserver observer + ) { + setTrackObserver(roomId, observer, null); + } + + /** + * Registers an observer to receive ICE connection state changes for the given StreamRoom. + * + * @param roomId ID of the StreamRoom + * @param observer callback receiving {@link PeerConnection.IceConnectionState} values + * @throws IllegalStateException thrown when no active session exists for the given room. + */ public void setConnectionStateObserver( @NonNull String roomId, Consumer observer @@ -253,17 +414,14 @@ public void setConnectionStateObserver( session.setOnConnectionChange(observer); } - public void setTrackObserver( - String roomId, - TrackObserver observer - ) { - setTrackObserver(roomId, observer, null); - } - /** - * @param streamHandle - * @param track - * @throws IllegalStateException when Stream with this StreamHandle doesn't exist. + * Removes a media track from a stream. + * After removing tracks, call {@link #updateStream(StreamHandle)} to propagate + * the change to other participants. + * + * @param streamHandle handle returned by {@link #createStream(String)} + * @param track {@link VideoTrack} or {@link AudioTrack} to remove + * @throws IllegalStateException thrown when Stream with this StreamHandle doesn't exist. */ public void removeTrack( @NonNull StreamHandle streamHandle, @@ -283,6 +441,14 @@ public void removeTrack( } } + /** + * Publishes the stream (with currently added tracks) to the server, + * making it visible to other participants in the room. + * + * @param streamHandle handle returned by {@link #createStream(String)} + * @return result of the publish operation containing stream information + * @throws IllegalStateException thrown when no stream exists for the given handle. + */ public StreamPublishResult publishStream(@NonNull StreamHandle streamHandle) { Objects.requireNonNull(streamHandle); RoomJanusSession session = pcManager.getSession(streamHandle); @@ -295,6 +461,16 @@ public StreamPublishResult publishStream(@NonNull StreamHandle streamHandle) { return api.publishStream(streamHandle); } + /** + * Updates a published stream after track changes. + * Call this after {@link #addTrack(StreamHandle, MediaStreamTrack)} or + * {@link #removeTrack(StreamHandle, MediaStreamTrack)} on an already-published stream + * to propagate the changes to other participants. + * + * @param streamHandle handle returned by {@link #createStream(String)} + * @return result of the update operation containing updated stream information + * @throws IllegalStateException thrown when no stream exists for the given handle. + */ public StreamPublishResult updateStream(@NonNull StreamHandle streamHandle) { Objects.requireNonNull(streamHandle); RoomJanusSession session = pcManager.getSession(streamHandle); @@ -307,11 +483,26 @@ public StreamPublishResult updateStream(@NonNull StreamHandle streamHandle) { return api.updateStream(streamHandle); } + /** + * Stops publishing the stream. + * + * @param streamHandle handle returned by {@link #createStream(String)} + * @throws IllegalStateException thrown when instance is closed. + */ public void unpublishStream(@NonNull StreamHandle streamHandle) { Objects.requireNonNull(streamHandle); api.unpublishStream(streamHandle); } + /** + * Subscribes to selected remote streams or tracks in a StreamRoom. + * {@link #joinStreamRoom(String)} must be called before this method. + * + * @param streamRoomId ID of the StreamRoom + * @param subscriptions list of {@link StreamSubscription} describing the remote + * streams to subscribe to + * @throws IllegalStateException thrown when no active session exists for the given room. + */ public void subscribeToRemoteStreams( String streamRoomId, List subscriptions @@ -330,6 +521,17 @@ public void subscribeToRemoteStreams( } + /** + * Modifies the current list of remote stream subscriptions in a StreamRoom. + * Allows atomically adding and removing remote stream subscriptions in a single call, + * avoiding the need to fully unsubscribe and resubscribe. + * + * @param streamRoomId ID of the StreamRoom + * @param subscriptionsToAdd list of {@link StreamSubscription} to add + * @param subscriptionsToRemove list of {@link StreamSubscription} to remove + * @throws IllegalStateException thrown when no active session or subscriber exists + * for the given room. + */ public void modifyRemoteStreamsSubscriptions( String streamRoomId, List subscriptionsToAdd, @@ -348,6 +550,14 @@ public void modifyRemoteStreamsSubscriptions( ); } + /** + * Unsubscribes from selected remote streams in a StreamRoom. + * + * @param streamRoomId ID of the StreamRoom + * @param subscriptionsToRemove list of {@link StreamSubscription} to remove + * @throws IllegalStateException thrown when no active session or subscriber exists + * for the given room. + */ public void unsubscribeFromRemoteStreams( String streamRoomId, List subscriptionsToRemove @@ -364,6 +574,12 @@ public void unsubscribeFromRemoteStreams( ); } + /** + * Controls whether encrypted media frames that cannot be decrypted should be dropped. + * + * @param streamRoomId ID of the StreamRoom + * @param enable if {@code true}, broken frames will be dropped + */ public void dropBrokenFrames( String streamRoomId, boolean enable @@ -376,14 +592,41 @@ public void dropBrokenFrames( } } + /** + * Subscribes to events for the StreamRoom as well as its individual streams, + * based on the provided subscription queries. + * + * @param subscriptionQueries list of queries built with + * {@link #buildSubscriptionQuery(StreamEventType, StreamEventSelectorType, String)} + * @return list of subscription IDs in matching order to {@code subscriptionQueries} + * @throws IllegalStateException thrown when instance is closed. + */ public List subscribeFor(List subscriptionQueries) { return api.subscribeFor(subscriptionQueries); } + /** + * Unsubscribes from events with the given subscription IDs. + * + * @param subscriptionIds list of subscription IDs returned by {@link #subscribeFor(List)} + * @throws IllegalStateException thrown when instance is closed. + */ public void unsubscribeFrom(List subscriptionIds) { api.unsubscribeFrom(subscriptionIds); } + /** + * Generates a subscription query string for events for the StreamRoom + * as well as its individual streams. + * The returned query should be passed to {@link #subscribeFor(List)} to start + * receiving the requested events. + * + * @param eventType type of event to listen for + * @param selectorType scope at which events are observed + * @param selectorId ID of the selected entity + * @return query string used for event subscription + * @throws IllegalStateException thrown when instance is closed + */ public String buildSubscriptionQuery( StreamEventType eventType, StreamEventSelectorType selectorType, @@ -396,6 +639,12 @@ public String buildSubscriptionQuery( ); } + /** + * Releases all resources associated with this instance. + * Leaves all active StreamRooms and releases allocated resources. + * + * @throws Exception thrown if an error occurs during cleanup + */ @Override public void close() throws Exception { pcManager.getRoomIds().forEach(this::leaveStreamRoom); diff --git a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/TrackFactory.java b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/TrackFactory.java index 9d102ebd..568e382f 100644 --- a/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/TrackFactory.java +++ b/privmx-endpoint-streams/android/src/main/java/com/simplito/java/privmx_endpoint/modules/stream/TrackFactory.java @@ -2,36 +2,86 @@ import org.webrtc.*; +/** + * Factory for creating WebRTC media sources and tracks. + * Provides methods for creating the audio and video objects needed + * to publish a stream via {@link StreamApi}. + * You do not create instances of this class directly — obtain the shared instance + * from {@link StreamApi#trackFactory} after constructing a {@link StreamApi}. + */ public class TrackFactory { private final PeerConnectionFactory factory; - TrackFactory(PeerConnectionManager pcManager){ + + TrackFactory(PeerConnectionManager pcManager) { factory = pcManager.pcFactory; } - public VideoSource createVideoSource(boolean isScreenCast){ + /** + * Creates a {@link VideoSource} that can capture a camera or screen with alignTimestamps to {@code true}. + * + * @param isScreenCast {@code true} if the source is capturing a screen share; + * {@code false} for a regular camera + * @return a new {@link VideoSource} instance + */ + public VideoSource createVideoSource(boolean isScreenCast) { return factory.createVideoSource(isScreenCast); } - public VideoSource createVideoSource(boolean isScreenCast, boolean alignTimestamps){ - return factory.createVideoSource(isScreenCast,alignTimestamps); + /** + * Creates a {@link VideoSource} with explicit timestamp alignment control. + * + * @param isScreenCast {@code true} if the source is capturing a screen share; + * {@code false} for a regular camera + * @param alignTimestamps if {@code} false - the caller is responsible for aligning + * frame timestamps to {@code rtc::TimeNanos()} — useful for + * higher accuracy when there is a significant delay between + * frame creation and delivery; if {@code true}, timestamps + * are automatically aligned to {@code rtc::TimeNanos()} + * upon arrival at the returned video source + * @return a new {@link VideoSource} instance + */ + public VideoSource createVideoSource(boolean isScreenCast, boolean alignTimestamps) { + return factory.createVideoSource(isScreenCast, alignTimestamps); } - public AudioSource createAudioSource(){ + /** + * Creates an {@link AudioSource} with default media constraints. + * The source captures audio from the device microphone. Default constraints + * enable standard WebRTC audio processing (echo cancellation, noise suppression, + * auto gain control). + * + * @return a new {@link AudioSource} instance + */ + public AudioSource createAudioSource() { return factory.createAudioSource(new MediaConstraints()); } + /** + * Creates a {@link VideoTrack} using the provided {@link VideoSource}. + * + * @param id unique identifier for this track within the peer connection + * @param videoSource source of video frames + * @return a new {@link VideoTrack} instance + */ public VideoTrack createVideoTrack( String id, VideoSource videoSource - ){ - return factory.createVideoTrack(id,videoSource); + ) { + return factory.createVideoTrack(id, videoSource); } + /** + * Creates an {@link AudioTrack} using the provided {@link AudioSource}. + * + * @param id unique identifier for this track within the peer connection + * @param audioSource source providing audio samples + * @return a new {@link AudioTrack} instance + */ public AudioTrack createAudioTrack( String id, AudioSource audioSource - ){ - return factory.createAudioTrack(id,audioSource); + ) { + return factory.createAudioTrack(id, audioSource); } } \ No newline at end of file