Compare commits

...

6 Commits

Author SHA1 Message Date
509485e173 3.0.8
All checks were successful
continuous-integration/drone/push Build is passing
2020-03-11 15:19:26 +01:00
e250443ca3 Add webrtc-adapter for compatibility
https://github.com/webrtcHacks/adapter

From MDN: https://developer.mozilla.org/en-US/docs/Web/API/Screen_Capture_API/Using_Screen_Capture

Note: It may be useful to note that recent versions of the WebRTC
adapter.js shim include implementations of getDisplayMedia() to enable
screen sharing on browsers that support it but do not implement the
current standard API. This works with at least Chrome, Edge, and
Firefox.
2020-03-11 15:18:28 +01:00
6b9c03eb84 3.0.7 2020-03-11 15:08:35 +01:00
9f1320a907 Add touchStart/touchEnd event handlers for video 2020-03-11 15:08:32 +01:00
d68ebdef79 3.0.6 2020-03-11 15:04:52 +01:00
a025fcad43 Add ability to toggle object-fit: cover on videos by long-pressing 2020-03-11 15:04:44 +01:00
7 changed files with 100 additions and 14 deletions

33
package-lock.json generated
View File

@ -1,6 +1,6 @@
{
"name": "peer-calls",
"version": "3.0.5",
"version": "3.0.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -4877,8 +4877,7 @@
},
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"resolved": "",
"dev": true
}
}
@ -14274,6 +14273,15 @@
"integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
"dev": true
},
"rtcpeerconnection-shim": {
"version": "1.2.15",
"resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz",
"integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==",
"dev": true,
"requires": {
"sdp": "^2.6.0"
}
},
"run-async": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz",
@ -14452,6 +14460,12 @@
}
}
},
"sdp": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz",
"integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw==",
"dev": true
},
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
@ -14805,8 +14819,7 @@
},
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"resolved": "",
"dev": true
}
}
@ -16325,6 +16338,16 @@
"integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==",
"dev": true
},
"webrtc-adapter": {
"version": "7.5.0",
"resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.5.0.tgz",
"integrity": "sha512-cUqlw310uLLSYvO8FTNCVmGWSMlMt6vuSDkcYL1nW+RUvAILJ3jEIvAUgFQU5EFGnU+mf9/No14BFv3U+hoxBQ==",
"dev": true,
"requires": {
"rtcpeerconnection-shim": "^1.2.15",
"sdp": "^2.12.0"
}
},
"whatwg-encoding": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz",

View File

@ -1,6 +1,6 @@
{
"name": "peer-calls",
"version": "3.0.5",
"version": "3.0.8",
"description": "Group peer to peer video calls for anybody.",
"repository": "https://github.com/jeremija/peer-calls",
"main": "lib/index.js",
@ -112,6 +112,7 @@
"ts-node": "^8.5.2",
"tsify": "^4.0.1",
"typescript": "^3.7.2",
"watchify": "^3.11.1"
"watchify": "^3.11.1",
"webrtc-adapter": "^7.5.0"
}
}

View File

@ -16,6 +16,7 @@ export interface VideoProps {
export default class Video extends React.PureComponent<VideoProps> {
videoRef = React.createRef<HTMLVideoElement>()
timeout?: number
static defaultProps = {
muted: false,
@ -23,8 +24,26 @@ export default class Video extends React.PureComponent<VideoProps> {
}
handleClick: ReactEventHandler<HTMLVideoElement> = e => {
const { onClick, userId } = this.props
this.props.play()
onClick(userId)
if (this.timeout) {
// if the timeout was cancelled, execute click
this.props.play()
onClick(userId)
}
this.timeout = undefined
}
handleMouseDown: ReactEventHandler<HTMLVideoElement> = e => {
clearTimeout(this.timeout)
this.timeout = window.setTimeout(this.toggleCover, 300)
}
handleMouseUp: ReactEventHandler<HTMLVideoElement> = e => {
clearTimeout(this.timeout)
}
toggleCover = () => {
this.timeout = undefined
const v = this.videoRef.current
if (v) {
v.style.objectFit = v.style.objectFit ? '' : 'cover'
}
}
componentDidMount () {
this.componentDidUpdate()
@ -52,6 +71,10 @@ export default class Video extends React.PureComponent<VideoProps> {
id={`video-${socket.id}`}
autoPlay
onClick={this.handleClick}
onMouseDown={this.handleMouseDown}
onTouchStart={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
onTouchEnd={this.handleMouseUp}
onLoadedMetadata={() => this.props.play()}
playsInline
ref={this.videoRef}

View File

@ -1,6 +1,7 @@
jest.mock('../actions/CallActions')
jest.mock('../socket')
jest.mock('../window')
jest.useFakeTimers()
import React from 'react'
import ReactDOM from 'react-dom'
@ -108,9 +109,14 @@ describe('App', () => {
})
describe('video', () => {
it('can be activated', () => {
beforeEach(() => {
dispatchSpy.mockReset()
})
it('can be activated', () => {
const video = node.querySelector('video')!
TestUtils.Simulate.mouseDown(video)
TestUtils.Simulate.mouseUp(video)
TestUtils.Simulate.click(video)
expect(dispatchSpy.mock.calls[0][0].type).toBe(constants.MEDIA_PLAY)
expect(dispatchSpy.mock.calls.slice(1)).toEqual([[{
@ -118,6 +124,18 @@ describe('App', () => {
payload: { userId: constants.ME + '_0' },
}]])
})
it('can toggle object-fit to/from cover by long-pressing', () => {
['cover', ''].forEach(objectFit => {
const video = node.querySelector('video')!
TestUtils.Simulate.mouseDown(video)
jest.runAllTimers()
TestUtils.Simulate.mouseUp(video)
TestUtils.Simulate.click(video)
expect(video.style.objectFit).toBe(objectFit)
expect(dispatchSpy.mock.calls.slice(1)).toEqual([])
})
})
})
})

View File

@ -1,4 +1,5 @@
import '@babel/polyfill'
import 'webrtc-adapter'
import App from './containers/App'
import React from 'react'
import ReactDOM from 'react-dom'

View File

@ -25,6 +25,10 @@
width: 100%;
height: 100%;
}
.video-actions {
display: none;
}
}
.video-container.active {
@ -43,6 +47,22 @@
video {
border-radius: 0;
cursor: inherit;
object-fit: contain;
}
.video-actions {
display: inherit;
position: absolute;
right: 0;
bottom: 0;
padding: 1rem;
font-family: monospace;
user-select: none;
.action:hover {
cursor: pointer;
color: white;
}
}
}

View File

@ -101,8 +101,8 @@ body.call {
}
input[type="text"] {
font-size: 1rem;
padding: 1rem 1rem 0.75rem;
font-size: 1.2rem;
padding: 1rem 0rem 0.75rem;
width: 100%;
margin-bottom: 1rem;
background: none;
@ -120,9 +120,9 @@ body.call {
}
input[type="submit"] {
// font-family: $font-monospace;
font-family: $font-monospace;
@include button($color-primary, $color-warning);
font-size: 1rem;
font-size: 1.2rem;
padding: 1rem 1rem;
}