mirror of
https://github.com/hcengineering/platform.git
synced 2025-05-11 18:01:59 +00:00
fix: patch getDisplayMedia in desktop app
Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
parent
d158fa5a21
commit
351843da15
@ -19,11 +19,11 @@ import { workbenchId, logOut } from '@hcengineering/workbench'
|
||||
|
||||
import { isOwnerOrMaintainer } from '@hcengineering/core'
|
||||
import { configurePlatform } from './platform'
|
||||
import { defineScreenShare, defineScreenRecorder } from './screenShare'
|
||||
import { defineScreenShare, defineGetDisplayMedia } from './screenShare'
|
||||
import { IPCMainExposed } from './types'
|
||||
|
||||
defineScreenShare()
|
||||
defineScreenRecorder()
|
||||
defineGetDisplayMedia()
|
||||
|
||||
void configurePlatform().then(() => {
|
||||
createApp(document.body)
|
||||
|
@ -5,53 +5,56 @@ import { showPopup } from '@hcengineering/ui'
|
||||
import { Track, LocalTrack, LocalAudioTrack, LocalVideoTrack, ParticipantEvent, TrackInvalidError, ScreenShareCaptureOptions, DeviceUnsupportedError, ScreenSharePresets } from 'livekit-client'
|
||||
|
||||
import { IPCMainExposed } from './types'
|
||||
import { setMetadata } from '@hcengineering/platform'
|
||||
import recordPlugin from '@hcengineering/recorder'
|
||||
|
||||
export async function getMediaStream (opts?: DisplayMediaStreamOptions): Promise<MediaStream> {
|
||||
if (opts === undefined) {
|
||||
throw new Error('opts must be provided')
|
||||
}
|
||||
const ipcMain = (window as any).electron as IPCMainExposed
|
||||
const sources = await ipcMain.getScreenSources()
|
||||
|
||||
const hasAccess = await ipcMain.getScreenAccess()
|
||||
if (!hasAccess) {
|
||||
log.error('No screen access granted')
|
||||
throw new Error('No screen access granted')
|
||||
export function defineGetDisplayMedia (): void {
|
||||
if (navigator?.mediaDevices === undefined) {
|
||||
console.warn('mediaDevices API not available')
|
||||
return
|
||||
}
|
||||
|
||||
if (navigator.mediaDevices.getDisplayMedia === undefined) {
|
||||
throw new DeviceUnsupportedError('getDisplayMedia not supported')
|
||||
}
|
||||
return await new Promise<MediaStream>((resolve, reject) => {
|
||||
showPopup(
|
||||
love.component.SelectScreenSourcePopup,
|
||||
{
|
||||
sources
|
||||
},
|
||||
'top',
|
||||
() => {
|
||||
reject(new Error('No source selected'))
|
||||
},
|
||||
(val) => {
|
||||
if (val != null) {
|
||||
opts.video = {
|
||||
mandatory: {
|
||||
...(typeof opts.video === 'boolean' ? {} : opts.video),
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: val
|
||||
}
|
||||
} as any
|
||||
resolve(window.navigator.mediaDevices.getUserMedia(opts))
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
export function defineScreenRecorder (): void {
|
||||
setMetadata(recordPlugin.metadata.GetCustomMediaStream, getMediaStream)
|
||||
navigator.mediaDevices.getDisplayMedia = async (opts?: DisplayMediaStreamOptions): Promise<MediaStream> => {
|
||||
if (opts === undefined) {
|
||||
throw new Error('opts must be provided')
|
||||
}
|
||||
|
||||
const ipcMain = (window as any).electron as IPCMainExposed
|
||||
const sources = await ipcMain.getScreenSources()
|
||||
|
||||
const hasAccess = await ipcMain.getScreenAccess()
|
||||
if (!hasAccess) {
|
||||
log.error('No screen access granted')
|
||||
throw new Error('No screen access granted')
|
||||
}
|
||||
|
||||
return await new Promise<MediaStream>((resolve, reject) => {
|
||||
showPopup(
|
||||
love.component.SelectScreenSourcePopup,
|
||||
{
|
||||
sources
|
||||
},
|
||||
'top',
|
||||
() => {
|
||||
reject(new Error('No source selected'))
|
||||
},
|
||||
(val) => {
|
||||
if (val != null) {
|
||||
opts.video = {
|
||||
mandatory: {
|
||||
...(typeof opts.video === 'boolean' ? {} : opts.video),
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: val
|
||||
}
|
||||
} as any
|
||||
resolve(window.navigator.mediaDevices.getUserMedia(opts))
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function defineScreenShare (): void {
|
||||
|
@ -196,3 +196,14 @@ export async function getMicrophoneStream (
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export async function getDisplayMedia (constraints: MediaStreamConstraints): Promise<MediaStream> {
|
||||
if (
|
||||
navigator?.mediaDevices?.getDisplayMedia !== undefined &&
|
||||
typeof navigator.mediaDevices.getDisplayMedia === 'function'
|
||||
) {
|
||||
return await navigator.mediaDevices.getDisplayMedia(constraints)
|
||||
}
|
||||
|
||||
throw new Error('getDisplayMedia not supported')
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { getDisplayMedia } from '@hcengineering/media'
|
||||
import { getMetadata } from '@hcengineering/platform'
|
||||
import presentation from '@hcengineering/presentation'
|
||||
import { showPopup } from '@hcengineering/ui'
|
||||
@ -69,7 +70,7 @@ export async function startRecording (options: RecordingOptions): Promise<void>
|
||||
|
||||
let displayStream: MediaStream
|
||||
try {
|
||||
displayStream = await navigator.mediaDevices.getDisplayMedia({
|
||||
displayStream = await getDisplayMedia({
|
||||
video: {
|
||||
frameRate: { ideal: fps ?? 30 }
|
||||
}
|
||||
|
@ -21,11 +21,6 @@ import { type UploadHandler } from '@hcengineering/uploader'
|
||||
*/
|
||||
export const recorderId = 'recorder' as Plugin
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
export type GetMediaStream = (options?: DisplayMediaStreamOptions) => Promise<MediaStream>
|
||||
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
@ -34,8 +29,7 @@ const recordPlugin = plugin(recorderId, {
|
||||
Record: '' as Asset
|
||||
},
|
||||
metadata: {
|
||||
StreamUrl: '' as Metadata<string>,
|
||||
GetCustomMediaStream: '' as Metadata<GetMediaStream>
|
||||
StreamUrl: '' as Metadata<string>
|
||||
},
|
||||
space: {
|
||||
Drive: '' as Ref<Drive>
|
||||
|
Loading…
Reference in New Issue
Block a user