mirror of
https://github.com/pion/mediadevices.git
synced 2026-04-22 15:57:27 +08:00
Add GetDisplayMedia
* Add selectScreen to select all registered drivers that can screenshare * Add GetDisplayMedia * Add screenshare example
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
## Instructions
|
||||
|
||||
### Download screenshare
|
||||
|
||||
```
|
||||
go get github.com/pion/mediadevices/examples/screenshare
|
||||
```
|
||||
|
||||
### Open example page
|
||||
|
||||
[jsfiddle.net](https://jsfiddle.net/z7ms3u5r/) you should see two text-areas and a 'Start Session' button
|
||||
|
||||
### Run screenshare with your browsers SessionDescription as stdin
|
||||
|
||||
In the jsfiddle the top textarea is your browser, copy that and:
|
||||
|
||||
#### Linux
|
||||
|
||||
Run `echo $BROWSER_SDP | screenshare`
|
||||
|
||||
### Input screenshare's SessionDescription into your browser
|
||||
|
||||
Copy the text that `screenshare` just emitted and copy into second text area
|
||||
|
||||
### Hit 'Start Session' in jsfiddle, enjoy your video!
|
||||
|
||||
A video should start playing in your browser above the input boxes, and will continue playing until you close the application.
|
||||
|
||||
Congrats, you have used pion-WebRTC! Now start building something cool
|
||||
@@ -0,0 +1,103 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pion/mediadevices"
|
||||
"github.com/pion/mediadevices/examples/internal/signal"
|
||||
_ "github.com/pion/mediadevices/pkg/codec/openh264" // This is required to register h264 video encoder
|
||||
_ "github.com/pion/mediadevices/pkg/codec/opus" // This is required to register opus audio encoder
|
||||
_ "github.com/pion/mediadevices/pkg/codec/vpx"
|
||||
"github.com/pion/mediadevices/pkg/frame"
|
||||
"github.com/pion/webrtc/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
videoCodecName = webrtc.VP8
|
||||
)
|
||||
|
||||
func main() {
|
||||
config := webrtc.Configuration{
|
||||
ICEServers: []webrtc.ICEServer{
|
||||
{
|
||||
URLs: []string{"stun:stun.l.google.com:19302"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// Wait for the offer to be pasted
|
||||
offer := webrtc.SessionDescription{}
|
||||
signal.Decode(signal.MustReadStdin(), &offer)
|
||||
|
||||
// Create a new RTCPeerConnection
|
||||
mediaEngine := webrtc.MediaEngine{}
|
||||
if err := mediaEngine.PopulateFromSDP(offer); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
api := webrtc.NewAPI(webrtc.WithMediaEngine(mediaEngine))
|
||||
peerConnection, err := api.NewPeerConnection(config)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Set the handler for ICE connection state
|
||||
// This will notify you when the peer has connected/disconnected
|
||||
peerConnection.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) {
|
||||
fmt.Printf("Connection State has changed %s \n", connectionState.String())
|
||||
})
|
||||
|
||||
md := mediadevices.NewMediaDevices(peerConnection)
|
||||
|
||||
s, err := md.GetDisplayMedia(mediadevices.MediaStreamConstraints{
|
||||
Video: func(c *mediadevices.MediaTrackConstraints) {
|
||||
c.CodecName = videoCodecName
|
||||
c.FrameFormat = frame.FormatI444
|
||||
c.Enabled = true
|
||||
c.Width = 640
|
||||
c.Height = 480
|
||||
c.BitRate = 100000 // 100kbps
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
for _, tracker := range s.GetTracks() {
|
||||
t := tracker.Track()
|
||||
tracker.OnEnded(func(err error) {
|
||||
fmt.Printf("Track (ID: %s, Label: %s) ended with error: %v\n",
|
||||
t.ID(), t.Label(), err)
|
||||
})
|
||||
_, err = peerConnection.AddTrack(t)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tweak transceiver direction to work with Firefox
|
||||
for _, t := range peerConnection.GetTransceivers() {
|
||||
t.Direction = webrtc.RTPTransceiverDirectionSendonly
|
||||
}
|
||||
|
||||
// Set the remote SessionDescription
|
||||
err = peerConnection.SetRemoteDescription(offer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create an answer
|
||||
answer, err := peerConnection.CreateAnswer(nil)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Sets the LocalDescription, and starts our UDP listeners
|
||||
err = peerConnection.SetLocalDescription(answer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Output the answer in base64 so we can paste it in browser
|
||||
fmt.Println(signal.Encode(answer))
|
||||
select {}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ var errNotFound = fmt.Errorf("failed to find the best driver that fits the const
|
||||
|
||||
// MediaDevices is an interface that's defined on https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices
|
||||
type MediaDevices interface {
|
||||
GetDisplayMedia(constraints MediaStreamConstraints) (MediaStream, error)
|
||||
GetUserMedia(constraints MediaStreamConstraints) (MediaStream, error)
|
||||
EnumerateDevices() []MediaDeviceInfo
|
||||
}
|
||||
@@ -75,6 +76,34 @@ func WithTrackGenerator(gen TrackGenerator) MediaDevicesOption {
|
||||
}
|
||||
}
|
||||
|
||||
// GetDisplayMedia prompts the user to select and grant permission to capture the contents
|
||||
// of a display or portion thereof (such as a window) as a MediaStream.
|
||||
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getDisplayMedia
|
||||
func (m *mediaDevices) GetDisplayMedia(constraints MediaStreamConstraints) (MediaStream, error) {
|
||||
trackers := make([]Tracker, 0)
|
||||
|
||||
var videoConstraints MediaTrackConstraints
|
||||
if constraints.Video != nil {
|
||||
constraints.Video(&videoConstraints)
|
||||
}
|
||||
|
||||
if videoConstraints.Enabled {
|
||||
tracker, err := m.selectScreen(videoConstraints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
trackers = append(trackers, tracker)
|
||||
}
|
||||
|
||||
s, err := NewMediaStream(trackers...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// GetUserMedia prompts the user for permission to use a media input which produces a MediaStream
|
||||
// with tracks containing the requested types of media.
|
||||
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia
|
||||
@@ -212,6 +241,27 @@ func (m *mediaDevices) selectVideo(constraints MediaTrackConstraints) (Tracker,
|
||||
return newVideoTrack(&m.MediaDevicesOptions, d, c)
|
||||
}
|
||||
|
||||
func (m *mediaDevices) selectScreen(constraints MediaTrackConstraints) (Tracker, error) {
|
||||
typeFilter := driver.FilterVideoRecorder()
|
||||
screenFilter := driver.FilterDeviceType(driver.Screen)
|
||||
filter := func(d driver.Driver) bool {
|
||||
return typeFilter(d) && screenFilter(d)
|
||||
}
|
||||
if constraints.DeviceID != "" {
|
||||
idFilter := driver.FilterID(constraints.DeviceID)
|
||||
filter = func(d driver.Driver) bool {
|
||||
return typeFilter(d) && screenFilter(d) && idFilter(d)
|
||||
}
|
||||
}
|
||||
|
||||
d, c, err := selectBestDriver(filter, constraints)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return newVideoTrack(&m.MediaDevicesOptions, d, c)
|
||||
}
|
||||
|
||||
func (m *mediaDevices) EnumerateDevices() []MediaDeviceInfo {
|
||||
drivers := driver.GetManager().Query(
|
||||
driver.FilterFn(func(driver.Driver) bool { return true }))
|
||||
|
||||
Reference in New Issue
Block a user