Compare commits
14 Commits
fa9c53eb35
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b743dab332 | ||
|
|
549a98bc48 | ||
|
|
4d5476d159 | ||
|
|
e0751b368a | ||
|
|
0f71b02271 | ||
|
|
f9b4269ce3 | ||
|
|
0475dd5766 | ||
|
|
a318876eb3 | ||
|
|
f20f01e6d6 | ||
|
|
93a9f2e5c9 | ||
|
|
d5916ac2be | ||
|
|
7d515bcd94 | ||
|
|
49cc5e1ab9 | ||
|
|
c9a0e6ee29 |
20
.github/workflows/docker-bake.hcl
vendored
@@ -3,14 +3,14 @@ variable "BASE_IMAGE" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group "default" {
|
group "default" {
|
||||||
targets = ["runner"]
|
targets = ["runner-base", "runner-builder"]
|
||||||
}
|
}
|
||||||
|
|
||||||
target "runner-base" {
|
target "runner-base" {
|
||||||
dockerfile = "containerfiles/runner-base.Containerfile"
|
dockerfile = "containerfiles/runner-base.Containerfile"
|
||||||
context = "."
|
context = "."
|
||||||
args = {
|
args = {
|
||||||
BASE_IMAGE = "${BASE_IMAGE}"
|
BASE_IMAGE = BASE_IMAGE
|
||||||
}
|
}
|
||||||
cache-from = ["type=gha,scope=runner-base-pr"]
|
cache-from = ["type=gha,scope=runner-base-pr"]
|
||||||
cache-to = ["type=gha,scope=runner-base-pr,mode=max"]
|
cache-to = ["type=gha,scope=runner-base-pr,mode=max"]
|
||||||
@@ -30,19 +30,3 @@ target "runner-builder" {
|
|||||||
runner-base = "target:runner-base"
|
runner-base = "target:runner-base"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
target "runner" {
|
|
||||||
dockerfile = "containerfiles/runner.Containerfile"
|
|
||||||
context = "."
|
|
||||||
args = {
|
|
||||||
RUNNER_BASE_IMAGE = "runner-base:latest"
|
|
||||||
RUNNER_BUILDER_IMAGE = "runner-builder:latest"
|
|
||||||
}
|
|
||||||
cache-from = ["type=gha,scope=runner-pr"]
|
|
||||||
cache-to = ["type=gha,scope=runner-pr,mode=max"]
|
|
||||||
tags = ["nestri-runner"]
|
|
||||||
contexts = {
|
|
||||||
runner-base = "target:runner-base"
|
|
||||||
runner-builder = "target:runner-builder"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
83
.github/workflows/play-standalone.yml
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
name: Build Nestri standalone playsite
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "containerfiles/playsite.Containerfile"
|
||||||
|
- ".github/workflows/play-standalone.yml"
|
||||||
|
- "packages/play-standalone/**"
|
||||||
|
- "packages/input/**"
|
||||||
|
push:
|
||||||
|
branches: [ dev, production ]
|
||||||
|
paths:
|
||||||
|
- "containerfiles/playsite.Containerfile"
|
||||||
|
- ".github/workflows/play-standalone.yml"
|
||||||
|
- "packages/play-standalone/**"
|
||||||
|
- "packages/input/**"
|
||||||
|
tags:
|
||||||
|
- v*.*.*
|
||||||
|
release:
|
||||||
|
types: [ created ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
IMAGE_NAME: nestrilabs/nestri
|
||||||
|
BASE_TAG_PREFIX: playsite
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-docker-pr:
|
||||||
|
name: Build image on PR
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Setup Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Build Docker image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
file: containerfiles/playsite.Containerfile
|
||||||
|
context: ./
|
||||||
|
push: false
|
||||||
|
load: true
|
||||||
|
tags: nestri:playsite
|
||||||
|
|
||||||
|
build-and-push-docker:
|
||||||
|
name: Build and push image
|
||||||
|
if: ${{ github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/production' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Log into registry ${{ env.REGISTRY }}
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ github.token }}
|
||||||
|
- name: Extract Container metadata
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/${{ env.BASE_TAG_PREFIX }}
|
||||||
|
#
|
||||||
|
#tag on release, and a nightly build for 'dev'
|
||||||
|
tags: |
|
||||||
|
type=raw,value=nightly,enable={{is_default_branch}}
|
||||||
|
type=raw,value={{branch}}
|
||||||
|
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'production') }}
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,pattern={{major}}
|
||||||
|
- name: Build Docker image
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
file: containerfiles/playsite.Containerfile
|
||||||
|
context: ./
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
3
.github/workflows/relay.yml
vendored
@@ -1,6 +1,5 @@
|
|||||||
#Tabs not spaces, you moron :)
|
name: Build Nestri relay
|
||||||
|
|
||||||
name: Build nestri:relay
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
|
|||||||
73
.github/workflows/runner-bases.yml
vendored
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
name: Build Nestri runner base images
|
||||||
|
|
||||||
|
on: [ workflow_call ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
IMAGE_NAME: nestrilabs/nestri
|
||||||
|
BASE_IMAGE: docker.io/cachyos/cachyos:latest
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push-bases:
|
||||||
|
name: Build and push images
|
||||||
|
if: ${{ github.ref == 'refs/heads/production' || github.ref == 'refs/heads/dev' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
variant:
|
||||||
|
- { suffix: "v2", base: "docker.io/cachyos/cachyos:latest" }
|
||||||
|
- { suffix: "v3", base: "docker.io/cachyos/cachyos-v3:latest" }
|
||||||
|
#- { suffix: "v4", base: "docker.io/cachyos/cachyos-v4:latest" } # Disabled until GHA has this
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Log into registry ${{ env.REGISTRY }}
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ github.token }}
|
||||||
|
- name: Setup Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Set Swap Space
|
||||||
|
uses: pierotofy/set-swap-space@master
|
||||||
|
with:
|
||||||
|
swap-size-gb: 20
|
||||||
|
- name: Build and push runner-base image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
file: containerfiles/runner-base.Containerfile
|
||||||
|
context: ./
|
||||||
|
push: true
|
||||||
|
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-base:latest-${{ matrix.variant.suffix }}
|
||||||
|
build-args: |
|
||||||
|
BASE_IMAGE=${{ matrix.variant.base }}
|
||||||
|
cache-from: type=gha,scope=runner-base-${{ matrix.variant.suffix }},mode=max
|
||||||
|
cache-to: type=gha,scope=runner-base-${{ matrix.variant.suffix }},mode=max
|
||||||
|
pull: true
|
||||||
|
- name: Build and push runner-builder image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
file: containerfiles/runner-builder.Containerfile
|
||||||
|
context: ./
|
||||||
|
push: true
|
||||||
|
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-builder:latest-${{ matrix.variant.suffix }}
|
||||||
|
build-args: |
|
||||||
|
RUNNER_BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-base:latest-${{ matrix.variant.suffix }}
|
||||||
|
cache-from: type=gha,scope=runner-builder-${{ matrix.variant.suffix }},mode=max
|
||||||
|
cache-to: type=gha,scope=runner-builder-${{ matrix.variant.suffix }},mode=max
|
||||||
|
- name: Build and push runner-common image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
file: containerfiles/runner-common.Containerfile
|
||||||
|
context: ./
|
||||||
|
push: true
|
||||||
|
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-common:latest-${{ matrix.variant.suffix }}
|
||||||
|
build-args: |
|
||||||
|
RUNNER_BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-base:latest-${{ matrix.variant.suffix }}
|
||||||
|
RUNNER_BUILDER_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-builder:latest-${{ matrix.variant.suffix }}
|
||||||
|
cache-from: type=gha,scope=runner-common-${{ matrix.variant.suffix }},mode=max
|
||||||
|
cache-to: type=gha,scope=runner-common-${{ matrix.variant.suffix }},mode=max
|
||||||
86
.github/workflows/runner-variants.yml
vendored
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
name: Build Nestri runner image variants
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: 7 0 * * 1,3,6 # Nightlies
|
||||||
|
push:
|
||||||
|
branches: [ dev, production ]
|
||||||
|
paths:
|
||||||
|
- "containerfiles/*runner.Containerfile"
|
||||||
|
- ".github/workflows/runner-variants.yml"
|
||||||
|
- "packages/scripts/**"
|
||||||
|
- "packages/configs/**"
|
||||||
|
tags:
|
||||||
|
- v*.*.*
|
||||||
|
release:
|
||||||
|
types: [ created ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
REGISTRY: ghcr.io
|
||||||
|
IMAGE_NAME: nestrilabs/nestri
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
bases:
|
||||||
|
uses: ./.github/workflows/runner-bases.yml
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
build-and-push-variants:
|
||||||
|
needs: [ bases ]
|
||||||
|
name: Build and push images
|
||||||
|
if: ${{ github.ref == 'refs/heads/production' || github.ref == 'refs/heads/dev' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
variant:
|
||||||
|
- { suffix: "v2", base: "docker.io/cachyos/cachyos:latest" }
|
||||||
|
- { suffix: "v3", base: "docker.io/cachyos/cachyos-v3:latest" }
|
||||||
|
#- { suffix: "v4", base: "docker.io/cachyos/cachyos-v4:latest" } # Disabled until GHA has this
|
||||||
|
runner:
|
||||||
|
- steam
|
||||||
|
- heroic
|
||||||
|
- minecraft
|
||||||
|
# ADD MORE HERE AS NEEDED #
|
||||||
|
steps:
|
||||||
|
- name: Checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
- name: Log into registry ${{ env.REGISTRY }}
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
registry: ${{ env.REGISTRY }}
|
||||||
|
username: ${{ github.actor }}
|
||||||
|
password: ${{ github.token }}
|
||||||
|
- name: Extract runner metadata
|
||||||
|
id: meta-runner
|
||||||
|
uses: docker/metadata-action@v5
|
||||||
|
with:
|
||||||
|
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner
|
||||||
|
tags: |
|
||||||
|
type=raw,value=nightly-${{ matrix.runner }}-${{ matrix.variant.suffix }},enable={{is_default_branch}}
|
||||||
|
type=raw,value={{branch}}-${{ matrix.runner }}-${{ matrix.variant.suffix }}
|
||||||
|
type=raw,value=latest-${{ matrix.runner }}-${{ matrix.variant.suffix }},enable=${{ github.ref == format('refs/heads/{0}', 'production') }}
|
||||||
|
type=semver,pattern={{version}}-${{ matrix.runner }}-${{ matrix.variant.suffix }}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}-${{ matrix.runner }}-${{ matrix.variant.suffix }}
|
||||||
|
type=semver,pattern={{major}}-${{ matrix.runner }}-${{ matrix.variant.suffix }}
|
||||||
|
- name: Setup Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v3
|
||||||
|
- name: Set Swap Space
|
||||||
|
uses: pierotofy/set-swap-space@master
|
||||||
|
with:
|
||||||
|
swap-size-gb: 20
|
||||||
|
- name: Build and push runner image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
file: containerfiles/${{ matrix.runner }}-runner.Containerfile
|
||||||
|
context: ./
|
||||||
|
push: true
|
||||||
|
tags: ${{ steps.meta-runner.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta-runner.outputs.labels }}
|
||||||
|
build-args: |
|
||||||
|
RUNNER_COMMON_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-common:latest-${{ matrix.variant.suffix }}
|
||||||
|
cache-from: type=gha,scope=runner-${{ matrix.runner }}-${{ matrix.variant.suffix }},mode=max
|
||||||
|
cache-to: type=gha,scope=runner-${{ matrix.runner }}-${{ matrix.variant.suffix }},mode=max
|
||||||
148
.github/workflows/runner.yml
vendored
@@ -1,148 +0,0 @@
|
|||||||
#Tabs not spaces, you moron :)
|
|
||||||
|
|
||||||
name: Build nestri-runner
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- "containerfiles/runner*.Containerfile"
|
|
||||||
- "packages/scripts/**"
|
|
||||||
- "packages/server/**"
|
|
||||||
- ".github/workflows/runner.yml"
|
|
||||||
schedule:
|
|
||||||
- cron: 7 0 * * 1,3,6 # Regularly to keep that build cache warm
|
|
||||||
push:
|
|
||||||
branches: [dev, production]
|
|
||||||
paths:
|
|
||||||
- "containerfiles/runner*.Containerfile"
|
|
||||||
- ".github/workflows/runner.yml"
|
|
||||||
- "packages/scripts/**"
|
|
||||||
- "packages/server/**"
|
|
||||||
tags:
|
|
||||||
- v*.*.*
|
|
||||||
release:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
env:
|
|
||||||
REGISTRY: ghcr.io
|
|
||||||
IMAGE_NAME: nestrilabs/nestri
|
|
||||||
BASE_IMAGE: docker.io/cachyos/cachyos:latest
|
|
||||||
|
|
||||||
# This makes our release ci quit prematurely
|
|
||||||
# concurrency:
|
|
||||||
# group: ci-${{ github.ref }}
|
|
||||||
# cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build-docker-pr:
|
|
||||||
name: Build images on PR
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
if: ${{ github.event_name == 'pull_request' }}
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Setup Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
-
|
|
||||||
name: Set Swap Space
|
|
||||||
uses: pierotofy/set-swap-space@master
|
|
||||||
with:
|
|
||||||
swap-size-gb: 20
|
|
||||||
-
|
|
||||||
name: Build images using bake
|
|
||||||
uses: docker/bake-action@v6
|
|
||||||
env:
|
|
||||||
BASE_IMAGE: ${{ env.BASE_IMAGE }}
|
|
||||||
with:
|
|
||||||
files: |
|
|
||||||
./.github/workflows/docker-bake.hcl
|
|
||||||
targets: runner
|
|
||||||
push: false
|
|
||||||
load: true
|
|
||||||
|
|
||||||
build-and-push-docker:
|
|
||||||
name: Build and push images
|
|
||||||
if: ${{ github.ref == 'refs/heads/production' || github.ref == 'refs/heads/dev' }}
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
variant:
|
|
||||||
- { suffix: "", base: "docker.io/cachyos/cachyos:latest" }
|
|
||||||
- { suffix: "-v3", base: "docker.io/cachyos/cachyos-v3:latest" }
|
|
||||||
#- { suffix: "-v4", base: "docker.io/cachyos/cachyos-v4:latest" } # Disabled until GHA has this
|
|
||||||
steps:
|
|
||||||
-
|
|
||||||
name: Checkout repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
-
|
|
||||||
name: Log into registry ${{ env.REGISTRY }}
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ github.actor }}
|
|
||||||
password: ${{ github.token }}
|
|
||||||
-
|
|
||||||
name: Extract runner metadata
|
|
||||||
id: meta-runner
|
|
||||||
uses: docker/metadata-action@v5
|
|
||||||
with:
|
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner
|
|
||||||
tags: |
|
|
||||||
type=raw,value=nightly${{ matrix.variant.suffix }},enable={{is_default_branch}}
|
|
||||||
type=raw,value={{branch}}${{ matrix.variant.suffix }}
|
|
||||||
type=raw,value=latest${{ matrix.variant.suffix }},enable=${{ github.ref == format('refs/heads/{0}', 'production') }}
|
|
||||||
type=semver,pattern={{version}}${{ matrix.variant.suffix }}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}${{ matrix.variant.suffix }}
|
|
||||||
type=semver,pattern={{major}}${{ matrix.variant.suffix }}
|
|
||||||
-
|
|
||||||
name: Setup Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
-
|
|
||||||
name: Set Swap Space
|
|
||||||
uses: pierotofy/set-swap-space@master
|
|
||||||
with:
|
|
||||||
swap-size-gb: 20
|
|
||||||
-
|
|
||||||
name: Build and push runner-base image
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
file: containerfiles/runner-base.Containerfile
|
|
||||||
context: ./
|
|
||||||
push: true
|
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-base:latest${{ matrix.variant.suffix }}
|
|
||||||
build-args: |
|
|
||||||
BASE_IMAGE=${{ matrix.variant.base }}
|
|
||||||
cache-from: type=gha,scope=runner-base${{ matrix.variant.suffix }},mode=max
|
|
||||||
cache-to: type=gha,scope=runner-base${{ matrix.variant.suffix }},mode=max
|
|
||||||
pull: ${{ github.event_name == 'schedule' }}
|
|
||||||
-
|
|
||||||
name: Build and push runner-builder image
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
file: containerfiles/runner-builder.Containerfile
|
|
||||||
context: ./
|
|
||||||
push: true
|
|
||||||
tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-builder:latest${{ matrix.variant.suffix }}
|
|
||||||
build-args: |
|
|
||||||
RUNNER_BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-base:latest${{ matrix.variant.suffix }}
|
|
||||||
cache-from: type=gha,scope=runner-builder${{ matrix.variant.suffix }},mode=max
|
|
||||||
cache-to: type=gha,scope=runner-builder${{ matrix.variant.suffix }},mode=max
|
|
||||||
-
|
|
||||||
name: Build and push runner image
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
file: containerfiles/runner.Containerfile
|
|
||||||
context: ./
|
|
||||||
push: true
|
|
||||||
tags: ${{ steps.meta-runner.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta-runner.outputs.labels }}
|
|
||||||
build-args: |
|
|
||||||
RUNNER_BASE_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-base:latest${{ matrix.variant.suffix }}
|
|
||||||
RUNNER_BUILDER_IMAGE=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/runner-builder:latest${{ matrix.variant.suffix }}
|
|
||||||
cache-from: type=gha,scope=runner${{ matrix.variant.suffix }},mode=max
|
|
||||||
cache-to: type=gha,scope=runner${{ matrix.variant.suffix }},mode=max
|
|
||||||
@@ -15,3 +15,4 @@ plugins:
|
|||||||
# Rust (nestri-server)
|
# Rust (nestri-server)
|
||||||
- remote: buf.build/community/neoeinstein-prost
|
- remote: buf.build/community/neoeinstein-prost
|
||||||
out: packages/server/src/proto
|
out: packages/server/src/proto
|
||||||
|
opt: flat_output_dir=true
|
||||||
|
|||||||
23
containerfiles/heroic-runner.Containerfile
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Container build arguments #
|
||||||
|
ARG RUNNER_COMMON_IMAGE=runner-common:latest
|
||||||
|
|
||||||
|
#*********************#
|
||||||
|
# Final Runtime Stage #
|
||||||
|
#*********************#
|
||||||
|
FROM ${RUNNER_COMMON_IMAGE}
|
||||||
|
|
||||||
|
### FLAVOR/VARIANT CONFIGURATION ###
|
||||||
|
## HEROIC LAUNCHER ##
|
||||||
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
|
pacman -S --noconfirm heroic-games-launcher-bin && \
|
||||||
|
# Cleanup
|
||||||
|
paccache -rk1 && \
|
||||||
|
rm -rf /usr/share/{info,man,doc}/*
|
||||||
|
|
||||||
|
## FLAVOR/VARIANT LAUNCH COMMAND ##
|
||||||
|
ENV NESTRI_LAUNCH_CMD="heroic"
|
||||||
|
### END OF FLAVOR/VARIANT CONFIGURATION ###
|
||||||
|
|
||||||
|
### REQUIRED DEFAULT ENTRYPOINT FOR FLAVOR/VARIANT ###
|
||||||
|
USER root
|
||||||
|
ENTRYPOINT ["supervisord", "-c", "/etc/nestri/supervisord.conf"]
|
||||||
24
containerfiles/minecraft-runner.Containerfile
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Container build arguments #
|
||||||
|
ARG RUNNER_COMMON_IMAGE=runner-common:latest
|
||||||
|
|
||||||
|
#*********************#
|
||||||
|
# Final Runtime Stage #
|
||||||
|
#*********************#
|
||||||
|
FROM ${RUNNER_COMMON_IMAGE}
|
||||||
|
|
||||||
|
### FLAVOR/VARIANT CONFIGURATION ###
|
||||||
|
## MINECRAFT ##
|
||||||
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
|
pacman -S --noconfirm paru && \
|
||||||
|
sudo -H -u ${NESTRI_USER} paru -S --noconfirm aur/minecraft-launcher && \
|
||||||
|
# Cleanup
|
||||||
|
paccache -rk1 && \
|
||||||
|
rm -rf /usr/share/{info,man,doc}/*
|
||||||
|
|
||||||
|
## FLAVOR/VARIANT LAUNCH COMMAND ##
|
||||||
|
ENV NESTRI_LAUNCH_CMD="minecraft-launcher"
|
||||||
|
### END OF FLAVOR/VARIANT CONFIGURATION ###
|
||||||
|
|
||||||
|
### REQUIRED DEFAULT ENTRYPOINT FOR FLAVOR/VARIANT ###
|
||||||
|
USER root
|
||||||
|
ENTRYPOINT ["supervisord", "-c", "/etc/nestri/supervisord.conf"]
|
||||||
@@ -15,7 +15,7 @@ ENV CARGO_HOME=/usr/local/cargo \
|
|||||||
|
|
||||||
# Install build essentials and caching tools
|
# Install build essentials and caching tools
|
||||||
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
pacman -Sy --noconfirm rustup git base-devel mold \
|
pacman -S --noconfirm rustup git base-devel mold \
|
||||||
meson pkgconf cmake git gcc make
|
meson pkgconf cmake git gcc make
|
||||||
|
|
||||||
# Override various linker with symlink so mold is forcefully used (ld, ld.lld, lld)
|
# Override various linker with symlink so mold is forcefully used (ld, ld.lld, lld)
|
||||||
@@ -28,7 +28,7 @@ RUN rustup default stable
|
|||||||
|
|
||||||
# Install cargo-chef with proper caching
|
# Install cargo-chef with proper caching
|
||||||
RUN --mount=type=cache,target=${CARGO_HOME}/registry \
|
RUN --mount=type=cache,target=${CARGO_HOME}/registry \
|
||||||
cargo install -j $(nproc) cargo-chef --locked
|
cargo install cargo-chef --locked
|
||||||
|
|
||||||
#*******************************#
|
#*******************************#
|
||||||
# vimputti manager build stages #
|
# vimputti manager build stages #
|
||||||
@@ -38,7 +38,7 @@ WORKDIR /builder
|
|||||||
|
|
||||||
# Install build dependencies
|
# Install build dependencies
|
||||||
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
pacman -Sy --noconfirm lib32-gcc-libs
|
pacman -S --noconfirm lib32-gcc-libs
|
||||||
|
|
||||||
# Clone repository
|
# Clone repository
|
||||||
RUN git clone --depth 1 --rev "2fde5376b6b9a38cdbd94ccc6a80c9d29a81a417" https://github.com/DatCaptainHorse/vimputti.git
|
RUN git clone --depth 1 --rev "2fde5376b6b9a38cdbd94ccc6a80c9d29a81a417" https://github.com/DatCaptainHorse/vimputti.git
|
||||||
@@ -83,7 +83,7 @@ WORKDIR /builder
|
|||||||
|
|
||||||
# Install build dependencies
|
# Install build dependencies
|
||||||
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
pacman -Sy --noconfirm gst-plugins-good gst-plugin-rswebrtc
|
pacman -S --noconfirm gst-plugins-good gst-plugin-rswebrtc
|
||||||
|
|
||||||
#--------------------------------------------------------------------
|
#--------------------------------------------------------------------
|
||||||
FROM nestri-server-deps AS nestri-server-planner
|
FROM nestri-server-deps AS nestri-server-planner
|
||||||
@@ -123,14 +123,14 @@ WORKDIR /builder
|
|||||||
|
|
||||||
# Install build dependencies
|
# Install build dependencies
|
||||||
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
pacman -Sy --noconfirm libxkbcommon wayland \
|
pacman -S --noconfirm libxkbcommon wayland \
|
||||||
gst-plugins-good gst-plugins-bad libinput
|
gst-plugins-good gst-plugins-bad libinput
|
||||||
|
|
||||||
RUN --mount=type=cache,target=${CARGO_HOME}/registry \
|
RUN --mount=type=cache,target=${CARGO_HOME}/registry \
|
||||||
cargo install cargo-c
|
cargo install cargo-c
|
||||||
|
|
||||||
# Clone repository
|
# Clone repository
|
||||||
RUN git clone --depth 1 --rev "a4abcfe2cffe2d33b564d1308b58504a5e3012b1" https://github.com/games-on-whales/gst-wayland-display.git
|
RUN git clone --depth 1 --rev "67b1183997fd7aaf57398e4b01bd64c4d2433c45" https://github.com/games-on-whales/gst-wayland-display.git
|
||||||
|
|
||||||
#--------------------------------------------------------------------
|
#--------------------------------------------------------------------
|
||||||
FROM gst-wayland-deps AS gst-wayland-planner
|
FROM gst-wayland-deps AS gst-wayland-planner
|
||||||
@@ -148,7 +148,7 @@ COPY --from=gst-wayland-planner /builder/gst-wayland-display/recipe.json .
|
|||||||
|
|
||||||
# Cache dependencies using cargo-chef
|
# Cache dependencies using cargo-chef
|
||||||
RUN --mount=type=cache,target=${CARGO_HOME}/registry \
|
RUN --mount=type=cache,target=${CARGO_HOME}/registry \
|
||||||
cargo chef cook --release --recipe-path recipe.json
|
cargo chef cook --release --recipe-path recipe.json --features cuda
|
||||||
|
|
||||||
|
|
||||||
ENV CARGO_TARGET_DIR=/builder/target
|
ENV CARGO_TARGET_DIR=/builder/target
|
||||||
@@ -158,7 +158,7 @@ COPY --from=gst-wayland-planner /builder/gst-wayland-display/ .
|
|||||||
# Build and install directly to artifacts
|
# Build and install directly to artifacts
|
||||||
RUN --mount=type=cache,target=${CARGO_HOME}/registry \
|
RUN --mount=type=cache,target=${CARGO_HOME}/registry \
|
||||||
--mount=type=cache,target=/builder/target \
|
--mount=type=cache,target=/builder/target \
|
||||||
cargo cinstall --prefix=${ARTIFACTS} --release
|
cargo cinstall --prefix=${ARTIFACTS} --release --features cuda
|
||||||
|
|
||||||
#*********************************#
|
#*********************************#
|
||||||
# Patched bubblewrap build stages #
|
# Patched bubblewrap build stages #
|
||||||
@@ -168,7 +168,7 @@ WORKDIR /builder
|
|||||||
|
|
||||||
# Install build dependencies
|
# Install build dependencies
|
||||||
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
pacman -Sy --noconfirm libtool libcap libselinux
|
pacman -S --noconfirm libtool libcap libselinux
|
||||||
|
|
||||||
# Copy patch file from host
|
# Copy patch file from host
|
||||||
COPY packages/patches/bubblewrap/ /builder/patches/
|
COPY packages/patches/bubblewrap/ /builder/patches/
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
ARG RUNNER_BASE_IMAGE=runner-base:latest
|
ARG RUNNER_BASE_IMAGE=runner-base:latest
|
||||||
ARG RUNNER_BUILDER_IMAGE=runner-builder:latest
|
ARG RUNNER_BUILDER_IMAGE=runner-builder:latest
|
||||||
|
|
||||||
#*********************#
|
#**********************#
|
||||||
# Final Runtime Stage #
|
# Runtime Common Stage #
|
||||||
#*********************#
|
#**********************#
|
||||||
FROM ${RUNNER_BASE_IMAGE} AS runtime
|
FROM ${RUNNER_BASE_IMAGE} AS runtime
|
||||||
FROM ${RUNNER_BUILDER_IMAGE} AS builder
|
FROM ${RUNNER_BUILDER_IMAGE} AS builder
|
||||||
FROM runtime
|
FROM runtime
|
||||||
@@ -12,11 +12,11 @@ FROM runtime
|
|||||||
### Package Installation ###
|
### Package Installation ###
|
||||||
# Core system components
|
# Core system components
|
||||||
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
pacman -Sy --needed --noconfirm \
|
pacman -S --needed --noconfirm \
|
||||||
vulkan-intel lib32-vulkan-intel vpl-gpu-rt \
|
vulkan-intel lib32-vulkan-intel vpl-gpu-rt \
|
||||||
vulkan-radeon lib32-vulkan-radeon \
|
vulkan-radeon lib32-vulkan-radeon \
|
||||||
mesa lib32-mesa \
|
mesa lib32-mesa vulkan-mesa-layers lib32-vulkan-mesa-layers \
|
||||||
steam gtk3 lib32-gtk3 \
|
gtk3 lib32-gtk3 \
|
||||||
sudo xorg-xwayland seatd libinput gamescope mangohud wlr-randr \
|
sudo xorg-xwayland seatd libinput gamescope mangohud wlr-randr \
|
||||||
pipewire pipewire-pulse pipewire-alsa wireplumber \
|
pipewire pipewire-pulse pipewire-alsa wireplumber \
|
||||||
noto-fonts-cjk supervisor jq pacman-contrib \
|
noto-fonts-cjk supervisor jq pacman-contrib \
|
||||||
@@ -67,15 +67,8 @@ RUN mkdir -p /etc/pipewire/pipewire.conf.d && \
|
|||||||
COPY packages/configs/wireplumber.conf.d/* /etc/wireplumber/wireplumber.conf.d/
|
COPY packages/configs/wireplumber.conf.d/* /etc/wireplumber/wireplumber.conf.d/
|
||||||
COPY packages/configs/pipewire.conf.d/* /etc/pipewire/pipewire.conf.d/
|
COPY packages/configs/pipewire.conf.d/* /etc/pipewire/pipewire.conf.d/
|
||||||
|
|
||||||
## Steam Configs - Proton (Experimental flavor) ##
|
|
||||||
RUN mkdir -p "${NESTRI_HOME}/.local/share/Steam/config"
|
|
||||||
|
|
||||||
COPY packages/configs/steam/config.vdf "${NESTRI_HOME}/.local/share/Steam/config/"
|
|
||||||
|
|
||||||
## MangoHud Config ##
|
## MangoHud Config ##
|
||||||
RUN mkdir -p "${NESTRI_HOME}/.config/MangoHud"
|
COPY packages/configs/MangoHud/MangoHud.conf /etc/nestri/configs/MangoHud/
|
||||||
|
|
||||||
COPY packages/configs/MangoHud/MangoHud.conf "${NESTRI_HOME}/.config/MangoHud/"
|
|
||||||
|
|
||||||
### Artifacts from Builder ###
|
### Artifacts from Builder ###
|
||||||
COPY --from=builder /artifacts/bin/nestri-server /usr/bin/
|
COPY --from=builder /artifacts/bin/nestri-server /usr/bin/
|
||||||
@@ -93,7 +86,3 @@ RUN chmod +x /etc/nestri/{envs.sh,entrypoint*.sh} && \
|
|||||||
setcap cap_net_admin+ep /usr/bin/vimputti-manager && \
|
setcap cap_net_admin+ep /usr/bin/vimputti-manager && \
|
||||||
dbus-uuidgen > /etc/machine-id && \
|
dbus-uuidgen > /etc/machine-id && \
|
||||||
LANG=en_US.UTF-8 locale-gen
|
LANG=en_US.UTF-8 locale-gen
|
||||||
|
|
||||||
# Root for most container engines, nestri-user compatible for apptainer without fakeroot
|
|
||||||
USER root
|
|
||||||
ENTRYPOINT ["supervisord", "-c", "/etc/nestri/supervisord.conf"]
|
|
||||||
27
containerfiles/steam-runner.Containerfile
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Container build arguments #
|
||||||
|
ARG RUNNER_COMMON_IMAGE=runner-common:latest
|
||||||
|
|
||||||
|
#*********************#
|
||||||
|
# Final Runtime Stage #
|
||||||
|
#*********************#
|
||||||
|
FROM ${RUNNER_COMMON_IMAGE}
|
||||||
|
|
||||||
|
### FLAVOR/VARIANT CONFIGURATION ###
|
||||||
|
## STEAM ##
|
||||||
|
RUN --mount=type=cache,target=/var/cache/pacman/pkg \
|
||||||
|
pacman -S --noconfirm steam && \
|
||||||
|
# Cleanup
|
||||||
|
paccache -rk1 && \
|
||||||
|
rm -rf /usr/share/{info,man,doc}/*
|
||||||
|
|
||||||
|
## Steam Configs - Proton (Experimental flavor) ##
|
||||||
|
RUN mkdir -p "${NESTRI_HOME}/.local/share/Steam/config"
|
||||||
|
COPY packages/configs/steam/config.vdf "${NESTRI_HOME}/.local/share/Steam/config/"
|
||||||
|
|
||||||
|
## FLAVOR/VARIANT LAUNCH COMMAND ##
|
||||||
|
ENV NESTRI_LAUNCH_CMD="steam -tenfoot -cef-force-gpu"
|
||||||
|
### END OF FLAVOR/VARIANT CONFIGURATION ###
|
||||||
|
|
||||||
|
### REQUIRED DEFAULT ENTRYPOINT FOR FLAVOR/VARIANT ###
|
||||||
|
USER root
|
||||||
|
ENTRYPOINT ["supervisord", "-c", "/etc/nestri/supervisord.conf"]
|
||||||
@@ -2,6 +2,6 @@ context.properties = {
|
|||||||
default.clock.rate = 48000
|
default.clock.rate = 48000
|
||||||
default.clock.allowed-rates = [48000]
|
default.clock.allowed-rates = [48000]
|
||||||
default.clock.min-quantum = 128
|
default.clock.min-quantum = 128
|
||||||
default.clock.max-quantum = 256
|
default.clock.max-quantum = 1024
|
||||||
default.clock.quantum = 128
|
default.clock.quantum = 512
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
],
|
],
|
||||||
"apply_properties": {
|
"apply_properties": {
|
||||||
"pulse.min.req": 128,
|
"pulse.min.req": 128,
|
||||||
"pulse.max.req": 256,
|
"pulse.max.req": 1024,
|
||||||
"pulse.idle.timeout": 0
|
"pulse.idle.timeout": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3
packages/input/.containerignore
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
.idea/
|
||||||
|
dist/
|
||||||
|
node_modules/
|
||||||
@@ -36,10 +36,8 @@ export class Keyboard {
|
|||||||
if (this.connected) this.stop();
|
if (this.connected) this.stop();
|
||||||
|
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
document.addEventListener("keydown", this.keydownListener, {
|
document.addEventListener("keydown", this.keydownListener);
|
||||||
passive: false,
|
document.addEventListener("keyup", this.keyupListener);
|
||||||
});
|
|
||||||
document.addEventListener("keyup", this.keyupListener, { passive: false });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private stop() {
|
private stop() {
|
||||||
@@ -73,6 +71,6 @@ export class Keyboard {
|
|||||||
private keyToVirtualKeyCode(code: string) {
|
private keyToVirtualKeyCode(code: string) {
|
||||||
// Treat Home key as Escape - TODO: Make user-configurable
|
// Treat Home key as Escape - TODO: Make user-configurable
|
||||||
if (code === "Home") return 1;
|
if (code === "Home") return 1;
|
||||||
return keyCodeToLinuxEventCode[code] || undefined;
|
return keyCodeToLinuxEventCode[code] || 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ export class Mouse {
|
|||||||
this.wrtc = webrtc;
|
this.wrtc = webrtc;
|
||||||
this.canvas = canvas;
|
this.canvas = canvas;
|
||||||
|
|
||||||
this.sendInterval = 1000 / webrtc.currentFrameRate;
|
|
||||||
|
|
||||||
this.mousemoveListener = (e: MouseEvent) => {
|
this.mousemoveListener = (e: MouseEvent) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@@ -77,18 +75,10 @@ export class Mouse {
|
|||||||
|
|
||||||
if (document.pointerLockElement == this.canvas) {
|
if (document.pointerLockElement == this.canvas) {
|
||||||
this.connected = true;
|
this.connected = true;
|
||||||
this.canvas.addEventListener("mousemove", this.mousemoveListener, {
|
this.canvas.addEventListener("mousemove", this.mousemoveListener);
|
||||||
passive: false,
|
this.canvas.addEventListener("mousedown", this.mousedownListener);
|
||||||
});
|
this.canvas.addEventListener("mouseup", this.mouseupListener);
|
||||||
this.canvas.addEventListener("mousedown", this.mousedownListener, {
|
this.canvas.addEventListener("wheel", this.mousewheelListener);
|
||||||
passive: false,
|
|
||||||
});
|
|
||||||
this.canvas.addEventListener("mouseup", this.mouseupListener, {
|
|
||||||
passive: false,
|
|
||||||
});
|
|
||||||
this.canvas.addEventListener("wheel", this.mousewheelListener, {
|
|
||||||
passive: false,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
if (this.connected) {
|
if (this.connected) {
|
||||||
this.stop();
|
this.stop();
|
||||||
@@ -106,7 +96,7 @@ export class Mouse {
|
|||||||
|
|
||||||
private startProcessing() {
|
private startProcessing() {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
if (this.connected && (this.movementX !== 0 || this.movementY !== 0)) {
|
if (this.connected) {
|
||||||
this.sendAggregatedMouseMove();
|
this.sendAggregatedMouseMove();
|
||||||
this.movementX = 0;
|
this.movementX = 0;
|
||||||
this.movementY = 0;
|
this.movementY = 0;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
// @generated by protoc-gen-es v2.10.1 with parameter "target=ts"
|
||||||
// @generated from file latency_tracker.proto (package proto, syntax proto3)
|
// @generated from file latency_tracker.proto (package proto, syntax proto3)
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
// @generated by protoc-gen-es v2.10.1 with parameter "target=ts"
|
||||||
// @generated from file messages.proto (package proto, syntax proto3)
|
// @generated from file messages.proto (package proto, syntax proto3)
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
@@ -90,6 +90,8 @@ export type ProtoMessage = Message<"proto.ProtoMessage"> & {
|
|||||||
case: "keyDown";
|
case: "keyDown";
|
||||||
} | {
|
} | {
|
||||||
/**
|
/**
|
||||||
|
* ProtoClipboard clipboard = 9;
|
||||||
|
*
|
||||||
* @generated from field: proto.ProtoKeyUp key_up = 8;
|
* @generated from field: proto.ProtoKeyUp key_up = 8;
|
||||||
*/
|
*/
|
||||||
value: ProtoKeyUp;
|
value: ProtoKeyUp;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// @generated by protoc-gen-es v2.10.0 with parameter "target=ts"
|
// @generated by protoc-gen-es v2.10.1 with parameter "target=ts"
|
||||||
// @generated from file types.proto (package proto, syntax proto3)
|
// @generated from file types.proto (package proto, syntax proto3)
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ import {
|
|||||||
ProtoClientRequestRoomStream,
|
ProtoClientRequestRoomStream,
|
||||||
ProtoClientRequestRoomStreamSchema,
|
ProtoClientRequestRoomStreamSchema,
|
||||||
ProtoICE,
|
ProtoICE,
|
||||||
ProtoICESchema, ProtoRaw,
|
ProtoICESchema,
|
||||||
|
ProtoRaw,
|
||||||
ProtoSDP,
|
ProtoSDP,
|
||||||
ProtoSDPSchema
|
ProtoSDPSchema,
|
||||||
} from "./proto/types_pb";
|
} from "./proto/types_pb";
|
||||||
import { P2PMessageStream } from "./streamwrapper";
|
import { P2PMessageStream } from "./streamwrapper";
|
||||||
|
|
||||||
@@ -38,7 +39,6 @@ export class WebRTCStream {
|
|||||||
private _roomName: string | undefined = undefined;
|
private _roomName: string | undefined = undefined;
|
||||||
private _isConnected: boolean = false;
|
private _isConnected: boolean = false;
|
||||||
private _dataChannelCallbacks: Array<(data: any) => void> = [];
|
private _dataChannelCallbacks: Array<(data: any) => void> = [];
|
||||||
currentFrameRate: number = 100;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
serverURL: string,
|
serverURL: string,
|
||||||
@@ -126,11 +126,19 @@ export class WebRTCStream {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this._msgStream.on("session-assigned", (data: ProtoClientRequestRoomStream) => {
|
this._msgStream.on(
|
||||||
this._sessionId = data.sessionId;
|
"session-assigned",
|
||||||
localStorage.setItem("nestri-session-id", this._sessionId);
|
(data: ProtoClientRequestRoomStream) => {
|
||||||
console.log("Session ID assigned:", this._sessionId, "for room:", data.roomName);
|
this._sessionId = data.sessionId;
|
||||||
});
|
localStorage.setItem("nestri-session-id", this._sessionId);
|
||||||
|
console.log(
|
||||||
|
"Session ID assigned:",
|
||||||
|
this._sessionId,
|
||||||
|
"for room:",
|
||||||
|
data.roomName,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
this._msgStream.on("offer", async (data: ProtoSDP) => {
|
this._msgStream.on("offer", async (data: ProtoSDP) => {
|
||||||
if (!this._pc) {
|
if (!this._pc) {
|
||||||
@@ -293,26 +301,8 @@ export class WebRTCStream {
|
|||||||
this._onConnected(
|
this._onConnected(
|
||||||
new MediaStream([this._audioTrack, this._videoTrack]),
|
new MediaStream([this._audioTrack, this._videoTrack]),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Continuously set low-latency target
|
|
||||||
this._pc.getReceivers().forEach((receiver: RTCRtpReceiver) => {
|
|
||||||
let intervalLoop = setInterval(async () => {
|
|
||||||
if (
|
|
||||||
receiver.track.readyState !== "live" ||
|
|
||||||
(receiver.transport && receiver.transport.state !== "connected")
|
|
||||||
) {
|
|
||||||
clearInterval(intervalLoop);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
// @ts-ignore
|
|
||||||
receiver.jitterBufferTarget = receiver.jitterBufferDelayHint = receiver.playoutDelayHint = 0;
|
|
||||||
}
|
|
||||||
}, 50);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._gatherFrameRate();
|
|
||||||
} else if (
|
} else if (
|
||||||
this._pc.connectionState === "failed" ||
|
this._pc.connectionState === "failed" ||
|
||||||
this._pc.connectionState === "closed" ||
|
this._pc.connectionState === "closed" ||
|
||||||
@@ -412,11 +402,16 @@ export class WebRTCStream {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private _gatherFrameRate() {
|
private async _gatherStats(): Promise<any> {
|
||||||
if (this._pc === undefined || this._videoTrack === undefined) return;
|
if (
|
||||||
|
this._pc === undefined ||
|
||||||
|
this._videoTrack === undefined ||
|
||||||
|
!this._isConnected
|
||||||
|
)
|
||||||
|
return null;
|
||||||
|
|
||||||
const videoInfoPromise = new Promise<{ fps: number }>((resolve) => {
|
return new Promise<any>((resolve) => {
|
||||||
// Keep trying to get fps until it's found
|
// Keep trying to get stats until gotten
|
||||||
const interval = setInterval(async () => {
|
const interval = setInterval(async () => {
|
||||||
if (this._pc === undefined) {
|
if (this._pc === undefined) {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
@@ -428,15 +423,11 @@ export class WebRTCStream {
|
|||||||
if (report.type === "inbound-rtp") {
|
if (report.type === "inbound-rtp") {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
|
|
||||||
resolve({ fps: report.framesPerSecond });
|
resolve({ pli: report.pliCount, nack: report.nackCount });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, 250);
|
}, 250);
|
||||||
});
|
});
|
||||||
|
|
||||||
videoInfoPromise.then((value) => {
|
|
||||||
this.currentFrameRate = value.fps;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send binary message through the data channel
|
// Send binary message through the data channel
|
||||||
|
|||||||
101
packages/play-standalone/android/.gitignore
vendored
@@ -1,101 +0,0 @@
|
|||||||
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
|
|
||||||
|
|
||||||
# Built application files
|
|
||||||
*.apk
|
|
||||||
*.aar
|
|
||||||
*.ap_
|
|
||||||
*.aab
|
|
||||||
|
|
||||||
# Files for the ART/Dalvik VM
|
|
||||||
*.dex
|
|
||||||
|
|
||||||
# Java class files
|
|
||||||
*.class
|
|
||||||
|
|
||||||
# Generated files
|
|
||||||
bin/
|
|
||||||
gen/
|
|
||||||
out/
|
|
||||||
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
|
||||||
# release/
|
|
||||||
|
|
||||||
# Gradle files
|
|
||||||
.gradle/
|
|
||||||
build/
|
|
||||||
|
|
||||||
# Local configuration file (sdk path, etc)
|
|
||||||
local.properties
|
|
||||||
|
|
||||||
# Proguard folder generated by Eclipse
|
|
||||||
proguard/
|
|
||||||
|
|
||||||
# Log Files
|
|
||||||
*.log
|
|
||||||
|
|
||||||
# Android Studio Navigation editor temp files
|
|
||||||
.navigation/
|
|
||||||
|
|
||||||
# Android Studio captures folder
|
|
||||||
captures/
|
|
||||||
|
|
||||||
# IntelliJ
|
|
||||||
*.iml
|
|
||||||
.idea/workspace.xml
|
|
||||||
.idea/tasks.xml
|
|
||||||
.idea/gradle.xml
|
|
||||||
.idea/assetWizardSettings.xml
|
|
||||||
.idea/dictionaries
|
|
||||||
.idea/libraries
|
|
||||||
# Android Studio 3 in .gitignore file.
|
|
||||||
.idea/caches
|
|
||||||
.idea/modules.xml
|
|
||||||
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
|
|
||||||
.idea/navEditor.xml
|
|
||||||
|
|
||||||
# Keystore files
|
|
||||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
|
||||||
#*.jks
|
|
||||||
#*.keystore
|
|
||||||
|
|
||||||
# External native build folder generated in Android Studio 2.2 and later
|
|
||||||
.externalNativeBuild
|
|
||||||
.cxx/
|
|
||||||
|
|
||||||
# Google Services (e.g. APIs or Firebase)
|
|
||||||
# google-services.json
|
|
||||||
|
|
||||||
# Freeline
|
|
||||||
freeline.py
|
|
||||||
freeline/
|
|
||||||
freeline_project_description.json
|
|
||||||
|
|
||||||
# fastlane
|
|
||||||
fastlane/report.xml
|
|
||||||
fastlane/Preview.html
|
|
||||||
fastlane/screenshots
|
|
||||||
fastlane/test_output
|
|
||||||
fastlane/readme.md
|
|
||||||
|
|
||||||
# Version control
|
|
||||||
vcs.xml
|
|
||||||
|
|
||||||
# lint
|
|
||||||
lint/intermediates/
|
|
||||||
lint/generated/
|
|
||||||
lint/outputs/
|
|
||||||
lint/tmp/
|
|
||||||
# lint/reports/
|
|
||||||
|
|
||||||
# Android Profiling
|
|
||||||
*.hprof
|
|
||||||
|
|
||||||
# Cordova plugins for Capacitor
|
|
||||||
capacitor-cordova-android-plugins
|
|
||||||
|
|
||||||
# Copied web assets
|
|
||||||
app/src/main/assets/public
|
|
||||||
|
|
||||||
# Generated Config files
|
|
||||||
app/src/main/assets/capacitor.config.json
|
|
||||||
app/src/main/assets/capacitor.plugins.json
|
|
||||||
app/src/main/res/xml/config.xml
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
/build/*
|
|
||||||
!/build/.npmkeep
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
apply plugin: 'com.android.application'
|
|
||||||
|
|
||||||
android {
|
|
||||||
namespace "com.nestri.play"
|
|
||||||
compileSdk rootProject.ext.compileSdkVersion
|
|
||||||
defaultConfig {
|
|
||||||
applicationId "com.nestri.play"
|
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
|
||||||
versionCode 1
|
|
||||||
versionName "1.0"
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
||||||
aaptOptions {
|
|
||||||
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
|
||||||
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
|
|
||||||
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
minifyEnabled false
|
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
flatDir{
|
|
||||||
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
|
||||||
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
||||||
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
|
|
||||||
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
|
|
||||||
implementation project(':capacitor-android')
|
|
||||||
testImplementation "junit:junit:$junitVersion"
|
|
||||||
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
||||||
implementation project(':capacitor-cordova-android-plugins')
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: 'capacitor.build.gradle'
|
|
||||||
|
|
||||||
try {
|
|
||||||
def servicesJSON = file('google-services.json')
|
|
||||||
if (servicesJSON.text) {
|
|
||||||
apply plugin: 'com.google.gms.google-services'
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
|
||||||
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
|
||||||
|
|
||||||
android {
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_21
|
|
||||||
targetCompatibility JavaVersion.VERSION_21
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
|
||||||
dependencies {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (hasProperty('postBuildExtras')) {
|
|
||||||
postBuildExtras()
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Add project specific ProGuard rules here.
|
|
||||||
# You can control the set of applied configuration files using the
|
|
||||||
# proguardFiles setting in build.gradle.
|
|
||||||
#
|
|
||||||
# For more details, see
|
|
||||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
|
||||||
|
|
||||||
# If your project uses WebView with JS, uncomment the following
|
|
||||||
# and specify the fully qualified class name to the JavaScript interface
|
|
||||||
# class:
|
|
||||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
|
||||||
# public *;
|
|
||||||
#}
|
|
||||||
|
|
||||||
# Uncomment this to preserve the line number information for
|
|
||||||
# debugging stack traces.
|
|
||||||
#-keepattributes SourceFile,LineNumberTable
|
|
||||||
|
|
||||||
# If you keep the line number information, uncomment this to
|
|
||||||
# hide the original source file name.
|
|
||||||
#-renamesourcefileattribute SourceFile
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
package com.getcapacitor.myapp;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instrumented test, which will execute on an Android device.
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class ExampleInstrumentedTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void useAppContext() throws Exception {
|
|
||||||
// Context of the app under test.
|
|
||||||
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
|
||||||
|
|
||||||
assertEquals("com.getcapacitor.app", appContext.getPackageName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
|
|
||||||
<application
|
|
||||||
android:allowBackup="true"
|
|
||||||
android:icon="@mipmap/ic_launcher"
|
|
||||||
android:label="@string/app_name"
|
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
|
||||||
android:supportsRtl="true"
|
|
||||||
android:theme="@style/AppTheme">
|
|
||||||
|
|
||||||
<activity
|
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
|
|
||||||
android:name=".MainActivity"
|
|
||||||
android:label="@string/title_activity_main"
|
|
||||||
android:theme="@style/AppTheme.NoActionBarLaunch"
|
|
||||||
android:launchMode="singleTask"
|
|
||||||
android:exported="true">
|
|
||||||
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<provider
|
|
||||||
android:name="androidx.core.content.FileProvider"
|
|
||||||
android:authorities="${applicationId}.fileprovider"
|
|
||||||
android:exported="false"
|
|
||||||
android:grantUriPermissions="true">
|
|
||||||
<meta-data
|
|
||||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
|
||||||
android:resource="@xml/file_paths"></meta-data>
|
|
||||||
</provider>
|
|
||||||
</application>
|
|
||||||
|
|
||||||
<!-- Permissions -->
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
|
||||||
</manifest>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
package com.nestri.play;
|
|
||||||
|
|
||||||
import com.getcapacitor.BridgeActivity;
|
|
||||||
|
|
||||||
public class MainActivity extends BridgeActivity {}
|
|
||||||
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 7.7 KiB |
|
Before Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 17 KiB |
@@ -1,34 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:aapt="http://schemas.android.com/aapt"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportHeight="108"
|
|
||||||
android:viewportWidth="108">
|
|
||||||
<path
|
|
||||||
android:fillType="evenOdd"
|
|
||||||
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
|
||||||
android:strokeColor="#00000000"
|
|
||||||
android:strokeWidth="1">
|
|
||||||
<aapt:attr name="android:fillColor">
|
|
||||||
<gradient
|
|
||||||
android:endX="78.5885"
|
|
||||||
android:endY="90.9159"
|
|
||||||
android:startX="48.7653"
|
|
||||||
android:startY="61.0927"
|
|
||||||
android:type="linear">
|
|
||||||
<item
|
|
||||||
android:color="#44000000"
|
|
||||||
android:offset="0.0" />
|
|
||||||
<item
|
|
||||||
android:color="#00000000"
|
|
||||||
android:offset="1.0" />
|
|
||||||
</gradient>
|
|
||||||
</aapt:attr>
|
|
||||||
</path>
|
|
||||||
<path
|
|
||||||
android:fillColor="#FFFFFF"
|
|
||||||
android:fillType="nonZero"
|
|
||||||
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
|
||||||
android:strokeColor="#00000000"
|
|
||||||
android:strokeWidth="1" />
|
|
||||||
</vector>
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="108dp"
|
|
||||||
android:height="108dp"
|
|
||||||
android:viewportHeight="108"
|
|
||||||
android:viewportWidth="108">
|
|
||||||
<path
|
|
||||||
android:fillColor="#26A69A"
|
|
||||||
android:pathData="M0,0h108v108h-108z" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M9,0L9,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,0L19,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,0L29,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,0L39,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,0L49,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,0L59,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,0L69,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,0L79,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M89,0L89,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M99,0L99,108"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,9L108,9"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,19L108,19"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,29L108,29"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,39L108,39"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,49L108,49"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,59L108,59"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,69L108,69"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,79L108,79"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,89L108,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M0,99L108,99"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,29L89,29"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,39L89,39"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,49L89,49"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,59L89,59"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,69L89,69"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M19,79L89,79"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M29,19L29,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M39,19L39,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M49,19L49,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M59,19L59,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M69,19L69,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
<path
|
|
||||||
android:fillColor="#00000000"
|
|
||||||
android:pathData="M79,19L79,89"
|
|
||||||
android:strokeColor="#33FFFFFF"
|
|
||||||
android:strokeWidth="0.8" />
|
|
||||||
</vector>
|
|
||||||
|
Before Width: | Height: | Size: 3.9 KiB |
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
tools:context=".MainActivity">
|
|
||||||
|
|
||||||
<WebView
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent" />
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@color/ic_launcher_background"/>
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
||||||
</adaptive-icon>
|
|
||||||
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 6.5 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 16 KiB |
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
<color name="ic_launcher_background">#FFFFFF</color>
|
|
||||||
</resources>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version='1.0' encoding='utf-8'?>
|
|
||||||
<resources>
|
|
||||||
<string name="app_name">Nestri Play</string>
|
|
||||||
<string name="title_activity_main">Nestri Play</string>
|
|
||||||
<string name="package_name">com.nestri.play</string>
|
|
||||||
<string name="custom_url_scheme">com.nestri.play</string>
|
|
||||||
</resources>
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<resources>
|
|
||||||
|
|
||||||
<!-- Base application theme. -->
|
|
||||||
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
|
||||||
<!-- Customize your theme here. -->
|
|
||||||
<item name="colorPrimary">@color/colorPrimary</item>
|
|
||||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
|
||||||
<item name="colorAccent">@color/colorAccent</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
|
|
||||||
<item name="windowActionBar">false</item>
|
|
||||||
<item name="windowNoTitle">true</item>
|
|
||||||
<item name="android:background">@null</item>
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
|
||||||
<item name="android:background">@drawable/splash</item>
|
|
||||||
</style>
|
|
||||||
</resources>
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<external-path name="my_images" path="." />
|
|
||||||
<cache-path name="my_cache_images" path="." />
|
|
||||||
</paths>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package com.getcapacitor.myapp;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Example local unit test, which will execute on the development machine (host).
|
|
||||||
*
|
|
||||||
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
|
||||||
*/
|
|
||||||
public class ExampleUnitTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void addition_isCorrect() throws Exception {
|
|
||||||
assertEquals(4, 2 + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:8.7.2'
|
|
||||||
classpath 'com.google.gms:google-services:4.4.2'
|
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
|
||||||
// in the individual module build.gradle files
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "variables.gradle"
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
google()
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task clean(type: Delete) {
|
|
||||||
delete rootProject.buildDir
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
|
||||||
include ':capacitor-android'
|
|
||||||
project(':capacitor-android').projectDir = new File('../../../node_modules/@capacitor/android/capacitor')
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# Project-wide Gradle settings.
|
|
||||||
|
|
||||||
# IDE (e.g. Android Studio) users:
|
|
||||||
# Gradle settings configured through the IDE *will override*
|
|
||||||
# any settings specified in this file.
|
|
||||||
|
|
||||||
# For more details on how to configure your build environment visit
|
|
||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
|
||||||
|
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
|
||||||
org.gradle.jvmargs=-Xmx1536m
|
|
||||||
|
|
||||||
# When configured, Gradle will run in incubating parallel mode.
|
|
||||||
# This option should only be used with decoupled projects. More details, visit
|
|
||||||
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
|
||||||
# org.gradle.parallel=true
|
|
||||||
|
|
||||||
# AndroidX package structure to make it clearer which packages are bundled with the
|
|
||||||
# Android operating system, and which are packaged with your app's APK
|
|
||||||
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
|
||||||
android.useAndroidX=true
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
|
||||||
networkTimeout=10000
|
|
||||||
validateDistributionUrl=true
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
252
packages/play-standalone/android/gradlew
vendored
@@ -1,252 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright © 2015-2021 the original authors.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
#
|
|
||||||
|
|
||||||
##############################################################################
|
|
||||||
#
|
|
||||||
# Gradle start up script for POSIX generated by Gradle.
|
|
||||||
#
|
|
||||||
# Important for running:
|
|
||||||
#
|
|
||||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
|
||||||
# noncompliant, but you have some other compliant shell such as ksh or
|
|
||||||
# bash, then to run this script, type that shell name before the whole
|
|
||||||
# command line, like:
|
|
||||||
#
|
|
||||||
# ksh Gradle
|
|
||||||
#
|
|
||||||
# Busybox and similar reduced shells will NOT work, because this script
|
|
||||||
# requires all of these POSIX shell features:
|
|
||||||
# * functions;
|
|
||||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
|
||||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
|
||||||
# * compound commands having a testable exit status, especially «case»;
|
|
||||||
# * various built-in commands including «command», «set», and «ulimit».
|
|
||||||
#
|
|
||||||
# Important for patching:
|
|
||||||
#
|
|
||||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
|
||||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
|
||||||
#
|
|
||||||
# The "traditional" practice of packing multiple parameters into a
|
|
||||||
# space-separated string is a well documented source of bugs and security
|
|
||||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
|
||||||
# options in "$@", and eventually passing that to Java.
|
|
||||||
#
|
|
||||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
|
||||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
|
||||||
# see the in-line comments for details.
|
|
||||||
#
|
|
||||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
|
||||||
# Darwin, MinGW, and NonStop.
|
|
||||||
#
|
|
||||||
# (3) This script is generated from the Groovy template
|
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
|
||||||
# within the Gradle project.
|
|
||||||
#
|
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
|
||||||
#
|
|
||||||
##############################################################################
|
|
||||||
|
|
||||||
# Attempt to set APP_HOME
|
|
||||||
|
|
||||||
# Resolve links: $0 may be a link
|
|
||||||
app_path=$0
|
|
||||||
|
|
||||||
# Need this for daisy-chained symlinks.
|
|
||||||
while
|
|
||||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
|
||||||
[ -h "$app_path" ]
|
|
||||||
do
|
|
||||||
ls=$( ls -ld "$app_path" )
|
|
||||||
link=${ls#*' -> '}
|
|
||||||
case $link in #(
|
|
||||||
/*) app_path=$link ;; #(
|
|
||||||
*) app_path=$APP_HOME$link ;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# This is normally unused
|
|
||||||
# shellcheck disable=SC2034
|
|
||||||
APP_BASE_NAME=${0##*/}
|
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
|
||||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
|
||||||
' "$PWD" ) || exit
|
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
|
||||||
MAX_FD=maximum
|
|
||||||
|
|
||||||
warn () {
|
|
||||||
echo "$*"
|
|
||||||
} >&2
|
|
||||||
|
|
||||||
die () {
|
|
||||||
echo
|
|
||||||
echo "$*"
|
|
||||||
echo
|
|
||||||
exit 1
|
|
||||||
} >&2
|
|
||||||
|
|
||||||
# OS specific support (must be 'true' or 'false').
|
|
||||||
cygwin=false
|
|
||||||
msys=false
|
|
||||||
darwin=false
|
|
||||||
nonstop=false
|
|
||||||
case "$( uname )" in #(
|
|
||||||
CYGWIN* ) cygwin=true ;; #(
|
|
||||||
Darwin* ) darwin=true ;; #(
|
|
||||||
MSYS* | MINGW* ) msys=true ;; #(
|
|
||||||
NONSTOP* ) nonstop=true ;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
|
||||||
if [ -n "$JAVA_HOME" ] ; then
|
|
||||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
|
||||||
# IBM's JDK on AIX uses strange locations for the executables
|
|
||||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
|
||||||
else
|
|
||||||
JAVACMD=$JAVA_HOME/bin/java
|
|
||||||
fi
|
|
||||||
if [ ! -x "$JAVACMD" ] ; then
|
|
||||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
JAVACMD=java
|
|
||||||
if ! command -v java >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
|
||||||
location of your Java installation."
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
|
||||||
case $MAX_FD in #(
|
|
||||||
max*)
|
|
||||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
|
||||||
# shellcheck disable=SC2039,SC3045
|
|
||||||
MAX_FD=$( ulimit -H -n ) ||
|
|
||||||
warn "Could not query maximum file descriptor limit"
|
|
||||||
esac
|
|
||||||
case $MAX_FD in #(
|
|
||||||
'' | soft) :;; #(
|
|
||||||
*)
|
|
||||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
|
||||||
# shellcheck disable=SC2039,SC3045
|
|
||||||
ulimit -n "$MAX_FD" ||
|
|
||||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Collect all arguments for the java command, stacking in reverse order:
|
|
||||||
# * args from the command line
|
|
||||||
# * the main class name
|
|
||||||
# * -classpath
|
|
||||||
# * -D...appname settings
|
|
||||||
# * --module-path (only if needed)
|
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
|
||||||
|
|
||||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
|
||||||
if "$cygwin" || "$msys" ; then
|
|
||||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
|
||||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
|
||||||
|
|
||||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
|
||||||
|
|
||||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
|
||||||
for arg do
|
|
||||||
if
|
|
||||||
case $arg in #(
|
|
||||||
-*) false ;; # don't mess with options #(
|
|
||||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
|
||||||
[ -e "$t" ] ;; #(
|
|
||||||
*) false ;;
|
|
||||||
esac
|
|
||||||
then
|
|
||||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
|
||||||
fi
|
|
||||||
# Roll the args list around exactly as many times as the number of
|
|
||||||
# args, so each arg winds up back in the position where it started, but
|
|
||||||
# possibly modified.
|
|
||||||
#
|
|
||||||
# NB: a `for` loop captures its iteration list before it begins, so
|
|
||||||
# changing the positional parameters here affects neither the number of
|
|
||||||
# iterations, nor the values presented in `arg`.
|
|
||||||
shift # remove old arg
|
|
||||||
set -- "$@" "$arg" # push replacement arg
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
|
||||||
# and any embedded shellness will be escaped.
|
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
|
||||||
# treated as '${Hostname}' itself on the command line.
|
|
||||||
|
|
||||||
set -- \
|
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
|
||||||
-classpath "$CLASSPATH" \
|
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
|
||||||
"$@"
|
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
|
||||||
if ! command -v xargs >/dev/null 2>&1
|
|
||||||
then
|
|
||||||
die "xargs is not available"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Use "xargs" to parse quoted args.
|
|
||||||
#
|
|
||||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
|
||||||
#
|
|
||||||
# In Bash we could simply go:
|
|
||||||
#
|
|
||||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
|
||||||
# set -- "${ARGS[@]}" "$@"
|
|
||||||
#
|
|
||||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
|
||||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
|
||||||
# character that might be a shell metacharacter, then use eval to reverse
|
|
||||||
# that process (while maintaining the separation between arguments), and wrap
|
|
||||||
# the whole thing up as a single "set" statement.
|
|
||||||
#
|
|
||||||
# This will of course break if any of these variables contains a newline or
|
|
||||||
# an unmatched quote.
|
|
||||||
#
|
|
||||||
|
|
||||||
eval "set -- $(
|
|
||||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
|
||||||
xargs -n1 |
|
|
||||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
|
||||||
tr '\n' ' '
|
|
||||||
)" '"$@"'
|
|
||||||
|
|
||||||
exec "$JAVACMD" "$@"
|
|
||||||
94
packages/play-standalone/android/gradlew.bat
vendored
@@ -1,94 +0,0 @@
|
|||||||
@rem
|
|
||||||
@rem Copyright 2015 the original author or authors.
|
|
||||||
@rem
|
|
||||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
@rem you may not use this file except in compliance with the License.
|
|
||||||
@rem You may obtain a copy of the License at
|
|
||||||
@rem
|
|
||||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
@rem
|
|
||||||
@rem Unless required by applicable law or agreed to in writing, software
|
|
||||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
@rem See the License for the specific language governing permissions and
|
|
||||||
@rem limitations under the License.
|
|
||||||
@rem
|
|
||||||
@rem SPDX-License-Identifier: Apache-2.0
|
|
||||||
@rem
|
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
|
||||||
@rem ##########################################################################
|
|
||||||
@rem
|
|
||||||
@rem Gradle startup script for Windows
|
|
||||||
@rem
|
|
||||||
@rem ##########################################################################
|
|
||||||
|
|
||||||
@rem Set local scope for the variables with windows NT shell
|
|
||||||
if "%OS%"=="Windows_NT" setlocal
|
|
||||||
|
|
||||||
set DIRNAME=%~dp0
|
|
||||||
if "%DIRNAME%"=="" set DIRNAME=.
|
|
||||||
@rem This is normally unused
|
|
||||||
set APP_BASE_NAME=%~n0
|
|
||||||
set APP_HOME=%DIRNAME%
|
|
||||||
|
|
||||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
|
||||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
|
||||||
|
|
||||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
|
||||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
|
||||||
|
|
||||||
@rem Find java.exe
|
|
||||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
|
||||||
|
|
||||||
set JAVA_EXE=java.exe
|
|
||||||
%JAVA_EXE% -version >NUL 2>&1
|
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
|
||||||
|
|
||||||
echo. 1>&2
|
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
|
||||||
echo. 1>&2
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
|
||||||
echo location of your Java installation. 1>&2
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:findJavaFromJavaHome
|
|
||||||
set JAVA_HOME=%JAVA_HOME:"=%
|
|
||||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|
||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
|
||||||
|
|
||||||
echo. 1>&2
|
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
|
||||||
echo. 1>&2
|
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
|
||||||
echo location of your Java installation. 1>&2
|
|
||||||
|
|
||||||
goto fail
|
|
||||||
|
|
||||||
:execute
|
|
||||||
@rem Setup the command line
|
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
|
||||||
|
|
||||||
:end
|
|
||||||
@rem End local scope for the variables with windows NT shell
|
|
||||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
|
||||||
|
|
||||||
:fail
|
|
||||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
|
||||||
rem the _cmd.exe /c_ return code!
|
|
||||||
set EXIT_CODE=%ERRORLEVEL%
|
|
||||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
|
||||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
|
||||||
exit /b %EXIT_CODE%
|
|
||||||
|
|
||||||
:mainEnd
|
|
||||||
if "%OS%"=="Windows_NT" endlocal
|
|
||||||
|
|
||||||
:omega
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
include ':app'
|
|
||||||
include ':capacitor-cordova-android-plugins'
|
|
||||||
project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
|
|
||||||
|
|
||||||
apply from: 'capacitor.settings.gradle'
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
ext {
|
|
||||||
minSdkVersion = 23
|
|
||||||
compileSdkVersion = 35
|
|
||||||
targetSdkVersion = 35
|
|
||||||
androidxActivityVersion = '1.9.2'
|
|
||||||
androidxAppCompatVersion = '1.7.0'
|
|
||||||
androidxCoordinatorLayoutVersion = '1.2.0'
|
|
||||||
androidxCoreVersion = '1.15.0'
|
|
||||||
androidxFragmentVersion = '1.8.4'
|
|
||||||
coreSplashScreenVersion = '1.0.1'
|
|
||||||
androidxWebkitVersion = '1.12.1'
|
|
||||||
junitVersion = '4.13.2'
|
|
||||||
androidxJunitVersion = '1.2.1'
|
|
||||||
androidxEspressoCoreVersion = '3.6.1'
|
|
||||||
cordovaAndroidVersion = '10.1.1'
|
|
||||||
}
|
|
||||||
@@ -2,10 +2,12 @@
|
|||||||
import { defineConfig, envField } from "astro/config";
|
import { defineConfig, envField } from "astro/config";
|
||||||
import node from "@astrojs/node";
|
import node from "@astrojs/node";
|
||||||
|
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
output: "static",
|
adapter: node({
|
||||||
|
mode: 'standalone',
|
||||||
|
}),
|
||||||
|
output: "server",
|
||||||
server: {
|
server: {
|
||||||
"host": "0.0.0.0",
|
"host": "0.0.0.0",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import type { CapacitorConfig } from '@capacitor/cli';
|
|
||||||
|
|
||||||
const config: CapacitorConfig = {
|
|
||||||
appId: 'com.nestri.play',
|
|
||||||
appName: 'Nestri Play',
|
|
||||||
webDir: 'dist'
|
|
||||||
};
|
|
||||||
|
|
||||||
export default config;
|
|
||||||
@@ -5,16 +5,10 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev",
|
||||||
"build": "astro build",
|
"build": "astro build",
|
||||||
"build:cap": "astro build && npx cap copy",
|
|
||||||
"preview": "astro preview",
|
"preview": "astro preview",
|
||||||
"astro": "astro",
|
"astro": "astro"
|
||||||
"sync:android": "npm run build && npx cap sync android"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@capacitor/android": "^7.4.3",
|
|
||||||
"@capacitor/cli": "^7.4.3",
|
|
||||||
"@capacitor/core": "^7.4.3",
|
|
||||||
"@capacitor/ios": "^7.4.3",
|
|
||||||
"@astrojs/node": "9.5.0",
|
"@astrojs/node": "9.5.0",
|
||||||
"@nestri/input": "*",
|
"@nestri/input": "*",
|
||||||
"astro": "5.15.1"
|
"astro": "5.15.1"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
import DefaultLayout from "../layouts/DefaultLayout.astro";
|
import DefaultLayout from "../layouts/DefaultLayout.astro";
|
||||||
|
const { room } = Astro.params;
|
||||||
|
|
||||||
// Passing of environment variables to the client side
|
// Passing of environment variables to the client side
|
||||||
// gotta love node and it's ecosystem..
|
// gotta love node and it's ecosystem..
|
||||||
@@ -18,7 +19,7 @@ if (envs_map.size > 0) {
|
|||||||
<DefaultLayout>
|
<DefaultLayout>
|
||||||
<h1 id="offlineText" class="offline">Offline</h1>
|
<h1 id="offlineText" class="offline">Offline</h1>
|
||||||
<h1 id="loadingText" class="loading">Warming up the GPU...</h1>
|
<h1 id="loadingText" class="loading">Warming up the GPU...</h1>
|
||||||
<canvas id="playCanvas" class="playCanvas"></canvas>
|
<canvas id="playCanvas" class="playCanvas" data-room={room}></canvas>
|
||||||
<div id="ENVS" data-envs={envs}></div>
|
<div id="ENVS" data-envs={envs}></div>
|
||||||
</DefaultLayout>
|
</DefaultLayout>
|
||||||
|
|
||||||
@@ -41,9 +42,9 @@ if (envs_map.size > 0) {
|
|||||||
const offlineText = document.getElementById("offlineText")! as HTMLHeadingElement;
|
const offlineText = document.getElementById("offlineText")! as HTMLHeadingElement;
|
||||||
const loadingText = document.getElementById("loadingText")! as HTMLHeadingElement;
|
const loadingText = document.getElementById("loadingText")! as HTMLHeadingElement;
|
||||||
|
|
||||||
const room = window.location.hash.substring(1);
|
const room = canvas.dataset.room;
|
||||||
if (!room || room.length <= 0) {
|
if (!room || room.length <= 0) {
|
||||||
throw new Error("Room parameter is required in URL hash");
|
throw new Error("Room parameter is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
offlineText.style.display = "flex";
|
offlineText.style.display = "flex";
|
||||||
@@ -98,9 +99,6 @@ if (envs_map.size > 0) {
|
|||||||
});
|
});
|
||||||
window.addEventListener("gamepaddisconnected", (e) => {
|
window.addEventListener("gamepaddisconnected", (e) => {
|
||||||
console.log("Gamepad disconnected:", e.gamepad);
|
console.log("Gamepad disconnected:", e.gamepad);
|
||||||
if (e.gamepad.id.toLowerCase().includes("nestri"))
|
|
||||||
return;
|
|
||||||
|
|
||||||
let disconnected = nestriControllers.find((c) => c.getSlot() === e.gamepad.index);
|
let disconnected = nestriControllers.find((c) => c.getSlot() === e.gamepad.index);
|
||||||
if (disconnected) {
|
if (disconnected) {
|
||||||
disconnected.dispose();
|
disconnected.dispose();
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
---
|
|
||||||
import { ClientRouter } from "astro:transitions";
|
|
||||||
import { navigate } from "astro:transitions/client";
|
|
||||||
---
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width">
|
|
||||||
<title>Nestri Play</title>
|
|
||||||
<ClientRouter />
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
font-family: sans-serif;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
height: 100vh;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
form {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 1rem;
|
|
||||||
padding: 2rem;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 8px;
|
|
||||||
}
|
|
||||||
div {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
label {
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
input {
|
|
||||||
padding: 0.5rem;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
padding: 0.75rem;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
button:hover {
|
|
||||||
background-color: #0056b3;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<form id="join-form">
|
|
||||||
<h1>Nestri Play</h1>
|
|
||||||
<div>
|
|
||||||
<label for="room">Room</label>
|
|
||||||
<input type="text" id="room" name="room" required list="room-list">
|
|
||||||
<datalist id="room-list"></datalist>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="peerURL">peerURL</label>
|
|
||||||
<input type="text" id="peerURL" name="peerURL" required list="peerURL-list">
|
|
||||||
<datalist id="peerURL-list"></datalist>
|
|
||||||
</div>
|
|
||||||
<button type="submit">Join</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import { navigate } from "astro:transitions/client";
|
|
||||||
|
|
||||||
const roomInput = document.getElementById('room') as HTMLInputElement;
|
|
||||||
const peerURLInput = document.getElementById('peerURL') as HTMLInputElement;
|
|
||||||
const roomList = document.getElementById('room-list');
|
|
||||||
const peerURLList = document.getElementById('peerURL-list');
|
|
||||||
|
|
||||||
// Load values from cookies
|
|
||||||
function getCookie(name) {
|
|
||||||
const value = `; ${document.cookie}`;
|
|
||||||
const parts = value.split(`; ${name}=`);
|
|
||||||
if (parts.length === 2) {
|
|
||||||
const cookieValue = parts.pop()?.split(';').shift();
|
|
||||||
return cookieValue ? decodeURIComponent(cookieValue) : undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setCookie(name, value, days) {
|
|
||||||
const d = new Date();
|
|
||||||
d.setTime(d.getTime() + (days*24*60*60*1000));
|
|
||||||
const expires = "expires="+ d.toUTCString();
|
|
||||||
document.cookie = name + "=" + encodeURIComponent(value) + ";" + expires + ";path=/";
|
|
||||||
}
|
|
||||||
|
|
||||||
const storedRooms = JSON.parse(getCookie('nestri-rooms') || '[]');
|
|
||||||
const storedPeerURLs = JSON.parse(getCookie('nestri-peerURLs') || '[]');
|
|
||||||
|
|
||||||
if (roomList) {
|
|
||||||
storedRooms.forEach(room => {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = room;
|
|
||||||
roomList.appendChild(option);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (peerURLList) {
|
|
||||||
storedPeerURLs.forEach(peerURL => {
|
|
||||||
const option = document.createElement('option');
|
|
||||||
option.value = peerURL;
|
|
||||||
peerURLList.appendChild(option);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storedRooms.length > 0 && roomInput) {
|
|
||||||
roomInput.value = storedRooms[0];
|
|
||||||
}
|
|
||||||
if (storedPeerURLs.length > 0 && peerURLInput) {
|
|
||||||
peerURLInput.value = storedPeerURLs[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('join-form')?.addEventListener('submit', function(event) {
|
|
||||||
event.preventDefault();
|
|
||||||
const room = roomInput.value;
|
|
||||||
const peerURL = peerURLInput.value;
|
|
||||||
|
|
||||||
// Save values to cookies
|
|
||||||
const newRooms = [room, ...storedRooms.filter(r => r !== room)].slice(0, 10);
|
|
||||||
const newPeerURLs = [peerURL, ...storedPeerURLs.filter(p => p !== peerURL)].slice(0, 10);
|
|
||||||
|
|
||||||
setCookie('nestri-rooms', JSON.stringify(newRooms), 365);
|
|
||||||
setCookie('nestri-peerURLs', JSON.stringify(newPeerURLs), 365);
|
|
||||||
|
|
||||||
if (room && peerURL) {
|
|
||||||
navigate(`/play/index.html?peerURL=${encodeURIComponent(peerURL)}#${room}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -2,6 +2,7 @@ package common
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/pion/interceptor/pkg/nack"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@@ -30,20 +31,121 @@ func InitWebRTCAPI() error {
|
|||||||
return fmt.Errorf("failed to register extensions: %w", err)
|
return fmt.Errorf("failed to register extensions: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default codecs cover our needs
|
// Register codecs
|
||||||
err = mediaEngine.RegisterDefaultCodecs()
|
for _, codec := range []webrtc.RTPCodecParameters{
|
||||||
if err != nil {
|
{
|
||||||
return err
|
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 2, SDPFmtpLine: "minptime=10;useinbandfec=1"},
|
||||||
|
PayloadType: 111,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
if err = mediaEngine.RegisterCodec(codec, webrtc.RTPCodecTypeAudio); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
videoRTCPFeedback := []webrtc.RTCPFeedback{{"nack", ""}, {"nack", "pli"}}
|
||||||
|
for _, codec := range []webrtc.RTPCodecParameters{
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
||||||
|
MimeType: webrtc.MimeTypeH264, ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f",
|
||||||
|
RTCPFeedback: videoRTCPFeedback,
|
||||||
|
},
|
||||||
|
PayloadType: 102,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
||||||
|
MimeType: webrtc.MimeTypeH264, ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f",
|
||||||
|
RTCPFeedback: videoRTCPFeedback,
|
||||||
|
},
|
||||||
|
PayloadType: 104,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
||||||
|
MimeType: webrtc.MimeTypeH264, ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f",
|
||||||
|
RTCPFeedback: videoRTCPFeedback,
|
||||||
|
},
|
||||||
|
PayloadType: 106,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
||||||
|
MimeType: webrtc.MimeTypeH264, ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f",
|
||||||
|
RTCPFeedback: videoRTCPFeedback,
|
||||||
|
},
|
||||||
|
PayloadType: 108,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
||||||
|
MimeType: webrtc.MimeTypeH264, ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=4d001f",
|
||||||
|
RTCPFeedback: videoRTCPFeedback,
|
||||||
|
},
|
||||||
|
PayloadType: 127,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
||||||
|
MimeType: webrtc.MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=4d001f",
|
||||||
|
RTCPFeedback: videoRTCPFeedback,
|
||||||
|
},
|
||||||
|
PayloadType: 39,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
||||||
|
MimeType: webrtc.MimeTypeH265,
|
||||||
|
ClockRate: 90000,
|
||||||
|
RTCPFeedback: videoRTCPFeedback,
|
||||||
|
},
|
||||||
|
PayloadType: 116,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeAV1, ClockRate: 90000, RTCPFeedback: videoRTCPFeedback},
|
||||||
|
PayloadType: 45,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP9, ClockRate: 90000, SDPFmtpLine: "profile-id=0", RTCPFeedback: videoRTCPFeedback},
|
||||||
|
PayloadType: 98,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{MimeType: webrtc.MimeTypeVP9, ClockRate: 90000, SDPFmtpLine: "profile-id=2", RTCPFeedback: videoRTCPFeedback},
|
||||||
|
PayloadType: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
RTPCodecCapability: webrtc.RTPCodecCapability{
|
||||||
|
MimeType: webrtc.MimeTypeH264, ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=64001f",
|
||||||
|
RTCPFeedback: videoRTCPFeedback,
|
||||||
|
},
|
||||||
|
PayloadType: 112,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
if err = mediaEngine.RegisterCodec(codec, webrtc.RTPCodecTypeVideo); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interceptor registry
|
// Interceptor registry
|
||||||
interceptorRegistry := &interceptor.Registry{}
|
interceptorRegistry := &interceptor.Registry{}
|
||||||
|
|
||||||
// Use default set
|
// Register our interceptors..
|
||||||
err = webrtc.RegisterDefaultInterceptors(mediaEngine, interceptorRegistry)
|
nackGenFactory, err := nack.NewGeneratorInterceptor()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
interceptorRegistry.Add(nackGenFactory)
|
||||||
|
nackRespFactory, err := nack.NewResponderInterceptor()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
interceptorRegistry.Add(nackRespFactory)
|
||||||
|
|
||||||
|
if err = webrtc.ConfigureRTCPReports(interceptorRegistry); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Setting engine
|
// Setting engine
|
||||||
settingEngine := webrtc.SettingEngine{}
|
settingEngine := webrtc.SettingEngine{}
|
||||||
@@ -53,7 +155,7 @@ func InitWebRTCAPI() error {
|
|||||||
|
|
||||||
nat11IP := GetFlags().NAT11IP
|
nat11IP := GetFlags().NAT11IP
|
||||||
if len(nat11IP) > 0 {
|
if len(nat11IP) > 0 {
|
||||||
settingEngine.SetNAT1To1IPs([]string{nat11IP}, webrtc.ICECandidateTypeSrflx)
|
settingEngine.SetNAT1To1IPs([]string{nat11IP}, webrtc.ICECandidateTypeHost)
|
||||||
slog.Info("Using NAT 1:1 IP for WebRTC", "nat11_ip", nat11IP)
|
slog.Info("Using NAT 1:1 IP for WebRTC", "nat11_ip", nat11IP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ func getLocalIP() string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
for _, address := range addrs {
|
for _, address := range addrs {
|
||||||
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsPrivate() && !ipnet.IP.IsUnspecified() {
|
||||||
if ipnet.IP.To4() != nil || ipnet.IP != nil {
|
if ipnet.IP.To4() != nil || ipnet.IP != nil {
|
||||||
return ipnet.IP.String()
|
return ipnet.IP.String()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ import (
|
|||||||
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
|
rcmgr "github.com/libp2p/go-libp2p/p2p/host/resource-manager"
|
||||||
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
|
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
|
||||||
"github.com/libp2p/go-libp2p/p2p/security/noise"
|
"github.com/libp2p/go-libp2p/p2p/security/noise"
|
||||||
|
p2pquic "github.com/libp2p/go-libp2p/p2p/transport/quic"
|
||||||
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
|
"github.com/libp2p/go-libp2p/p2p/transport/quicreuse"
|
||||||
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
"github.com/libp2p/go-libp2p/p2p/transport/tcp"
|
||||||
ws "github.com/libp2p/go-libp2p/p2p/transport/websocket"
|
|
||||||
webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
|
webtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
|
||||||
"github.com/multiformats/go-multiaddr"
|
"github.com/multiformats/go-multiaddr"
|
||||||
"github.com/oklog/ulid/v2"
|
"github.com/oklog/ulid/v2"
|
||||||
@@ -91,10 +91,10 @@ func NewRelay(ctx context.Context, port int, identityKey crypto.PrivKey) (*Relay
|
|||||||
listenAddrs := []string{
|
listenAddrs := []string{
|
||||||
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port), // IPv4 - Raw TCP
|
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", port), // IPv4 - Raw TCP
|
||||||
fmt.Sprintf("/ip6/::/tcp/%d", port), // IPv6 - Raw TCP
|
fmt.Sprintf("/ip6/::/tcp/%d", port), // IPv6 - Raw TCP
|
||||||
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d/ws", port), // IPv4 - TCP WebSocket
|
|
||||||
fmt.Sprintf("/ip6/::/tcp/%d/ws", port), // IPv6 - TCP WebSocket
|
|
||||||
fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic-v1/webtransport", port), // IPv4 - UDP QUIC WebTransport
|
fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic-v1/webtransport", port), // IPv4 - UDP QUIC WebTransport
|
||||||
fmt.Sprintf("/ip6/::/udp/%d/quic-v1/webtransport", port), // IPv6 - UDP QUIC WebTransport
|
fmt.Sprintf("/ip6/::/udp/%d/quic-v1/webtransport", port), // IPv6 - UDP QUIC WebTransport
|
||||||
|
fmt.Sprintf("/ip4/0.0.0.0/udp/%d/quic-v1", port), // IPv4 - UDP Raw QUIC
|
||||||
|
fmt.Sprintf("/ip6/::/udp/%d/quic-v1", port), // IPv6 - UDP Raw QUIC
|
||||||
}
|
}
|
||||||
|
|
||||||
var muAddrs []multiaddr.Multiaddr
|
var muAddrs []multiaddr.Multiaddr
|
||||||
@@ -112,8 +112,8 @@ func NewRelay(ctx context.Context, port int, identityKey crypto.PrivKey) (*Relay
|
|||||||
libp2p.Identity(identityKey),
|
libp2p.Identity(identityKey),
|
||||||
// Enable required transports
|
// Enable required transports
|
||||||
libp2p.Transport(tcp.NewTCPTransport),
|
libp2p.Transport(tcp.NewTCPTransport),
|
||||||
libp2p.Transport(ws.New),
|
|
||||||
libp2p.Transport(webtransport.New),
|
libp2p.Transport(webtransport.New),
|
||||||
|
libp2p.Transport(p2pquic.NewTransport),
|
||||||
// Other options
|
// Other options
|
||||||
libp2p.ListenAddrs(muAddrs...),
|
libp2p.ListenAddrs(muAddrs...),
|
||||||
libp2p.Security(noise.ID, noise.New),
|
libp2p.Security(noise.ID, noise.New),
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math"
|
|
||||||
"relay/internal/common"
|
"relay/internal/common"
|
||||||
"relay/internal/connections"
|
"relay/internal/connections"
|
||||||
"relay/internal/shared"
|
"relay/internal/shared"
|
||||||
@@ -606,52 +605,8 @@ func (sp *StreamProtocol) handleStreamPush(stream network.Stream) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate differences
|
// Broadcast
|
||||||
var timeDiff int64
|
room.BroadcastPacket(remoteTrack.Kind(), rtpPacket)
|
||||||
var sequenceDiff int
|
|
||||||
|
|
||||||
if remoteTrack.Kind() == webrtc.RTPCodecTypeVideo {
|
|
||||||
timeDiff = int64(rtpPacket.Timestamp) - int64(room.LastVideoTimestamp)
|
|
||||||
if !room.VideoTimestampSet {
|
|
||||||
timeDiff = 0
|
|
||||||
room.VideoTimestampSet = true
|
|
||||||
} else if timeDiff < -(math.MaxUint32 / 10) {
|
|
||||||
timeDiff += math.MaxUint32 + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
sequenceDiff = int(rtpPacket.SequenceNumber) - int(room.LastVideoSequenceNumber)
|
|
||||||
if !room.VideoSequenceSet {
|
|
||||||
sequenceDiff = 0
|
|
||||||
room.VideoSequenceSet = true
|
|
||||||
} else if sequenceDiff < -(math.MaxUint16 / 10) {
|
|
||||||
sequenceDiff += math.MaxUint16 + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
room.LastVideoTimestamp = rtpPacket.Timestamp
|
|
||||||
room.LastVideoSequenceNumber = rtpPacket.SequenceNumber
|
|
||||||
} else { // Audio
|
|
||||||
timeDiff = int64(rtpPacket.Timestamp) - int64(room.LastAudioTimestamp)
|
|
||||||
if !room.AudioTimestampSet {
|
|
||||||
timeDiff = 0
|
|
||||||
room.AudioTimestampSet = true
|
|
||||||
} else if timeDiff < -(math.MaxUint32 / 10) {
|
|
||||||
timeDiff += math.MaxUint32 + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
sequenceDiff = int(rtpPacket.SequenceNumber) - int(room.LastAudioSequenceNumber)
|
|
||||||
if !room.AudioSequenceSet {
|
|
||||||
sequenceDiff = 0
|
|
||||||
room.AudioSequenceSet = true
|
|
||||||
} else if sequenceDiff < -(math.MaxUint16 / 10) {
|
|
||||||
sequenceDiff += math.MaxUint16 + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
room.LastAudioTimestamp = rtpPacket.Timestamp
|
|
||||||
room.LastAudioSequenceNumber = rtpPacket.SequenceNumber
|
|
||||||
}
|
|
||||||
|
|
||||||
// Broadcast with differences
|
|
||||||
room.BroadcastPacketRetimed(remoteTrack.Kind(), rtpPacket, timeDiff, sequenceDiff)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
slog.Debug("Track closed for room", "room", room.Name, "track_kind", remoteTrack.Kind().String())
|
slog.Debug("Track closed for room", "room", room.Name, "track_kind", remoteTrack.Kind().String())
|
||||||
|
|||||||
@@ -106,28 +106,15 @@ func (p *Participant) Close() {
|
|||||||
func (p *Participant) packetWriter() {
|
func (p *Participant) packetWriter() {
|
||||||
for pkt := range p.packetQueue {
|
for pkt := range p.packetQueue {
|
||||||
var track *webrtc.TrackLocalStaticRTP
|
var track *webrtc.TrackLocalStaticRTP
|
||||||
var sequenceNumber uint16
|
|
||||||
var timestamp uint32
|
|
||||||
|
|
||||||
// No mutex needed - only this goroutine modifies these
|
// No mutex needed - only this goroutine modifies these
|
||||||
if pkt.kind == webrtc.RTPCodecTypeAudio {
|
if pkt.kind == webrtc.RTPCodecTypeAudio {
|
||||||
track = p.AudioTrack
|
track = p.AudioTrack
|
||||||
p.AudioSequenceNumber = uint16(int(p.AudioSequenceNumber) + pkt.sequenceDiff)
|
|
||||||
p.AudioTimestamp = uint32(int64(p.AudioTimestamp) + pkt.timeDiff)
|
|
||||||
sequenceNumber = p.AudioSequenceNumber
|
|
||||||
timestamp = p.AudioTimestamp
|
|
||||||
} else {
|
} else {
|
||||||
track = p.VideoTrack
|
track = p.VideoTrack
|
||||||
p.VideoSequenceNumber = uint16(int(p.VideoSequenceNumber) + pkt.sequenceDiff)
|
|
||||||
p.VideoTimestamp = uint32(int64(p.VideoTimestamp) + pkt.timeDiff)
|
|
||||||
sequenceNumber = p.VideoSequenceNumber
|
|
||||||
timestamp = p.VideoTimestamp
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if track != nil {
|
if track != nil {
|
||||||
pkt.packet.SequenceNumber = sequenceNumber
|
|
||||||
pkt.packet.Timestamp = timestamp
|
|
||||||
|
|
||||||
if err := track.WriteRTP(pkt.packet); err != nil && !errors.Is(err, io.ErrClosedPipe) {
|
if err := track.WriteRTP(pkt.packet); err != nil && !errors.Is(err, io.ErrClosedPipe) {
|
||||||
slog.Error("WriteRTP failed", "participant", p.ID, "kind", pkt.kind, "err", err)
|
slog.Error("WriteRTP failed", "participant", p.ID, "kind", pkt.kind, "err", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ var participantPacketPool = sync.Pool{
|
|||||||
type participantPacket struct {
|
type participantPacket struct {
|
||||||
kind webrtc.RTPCodecType
|
kind webrtc.RTPCodecType
|
||||||
packet *rtp.Packet
|
packet *rtp.Packet
|
||||||
timeDiff int64
|
|
||||||
sequenceDiff int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type RoomInfo struct {
|
type RoomInfo struct {
|
||||||
@@ -141,7 +139,7 @@ func (r *Room) IsOnline() bool {
|
|||||||
return r.PeerConnection != nil
|
return r.PeerConnection != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Room) BroadcastPacketRetimed(kind webrtc.RTPCodecType, pkt *rtp.Packet, timeDiff int64, sequenceDiff int) {
|
func (r *Room) BroadcastPacket(kind webrtc.RTPCodecType, pkt *rtp.Packet) {
|
||||||
// Lock-free load of channel slice
|
// Lock-free load of channel slice
|
||||||
channels := r.participantChannels.Load()
|
channels := r.participantChannels.Load()
|
||||||
|
|
||||||
@@ -155,9 +153,7 @@ func (r *Room) BroadcastPacketRetimed(kind webrtc.RTPCodecType, pkt *rtp.Packet,
|
|||||||
// Get packet struct from pool
|
// Get packet struct from pool
|
||||||
pp := participantPacketPool.Get().(*participantPacket)
|
pp := participantPacketPool.Get().(*participantPacket)
|
||||||
pp.kind = kind
|
pp.kind = kind
|
||||||
pp.packet = pkt.Clone()
|
pp.packet = pkt
|
||||||
pp.timeDiff = timeDiff
|
|
||||||
pp.sequenceDiff = sequenceDiff
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case ch <- pp:
|
case ch <- pp:
|
||||||
|
|||||||
@@ -348,18 +348,8 @@ main() {
|
|||||||
setup_namespaceless
|
setup_namespaceless
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Make sure /run/udev/ directory exists with /run/udev/control, needed for virtual controller support
|
# Wait for vimputti socket before switching to application startup
|
||||||
if [[ ! -d "/run/udev" || ! -e "/run/udev/control" ]]; then
|
wait_for_socket "/tmp/vimputti-0" "vimputti" || exit 1
|
||||||
log "Creating /run/udev directory and control file.."
|
|
||||||
$ENTCMD_PREFIX mkdir -p /run/udev || {
|
|
||||||
log "Error: Failed to create /run/udev directory"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
$ENTCMD_PREFIX touch /run/udev/control || {
|
|
||||||
log "Error: Failed to create /run/udev/control file"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Switch to nestri runner entrypoint
|
# Switch to nestri runner entrypoint
|
||||||
log "Switching to application startup entrypoint..."
|
log "Switching to application startup entrypoint..."
|
||||||
|
|||||||
@@ -106,12 +106,9 @@ start_compositor() {
|
|||||||
kill_if_running "${COMPOSITOR_PID:-}" "compositor"
|
kill_if_running "${COMPOSITOR_PID:-}" "compositor"
|
||||||
kill_if_running "${APP_PID:-}" "application"
|
kill_if_running "${APP_PID:-}" "application"
|
||||||
|
|
||||||
# Set default values only if variables are unset (not empty)
|
# Set default compositor if unset
|
||||||
if [[ -z "${NESTRI_LAUNCH_CMD+x}" ]]; then
|
|
||||||
NESTRI_LAUNCH_CMD="dbus-launch steam -tenfoot -cef-force-gpu"
|
|
||||||
fi
|
|
||||||
if [[ -z "${NESTRI_LAUNCH_COMPOSITOR+x}" ]]; then
|
if [[ -z "${NESTRI_LAUNCH_COMPOSITOR+x}" ]]; then
|
||||||
NESTRI_LAUNCH_COMPOSITOR="gamescope --backend wayland --force-grab-cursor -g -f --rt --mangoapp -W ${WIDTH} -H ${HEIGHT} -r ${FRAMERATE:-60}"
|
NESTRI_LAUNCH_COMPOSITOR="gamescope --backend wayland -g -f --rt -W ${WIDTH} -H ${HEIGHT} -r ${FRAMERATE:-60}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If PRELOAD_SHIM_arch's are set and exist, set LD_PRELOAD for 32/64-bit apps
|
# If PRELOAD_SHIM_arch's are set and exist, set LD_PRELOAD for 32/64-bit apps
|
||||||
@@ -121,6 +118,16 @@ start_compositor() {
|
|||||||
log "Using LD_PRELOAD shim(s)"
|
log "Using LD_PRELOAD shim(s)"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Configure launch cmd with dbus if set
|
||||||
|
local launch_cmd=""
|
||||||
|
if [[ -n "${NESTRI_LAUNCH_CMD+x}" ]]; then
|
||||||
|
if $do_ld_preload; then
|
||||||
|
launch_cmd="LD_PRELOAD='/usr/\$LIB/libvimputti_shim.so' dbus-launch $NESTRI_LAUNCH_CMD"
|
||||||
|
else
|
||||||
|
launch_cmd="dbus-launch $NESTRI_LAUNCH_CMD"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Launch compositor if configured
|
# Launch compositor if configured
|
||||||
if [[ -n "${NESTRI_LAUNCH_COMPOSITOR}" ]]; then
|
if [[ -n "${NESTRI_LAUNCH_COMPOSITOR}" ]]; then
|
||||||
local compositor_cmd="$NESTRI_LAUNCH_COMPOSITOR"
|
local compositor_cmd="$NESTRI_LAUNCH_COMPOSITOR"
|
||||||
@@ -129,17 +136,12 @@ start_compositor() {
|
|||||||
# Check if this is a gamescope command
|
# Check if this is a gamescope command
|
||||||
if [[ "$compositor_cmd" == *"gamescope"* ]]; then
|
if [[ "$compositor_cmd" == *"gamescope"* ]]; then
|
||||||
is_gamescope=true
|
is_gamescope=true
|
||||||
if [[ -n "$NESTRI_LAUNCH_CMD" ]] && [[ "$compositor_cmd" != *" -- "* ]]; then
|
if [[ -n "$launch_cmd" ]] && [[ "$compositor_cmd" != *" -- "* ]]; then
|
||||||
# If steam in launch command, enable gamescope integration via -e
|
# If steam in launch command, enable gamescope integration via -e and enable mangohud
|
||||||
if [[ "$NESTRI_LAUNCH_CMD" == *"steam"* ]]; then
|
if [[ "$launch_cmd" == *"steam"* ]]; then
|
||||||
compositor_cmd+=" -e"
|
compositor_cmd+=" --mangoapp -e"
|
||||||
fi
|
|
||||||
# If ld_preload is true, add env with LD_PRELOAD
|
|
||||||
if $do_ld_preload; then
|
|
||||||
compositor_cmd+=" -- env LD_PRELOAD='/usr/\$LIB/libvimputti_shim.so' bash -c $(printf %q "$NESTRI_LAUNCH_CMD")"
|
|
||||||
else
|
|
||||||
compositor_cmd+=" -- bash -c $(printf %q "$NESTRI_LAUNCH_CMD")"
|
|
||||||
fi
|
fi
|
||||||
|
compositor_cmd+=" -- bash -c $(printf %q "$launch_cmd")"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -185,9 +187,9 @@ start_compositor() {
|
|||||||
WAYLAND_DISPLAY=wayland-0 wlr-randr --output "$OUTPUT_NAME" --custom-mode "$WIDTH"x"$HEIGHT"
|
WAYLAND_DISPLAY=wayland-0 wlr-randr --output "$OUTPUT_NAME" --custom-mode "$WIDTH"x"$HEIGHT"
|
||||||
log "Patched resolution with wlr-randr"
|
log "Patched resolution with wlr-randr"
|
||||||
|
|
||||||
if [[ -n "${NESTRI_LAUNCH_CMD}" ]]; then
|
if [[ -n "$launch_cmd" ]]; then
|
||||||
log "Starting application: $NESTRI_LAUNCH_CMD"
|
log "Starting application: $launch_cmd"
|
||||||
WAYLAND_DISPLAY="$COMPOSITOR_SOCKET" /bin/bash -c "$NESTRI_LAUNCH_CMD" &
|
WAYLAND_DISPLAY="$COMPOSITOR_SOCKET" bash -c "$launch_cmd" &
|
||||||
APP_PID=$!
|
APP_PID=$!
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@@ -200,9 +202,9 @@ start_compositor() {
|
|||||||
log "Warning: Compositor socket not found after 15 seconds ($COMPOSITOR_SOCKET)"
|
log "Warning: Compositor socket not found after 15 seconds ($COMPOSITOR_SOCKET)"
|
||||||
else
|
else
|
||||||
# Launch standalone application if no compositor
|
# Launch standalone application if no compositor
|
||||||
if [[ -n "${NESTRI_LAUNCH_CMD}" ]]; then
|
if [[ -n "$launch_cmd" ]]; then
|
||||||
log "Starting application: $NESTRI_LAUNCH_CMD"
|
log "Starting standalone application: $launch_cmd"
|
||||||
WAYLAND_DISPLAY=wayland-1 /bin/bash -c "$NESTRI_LAUNCH_CMD" &
|
WAYLAND_DISPLAY=wayland-1 bash -c "$launch_cmd" &
|
||||||
APP_PID=$!
|
APP_PID=$!
|
||||||
else
|
else
|
||||||
log "No compositor or application configured"
|
log "No compositor or application configured"
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ export USER=${NESTRI_USER}
|
|||||||
export LANG=${NESTRI_LANG}
|
export LANG=${NESTRI_LANG}
|
||||||
export HOME=${NESTRI_HOME}
|
export HOME=${NESTRI_HOME}
|
||||||
export XDG_RUNTIME_DIR=${NESTRI_XDG_RUNTIME_DIR}
|
export XDG_RUNTIME_DIR=${NESTRI_XDG_RUNTIME_DIR}
|
||||||
export XDG_SESSION_TYPE=x11
|
|
||||||
export DISPLAY=:0
|
|
||||||
|
|
||||||
# Causes some setups to break
|
# Causes some setups to break
|
||||||
export PROTON_NO_FSYNC=1
|
export PROTON_NO_FSYNC=1
|
||||||
@@ -13,3 +11,6 @@ export PROTON_NO_FSYNC=1
|
|||||||
# Make gstreamer GL elements work without display output (NVIDIA issue..)
|
# Make gstreamer GL elements work without display output (NVIDIA issue..)
|
||||||
export GST_GL_API=gles2
|
export GST_GL_API=gles2
|
||||||
export GST_GL_WINDOW=surfaceless
|
export GST_GL_WINDOW=surfaceless
|
||||||
|
|
||||||
|
# Gamescope does not respect MangoHud default config location
|
||||||
|
export MANGOHUD_CONFIGFILE=/etc/nestri/configs/MangoHud/MangoHud.conf
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ autorestart=true
|
|||||||
autostart=true
|
autostart=true
|
||||||
startretries=3
|
startretries=3
|
||||||
priority=3
|
priority=3
|
||||||
nice=-10
|
nice=-2
|
||||||
environment=HOME=%(ENV_NESTRI_HOME)s,XDG_RUNTIME_DIR=%(ENV_NESTRI_XDG_RUNTIME_DIR)s
|
environment=HOME=%(ENV_NESTRI_HOME)s,XDG_RUNTIME_DIR=%(ENV_NESTRI_XDG_RUNTIME_DIR)s
|
||||||
|
|
||||||
[program:pipewire-pulse]
|
[program:pipewire-pulse]
|
||||||
@@ -28,7 +28,7 @@ autorestart=true
|
|||||||
autostart=true
|
autostart=true
|
||||||
startretries=3
|
startretries=3
|
||||||
priority=4
|
priority=4
|
||||||
nice=-10
|
nice=-2
|
||||||
environment=HOME=%(ENV_NESTRI_HOME)s,XDG_RUNTIME_DIR=%(ENV_NESTRI_XDG_RUNTIME_DIR)s
|
environment=HOME=%(ENV_NESTRI_HOME)s,XDG_RUNTIME_DIR=%(ENV_NESTRI_XDG_RUNTIME_DIR)s
|
||||||
|
|
||||||
[program:wireplumber]
|
[program:wireplumber]
|
||||||
@@ -38,7 +38,7 @@ autorestart=true
|
|||||||
autostart=true
|
autostart=true
|
||||||
startretries=3
|
startretries=3
|
||||||
priority=5
|
priority=5
|
||||||
nice=-10
|
nice=-2
|
||||||
environment=HOME=%(ENV_NESTRI_HOME)s,XDG_RUNTIME_DIR=%(ENV_NESTRI_XDG_RUNTIME_DIR)s
|
environment=HOME=%(ENV_NESTRI_HOME)s,XDG_RUNTIME_DIR=%(ENV_NESTRI_XDG_RUNTIME_DIR)s
|
||||||
|
|
||||||
[program:vimputti-manager]
|
[program:vimputti-manager]
|
||||||
|
|||||||
739
packages/server/Cargo.lock
generated
@@ -28,7 +28,7 @@ prost = "0.14"
|
|||||||
prost-types = "0.14"
|
prost-types = "0.14"
|
||||||
parking_lot = "0.12"
|
parking_lot = "0.12"
|
||||||
byteorder = "1.5"
|
byteorder = "1.5"
|
||||||
libp2p = { version = "0.56", features = ["identify", "dns", "tcp", "noise", "ping", "tokio", "serde", "yamux", "macros", "websocket", "autonat"] }
|
libp2p = { version = "0.56", features = ["identify", "dns", "tcp", "noise", "ping", "tokio", "serde", "yamux", "macros", "autonat", "quic"] }
|
||||||
libp2p-identify = "0.47"
|
libp2p-identify = "0.47"
|
||||||
libp2p-ping = "0.47"
|
libp2p-ping = "0.47"
|
||||||
libp2p-autonat = { version = "0.15", features = ["v2"] }
|
libp2p-autonat = { version = "0.15", features = ["v2"] }
|
||||||
@@ -37,7 +37,7 @@ libp2p-yamux = "0.47"
|
|||||||
libp2p-noise = "0.46"
|
libp2p-noise = "0.46"
|
||||||
libp2p-dns = { version = "0.44", features = ["tokio"] }
|
libp2p-dns = { version = "0.44", features = ["tokio"] }
|
||||||
libp2p-tcp = { version = "0.44", features = ["tokio"] }
|
libp2p-tcp = { version = "0.44", features = ["tokio"] }
|
||||||
libp2p-websocket = "0.45"
|
libp2p-quic = { version = "0.13", features = ["tokio"] }
|
||||||
dashmap = "6.1"
|
dashmap = "6.1"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
unsigned-varint = "0.8"
|
unsigned-varint = "0.8"
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.90"
|
channel = "1.91"
|
||||||
@@ -122,6 +122,14 @@ impl Args {
|
|||||||
.value_parser(value_parser!(encoding_args::RateControlMethod))
|
.value_parser(value_parser!(encoding_args::RateControlMethod))
|
||||||
.default_value("cbr"),
|
.default_value("cbr"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("video-latency-control")
|
||||||
|
.long("video-latency-control")
|
||||||
|
.env("VIDEO_LATENCY_CONTROL")
|
||||||
|
.help("Video latency control")
|
||||||
|
.value_parser(value_parser!(encoding_args::LatencyControl))
|
||||||
|
.default_value("lowest-latency"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("video-cqp")
|
Arg::new("video-cqp")
|
||||||
.long("video-cqp")
|
.long("video-cqp")
|
||||||
@@ -165,6 +173,14 @@ impl Args {
|
|||||||
)
|
)
|
||||||
.default_value("8"),
|
.default_value("8"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("keyframe-dist-secs")
|
||||||
|
.long("keyframe-dist-secs")
|
||||||
|
.env("KEYFRAME_DIST_SECS")
|
||||||
|
.help("Distance between keyframes in seconds")
|
||||||
|
.value_parser(value_parser!(u32).range(1..))
|
||||||
|
.default_value("1"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("audio-capture-method")
|
Arg::new("audio-capture-method")
|
||||||
.long("audio-capture-method")
|
.long("audio-capture-method")
|
||||||
@@ -195,6 +211,14 @@ impl Args {
|
|||||||
.value_parser(value_parser!(encoding_args::RateControlMethod))
|
.value_parser(value_parser!(encoding_args::RateControlMethod))
|
||||||
.default_value("cbr"),
|
.default_value("cbr"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("audio-latency-control")
|
||||||
|
.long("audio-latency-control")
|
||||||
|
.env("AUDIO_LATENCY_CONTROL")
|
||||||
|
.help("Audio latency control")
|
||||||
|
.value_parser(value_parser!(encoding_args::LatencyControl))
|
||||||
|
.default_value("lowest-latency"),
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("audio-bitrate")
|
Arg::new("audio-bitrate")
|
||||||
.long("audio-bitrate")
|
.long("audio-bitrate")
|
||||||
|
|||||||
@@ -60,6 +60,12 @@ pub enum RateControl {
|
|||||||
CBR(RateControlCBR),
|
CBR(RateControlCBR),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, ValueEnum)]
|
||||||
|
pub enum LatencyControl {
|
||||||
|
LowestLatency,
|
||||||
|
HighestQuality,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct EncodingOptionsBase {
|
pub struct EncodingOptionsBase {
|
||||||
/// Codec (e.g. "h264", "opus" etc.)
|
/// Codec (e.g. "h264", "opus" etc.)
|
||||||
pub codec: Codec,
|
pub codec: Codec,
|
||||||
@@ -67,6 +73,8 @@ pub struct EncodingOptionsBase {
|
|||||||
pub encoder: Option<String>,
|
pub encoder: Option<String>,
|
||||||
/// Rate control method (e.g. "cqp", "vbr", "cbr")
|
/// Rate control method (e.g. "cqp", "vbr", "cbr")
|
||||||
pub rate_control: RateControl,
|
pub rate_control: RateControl,
|
||||||
|
/// Latency control option, what to tweak settings towards (latency or quality)
|
||||||
|
pub latency_control: LatencyControl,
|
||||||
}
|
}
|
||||||
impl EncodingOptionsBase {
|
impl EncodingOptionsBase {
|
||||||
pub fn debug_print(&self) {
|
pub fn debug_print(&self) {
|
||||||
@@ -87,6 +95,14 @@ impl EncodingOptionsBase {
|
|||||||
tracing::info!("-> Target Bitrate: {}", cbr.target_bitrate);
|
tracing::info!("-> Target Bitrate: {}", cbr.target_bitrate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
match &self.latency_control {
|
||||||
|
LatencyControl::LowestLatency => {
|
||||||
|
tracing::info!("> Latency Control: Priorizing lowest latency");
|
||||||
|
}
|
||||||
|
LatencyControl::HighestQuality => {
|
||||||
|
tracing::info!("> Latency Control: Priorizing quality at the cost of latency");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,6 +110,7 @@ pub struct VideoEncodingOptions {
|
|||||||
pub base: EncodingOptionsBase,
|
pub base: EncodingOptionsBase,
|
||||||
pub encoder_type: EncoderType,
|
pub encoder_type: EncoderType,
|
||||||
pub bit_depth: u32,
|
pub bit_depth: u32,
|
||||||
|
pub keyframe_dist_secs: u32,
|
||||||
}
|
}
|
||||||
impl VideoEncodingOptions {
|
impl VideoEncodingOptions {
|
||||||
pub fn from_matches(matches: &clap::ArgMatches) -> Self {
|
pub fn from_matches(matches: &clap::ArgMatches) -> Self {
|
||||||
@@ -125,6 +142,10 @@ impl VideoEncodingOptions {
|
|||||||
max_bitrate: matches.get_one::<u32>("video-bitrate-max").unwrap().clone(),
|
max_bitrate: matches.get_one::<u32>("video-bitrate-max").unwrap().clone(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
latency_control: matches
|
||||||
|
.get_one::<LatencyControl>("video-latency-control")
|
||||||
|
.unwrap_or(&LatencyControl::LowestLatency)
|
||||||
|
.clone(),
|
||||||
},
|
},
|
||||||
encoder_type: matches
|
encoder_type: matches
|
||||||
.get_one::<EncoderType>("video-encoder-type")
|
.get_one::<EncoderType>("video-encoder-type")
|
||||||
@@ -134,6 +155,10 @@ impl VideoEncodingOptions {
|
|||||||
.get_one::<u32>("video-bit-depth")
|
.get_one::<u32>("video-bit-depth")
|
||||||
.copied()
|
.copied()
|
||||||
.unwrap_or(8),
|
.unwrap_or(8),
|
||||||
|
keyframe_dist_secs: matches
|
||||||
|
.get_one::<u32>("keyframe-dist-secs")
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +167,7 @@ impl VideoEncodingOptions {
|
|||||||
self.base.debug_print();
|
self.base.debug_print();
|
||||||
tracing::info!("> Encoder Type: {}", self.encoder_type.as_str());
|
tracing::info!("> Encoder Type: {}", self.encoder_type.as_str());
|
||||||
tracing::info!("> Bit Depth: {}", self.bit_depth);
|
tracing::info!("> Bit Depth: {}", self.bit_depth);
|
||||||
|
tracing::info!("> Keyframe Distance Seconds: {}", self.keyframe_dist_secs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Deref for VideoEncodingOptions {
|
impl Deref for VideoEncodingOptions {
|
||||||
@@ -208,6 +234,10 @@ impl AudioEncodingOptions {
|
|||||||
}),
|
}),
|
||||||
wot => panic!("Invalid rate control method for audio: {}", wot.as_str()),
|
wot => panic!("Invalid rate control method for audio: {}", wot.as_str()),
|
||||||
},
|
},
|
||||||
|
latency_control: matches
|
||||||
|
.get_one::<LatencyControl>("audio-latency-control")
|
||||||
|
.unwrap_or(&LatencyControl::LowestLatency)
|
||||||
|
.clone(),
|
||||||
},
|
},
|
||||||
capture_method: matches
|
capture_method: matches
|
||||||
.get_one::<AudioCaptureMethod>("audio-capture-method")
|
.get_one::<AudioCaptureMethod>("audio-capture-method")
|
||||||
|
|||||||
@@ -74,7 +74,6 @@ pub enum EncoderAPI {
|
|||||||
QSV,
|
QSV,
|
||||||
VAAPI,
|
VAAPI,
|
||||||
NVENC,
|
NVENC,
|
||||||
AMF,
|
|
||||||
SOFTWARE,
|
SOFTWARE,
|
||||||
UNKNOWN,
|
UNKNOWN,
|
||||||
}
|
}
|
||||||
@@ -85,7 +84,6 @@ impl EncoderAPI {
|
|||||||
Self::QSV => "Intel QuickSync Video",
|
Self::QSV => "Intel QuickSync Video",
|
||||||
Self::VAAPI => "Video Acceleration API",
|
Self::VAAPI => "Video Acceleration API",
|
||||||
Self::NVENC => "NVIDIA NVENC",
|
Self::NVENC => "NVIDIA NVENC",
|
||||||
Self::AMF => "AMD Media Framework",
|
|
||||||
Self::SOFTWARE => "Software",
|
Self::SOFTWARE => "Software",
|
||||||
Self::UNKNOWN => "Unknown",
|
Self::UNKNOWN => "Unknown",
|
||||||
}
|
}
|
||||||
@@ -167,8 +165,6 @@ fn get_encoder_api(encoder: &str, encoder_type: &EncoderType) -> EncoderAPI {
|
|||||||
EncoderAPI::VAAPI
|
EncoderAPI::VAAPI
|
||||||
} else if encoder.starts_with("nv") {
|
} else if encoder.starts_with("nv") {
|
||||||
EncoderAPI::NVENC
|
EncoderAPI::NVENC
|
||||||
} else if encoder.starts_with("amf") {
|
|
||||||
EncoderAPI::AMF
|
|
||||||
} else {
|
} else {
|
||||||
EncoderAPI::UNKNOWN
|
EncoderAPI::UNKNOWN
|
||||||
}
|
}
|
||||||
@@ -275,9 +271,9 @@ pub fn encoder_low_latency_params(
|
|||||||
encoder: &VideoEncoderInfo,
|
encoder: &VideoEncoderInfo,
|
||||||
_rate_control: &RateControl,
|
_rate_control: &RateControl,
|
||||||
framerate: u32,
|
framerate: u32,
|
||||||
|
keyframe_dist_secs: u32,
|
||||||
) -> VideoEncoderInfo {
|
) -> VideoEncoderInfo {
|
||||||
// 1 second keyframe interval for fast recovery, is this too taxing?
|
let mut encoder_optz = encoder_gop_params(encoder, framerate * keyframe_dist_secs);
|
||||||
let mut encoder_optz = encoder_gop_params(encoder, framerate);
|
|
||||||
|
|
||||||
match encoder_optz.encoder_api {
|
match encoder_optz.encoder_api {
|
||||||
EncoderAPI::QSV => {
|
EncoderAPI::QSV => {
|
||||||
@@ -293,16 +289,6 @@ pub fn encoder_low_latency_params(
|
|||||||
encoder_optz.set_parameter("tune", "ultra-low-latency");
|
encoder_optz.set_parameter("tune", "ultra-low-latency");
|
||||||
encoder_optz.set_parameter("zerolatency", "true");
|
encoder_optz.set_parameter("zerolatency", "true");
|
||||||
}
|
}
|
||||||
EncoderAPI::AMF => {
|
|
||||||
encoder_optz.set_parameter("preset", "speed");
|
|
||||||
let usage = match encoder_optz.codec {
|
|
||||||
VideoCodec::H264 | VideoCodec::H265 => "ultra-low-latency",
|
|
||||||
VideoCodec::AV1 => "low-latency",
|
|
||||||
};
|
|
||||||
if !usage.is_empty() {
|
|
||||||
encoder_optz.set_parameter("usage", usage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EncoderAPI::SOFTWARE => match encoder_optz.name.as_str() {
|
EncoderAPI::SOFTWARE => match encoder_optz.name.as_str() {
|
||||||
"openh264enc" => {
|
"openh264enc" => {
|
||||||
encoder_optz.set_parameter("complexity", "low");
|
encoder_optz.set_parameter("complexity", "low");
|
||||||
@@ -330,6 +316,56 @@ pub fn encoder_low_latency_params(
|
|||||||
encoder_optz
|
encoder_optz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encoder_high_quality_params(
|
||||||
|
encoder: &VideoEncoderInfo,
|
||||||
|
_rate_control: &RateControl,
|
||||||
|
framerate: u32,
|
||||||
|
keyframe_dist_secs: u32,
|
||||||
|
) -> VideoEncoderInfo {
|
||||||
|
let mut encoder_optz = encoder_gop_params(encoder, framerate * keyframe_dist_secs);
|
||||||
|
|
||||||
|
match encoder_optz.encoder_api {
|
||||||
|
EncoderAPI::QSV => {
|
||||||
|
encoder_optz.set_parameter("low-latency", "false");
|
||||||
|
encoder_optz.set_parameter("target-usage", "1");
|
||||||
|
}
|
||||||
|
EncoderAPI::VAAPI => {
|
||||||
|
encoder_optz.set_parameter("target-usage", "1");
|
||||||
|
}
|
||||||
|
EncoderAPI::NVENC => {
|
||||||
|
encoder_optz.set_parameter("multi-pass", "two-pass");
|
||||||
|
encoder_optz.set_parameter("preset", "p7");
|
||||||
|
encoder_optz.set_parameter("tune", "high-quality");
|
||||||
|
encoder_optz.set_parameter("zerolatency", "false");
|
||||||
|
encoder_optz.set_parameter("spatial-aq", "true");
|
||||||
|
encoder_optz.set_parameter("rc-lookahead", "3");
|
||||||
|
}
|
||||||
|
EncoderAPI::SOFTWARE => match encoder_optz.name.as_str() {
|
||||||
|
"openh264enc" => {
|
||||||
|
encoder_optz.set_parameter("complexity", "high");
|
||||||
|
encoder_optz.set_parameter("usage-type", "screen");
|
||||||
|
}
|
||||||
|
"x264enc" => {
|
||||||
|
encoder_optz.set_parameter("rc-lookahead", "3");
|
||||||
|
encoder_optz.set_parameter("speed-preset", "medium");
|
||||||
|
}
|
||||||
|
"svtav1enc" => {
|
||||||
|
encoder_optz.set_parameter("preset", "8");
|
||||||
|
encoder_optz.set_parameter("parameters-string", "lookahead=3");
|
||||||
|
}
|
||||||
|
"av1enc" => {
|
||||||
|
encoder_optz.set_parameter("usage-profile", "realtime");
|
||||||
|
encoder_optz.set_parameter("cpu-used", "8");
|
||||||
|
encoder_optz.set_parameter("lag-in-frames", "3");
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
},
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder_optz
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_compatible_encoders(gpus: &Vec<GPUInfo>) -> Vec<VideoEncoderInfo> {
|
pub fn get_compatible_encoders(gpus: &Vec<GPUInfo>) -> Vec<VideoEncoderInfo> {
|
||||||
let mut encoders = Vec::new();
|
let mut encoders = Vec::new();
|
||||||
let registry = gstreamer::Registry::get();
|
let registry = gstreamer::Registry::get();
|
||||||
@@ -427,16 +463,6 @@ pub fn get_compatible_encoders(gpus: &Vec<GPUInfo>) -> Vec<VideoEncoderInfo> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EncoderAPI::AMF if element.has_property("device") => {
|
|
||||||
let device_id = match element.property_value("device").get::<u32>() {
|
|
||||||
Ok(v) => Some(v as usize),
|
|
||||||
Err(_) => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
device_id.and_then(|id| {
|
|
||||||
get_gpus_by_vendor(&gpus, GPUVendor::AMD).get(id).cloned()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -549,7 +575,6 @@ pub fn get_best_compatible_encoder(
|
|||||||
score += match encoder.encoder_api {
|
score += match encoder.encoder_api {
|
||||||
EncoderAPI::NVENC => 3,
|
EncoderAPI::NVENC => 3,
|
||||||
EncoderAPI::QSV => 3,
|
EncoderAPI::QSV => 3,
|
||||||
EncoderAPI::AMF => 3,
|
|
||||||
EncoderAPI::VAAPI => 2,
|
EncoderAPI::VAAPI => 2,
|
||||||
EncoderAPI::SOFTWARE => 1,
|
EncoderAPI::SOFTWARE => 1,
|
||||||
EncoderAPI::UNKNOWN => 0,
|
EncoderAPI::UNKNOWN => 0,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ mod p2p;
|
|||||||
mod proto;
|
mod proto;
|
||||||
|
|
||||||
use crate::args::encoding_args;
|
use crate::args::encoding_args;
|
||||||
|
use crate::args::encoding_args::LatencyControl;
|
||||||
use crate::enc_helper::{EncoderAPI, EncoderType};
|
use crate::enc_helper::{EncoderAPI, EncoderType};
|
||||||
use crate::gpu::{GPUInfo, GPUVendor};
|
use crate::gpu::{GPUInfo, GPUVendor};
|
||||||
use crate::input::controller::ControllerManager;
|
use crate::input::controller::ControllerManager;
|
||||||
@@ -130,11 +131,20 @@ fn handle_encoder_video_settings(
|
|||||||
args: &args::Args,
|
args: &args::Args,
|
||||||
video_encoder: &enc_helper::VideoEncoderInfo,
|
video_encoder: &enc_helper::VideoEncoderInfo,
|
||||||
) -> enc_helper::VideoEncoderInfo {
|
) -> enc_helper::VideoEncoderInfo {
|
||||||
let mut optimized_encoder = enc_helper::encoder_low_latency_params(
|
let mut optimized_encoder = match args.encoding.video.latency_control {
|
||||||
&video_encoder,
|
LatencyControl::LowestLatency => enc_helper::encoder_low_latency_params(
|
||||||
&args.encoding.video.rate_control,
|
&video_encoder,
|
||||||
args.app.framerate,
|
&args.encoding.video.rate_control,
|
||||||
);
|
args.app.framerate,
|
||||||
|
args.encoding.video.keyframe_dist_secs,
|
||||||
|
),
|
||||||
|
LatencyControl::HighestQuality => enc_helper::encoder_high_quality_params(
|
||||||
|
&video_encoder,
|
||||||
|
&args.encoding.video.rate_control,
|
||||||
|
args.app.framerate,
|
||||||
|
args.encoding.video.keyframe_dist_secs,
|
||||||
|
),
|
||||||
|
};
|
||||||
// Handle rate-control method
|
// Handle rate-control method
|
||||||
match &args.encoding.video.rate_control {
|
match &args.encoding.video.rate_control {
|
||||||
encoding_args::RateControl::CQP(cqp) => {
|
encoding_args::RateControl::CQP(cqp) => {
|
||||||
@@ -429,39 +439,34 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
webrtcsink.set_property("do-retransmission", false);
|
webrtcsink.set_property("do-retransmission", false);
|
||||||
|
|
||||||
/* Queues */
|
/* Queues */
|
||||||
let video_queue = gstreamer::ElementFactory::make("queue")
|
// Sink queues
|
||||||
|
let video_sink_queue = gstreamer::ElementFactory::make("queue").build()?;
|
||||||
|
let audio_sink_queue = gstreamer::ElementFactory::make("queue").build()?;
|
||||||
|
|
||||||
|
// Source queues
|
||||||
|
let video_source_queue = gstreamer::ElementFactory::make("queue")
|
||||||
.property("max-size-buffers", 2u32)
|
.property("max-size-buffers", 2u32)
|
||||||
.property("max-size-time", 0u64)
|
.property("max-size-time", 0u64)
|
||||||
.property("max-size-bytes", 0u32)
|
.property("max-size-bytes", 0u32)
|
||||||
.build()?;
|
.build()?;
|
||||||
|
let audio_source_queue = gstreamer::ElementFactory::make("queue")
|
||||||
let audio_queue = gstreamer::ElementFactory::make("queue")
|
|
||||||
.property("max-size-buffers", 2u32)
|
.property("max-size-buffers", 2u32)
|
||||||
.property("max-size-time", 0u64)
|
.property("max-size-time", 0u64)
|
||||||
.property("max-size-bytes", 0u32)
|
.property("max-size-bytes", 0u32)
|
||||||
.build()?;
|
.build()?;
|
||||||
|
|
||||||
/* Clock Sync */
|
|
||||||
let video_clocksync = gstreamer::ElementFactory::make("clocksync")
|
|
||||||
.property("sync-to-first", true)
|
|
||||||
.build()?;
|
|
||||||
|
|
||||||
let audio_clocksync = gstreamer::ElementFactory::make("clocksync")
|
|
||||||
.property("sync-to-first", true)
|
|
||||||
.build()?;
|
|
||||||
|
|
||||||
// Add elements to the pipeline
|
// Add elements to the pipeline
|
||||||
pipeline.add_many(&[
|
pipeline.add_many(&[
|
||||||
webrtcsink.upcast_ref(),
|
webrtcsink.upcast_ref(),
|
||||||
|
&video_sink_queue,
|
||||||
|
&audio_sink_queue,
|
||||||
&video_encoder,
|
&video_encoder,
|
||||||
&caps_filter,
|
&caps_filter,
|
||||||
&video_queue,
|
&video_source_queue,
|
||||||
&video_clocksync,
|
|
||||||
&video_source,
|
&video_source,
|
||||||
&audio_encoder,
|
&audio_encoder,
|
||||||
&audio_capsfilter,
|
&audio_capsfilter,
|
||||||
&audio_queue,
|
&audio_source_queue,
|
||||||
&audio_clocksync,
|
|
||||||
&audio_rate,
|
&audio_rate,
|
||||||
&audio_converter,
|
&audio_converter,
|
||||||
&audio_source,
|
&audio_source,
|
||||||
@@ -493,16 +498,24 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
&audio_converter,
|
&audio_converter,
|
||||||
&audio_rate,
|
&audio_rate,
|
||||||
&audio_capsfilter,
|
&audio_capsfilter,
|
||||||
&audio_queue,
|
&audio_source_queue,
|
||||||
&audio_clocksync,
|
|
||||||
&audio_encoder,
|
&audio_encoder,
|
||||||
])?;
|
])?;
|
||||||
|
|
||||||
// Link audio parser to audio encoder if present, otherwise just webrtcsink
|
// Link audio parser to audio encoder if present, otherwise just webrtcsink
|
||||||
if let Some(parser) = &audio_parser {
|
if let Some(parser) = &audio_parser {
|
||||||
gstreamer::Element::link_many(&[&audio_encoder, parser, webrtcsink.upcast_ref()])?;
|
gstreamer::Element::link_many(&[
|
||||||
|
&audio_encoder,
|
||||||
|
parser,
|
||||||
|
&audio_sink_queue,
|
||||||
|
webrtcsink.upcast_ref(),
|
||||||
|
])?;
|
||||||
} else {
|
} else {
|
||||||
gstreamer::Element::link_many(&[&audio_encoder, webrtcsink.upcast_ref()])?;
|
gstreamer::Element::link_many(&[
|
||||||
|
&audio_encoder,
|
||||||
|
&audio_sink_queue,
|
||||||
|
webrtcsink.upcast_ref(),
|
||||||
|
])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// With zero-copy..
|
// With zero-copy..
|
||||||
@@ -512,26 +525,20 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
gstreamer::Element::link_many(&[
|
gstreamer::Element::link_many(&[
|
||||||
&video_source,
|
&video_source,
|
||||||
&caps_filter,
|
&caps_filter,
|
||||||
&video_queue,
|
&video_source_queue,
|
||||||
&video_clocksync,
|
|
||||||
&vapostproc,
|
&vapostproc,
|
||||||
&va_caps_filter,
|
&va_caps_filter,
|
||||||
&video_encoder,
|
&video_encoder,
|
||||||
])?;
|
])?;
|
||||||
} else if video_encoder_info.encoder_api == EncoderAPI::NVENC {
|
} else if video_encoder_info.encoder_api == EncoderAPI::NVENC {
|
||||||
// NVENC pipeline
|
// NVENC pipeline
|
||||||
gstreamer::Element::link_many(&[
|
gstreamer::Element::link_many(&[&video_source, &caps_filter, &video_encoder])?;
|
||||||
&video_source,
|
|
||||||
&caps_filter,
|
|
||||||
&video_encoder,
|
|
||||||
])?;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gstreamer::Element::link_many(&[
|
gstreamer::Element::link_many(&[
|
||||||
&video_source,
|
&video_source,
|
||||||
&caps_filter,
|
&caps_filter,
|
||||||
&video_queue,
|
&video_source_queue,
|
||||||
&video_clocksync,
|
|
||||||
&video_converter.unwrap(),
|
&video_converter.unwrap(),
|
||||||
&video_encoder,
|
&video_encoder,
|
||||||
])?;
|
])?;
|
||||||
@@ -539,21 +546,24 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
// Link video parser if present with webrtcsink, otherwise just link webrtc sink
|
// Link video parser if present with webrtcsink, otherwise just link webrtc sink
|
||||||
if let Some(parser) = &video_parser {
|
if let Some(parser) = &video_parser {
|
||||||
gstreamer::Element::link_many(&[&video_encoder, parser, webrtcsink.upcast_ref()])?;
|
gstreamer::Element::link_many(&[
|
||||||
|
&video_encoder,
|
||||||
|
parser,
|
||||||
|
&video_sink_queue,
|
||||||
|
webrtcsink.upcast_ref(),
|
||||||
|
])?;
|
||||||
} else {
|
} else {
|
||||||
gstreamer::Element::link_many(&[&video_encoder, webrtcsink.upcast_ref()])?;
|
gstreamer::Element::link_many(&[
|
||||||
|
&video_encoder,
|
||||||
|
&video_sink_queue,
|
||||||
|
webrtcsink.upcast_ref(),
|
||||||
|
])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure QOS is disabled to avoid latency
|
video_source.set_property("do-timestamp", &false);
|
||||||
video_encoder.set_property("qos", true);
|
audio_source.set_property("do-timestamp", &false);
|
||||||
|
|
||||||
// Optimize latency of pipeline
|
// Optimize latency of pipeline
|
||||||
video_source
|
|
||||||
.sync_state_with_parent()
|
|
||||||
.expect("failed to sync with parent");
|
|
||||||
video_source.set_property("do-timestamp", &true);
|
|
||||||
audio_source.set_property("do-timestamp", &true);
|
|
||||||
|
|
||||||
pipeline.set_property("latency", &0u64);
|
pipeline.set_property("latency", &0u64);
|
||||||
pipeline.set_property("async-handling", true);
|
pipeline.set_property("async-handling", true);
|
||||||
pipeline.set_property("message-forward", true);
|
pipeline.set_property("message-forward", true);
|
||||||
|
|||||||
@@ -55,9 +55,8 @@ impl NestriP2P {
|
|||||||
noise::Config::new,
|
noise::Config::new,
|
||||||
yamux::Config::default,
|
yamux::Config::default,
|
||||||
)?
|
)?
|
||||||
|
.with_quic()
|
||||||
.with_dns()?
|
.with_dns()?
|
||||||
.with_websocket(noise::Config::new, yamux::Config::default)
|
|
||||||
.await?
|
|
||||||
.with_behaviour(|key| NestriBehaviour::new(key.public()))?
|
.with_behaviour(|key| NestriBehaviour::new(key.public()))?
|
||||||
.build(),
|
.build(),
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
// @generated
|
// @generated
|
||||||
// This file is @generated by prost-build.
|
// This file is @generated by prost-build.
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoTimestampEntry {
|
pub struct ProtoTimestampEntry {
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
pub stage: ::prost::alloc::string::String,
|
pub stage: ::prost::alloc::string::String,
|
||||||
#[prost(message, optional, tag="2")]
|
#[prost(message, optional, tag="2")]
|
||||||
pub time: ::core::option::Option<::prost_types::Timestamp>,
|
pub time: ::core::option::Option<::prost_types::Timestamp>,
|
||||||
}
|
}
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct ProtoLatencyTracker {
|
pub struct ProtoLatencyTracker {
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
@@ -19,8 +17,7 @@ pub struct ProtoLatencyTracker {
|
|||||||
// Mouse messages
|
// Mouse messages
|
||||||
|
|
||||||
/// MouseMove message
|
/// MouseMove message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoMouseMove {
|
pub struct ProtoMouseMove {
|
||||||
#[prost(int32, tag="1")]
|
#[prost(int32, tag="1")]
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
@@ -28,8 +25,7 @@ pub struct ProtoMouseMove {
|
|||||||
pub y: i32,
|
pub y: i32,
|
||||||
}
|
}
|
||||||
/// MouseMoveAbs message
|
/// MouseMoveAbs message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoMouseMoveAbs {
|
pub struct ProtoMouseMoveAbs {
|
||||||
#[prost(int32, tag="1")]
|
#[prost(int32, tag="1")]
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
@@ -37,8 +33,7 @@ pub struct ProtoMouseMoveAbs {
|
|||||||
pub y: i32,
|
pub y: i32,
|
||||||
}
|
}
|
||||||
/// MouseWheel message
|
/// MouseWheel message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoMouseWheel {
|
pub struct ProtoMouseWheel {
|
||||||
#[prost(int32, tag="1")]
|
#[prost(int32, tag="1")]
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
@@ -46,15 +41,13 @@ pub struct ProtoMouseWheel {
|
|||||||
pub y: i32,
|
pub y: i32,
|
||||||
}
|
}
|
||||||
/// MouseKeyDown message
|
/// MouseKeyDown message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoMouseKeyDown {
|
pub struct ProtoMouseKeyDown {
|
||||||
#[prost(int32, tag="1")]
|
#[prost(int32, tag="1")]
|
||||||
pub key: i32,
|
pub key: i32,
|
||||||
}
|
}
|
||||||
/// MouseKeyUp message
|
/// MouseKeyUp message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoMouseKeyUp {
|
pub struct ProtoMouseKeyUp {
|
||||||
#[prost(int32, tag="1")]
|
#[prost(int32, tag="1")]
|
||||||
pub key: i32,
|
pub key: i32,
|
||||||
@@ -62,24 +55,26 @@ pub struct ProtoMouseKeyUp {
|
|||||||
// Keyboard messages
|
// Keyboard messages
|
||||||
|
|
||||||
/// KeyDown message
|
/// KeyDown message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoKeyDown {
|
pub struct ProtoKeyDown {
|
||||||
#[prost(int32, tag="1")]
|
#[prost(int32, tag="1")]
|
||||||
pub key: i32,
|
pub key: i32,
|
||||||
}
|
}
|
||||||
/// KeyUp message
|
/// KeyUp message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, Copy, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoKeyUp {
|
pub struct ProtoKeyUp {
|
||||||
#[prost(int32, tag="1")]
|
#[prost(int32, tag="1")]
|
||||||
pub key: i32,
|
pub key: i32,
|
||||||
}
|
}
|
||||||
|
// Clipboard message
|
||||||
|
// message ProtoClipboard {
|
||||||
|
// string content = 1; // Clipboard content
|
||||||
|
// }
|
||||||
|
|
||||||
// Controller messages
|
// Controller messages
|
||||||
|
|
||||||
/// ControllerAttach message
|
/// ControllerAttach message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoControllerAttach {
|
pub struct ProtoControllerAttach {
|
||||||
/// One of the following enums: "ps", "xbox" or "switch"
|
/// One of the following enums: "ps", "xbox" or "switch"
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
@@ -92,8 +87,7 @@ pub struct ProtoControllerAttach {
|
|||||||
pub session_id: ::prost::alloc::string::String,
|
pub session_id: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
/// ControllerDetach message
|
/// ControllerDetach message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoControllerDetach {
|
pub struct ProtoControllerDetach {
|
||||||
/// Session specific slot number (0-3)
|
/// Session specific slot number (0-3)
|
||||||
#[prost(int32, tag="1")]
|
#[prost(int32, tag="1")]
|
||||||
@@ -103,8 +97,7 @@ pub struct ProtoControllerDetach {
|
|||||||
pub session_id: ::prost::alloc::string::String,
|
pub session_id: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
/// ControllerRumble message
|
/// ControllerRumble message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoControllerRumble {
|
pub struct ProtoControllerRumble {
|
||||||
/// Session specific slot number (0-3)
|
/// Session specific slot number (0-3)
|
||||||
#[prost(int32, tag="1")]
|
#[prost(int32, tag="1")]
|
||||||
@@ -123,7 +116,6 @@ pub struct ProtoControllerRumble {
|
|||||||
pub duration: i32,
|
pub duration: i32,
|
||||||
}
|
}
|
||||||
/// ControllerStateBatch - single message containing full or partial controller state
|
/// ControllerStateBatch - single message containing full or partial controller state
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct ProtoControllerStateBatch {
|
pub struct ProtoControllerStateBatch {
|
||||||
/// Session specific slot number (0-3)
|
/// Session specific slot number (0-3)
|
||||||
@@ -188,8 +180,8 @@ pub mod proto_controller_state_batch {
|
|||||||
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
/// (if the ProtoBuf definition does not change) and safe for programmatic use.
|
||||||
pub fn as_str_name(&self) -> &'static str {
|
pub fn as_str_name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
UpdateType::FullState => "FULL_STATE",
|
Self::FullState => "FULL_STATE",
|
||||||
UpdateType::Delta => "DELTA",
|
Self::Delta => "DELTA",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||||
@@ -204,8 +196,7 @@ pub mod proto_controller_state_batch {
|
|||||||
}
|
}
|
||||||
// WebRTC + signaling
|
// WebRTC + signaling
|
||||||
|
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct RtcIceCandidateInit {
|
pub struct RtcIceCandidateInit {
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
pub candidate: ::prost::alloc::string::String,
|
pub candidate: ::prost::alloc::string::String,
|
||||||
@@ -216,8 +207,7 @@ pub struct RtcIceCandidateInit {
|
|||||||
#[prost(string, optional, tag="4")]
|
#[prost(string, optional, tag="4")]
|
||||||
pub username_fragment: ::core::option::Option<::prost::alloc::string::String>,
|
pub username_fragment: ::core::option::Option<::prost::alloc::string::String>,
|
||||||
}
|
}
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct RtcSessionDescriptionInit {
|
pub struct RtcSessionDescriptionInit {
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
pub sdp: ::prost::alloc::string::String,
|
pub sdp: ::prost::alloc::string::String,
|
||||||
@@ -225,29 +215,25 @@ pub struct RtcSessionDescriptionInit {
|
|||||||
pub r#type: ::prost::alloc::string::String,
|
pub r#type: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
/// ProtoICE message
|
/// ProtoICE message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoIce {
|
pub struct ProtoIce {
|
||||||
#[prost(message, optional, tag="1")]
|
#[prost(message, optional, tag="1")]
|
||||||
pub candidate: ::core::option::Option<RtcIceCandidateInit>,
|
pub candidate: ::core::option::Option<RtcIceCandidateInit>,
|
||||||
}
|
}
|
||||||
/// ProtoSDP message
|
/// ProtoSDP message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoSdp {
|
pub struct ProtoSdp {
|
||||||
#[prost(message, optional, tag="1")]
|
#[prost(message, optional, tag="1")]
|
||||||
pub sdp: ::core::option::Option<RtcSessionDescriptionInit>,
|
pub sdp: ::core::option::Option<RtcSessionDescriptionInit>,
|
||||||
}
|
}
|
||||||
/// ProtoRaw message
|
/// ProtoRaw message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoRaw {
|
pub struct ProtoRaw {
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
pub data: ::prost::alloc::string::String,
|
pub data: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
/// ProtoClientRequestRoomStream message
|
/// ProtoClientRequestRoomStream message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoClientRequestRoomStream {
|
pub struct ProtoClientRequestRoomStream {
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
pub room_name: ::prost::alloc::string::String,
|
pub room_name: ::prost::alloc::string::String,
|
||||||
@@ -255,8 +241,7 @@ pub struct ProtoClientRequestRoomStream {
|
|||||||
pub session_id: ::prost::alloc::string::String,
|
pub session_id: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
/// ProtoClientDisconnected message
|
/// ProtoClientDisconnected message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoClientDisconnected {
|
pub struct ProtoClientDisconnected {
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
pub session_id: ::prost::alloc::string::String,
|
pub session_id: ::prost::alloc::string::String,
|
||||||
@@ -264,13 +249,11 @@ pub struct ProtoClientDisconnected {
|
|||||||
pub controller_slots: ::prost::alloc::vec::Vec<i32>,
|
pub controller_slots: ::prost::alloc::vec::Vec<i32>,
|
||||||
}
|
}
|
||||||
/// ProtoServerPushStream message
|
/// ProtoServerPushStream message
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
|
||||||
pub struct ProtoServerPushStream {
|
pub struct ProtoServerPushStream {
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
pub room_name: ::prost::alloc::string::String,
|
pub room_name: ::prost::alloc::string::String,
|
||||||
}
|
}
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct ProtoMessageBase {
|
pub struct ProtoMessageBase {
|
||||||
#[prost(string, tag="1")]
|
#[prost(string, tag="1")]
|
||||||
@@ -278,7 +261,6 @@ pub struct ProtoMessageBase {
|
|||||||
#[prost(message, optional, tag="2")]
|
#[prost(message, optional, tag="2")]
|
||||||
pub latency: ::core::option::Option<ProtoLatencyTracker>,
|
pub latency: ::core::option::Option<ProtoLatencyTracker>,
|
||||||
}
|
}
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct ProtoMessage {
|
pub struct ProtoMessage {
|
||||||
#[prost(message, optional, tag="1")]
|
#[prost(message, optional, tag="1")]
|
||||||
@@ -288,8 +270,7 @@ pub struct ProtoMessage {
|
|||||||
}
|
}
|
||||||
/// Nested message and enum types in `ProtoMessage`.
|
/// Nested message and enum types in `ProtoMessage`.
|
||||||
pub mod proto_message {
|
pub mod proto_message {
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
|
||||||
pub enum Payload {
|
pub enum Payload {
|
||||||
/// Input types
|
/// Input types
|
||||||
#[prost(message, tag="2")]
|
#[prost(message, tag="2")]
|
||||||
@@ -304,6 +285,7 @@ pub mod proto_message {
|
|||||||
MouseKeyUp(super::ProtoMouseKeyUp),
|
MouseKeyUp(super::ProtoMouseKeyUp),
|
||||||
#[prost(message, tag="7")]
|
#[prost(message, tag="7")]
|
||||||
KeyDown(super::ProtoKeyDown),
|
KeyDown(super::ProtoKeyDown),
|
||||||
|
/// ProtoClipboard clipboard = 9;
|
||||||
#[prost(message, tag="8")]
|
#[prost(message, tag="8")]
|
||||||
KeyUp(super::ProtoKeyUp),
|
KeyUp(super::ProtoKeyUp),
|
||||||
/// Controller input types
|
/// Controller input types
|
||||||
|
|||||||