{"id":13806832,"url":"https://github.com/KristofferStrube/Blazor.MediaCaptureStreams","last_synced_at":"2025-05-13T22:30:57.909Z","repository":{"id":153378956,"uuid":"628710008","full_name":"KristofferStrube/Blazor.MediaCaptureStreams","owner":"KristofferStrube","description":"A Blazor wrapper for the Media Capture and Streams browser API.","archived":false,"fork":false,"pushed_at":"2024-10-23T20:43:45.000Z","size":8197,"stargazers_count":72,"open_issues_count":1,"forks_count":7,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-10-24T07:35:14.444Z","etag":null,"topics":["audio","blazor","blazor-webassembly","camera","csharp","devices","media-capture-and-streams-api","mediastream","mediastream-api","microphone","video","wasm","webassembly","webidl"],"latest_commit_sha":null,"homepage":"https://kristofferstrube.github.io/Blazor.MediaCaptureStreams/","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/KristofferStrube.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-04-16T19:26:56.000Z","updated_at":"2024-10-23T20:41:27.000Z","dependencies_parsed_at":null,"dependency_job_id":"a6f2dafe-6f06-4f16-8e3b-69e4de57a2ec","html_url":"https://github.com/KristofferStrube/Blazor.MediaCaptureStreams","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KristofferStrube%2FBlazor.MediaCaptureStreams","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KristofferStrube%2FBlazor.MediaCaptureStreams/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KristofferStrube%2FBlazor.MediaCaptureStreams/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/KristofferStrube%2FBlazor.MediaCaptureStreams/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/KristofferStrube","download_url":"https://codeload.github.com/KristofferStrube/Blazor.MediaCaptureStreams/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225260780,"owners_count":17446108,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio","blazor","blazor-webassembly","camera","csharp","devices","media-capture-and-streams-api","mediastream","mediastream-api","microphone","video","wasm","webassembly","webidl"],"created_at":"2024-08-04T01:01:16.814Z","updated_at":"2024-11-18T22:32:45.945Z","avatar_url":"https://github.com/KristofferStrube.png","language":"C#","funding_links":[],"categories":["Sample Projects"],"sub_categories":["Others"],"readme":"[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](/LICENSE)\r\n[![GitHub issues](https://img.shields.io/github/issues/KristofferStrube/Blazor.MediaCaptureStreams)](https://github.com/KristofferStrube/Blazor.MediaCaptureStreams/issues)\r\n[![GitHub forks](https://img.shields.io/github/forks/KristofferStrube/Blazor.MediaCaptureStreams)](https://github.com/KristofferStrube/Blazor.MediaCaptureStreams/network/members)\r\n[![GitHub stars](https://img.shields.io/github/stars/KristofferStrube/Blazor.MediaCaptureStreams)](https://github.com/KristofferStrube/Blazor.MediaCaptureStreams/stargazers)\r\n[![NuGet Downloads (official NuGet)](https://img.shields.io/nuget/dt/KristofferStrube.Blazor.MediaCaptureStreams?label=NuGet%20Downloads)](https://www.nuget.org/packages/KristofferStrube.Blazor.MediaCaptureStreams/)\r\n\r\n# Blazor.MediaCaptureStreams\r\nA Blazor wrapper for the [Media Capture and Streams](https://www.w3.org/TR/mediacapture-streams/) browser API.\r\n\r\nThe API standardizes ways to request access to local multimedia devices, such as microphones or video cameras. This also includes the MediaStream API, which provides the means to control where multimedia stream data is consumed, and provides some information and configuration options for the devices that produce the media. This project implements a wrapper around the API for Blazor so that we can easily and safely interact with the media streams of the browser.\r\n\r\n# Demo\r\nThe sample project can be demoed at https://kristofferstrube.github.io/Blazor.MediaCaptureStreams/\r\n\r\nOn each page, you can find the corresponding code for the example in the top right corner.\r\n\r\nOn the [API Coverage Status](https://kristofferstrube.github.io/Blazor.MediaCaptureStreams/Status) page you can see how much of the WebIDL specs this wrapper has covered.\r\n\r\n# Getting Started\r\n## Prerequisites\r\nYou need to install .NET 7.0 or newer to use the library.\r\n\r\n[Download .NET 7](https://dotnet.microsoft.com/download/dotnet/7.0)\r\n\r\n## Installation\r\nYou can install the package via NuGet with the Package Manager in your IDE or alternatively using the command line:\r\n```bash\r\ndotnet add package KristofferStrube.Blazor.MediaCaptureStreams\r\n```\r\n\r\n# Usage\r\nThe package can be used in Blazor WebAssembly and Blazor Server projects.\r\n## Import\r\nYou need to reference the package in order to use it in your pages. This can be done in `_Import.razor` by adding the following.\r\n```razor\r\n@using KristofferStrube.Blazor.MediaCaptureStreams\r\n```\r\n\r\n## Add to service collection\r\nThe library has one service which is the `IMediaDevicesService` which can be used to access the `MediaDevices` of the current browser context. An easy way to make the service available on all your pages is by registering it in the `IServiceCollection` so that it can be dependency injected in the pages that need it. This is done in `Program.cs` by using our extension `AddMediaDevicesService()` before you build the host like we do in the following code block. If you use Blazor WASM you also need to invoke the `SetupErrorHandlingJSInterop()` extension on the `IServiceProvider` after building the host but before running like do we here:\r\n```csharp\r\nvar builder = WebAssemblyHostBuilder.CreateDefault(args);\r\nbuilder.RootComponents.Add\u003cApp\u003e(\"#app\");\r\nbuilder.RootComponents.Add\u003cHeadOutlet\u003e(\"head::after\");\r\n\r\nbuilder.Services.AddScoped(sp =\u003e new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });\r\n\r\n// Adding IMediaDevicesService to service collection.\r\nbuilder.Services.AddMediaDevicesService();\r\n\r\nvar app = builder.Build();\r\n\r\n// For Blazor WASM you need to call this to make Error Handling JS Interop.\r\nawait app.Services.SetupErrorHandlingJSInterop();\r\n\r\nawait app.RunAsync();\r\n```\r\n\r\n## Inject in page\r\nThen the service can be injected into a page\r\n```razor\r\n@inject IMediaDevicesService MediaDevicesService;\r\n```\r\nand we can use it to get the `MediaDevices` object that is the primary access point for the API and open a `MediaStream` representing a microphone device like so:\r\n```razor\r\n@if (error is not null)\r\n{\r\n    \u003ccode\u003e@error\u003c/code\u003e\r\n}\r\nelse if (deviceLabel is not null)\r\n{\r\n    \u003cp\u003eWe opened the media device with label: \u003cb\u003e@deviceLabel\u003c/b\u003e\u003c/p\u003e\r\n}\r\nelse\r\n{\r\n    \u003cbutton @onclick=\"Open\"\u003eOpen Microphone MediaStream\u003c/button\u003e\r\n}\r\n\r\n@code {\r\n    private string? deviceLabel;\r\n    private string? error;\r\n\r\n    private async Task Open()\r\n    {\r\n        try\r\n        {\r\n            MediaDevices mediaDevices = await MediaDevicesService.GetMediaDevicesAsync();\r\n            MediaStream mediaStream = await mediaDevices.GetUserMediaAsync(new MediaStreamConstraints() { Audio = true });\r\n            MediaStreamTrack[] audioTracks = await mediaStream.GetAudioTracksAsync();\r\n            deviceLabel = await audioTracks.First().GetLabelAsync();\r\n        }\r\n        catch (WebIDLException ex)\r\n        {\r\n            error = $\"{ex.GetType().Name}: {ex.Message}\";\r\n        }\r\n    }\r\n}\r\n```\r\nWe can read, process, and record the `MediaStream` and `MediaStreamTrack`s through other API's. Among these are the [Web Audio](https://www.w3.org/TR/webaudio/), [WebRTC](https://www.w3.org/TR/webrtc/), [MediaStream Image Capture](https://www.w3.org/TR/image-capture/), and [MediaStream Recording](https://www.w3.org/TR/mediastream-recording/) API's. We are currently working on making a Blazor wrapper for the Web Audio API in the [Blazor.WebAudio project](https://github.com/KristofferStrube/Blazor.WebAudio). If you want an example of outputting the content of a video stream track check out [the live video demo sample](https://kristofferstrube.github.io/Blazor.MediaCaptureStreams/Video)\r\n\r\nBut before using the `MediaStream` and `MediaStreamTrack`s in other API's we can further constrain the details of the streams. We can do this by parsing some `MediaTrackConstraints` to the `Audio` property of the `MediaStreamConstraints` in our previous example. But before we make constraints we can also check what the possible range of values is for our devices so that we don't try to overconstrain the media devices. In the following sample, we open a `MediaStream` representing some camera, then check the capabilities of its first track and apply some new constraints to it depending on the constraints' max values for the resolution.\r\n\r\n```csharp\r\nMediaDevices mediaDevices = await MediaDevicesService.GetMediaDevicesAsync();\r\nMediaStream mediaStream = await mediaDevices.GetUserMediaAsync(new MediaStreamConstraints() { Video = true });\r\n\r\nMediaStreamTrack[] videoTracks = await mediaStream.GetVideoTracksAsync();\r\nMediaStreamTrack firstVideoTrack = videoTracks.First();\r\n\r\nMediaTrackCapabilities capabilities = await firstVideoTrack.GetCapabilitiesAsync();\r\nawait firstVideoTrack.ApplyContraintsAsync(new MediaTrackConstraints()\r\n    {\r\n        Height = capabilities.Height?.Max,\r\n        Width = capabilities.Width?.Max\r\n    });\r\n```\r\n\r\nIf we had not checked the capabilities of the track before setting its values we could potentially have set some values outside the valid range. If we did this we would get an `OverConstrainedException` that we could catch as we did with the more general `WebIDLException` in the previous sample.\r\n\r\n# Issues\r\nFeel free to open issues on the repository if you find any errors with the package or have wishes for features.\r\n\r\n# Related repositories\r\nThis project uses the *Blazor.WebIDL* package to make error handling JSInterop and it uses the *Blazor.DOM* package to listen to events from the *EventTarget*'s in the package like `MediaDevices`, `MediaStream`, and `MediaStreamTrack`.\r\n- https://github.com/KristofferStrube/Blazor.WebIDL\r\n- https://github.com/KristofferStrube/Blazor.DOM\r\n\r\nThe project is used in the *Blazor.WebAudio* library to create `AudioNode`s representing microphones that can be used together with other audio sources in many different ways. You can also record your audio and video mediastreams using the `Blazor.MediaStreamRecording` library.\r\n- https://github.com/KristofferStrube/Blazor.WebAudio\r\n- https://github.com/KristofferStrube/Blazor.MediaStreamRecording\r\n\r\n\r\n# Related articles\r\nThis repository was built with inspiration and help from the following series of articles:\r\n\r\n- [Typed exceptions for JSInterop in Blazor](https://kristoffer-strube.dk/post/typed-exceptions-for-jsinterop-in-blazor/)\r\n- [Wrapping Compression Streams in Blazor](https://kristoffer-strube.dk/post/wrapping-compression-streams-in-blazor/)\r\n- [Wrapping JavaScript libraries in Blazor WebAssembly/WASM](https://blog.elmah.io/wrapping-javascript-libraries-in-blazor-webassembly-wasm/)\r\n- [Call anonymous C# functions from JS in Blazor WASM](https://blog.elmah.io/call-anonymous-c-functions-from-js-in-blazor-wasm/)\r\n- [Using JS Object References in Blazor WASM to wrap JS libraries](https://blog.elmah.io/using-js-object-references-in-blazor-wasm-to-wrap-js-libraries/)\r\n- [Blazor WASM 404 error and fix for GitHub Pages](https://blog.elmah.io/blazor-wasm-404-error-and-fix-for-github-pages/)\r\n- [How to fix Blazor WASM base path problems](https://blog.elmah.io/how-to-fix-blazor-wasm-base-path-problems/)\r\n\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKristofferStrube%2FBlazor.MediaCaptureStreams","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FKristofferStrube%2FBlazor.MediaCaptureStreams","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FKristofferStrube%2FBlazor.MediaCaptureStreams/lists"}