/// <summary>
        /// Create a video track from a local video capture device (webcam).
        ///
        /// The video track receives its video data from an underlying hidden source associated with
        /// the track and producing video frames by capturing them from a capture device accessible
        /// from the local host machine, generally a USB webcam or built-in device camera.
        ///
        /// The underlying video source initially starts in the capturing state, and will remain live
        /// for as long as the track is alive. It can be added to a peer connection by assigning it to
        /// the <see cref="Transceiver.LocalVideoTrack"/> property of a video transceiver of that peer
        /// connection. Once attached to the peer connection, it can temporarily be disabled and re-enabled
        /// (see <see cref="Enabled"/>) while remaining attached to it.
        ///
        /// Note that disabling the track does not release the device; the source retains exclusive access to it.
        /// Therefore in general multiple tracks cannot be created using a single video capture device.
        /// </summary>
        /// <param name="settings">Video capture settings for configuring the capture device associated with
        /// the underlying video track source.</param>
        /// <returns>This returns a task which, upon successful completion, provides an instance of
        /// <see cref="LocalVideoTrack"/> representing the newly created video track.</returns>
        /// <remarks>
        /// On UWP this requires the "webcam" capability.
        /// See <see href="https://docs.microsoft.com/en-us/windows/uwp/packaging/app-capability-declarations"/>
        /// for more details.
        ///
        /// The video capture device may be accessed several times during the initializing process,
        /// generally once for listing and validating the capture format, and once for actually starting
        /// the video capture.
        ///
        /// Note that the capture device must support a capture format with the given constraints of profile
        /// ID or kind, capture resolution, and framerate, otherwise the call will fail. That is, there is no
        /// fallback mechanism selecting a closest match. Developers should use
        /// <see cref="PeerConnection.GetVideoCaptureFormatsAsync(string)"/> to list the supported formats ahead
        /// of calling <see cref="CreateFromDeviceAsync(LocalVideoTrackSettings)"/>, and can build their own
        /// fallback mechanism on top of this call if needed.
        /// </remarks>
        /// <exception xref="InvalidOperationException">The peer connection is not intialized.</exception>
        /// <example>
        /// Create a video track called "MyTrack", with Mixed Reality Capture (MRC) enabled.
        /// This assumes that the platform supports MRC. Note that if MRC is not available
        /// the call will still succeed, but will return a track without MRC enabled.
        /// <code>
        /// var settings = new LocalVideoTrackSettings
        /// {
        ///     trackName = "MyTrack",
        ///     enableMrc = true
        /// };
        /// var videoTrack = await LocalVideoTrack.CreateFromDeviceAsync(settings);
        /// </code>
        /// Create a video track from a local webcam, asking for a capture format suited for video conferencing,
        /// and a target framerate of 30 frames per second (FPS). The implementation will select an appropriate
        /// capture resolution. This assumes that the device supports video profiles, and has at least one capture
        /// format supporting 30 FPS capture associated with the VideoConferencing profile. Otherwise the call
        /// will fail.
        /// <code>
        /// var settings = new LocalVideoTrackSettings
        /// {
        ///     videoProfileKind = VideoProfileKind.VideoConferencing,
        ///     framerate = 30.0
        /// };
        /// var videoTrack = await LocalVideoTrack.CreateFromDeviceAsync(settings);
        /// </code>
        /// </example>
        /// <seealso cref="Transceiver.LocalVideoTrack"/>
        public static Task <LocalVideoTrack> CreateFromDeviceAsync(LocalVideoTrackSettings settings = null)
        {
            return(Task.Run(() =>
            {
                // On UWP this cannot be called from the main UI thread, so always call it from
                // a background worker thread.

                string trackName = settings?.trackName;
                if (string.IsNullOrEmpty(trackName))
                {
                    trackName = Guid.NewGuid().ToString();
                }

                // Create interop wrappers
                var track = new LocalVideoTrack(trackName);

                // Parse settings
                var config = new PeerConnectionInterop.LocalVideoTrackInteropInitConfig(track, settings);

                // Create native implementation objects
                uint res = LocalVideoTrackInterop.LocalVideoTrack_CreateFromDevice(in config, trackName,
                                                                                   out LocalVideoTrackHandle trackHandle);
                Utils.ThrowOnErrorCode(res);
                track.SetHandle(trackHandle);
                return track;
            }));
        }
Beispiel #2
0
        /// <summary>
        /// Internal callback when a track stops using this source.
        /// </summary>
        /// <param name="track">The track not using this source anymore.</param>
        internal void OnTrackRemovedFromSource(LocalVideoTrack track)
        {
            Debug.Assert(!_nativeHandle.IsClosed);
            bool removed = _tracks.Remove(track);

            Debug.Assert(removed);
        }
Beispiel #3
0
        /// <summary>
        /// Create a video track from an existing video track source.
        ///
        /// This does not add the track to any peer connection. Instead, the track must be added manually to
        /// a video transceiver to be attached to a peer connection and transmitted to a remote peer.
        /// </summary>
        /// <param name="source">The track source which provides the raw video frames to the newly created track.</param>
        /// <param name="initConfig">Configuration to initialize the track being created.</param>
        /// <returns>Asynchronous task completed once the track is created.</returns>
        public static LocalVideoTrack CreateFromSource(VideoTrackSource source, LocalVideoTrackInitConfig initConfig)
        {
            if (source == null)
            {
                throw new ArgumentNullException();
            }

            // Parse and marshal the settings
            string trackName = initConfig?.trackName;

            if (string.IsNullOrEmpty(trackName))
            {
                trackName = Guid.NewGuid().ToString();
            }
            var config = new LocalVideoTrackInterop.TrackInitConfig
            {
                TrackName = trackName
            };

            // Create interop wrappers
            var track = new LocalVideoTrack(trackName);

            // Create native implementation objects
            uint res = LocalVideoTrackInterop.LocalVideoTrack_CreateFromSource(in config,
                                                                               source._nativeHandle, out LocalVideoTrackHandle trackHandle);

            Utils.ThrowOnErrorCode(res);

            // Finish creating the track, and bind it to the source
            track.FinishCreate(trackHandle, source);

            return(track);
        }
        /// <summary>
        /// Create a new local video track backed by an existing external video source.
        /// The track can be added to a peer connection by setting the <see cref="Transceiver.LocalVideoTrack"/>
        /// property.
        /// </summary>
        /// <param name="trackName">Name of the new local video track.</param>
        /// <param name="source">External video track source providing some video frames to the track.</param>
        /// <returns>The newly created local video track.</returns>
        /// <seealso cref="Transceiver.LocalVideoTrack"/>
        public static LocalVideoTrack CreateFromExternalSource(string trackName, ExternalVideoTrackSource source)
        {
            if (string.IsNullOrEmpty(trackName))
            {
                trackName = Guid.NewGuid().ToString();
            }

            // Create interop wrappers
            var track = new LocalVideoTrack(trackName, source);

            // Parse settings
            var config = new PeerConnectionInterop.LocalVideoTrackFromExternalSourceInteropInitConfig(trackName, source);

            // Create native implementation objects
            uint res = LocalVideoTrackInterop.LocalVideoTrack_CreateFromExternalSource(config, out LocalVideoTrackHandle trackHandle);

            Utils.ThrowOnErrorCode(res);
            track.SetHandle(trackHandle);
            return(track);
        }
Beispiel #5
0
        /// <summary>
        /// Create a video track from an existing video track source.
        ///
        /// This does not add the track to any peer connection. Instead, the track must be added manually to
        /// a video transceiver to be attached to a peer connection and transmitted to a remote peer.
        /// </summary>
        /// <param name="source">The track source which provides the raw video frames to the newly created track.</param>
        /// <param name="initConfig">Configuration to initialize the track being created.</param>
        /// <returns>Asynchronous task completed once the track is created.</returns>
        public static LocalVideoTrack CreateFromSource(VideoTrackSource source, LocalVideoTrackInitConfig initConfig)
        {
            if (source == null)
            {
                throw new ArgumentNullException();
            }

            // Parse and marshal the settings
            string trackName = initConfig?.trackName;

            if (string.IsNullOrEmpty(trackName))
            {
                trackName = Guid.NewGuid().ToString();
            }
            var config = new LocalVideoTrackInterop.TrackInitConfig
            {
                TrackName = trackName
            };

            // Create interop wrappers
            var track = new LocalVideoTrack(trackName);

            // Create native implementation objects
            uint res = LocalVideoTrackInterop.LocalVideoTrack_CreateFromSource(in config,
                                                                               source._nativeHandle, out LocalVideoTrackHandle trackHandle);

            Utils.ThrowOnErrorCode(res);

            // Finish creating the track, and bind it to the source
            Debug.Assert(!trackHandle.IsClosed);
            track._nativeHandle = trackHandle;
            track.Source        = source;
            source.OnTrackAddedToSource(track);

            // Note that this prevents the object from being garbage-collected until it is disposed.
            track._selfHandle = Utils.MakeWrapperRef(track);

            return(track);
        }
Beispiel #6
0
 /// <summary>
 /// Internal callback when a track starts using this source.
 /// </summary>
 /// <param name="track">The track using this source.</param>
 internal void OnTrackAddedToSource(LocalVideoTrack track)
 {
     Debug.Assert(!_nativeHandle.IsClosed);
     Debug.Assert(!_tracks.Contains(track));
     _tracks.Add(track);
 }