mirror of
https://github.com/koush/scrypted.git
synced 2026-02-05 23:22:13 +00:00
Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
db03775530 | ||
|
|
cccbc33f1a | ||
|
|
5f23873366 | ||
|
|
e43accae67 | ||
|
|
b3a0cda6f9 | ||
|
|
58c3348282 | ||
|
|
a9e6d76e99 | ||
|
|
3b58936387 | ||
|
|
3a14ab81c8 | ||
|
|
291178a7b5 | ||
|
|
b65faf1a79 | ||
|
|
9d8a1353c0 | ||
|
|
b29d793178 | ||
|
|
d8e406d415 | ||
|
|
4529872fd6 | ||
|
|
fa86c31340 | ||
|
|
94ded75d40 | ||
|
|
887b61cd7a | ||
|
|
48e3d30987 | ||
|
|
02dba3cd71 | ||
|
|
195769034d | ||
|
|
39c08aa378 | ||
|
|
fa8056d38e | ||
|
|
145f116c68 | ||
|
|
15b6f336e4 | ||
|
|
8b46f0a466 | ||
|
|
a20cc5cd89 | ||
|
|
3d068929fd |
@@ -250,7 +250,8 @@ export class BrowserSignalingSession implements RTCSignalingSession {
|
||||
function logSendCandidate(console: Console, type: string, session: RTCSignalingSession): RTCSignalingSendIceCandidate {
|
||||
return async (candidate) => {
|
||||
try {
|
||||
console.log(`${type} trickled candidate:`, candidate.sdpMLineIndex, candidate.candidate);
|
||||
if (localStorage.getItem('debugLog') === 'true')
|
||||
console.log(`${type} trickled candidate:`, candidate.sdpMLineIndex, candidate.candidate);
|
||||
await session.addIceCandidate(candidate);
|
||||
}
|
||||
catch (e) {
|
||||
@@ -308,11 +309,13 @@ export async function connectRTCSignalingClients(
|
||||
|
||||
const offer = await offerClient.createLocalDescription('offer', offerSetup as RTCAVSignalingSetup,
|
||||
disableTrickle ? undefined : answerQueue.queueSendCandidate);
|
||||
console.log('offer sdp', offer.sdp);
|
||||
if (localStorage.getItem('debugLog') === 'true')
|
||||
console.log('offer sdp', offer.sdp);
|
||||
await answerClient.setRemoteDescription(offer, answerSetup as RTCAVSignalingSetup);
|
||||
const answer = await answerClient.createLocalDescription('answer', answerSetup as RTCAVSignalingSetup,
|
||||
disableTrickle ? undefined : offerQueue.queueSendCandidate);
|
||||
console.log('answer sdp', answer.sdp);
|
||||
if (localStorage.getItem('debugLog') === 'true')
|
||||
console.log('answer sdp', answer.sdp);
|
||||
await offerClient.setRemoteDescription(answer, offerSetup as RTCAVSignalingSetup);
|
||||
offerQueue.flush();
|
||||
answerQueue.flush();
|
||||
|
||||
@@ -129,6 +129,16 @@ export function getNaluTypes(streamChunk: StreamChunk) {
|
||||
return getNaluTypesInNalu(streamChunk.chunks[streamChunk.chunks.length - 1].subarray(12))
|
||||
}
|
||||
|
||||
export function getNaluFragmentInformation(nalu: Buffer) {
|
||||
const naluType = nalu[0] & 0x1f;
|
||||
const fua = naluType === H264_NAL_TYPE_FU_A;
|
||||
return {
|
||||
fua,
|
||||
fuaStart: fua && !!(nalu[1] & 0x80),
|
||||
fuaEnd: fua && !!(nalu[1] & 0x40),
|
||||
}
|
||||
}
|
||||
|
||||
export function getNaluTypesInNalu(nalu: Buffer, fuaRequireStart = false, fuaRequireEnd = false) {
|
||||
const ret = new Set<number>();
|
||||
const naluType = nalu[0] & 0x1f;
|
||||
|
||||
@@ -63,7 +63,7 @@ RUN apt-get -y install \
|
||||
# which causes weird behavior in python which looks at the arch version
|
||||
# which still reports 64bit, even if running in 32bit docker.
|
||||
# this scenario is not supported and will be reported at runtime.
|
||||
RUN if [ "$(uname -m)" = "armv7l" ]; \
|
||||
RUN if [ "$(uname -m)" != "x86_64" ]; \
|
||||
then \
|
||||
apt-get -y install \
|
||||
python3-matplotlib \
|
||||
@@ -95,7 +95,8 @@ ENV SCRYPTED_INSTALL_PATH="/server"
|
||||
|
||||
# changing this forces pip and npm to perform reinstalls.
|
||||
# if this base image changes, this version must be updated.
|
||||
ENV SCRYPTED_BASE_VERSION=20230322
|
||||
ENV SCRYPTED_BASE_VERSION=20230329
|
||||
ENV SCRYPTED_DOCKER_FLAVOR=full
|
||||
|
||||
################################################################
|
||||
# End section generated from template/Dockerfile.full.footer
|
||||
|
||||
@@ -42,4 +42,5 @@ ENV SCRYPTED_INSTALL_PATH="/server"
|
||||
|
||||
# changing this forces pip and npm to perform reinstalls.
|
||||
# if this base image changes, this version must be updated.
|
||||
ENV SCRYPTED_BASE_VERSION=20230322
|
||||
ENV SCRYPTED_BASE_VERSION=20230329
|
||||
ENV SCRYPTED_DOCKER_FLAVOR=lite
|
||||
|
||||
@@ -21,4 +21,5 @@ ENV SCRYPTED_INSTALL_PATH="/server"
|
||||
|
||||
# changing this forces pip and npm to perform reinstalls.
|
||||
# if this base image changes, this version must be updated.
|
||||
ENV SCRYPTED_BASE_VERSION=20230322
|
||||
ENV SCRYPTED_BASE_VERSION=20230329
|
||||
ENV SCRYPTED_DOCKER_FLAVOR=thin
|
||||
|
||||
@@ -42,7 +42,7 @@ fi
|
||||
WATCHTOWER_HTTP_API_TOKEN=$(echo $RANDOM | md5sum)
|
||||
DOCKER_COMPOSE_YML=$SCRYPTED_HOME/docker-compose.yml
|
||||
echo "Created $DOCKER_COMPOSE_YML"
|
||||
curl -s https://raw.githubusercontent.com/koush/scrypted/main/docker/docker-compose.yml | sed s/SET_THIS_TO_SOME_RANDOM_TEXT/"$(echo $RANDOM | md5sum)"/g > $DOCKER_COMPOSE_YML
|
||||
curl -s https://raw.githubusercontent.com/koush/scrypted/main/docker/docker-compose.yml | sed s/SET_THIS_TO_SOME_RANDOM_TEXT/"$(echo $RANDOM | md5sum | head -c 32)"/g > $DOCKER_COMPOSE_YML
|
||||
|
||||
echo "Setting permissions on $SCRYPTED_HOME"
|
||||
chown -R $SERVICE_USER $SCRYPTED_HOME
|
||||
|
||||
@@ -10,7 +10,8 @@ ENV SCRYPTED_INSTALL_PATH="/server"
|
||||
|
||||
# changing this forces pip and npm to perform reinstalls.
|
||||
# if this base image changes, this version must be updated.
|
||||
ENV SCRYPTED_BASE_VERSION=20230322
|
||||
ENV SCRYPTED_BASE_VERSION=20230329
|
||||
ENV SCRYPTED_DOCKER_FLAVOR=full
|
||||
|
||||
################################################################
|
||||
# End section generated from template/Dockerfile.full.footer
|
||||
|
||||
@@ -60,7 +60,7 @@ RUN apt-get -y install \
|
||||
# which causes weird behavior in python which looks at the arch version
|
||||
# which still reports 64bit, even if running in 32bit docker.
|
||||
# this scenario is not supported and will be reported at runtime.
|
||||
RUN if [ "$(uname -m)" = "armv7l" ]; \
|
||||
RUN if [ "$(uname -m)" != "x86_64" ]; \
|
||||
then \
|
||||
apt-get -y install \
|
||||
python3-matplotlib \
|
||||
|
||||
8
packages/client/package-lock.json
generated
8
packages/client/package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "1.1.43",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@scrypted/types": "^0.2.76",
|
||||
"@scrypted/types": "^0.2.78",
|
||||
"axios": "^0.25.0",
|
||||
"engine.io-client": "^6.4.0",
|
||||
"rimraf": "^3.0.2"
|
||||
@@ -21,9 +21,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@scrypted/types": {
|
||||
"version": "0.2.76",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.2.76.tgz",
|
||||
"integrity": "sha512-/7n8ICkXj8TGba4cHvckLCgSNsOmOGQ8I+Jd8fX9sxkthgsZhF5At8PHhHdkCDS+yfSmfXHkcqluZZOfYPkpAg=="
|
||||
"version": "0.2.78",
|
||||
"resolved": "https://registry.npmjs.org/@scrypted/types/-/types-0.2.78.tgz",
|
||||
"integrity": "sha512-SiIUh9ph96aZPjt/oO+W/mlJobrP02ADwFDI9jnvw8/UegUti2x/7JE8Pi3kGXOIkN+cX74Qg4xJEMIpdpO1zw=="
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.0",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"typescript": "^4.9.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"@scrypted/types": "^0.2.76",
|
||||
"@scrypted/types": "^0.2.78",
|
||||
"axios": "^0.25.0",
|
||||
"engine.io-client": "^6.4.0",
|
||||
"rimraf": "^3.0.2"
|
||||
|
||||
4
plugins/coreml/package-lock.json
generated
4
plugins/coreml/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/coreml",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.8",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/coreml",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.8",
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk"
|
||||
}
|
||||
|
||||
@@ -41,5 +41,5 @@
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk"
|
||||
},
|
||||
"version": "0.1.5"
|
||||
"version": "0.1.8"
|
||||
}
|
||||
|
||||
48
plugins/homekit/package-lock.json
generated
48
plugins/homekit/package-lock.json
generated
@@ -1,25 +1,25 @@
|
||||
{
|
||||
"name": "@scrypted/homekit",
|
||||
"version": "1.2.21",
|
||||
"version": "1.2.22",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/homekit",
|
||||
"version": "1.2.21",
|
||||
"version": "1.2.22",
|
||||
"dependencies": {
|
||||
"@koush/werift-src": "file:../../external/werift",
|
||||
"check-disk-space": "^3.3.1",
|
||||
"hap-nodejs": "^0.11.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mkdirp": "^2.1.5"
|
||||
"mkdirp": "^2.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "^18.15.5",
|
||||
"@types/lodash": "^4.14.192",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/url-parse": "^1.4.8"
|
||||
}
|
||||
},
|
||||
@@ -126,7 +126,7 @@
|
||||
},
|
||||
"../../sdk": {
|
||||
"name": "@scrypted/sdk",
|
||||
"version": "0.2.85",
|
||||
"version": "0.2.86",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
@@ -276,9 +276,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.191",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
|
||||
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
|
||||
"version": "4.14.192",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.192.tgz",
|
||||
"integrity": "sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/ms": {
|
||||
@@ -288,9 +288,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz",
|
||||
"integrity": "sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==",
|
||||
"version": "18.15.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
|
||||
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/url-parse": {
|
||||
@@ -856,9 +856,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mkdirp": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.5.tgz",
|
||||
"integrity": "sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w==",
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
|
||||
"integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==",
|
||||
"bin": {
|
||||
"mkdirp": "dist/cjs/src/bin.js"
|
||||
},
|
||||
@@ -1276,9 +1276,9 @@
|
||||
}
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.191",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.191.tgz",
|
||||
"integrity": "sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==",
|
||||
"version": "4.14.192",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.192.tgz",
|
||||
"integrity": "sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/ms": {
|
||||
@@ -1288,9 +1288,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "18.15.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.5.tgz",
|
||||
"integrity": "sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==",
|
||||
"version": "18.15.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
|
||||
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/url-parse": {
|
||||
@@ -1698,9 +1698,9 @@
|
||||
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="
|
||||
},
|
||||
"mkdirp": {
|
||||
"version": "2.1.5",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.5.tgz",
|
||||
"integrity": "sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w=="
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.6.tgz",
|
||||
"integrity": "sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A=="
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/homekit",
|
||||
"version": "1.2.21",
|
||||
"version": "1.2.22",
|
||||
"description": "HomeKit Plugin for Scrypted",
|
||||
"scripts": {
|
||||
"scrypted-setup-project": "scrypted-setup-project",
|
||||
@@ -38,14 +38,14 @@
|
||||
"check-disk-space": "^3.3.1",
|
||||
"hap-nodejs": "^0.11.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mkdirp": "^2.1.5"
|
||||
"mkdirp": "^2.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
"@types/debug": "^4.1.7",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "^18.15.5",
|
||||
"@types/lodash": "^4.14.192",
|
||||
"@types/node": "^18.15.11",
|
||||
"@types/url-parse": "^1.4.8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,13 +303,19 @@ addSupportedType({
|
||||
}
|
||||
}
|
||||
|
||||
// if the camera is a device provider, merge in child devices and
|
||||
// ensure the devices are skipped by the rest of homekit by
|
||||
// reporting that they've been merged
|
||||
if (device.interfaces.includes(ScryptedInterface.DeviceProvider)) {
|
||||
// merge in lights
|
||||
const { devices } = mergeOnOffDevicesByType(device as ScryptedDevice as ScryptedDevice & DeviceProvider, accessory, ScryptedDeviceType.Light);
|
||||
mergeOnOffDevicesByType(device as ScryptedDevice as ScryptedDevice & DeviceProvider, accessory, ScryptedDeviceType.Light).devices.forEach(device => {
|
||||
homekitPlugin.mergedDevices.add(device.id)
|
||||
});
|
||||
|
||||
// ensure child devices are skipped by the rest of homekit by
|
||||
// reporting that they've been merged
|
||||
devices.map(device => homekitPlugin.mergedDevices.add(device.id));
|
||||
// merge in sirens
|
||||
mergeOnOffDevicesByType(device as ScryptedDevice as ScryptedDevice & DeviceProvider, accessory, ScryptedDeviceType.Siren).devices.forEach(device => {
|
||||
homekitPlugin.mergedDevices.add(device.id)
|
||||
});
|
||||
}
|
||||
|
||||
return accessory;
|
||||
|
||||
@@ -64,6 +64,9 @@ export class H264Repacketizer {
|
||||
extraPackets = 0;
|
||||
fuaMax: number;
|
||||
pendingFuA: RtpPacket[];
|
||||
// log whether a stapa sps/pps has been seen.
|
||||
// resets on every idr frame, to trigger codec information
|
||||
// to be resent.
|
||||
seenStapASps = false;
|
||||
fuaMin: number;
|
||||
|
||||
@@ -402,8 +405,12 @@ export class H264Repacketizer {
|
||||
// if this is an idr frame, but no sps has been sent via a stapa, dummy one up.
|
||||
// the stream may not contain codec information in stapa or may be sending it
|
||||
// in separate sps/pps packets which is not supported by homekit.
|
||||
if (originalNalType === NAL_TYPE_IDR && !this.seenStapASps)
|
||||
this.maybeSendSpsPps(packet, ret);
|
||||
if (originalNalType === NAL_TYPE_IDR) {
|
||||
if (!this.seenStapASps)
|
||||
this.maybeSendSpsPps(packet, ret);
|
||||
this.seenStapASps = false;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
if (this.pendingFuA) {
|
||||
@@ -486,10 +493,12 @@ export class H264Repacketizer {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nalType === NAL_TYPE_IDR && !this.seenStapASps) {
|
||||
if (nalType === NAL_TYPE_IDR) {
|
||||
// if this is an idr frame, but no sps has been sent, dummy one up.
|
||||
// the stream may not contain sps.
|
||||
this.maybeSendSpsPps(packet, ret);
|
||||
if (!this.seenStapASps)
|
||||
this.maybeSendSpsPps(packet, ret);
|
||||
this.seenStapASps = false;
|
||||
}
|
||||
|
||||
this.fragment(packet, ret);
|
||||
|
||||
@@ -9,7 +9,7 @@ export function probe(device: DummyDevice): boolean {
|
||||
}
|
||||
|
||||
export function getService(device: ScryptedDevice & OnOff, accessory: Accessory, serviceType: any): Service {
|
||||
const service = accessory.addService(serviceType, device.name);
|
||||
const service = accessory.addService(serviceType, device.name, device.nativeId);
|
||||
service.getCharacteristic(Characteristic.On)
|
||||
.on(CharacteristicEventTypes.SET, (value: CharacteristicValue, callback: CharacteristicSetCallback) => {
|
||||
callback();
|
||||
|
||||
4
plugins/objectdetector/package-lock.json
generated
4
plugins/objectdetector/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/objectdetector",
|
||||
"version": "0.0.119",
|
||||
"version": "0.0.121",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/objectdetector",
|
||||
"version": "0.0.119",
|
||||
"version": "0.0.121",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/objectdetector",
|
||||
"version": "0.0.119",
|
||||
"version": "0.0.121",
|
||||
"description": "Scrypted Video Analysis Plugin. Installed alongside a detection service like OpenCV or TensorFlow.",
|
||||
"author": "Scrypted",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
import { Deferred } from "@scrypted/common/src/deferred";
|
||||
import { addVideoFilterArguments } from "@scrypted/common/src/ffmpeg-helpers";
|
||||
import { ffmpegLogInitialOutput, safeKillFFmpeg, safePrintFFmpegArguments } from "@scrypted/common/src/media-helpers";
|
||||
import { readLength, readLine } from "@scrypted/common/src/read-stream";
|
||||
import { addVideoFilterArguments } from "@scrypted/common/src/ffmpeg-helpers";
|
||||
import sdk, { FFmpegInput, Image, ImageOptions, MediaObject, ScryptedDeviceBase, ScryptedMimeTypes, VideoFrame, VideoFrameGenerator, VideoFrameGeneratorOptions } from "@scrypted/sdk";
|
||||
import child_process from 'child_process';
|
||||
import sharp from 'sharp';
|
||||
import type sharp from 'sharp';
|
||||
import { Readable } from 'stream';
|
||||
|
||||
export let sharpLib: (input?:
|
||||
| Buffer
|
||||
| Uint8Array
|
||||
| Uint8ClampedArray
|
||||
| Int8Array
|
||||
| Uint16Array
|
||||
| Int16Array
|
||||
| Uint32Array
|
||||
| Int32Array
|
||||
| Float32Array
|
||||
| Float64Array
|
||||
| string,
|
||||
options?: sharp.SharpOptions) => sharp.Sharp;
|
||||
try {
|
||||
sharpLib = require('sharp');
|
||||
}
|
||||
catch (e) {
|
||||
console.warn('Sharp failed to load. FFmpeg Frame Generator will not function properly.')
|
||||
}
|
||||
|
||||
async function createVipsMediaObject(image: VipsImage): Promise<VideoFrame & MediaObject> {
|
||||
const ret = await sdk.mediaManager.createMediaObject(image, ScryptedMimeTypes.Image, {
|
||||
format: null,
|
||||
@@ -76,7 +96,20 @@ class VipsImage implements Image {
|
||||
resolveWithObject: true,
|
||||
});
|
||||
|
||||
const newImage = sharp(data, {
|
||||
const sharpLib = require('sharp') as (input?:
|
||||
| Buffer
|
||||
| Uint8Array
|
||||
| Uint8ClampedArray
|
||||
| Int8Array
|
||||
| Uint16Array
|
||||
| Int16Array
|
||||
| Uint32Array
|
||||
| Int32Array
|
||||
| Float32Array
|
||||
| Float64Array
|
||||
| string,
|
||||
options?) => sharp.Sharp;
|
||||
const newImage = sharpLib(data, {
|
||||
raw: info,
|
||||
});
|
||||
|
||||
@@ -177,7 +210,7 @@ export class FFmpegVideoFrameGenerator extends ScryptedDeviceBase implements Vid
|
||||
const raw = await frameDeferred.promise;
|
||||
const { width, height, data } = raw;
|
||||
|
||||
const image = sharp(data, {
|
||||
const image = sharpLib(data, {
|
||||
raw: {
|
||||
width,
|
||||
height,
|
||||
|
||||
@@ -4,7 +4,7 @@ import crypto from 'crypto';
|
||||
import { AutoenableMixinProvider } from "../../../common/src/autoenable-mixin-provider";
|
||||
import { SettingsMixinDeviceBase } from "../../../common/src/settings-mixin";
|
||||
import { DenoisedDetectionState } from './denoise';
|
||||
import { FFmpegVideoFrameGenerator } from './ffmpeg-videoframes';
|
||||
import { FFmpegVideoFrameGenerator, sharpLib } from './ffmpeg-videoframes';
|
||||
import { serverSupportsMixinEventMasking } from './server-version';
|
||||
import { sleep } from './sleep';
|
||||
import { getAllDevices, safeParseJson } from './util';
|
||||
@@ -201,7 +201,6 @@ class ObjectDetectionMixin extends SettingsMixinDeviceBase<VideoCamera & Camera
|
||||
if (this.hasMotionType)
|
||||
this.motionDetected = false;
|
||||
|
||||
this.detectorRunning = false;
|
||||
this.endObjectDetection();
|
||||
|
||||
this.maybeStartMotionDetection();
|
||||
@@ -333,8 +332,7 @@ class ObjectDetectionMixin extends SettingsMixinDeviceBase<VideoCamera & Camera
|
||||
if (!this.detectorRunning) {
|
||||
break;
|
||||
}
|
||||
const now = Date.now();
|
||||
if (now > this.analyzeStop) {
|
||||
if (!this.hasMotionType && Date.now() > this.analyzeStop) {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -820,9 +818,9 @@ class ObjectDetectionPlugin extends AutoenableMixinProvider implements Settings,
|
||||
{
|
||||
name: 'FFmpeg Frame Generator',
|
||||
type: ScryptedDeviceType.Builtin,
|
||||
interfaces: [
|
||||
interfaces: sharpLib ? [
|
||||
ScryptedInterface.VideoFrameGenerator,
|
||||
],
|
||||
] : [],
|
||||
nativeId: 'ffmpeg',
|
||||
}
|
||||
]
|
||||
|
||||
4
plugins/opencv/package-lock.json
generated
4
plugins/opencv/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/opencv",
|
||||
"version": "0.0.70",
|
||||
"version": "0.0.74",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/opencv",
|
||||
"version": "0.0.70",
|
||||
"version": "0.0.74",
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk"
|
||||
}
|
||||
|
||||
@@ -36,5 +36,5 @@
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk"
|
||||
},
|
||||
"version": "0.0.70"
|
||||
"version": "0.0.74"
|
||||
}
|
||||
|
||||
@@ -1,22 +1,46 @@
|
||||
from __future__ import annotations
|
||||
from time import sleep
|
||||
from detect import DetectionSession, DetectPlugin
|
||||
from typing import Any, List, Tuple
|
||||
import numpy as np
|
||||
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
from typing import Any, List, Tuple
|
||||
|
||||
import cv2
|
||||
import imutils
|
||||
Gst = None
|
||||
try:
|
||||
from gi.repository import Gst
|
||||
except:
|
||||
pass
|
||||
from scrypted_sdk.types import ObjectDetectionModel, ObjectDetectionResult, ObjectsDetected, Setting, VideoFrame
|
||||
import numpy as np
|
||||
import scrypted_sdk
|
||||
from PIL import Image
|
||||
from scrypted_sdk.types import (ObjectDetectionGeneratorSession,
|
||||
ObjectDetectionResult, ObjectsDetected,
|
||||
Setting, VideoFrame)
|
||||
|
||||
class OpenCVDetectionSession(DetectionSession):
|
||||
from detect import DetectPlugin
|
||||
|
||||
# vips is already multithreaded, but needs to be kicked off the python asyncio thread.
|
||||
toThreadExecutor = concurrent.futures.ThreadPoolExecutor(max_workers=2, thread_name_prefix="image")
|
||||
|
||||
async def to_thread(f):
|
||||
loop = asyncio.get_running_loop()
|
||||
return await loop.run_in_executor(toThreadExecutor, f)
|
||||
|
||||
async def ensureGrayData(data: bytes, size: Tuple[int, int], format: str):
|
||||
if format == 'gray':
|
||||
return data
|
||||
|
||||
def convert():
|
||||
if format == 'rgba':
|
||||
image = Image.frombuffer('RGBA', size, data)
|
||||
else:
|
||||
image = Image.frombuffer('RGB', size, data)
|
||||
|
||||
try:
|
||||
return image.convert('L').tobytes()
|
||||
finally:
|
||||
image.close()
|
||||
return await to_thread(convert)
|
||||
|
||||
|
||||
class OpenCVDetectionSession:
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.cap: cv2.VideoCapture = None
|
||||
self.previous_frame: Any = None
|
||||
self.curFrame = None
|
||||
@@ -35,21 +59,6 @@ defaultBlur = 5
|
||||
class OpenCVPlugin(DetectPlugin):
|
||||
def __init__(self, nativeId: str | None = None):
|
||||
super().__init__(nativeId=nativeId)
|
||||
self.color2Gray = None
|
||||
self.pixelFormat = "I420"
|
||||
self.pixelFormatChannelCount = 1
|
||||
|
||||
if True:
|
||||
self.retainAspectRatio = False
|
||||
self.color2Gray = None
|
||||
self.pixelFormat = "I420"
|
||||
self.pixelFormatChannelCount = 1
|
||||
else:
|
||||
self.retainAspectRatio = True
|
||||
self.color2Gray = cv2.COLOR_BGRA2GRAY
|
||||
self.pixelFormat = "BGRA"
|
||||
self.pixelFormatChannelCount = 4
|
||||
|
||||
|
||||
def getClasses(self) -> list[str]:
|
||||
return ['motion']
|
||||
@@ -91,9 +100,6 @@ class OpenCVPlugin(DetectPlugin):
|
||||
]
|
||||
|
||||
return settings
|
||||
|
||||
def get_pixel_format(self):
|
||||
return self.pixelFormat
|
||||
|
||||
def get_input_format(self) -> str:
|
||||
return 'gray'
|
||||
@@ -110,17 +116,10 @@ class OpenCVPlugin(DetectPlugin):
|
||||
blur = int(settings.get('blur', blur))
|
||||
return area, threshold, interval, blur
|
||||
|
||||
def detect(self, detection_session: OpenCVDetectionSession, frame, src_size, convert_to_src_size) -> ObjectsDetected:
|
||||
settings = detection_session.settings
|
||||
def detect(self, frame, settings: Any, detection_session: OpenCVDetectionSession, src_size, convert_to_src_size) -> ObjectsDetected:
|
||||
area, threshold, interval, blur = self.parse_settings(settings)
|
||||
|
||||
# see get_detection_input_size on undocumented size requirements for GRAY8
|
||||
if self.color2Gray != None:
|
||||
detection_session.gray = cv2.cvtColor(
|
||||
frame, self.color2Gray, dst=detection_session.gray)
|
||||
gray = detection_session.gray
|
||||
else:
|
||||
gray = frame
|
||||
gray = frame
|
||||
detection_session.curFrame = cv2.GaussianBlur(
|
||||
gray, (blur, blur), 0, dst=detection_session.curFrame)
|
||||
|
||||
@@ -154,8 +153,8 @@ class OpenCVPlugin(DetectPlugin):
|
||||
# if w * h != contour_area:
|
||||
# print("mismatch w/h", contour_area - w * h)
|
||||
|
||||
x2, y2, _ = convert_to_src_size((x + w, y + h))
|
||||
x, y, _ = convert_to_src_size((x, y))
|
||||
x2, y2 = convert_to_src_size((x + w, y + h))
|
||||
x, y = convert_to_src_size((x, y))
|
||||
w = x2 - x + 1
|
||||
h = y2 - y + 1
|
||||
|
||||
@@ -206,11 +205,24 @@ class OpenCVPlugin(DetectPlugin):
|
||||
detection_session.cap = None
|
||||
return super().end_session(detection_session)
|
||||
|
||||
async def run_detection_image(self, detection_session: DetectionSession, image: Image.Image, settings: Any, src_size, convert_to_src_size) -> Tuple[ObjectsDetected, Any]:
|
||||
# todo
|
||||
raise Exception('can not run motion detection on image')
|
||||
|
||||
async def run_detection_videoframe(self, videoFrame: VideoFrame, detection_session: OpenCVDetectionSession) -> ObjectsDetected:
|
||||
async def generateObjectDetections(self, videoFrames: Any, session: ObjectDetectionGeneratorSession = None) -> Any:
|
||||
try:
|
||||
ds = OpenCVDetectionSession()
|
||||
videoFrames = await scrypted_sdk.sdk.connectRPCObject(videoFrames)
|
||||
async for videoFrame in videoFrames:
|
||||
detected = await self.run_detection_videoframe(videoFrame, session and session.get('settings'), ds)
|
||||
yield {
|
||||
'__json_copy_serialize_children': True,
|
||||
'detected': detected,
|
||||
'videoFrame': videoFrame,
|
||||
}
|
||||
finally:
|
||||
try:
|
||||
await videoFrames.aclose()
|
||||
except:
|
||||
pass
|
||||
|
||||
async def run_detection_videoframe(self, videoFrame: VideoFrame, settings: Any, detection_session: OpenCVDetectionSession) -> ObjectsDetected:
|
||||
width = videoFrame.width
|
||||
height = videoFrame.height
|
||||
|
||||
@@ -234,64 +246,26 @@ class OpenCVPlugin(DetectPlugin):
|
||||
'height': height,
|
||||
}
|
||||
|
||||
format = videoFrame.format or 'gray'
|
||||
buffer = await videoFrame.toBuffer({
|
||||
'resize': resize,
|
||||
'format': format,
|
||||
})
|
||||
|
||||
def convert_to_src_size(point, normalize = False):
|
||||
return point[0] * scale, point[1] * scale, True
|
||||
mat = np.ndarray((height, width, self.pixelFormatChannelCount), buffer=buffer, dtype=np.uint8)
|
||||
detections = self.detect(
|
||||
detection_session, mat, (width, height), convert_to_src_size)
|
||||
return detections
|
||||
|
||||
async def run_detection_avframe(self, detection_session: DetectionSession, avframe, settings: Any, src_size, convert_to_src_size) -> Tuple[ObjectsDetected, Any]:
|
||||
if avframe.format.name != 'yuv420p' and avframe.format.name != 'yuvj420p':
|
||||
mat = avframe.to_ndarray(format='gray8')
|
||||
if format == 'gray':
|
||||
expectedLength = width * height
|
||||
# check if resize could not be completed
|
||||
if expectedLength != len(buffer):
|
||||
image = Image.frombuffer('L', (videoFrame.width, videoFrame.height), buffer)
|
||||
try:
|
||||
buffer = image.resize((width, height), Image.BILINEAR).tobytes()
|
||||
finally:
|
||||
image.close()
|
||||
else:
|
||||
mat = np.ndarray((avframe.height, avframe.width, self.pixelFormatChannelCount), buffer=avframe.planes[0], dtype=np.uint8)
|
||||
detections = self.detect(
|
||||
detection_session, mat, src_size, convert_to_src_size)
|
||||
if not detections or not len(detections['detections']):
|
||||
await self.detection_sleep(settings)
|
||||
return None, None
|
||||
return detections, None
|
||||
buffer = await ensureGrayData(buffer, (width, height), format)
|
||||
|
||||
async def run_detection_gstsample(self, detection_session: OpenCVDetectionSession, gst_sample, settings: Any, src_size, convert_to_src_size) -> ObjectsDetected:
|
||||
buf = gst_sample.get_buffer()
|
||||
caps = gst_sample.get_caps()
|
||||
# can't trust the width value, compute the stride
|
||||
height = caps.get_structure(0).get_value('height')
|
||||
width = caps.get_structure(0).get_value('width')
|
||||
result, info = buf.map(Gst.MapFlags.READ)
|
||||
if not result:
|
||||
return None, None
|
||||
try:
|
||||
mat = np.ndarray(
|
||||
(height,
|
||||
width,
|
||||
self.pixelFormatChannelCount),
|
||||
buffer=info.data,
|
||||
dtype=np.uint8)
|
||||
detections = self.detect(
|
||||
detection_session, mat, src_size, convert_to_src_size)
|
||||
# no point in triggering empty events.
|
||||
finally:
|
||||
buf.unmap(info)
|
||||
|
||||
if not detections or not len(detections['detections']):
|
||||
await self.detection_sleep(settings)
|
||||
return None, None
|
||||
return detections, None
|
||||
|
||||
def create_detection_session(self):
|
||||
return OpenCVDetectionSession()
|
||||
|
||||
async def detection_sleep(self, settings: Any):
|
||||
area, threshold, interval, blur = self.parse_settings(settings)
|
||||
# it is safe to block here because gstreamer creates a queue thread
|
||||
await asyncio.sleep(interval / 1000)
|
||||
|
||||
async def detection_event_notified(self, settings: Any):
|
||||
await self.detection_sleep(settings)
|
||||
return await super().detection_event_notified(settings)
|
||||
def convert_to_src_size(point):
|
||||
return point[0] * scale, point[1] * scale
|
||||
mat = np.ndarray((height, width, 1), buffer=buffer, dtype=np.uint8)
|
||||
detections = self.detect(mat, settings, detection_session, (videoFrame.width, videoFrame.height), convert_to_src_size)
|
||||
return detections
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../tensorflow-lite/src/pipeline
|
||||
@@ -3,10 +3,6 @@ numpy>=1.16.2
|
||||
# pillow for anything not intel linux
|
||||
Pillow>=5.4.1; sys_platform != 'linux' or platform_machine != 'x86_64'
|
||||
pillow-simd; sys_platform == 'linux' and platform_machine == 'x86_64'
|
||||
PyGObject>=3.30.4; sys_platform != 'win32'
|
||||
imutils>=0.5.0
|
||||
# not available on armhf
|
||||
av>=10.0.0; sys_platform != 'linux' or platform_machine == 'x86_64' or platform_machine == 'aarch64'
|
||||
# not available on armhf
|
||||
opencv-python; sys_platform != 'linux' or platform_machine == 'x86_64' or platform_machine == 'aarch64'
|
||||
|
||||
opencv-python; sys_platform != 'linux' or platform_machine == 'x86_64'
|
||||
|
||||
4
plugins/python-codecs/package-lock.json
generated
4
plugins/python-codecs/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/python-codecs",
|
||||
"version": "0.1.25",
|
||||
"version": "0.1.27",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/python-codecs",
|
||||
"version": "0.1.25",
|
||||
"version": "0.1.27",
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/python-codecs",
|
||||
"version": "0.1.25",
|
||||
"version": "0.1.27",
|
||||
"description": "Python Codecs for Scrypted",
|
||||
"keywords": [
|
||||
"scrypted",
|
||||
|
||||
@@ -37,7 +37,8 @@ class PILImage(scrypted_sdk.VideoFrame):
|
||||
|
||||
def save():
|
||||
bytesArray = io.BytesIO()
|
||||
pilImage.pilImage.save(bytesArray, format=options['format'])
|
||||
pilImage.pilImage.save(bytesArray, format='JPEG')
|
||||
# pilImage.pilImage.save(bytesArray, format=options['format'])
|
||||
return bytesArray.getvalue()
|
||||
|
||||
return await to_thread(lambda: save())
|
||||
|
||||
@@ -31,6 +31,10 @@ class VipsImage(scrypted_sdk.VideoFrame):
|
||||
mem = memoryview(rgb.write_to_memory())
|
||||
return mem
|
||||
return await to_thread(format)
|
||||
elif options['format'] == 'gray':
|
||||
def format():
|
||||
return memoryview(vipsImage.vipsImage.write_to_memory())
|
||||
return await to_thread(format)
|
||||
|
||||
return await to_thread(lambda: vipsImage.vipsImage.write_to_buffer('.' + options['format']))
|
||||
|
||||
|
||||
2
plugins/ring/.vscode/settings.json
vendored
2
plugins/ring/.vscode/settings.json
vendored
@@ -1,4 +1,4 @@
|
||||
|
||||
{
|
||||
"scrypted.debugHost": "koushik-ubuntu",
|
||||
"scrypted.debugHost": "127.0.0.1",
|
||||
}
|
||||
4
plugins/ring/package-lock.json
generated
4
plugins/ring/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/ring",
|
||||
"version": "0.0.106",
|
||||
"version": "0.0.107",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/ring",
|
||||
"version": "0.0.106",
|
||||
"version": "0.0.107",
|
||||
"dependencies": {
|
||||
"@koush/ring-client-api": "file:../../external/ring-client-api",
|
||||
"@scrypted/common": "file:../../common",
|
||||
|
||||
@@ -44,5 +44,5 @@
|
||||
"got": "11.8.6",
|
||||
"socket.io-client": "^2.5.0"
|
||||
},
|
||||
"version": "0.0.106"
|
||||
"version": "0.0.107"
|
||||
}
|
||||
|
||||
@@ -702,7 +702,6 @@ export class RingCameraDevice extends ScryptedDeviceBase implements DeviceProvid
|
||||
}
|
||||
|
||||
async getVideoClips(options?: VideoClipOptions): Promise<VideoClip[]> {
|
||||
this.videoClips = new Map<string, VideoClip>;
|
||||
const response = await this.camera.videoSearch({
|
||||
dateFrom: options.startTime,
|
||||
dateTo: options.endTime,
|
||||
|
||||
Submodule plugins/sample-cameraprovider updated: 24ee252e63...3b0721d898
@@ -75,6 +75,3 @@ class DetectPlugin(scrypted_sdk.ScryptedDeviceBase, ObjectDetection):
|
||||
vf = await scrypted_sdk.mediaManager.convertMediaObjectToBuffer(mediaObject, ScryptedMimeTypes.Image.value)
|
||||
|
||||
return await self.run_detection_videoframe(vf, session)
|
||||
|
||||
def get_pixel_format(self):
|
||||
return 'RGB'
|
||||
|
||||
4
plugins/tensorflow/package-lock.json
generated
4
plugins/tensorflow/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/tensorflow-lite",
|
||||
"version": "0.1.7",
|
||||
"version": "0.1.8",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/tensorflow-lite",
|
||||
"version": "0.1.7",
|
||||
"version": "0.1.8",
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk"
|
||||
}
|
||||
|
||||
@@ -41,5 +41,5 @@
|
||||
"devDependencies": {
|
||||
"@scrypted/sdk": "file:../../sdk"
|
||||
},
|
||||
"version": "0.1.7"
|
||||
"version": "0.1.8"
|
||||
}
|
||||
|
||||
4
plugins/webrtc/package-lock.json
generated
4
plugins/webrtc/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/webrtc",
|
||||
"version": "0.1.37",
|
||||
"version": "0.1.39",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/webrtc",
|
||||
"version": "0.1.37",
|
||||
"version": "0.1.39",
|
||||
"dependencies": {
|
||||
"@scrypted/common": "file:../../common",
|
||||
"@scrypted/sdk": "file:../../sdk",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/webrtc",
|
||||
"version": "0.1.37",
|
||||
"version": "0.1.39",
|
||||
"scripts": {
|
||||
"scrypted-setup-project": "scrypted-setup-project",
|
||||
"prescrypted-setup-project": "scrypted-package-json",
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Deferred } from "@scrypted/common/src/deferred";
|
||||
import sdk, { FFmpegInput, FFmpegTranscodeStream, Intercom, MediaObject, MediaStreamDestination, MediaStreamFeedback, RequestMediaStream, RTCAVSignalingSetup, RTCConnectionManagement, RTCMediaObjectTrack, RTCSignalingOptions, RTCSignalingSession, ScryptedDevice, ScryptedMimeTypes } from "@scrypted/sdk";
|
||||
import { ScryptedSessionControl } from "./session-control";
|
||||
import { requiredAudioCodecs, requiredVideoCodec } from "./webrtc-required-codecs";
|
||||
import { logIsPrivateIceTransport } from "./werift-util";
|
||||
import { isPrivateIceTransport, logIsPrivateIceTransport } from "./werift-util";
|
||||
|
||||
import { addVideoFilterArguments } from "@scrypted/common/src/ffmpeg-helpers";
|
||||
import { connectRTCSignalingClients } from "@scrypted/common/src/rtc-signaling";
|
||||
@@ -431,10 +431,6 @@ export class WebRTCConnectionManagement implements RTCConnectionManagement {
|
||||
waitConnected(this.pc)
|
||||
.then(() => logIsPrivateIceTransport(this.console, this.pc)).catch(() => {});
|
||||
|
||||
this.pc.signalingStateChange.subscribe(() => {
|
||||
this.console.log('sig change', this.pc.signalingState);
|
||||
})
|
||||
|
||||
this.weriftSignalingSession = new WeriftSignalingSession(console, this.pc);
|
||||
}
|
||||
|
||||
@@ -469,7 +465,7 @@ export class WebRTCConnectionManagement implements RTCConnectionManagement {
|
||||
createTrackForwarder: async (videoTransceiver: RTCRtpTransceiver, audioTransceiver: RTCRtpTransceiver) => {
|
||||
const ret = await createTrackForwarder({
|
||||
timeStart,
|
||||
...logIsPrivateIceTransport(console, this.pc),
|
||||
...isPrivateIceTransport(this.pc),
|
||||
requestMediaStream,
|
||||
videoTransceiver,
|
||||
audioTransceiver,
|
||||
@@ -582,7 +578,7 @@ export async function createRTCPeerConnectionSink(
|
||||
clientOffer = true,
|
||||
) {
|
||||
const clientOptions = await clientSignalingSession.getOptions();
|
||||
console.log('remote options', clientOptions);
|
||||
// console.log('remote options', clientOptions);
|
||||
|
||||
const connection = new WebRTCConnectionManagement(console, clientSignalingSession, maximumCompatibilityMode, clientOptions, {
|
||||
configuration,
|
||||
|
||||
@@ -223,6 +223,10 @@ export class WebRTCPlugin extends AutoenableMixinProvider implements DeviceCreat
|
||||
type: 'textarea',
|
||||
description: "RTCConfiguration that can be used to specify custom TURN and STUN servers. https://gist.github.com/koush/631d38ac8647a86baaac7b22d863f010",
|
||||
},
|
||||
debugLog: {
|
||||
title: 'Debug Log',
|
||||
type: 'boolean',
|
||||
}
|
||||
});
|
||||
bridge: WebRTCBridge;
|
||||
activeConnections = 0;
|
||||
|
||||
@@ -42,20 +42,15 @@ export function getWeriftIceServers(configuration: RTCConfiguration): RTCIceServ
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function logIsPrivateIceTransport(console: Console, pc: RTCPeerConnection) {
|
||||
export function isPrivateIceTransport(pc: RTCPeerConnection) {
|
||||
let isPrivate = true;
|
||||
let destinationId: string;
|
||||
for (const ice of pc.iceTransports) {
|
||||
const [address, port] = (ice.connection as any).nominated[1].remoteAddr;
|
||||
if (!destinationId)
|
||||
destinationId = address;
|
||||
const { turnServer } = ice.connection;
|
||||
isPrivate = isPrivate && ip.isPrivate(address);
|
||||
console.log('ice transport ip', {
|
||||
address,
|
||||
port,
|
||||
turnServer: !!turnServer,
|
||||
});
|
||||
|
||||
}
|
||||
console.log('Connection is local network:', isPrivate);
|
||||
const ipv4 = ip.isV4Format(destinationId);
|
||||
@@ -65,3 +60,10 @@ export function logIsPrivateIceTransport(console: Console, pc: RTCPeerConnection
|
||||
destinationId,
|
||||
};
|
||||
}
|
||||
|
||||
export function logIsPrivateIceTransport(console: Console, pc: RTCPeerConnection) {
|
||||
const ret = isPrivateIceTransport(pc);
|
||||
console.log('ice transport', ret);
|
||||
console.log('Connection is local network:', ret.isPrivate);
|
||||
return ret;
|
||||
}
|
||||
|
||||
4
sdk/package-lock.json
generated
4
sdk/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/sdk",
|
||||
"version": "0.2.85",
|
||||
"version": "0.2.86",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/sdk",
|
||||
"version": "0.2.85",
|
||||
"version": "0.2.86",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/sdk",
|
||||
"version": "0.2.85",
|
||||
"version": "0.2.86",
|
||||
"description": "",
|
||||
"main": "dist/src/index.js",
|
||||
"exports": {
|
||||
|
||||
4
sdk/types/package-lock.json
generated
4
sdk/types/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/types",
|
||||
"version": "0.2.77",
|
||||
"version": "0.2.78",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/types",
|
||||
"version": "0.2.77",
|
||||
"version": "0.2.78",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@types/rimraf": "^3.0.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/types",
|
||||
"version": "0.2.77",
|
||||
"version": "0.2.78",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"author": "",
|
||||
|
||||
4
server/package-lock.json
generated
4
server/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@scrypted/server",
|
||||
"version": "0.7.37",
|
||||
"version": "0.7.41",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@scrypted/server",
|
||||
"version": "0.7.37",
|
||||
"version": "0.7.41",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@mapbox/node-pre-gyp": "^1.0.10",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@scrypted/server",
|
||||
"version": "0.7.38",
|
||||
"version": "0.7.42",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"@mapbox/node-pre-gyp": "^1.0.10",
|
||||
|
||||
@@ -384,10 +384,9 @@ class PluginRemote:
|
||||
if platform.machine() == 'aarch64' and platform.architecture()[0] == '32bit':
|
||||
print('=============================================')
|
||||
print('Python machine vs architecture mismatch detected. Plugin installation may fail.')
|
||||
print('If Scrypted is running in docker, the docker version may be 32bit while the host kernel is 64bit.')
|
||||
print('This may be resolved by reinstalling a 64bit docker.')
|
||||
print('The docker architecture can be checked with the command: "file $(which docker)"')
|
||||
print('The host architecture can be checked with: "uname -m"')
|
||||
print('This issue occurs if a 32bit system was upgraded to a 64bit kernel.')
|
||||
print('Reverting to the 32bit kernel (or reflashing as native 64 bit is recommended.')
|
||||
print('https://github.com/koush/scrypted/issues/678')
|
||||
print('=============================================')
|
||||
|
||||
python_version = 'python%s' % str(
|
||||
@@ -423,7 +422,18 @@ class PluginRemote:
|
||||
pass
|
||||
|
||||
if need_pip:
|
||||
shutil.rmtree(python_prefix)
|
||||
try:
|
||||
for de in os.listdir(plugin_volume):
|
||||
if de.startswith('linux') or de.startswith('darwin') or de.startswith('win32') or de.startswith('python') or de.startswith('node'):
|
||||
filePath = os.path.join(plugin_volume, de)
|
||||
print('Removing old dependencies: %s' % filePath)
|
||||
try:
|
||||
shutil.rmtree(filePath)
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
|
||||
os.makedirs(python_prefix)
|
||||
|
||||
print('requirements.txt (outdated)')
|
||||
|
||||
@@ -311,7 +311,9 @@ export class PluginHost {
|
||||
|
||||
this.worker.stdout.on('data', data => console.log(data.toString()));
|
||||
this.worker.stderr.on('data', data => console.error(data.toString()));
|
||||
const consoleHeader = `${os.platform()} ${os.arch()} ${os.version()}\nserver version: ${serverVersion}\nplugin version: ${this.pluginId} ${this.packageJson.version}\n`;
|
||||
let consoleHeader = `${os.platform()} ${os.arch()} ${os.version()}\nserver version: ${serverVersion}\nplugin version: ${this.pluginId} ${this.packageJson.version}\n`;
|
||||
if (process.env.SCRYPTED_DOCKER_FLAVOR)
|
||||
consoleHeader += `${process.env.SCRYPTED_DOCKER_FLAVOR}\n`;
|
||||
this.consoleServer = createConsoleServer(this.worker.stdout, this.worker.stderr, consoleHeader);
|
||||
|
||||
const disconnect = () => {
|
||||
|
||||
Reference in New Issue
Block a user