Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix build of WASM-page using Go instead of TinyGo #44

Merged
merged 1 commit into from
Jan 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/workflows/gh-pages-deploy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@ jobs:
submodules: true
fetch-depth: 0

- name: Install tinygo
run: wget https://github.com/tinygo-org/tinygo/releases/download/v0.35.0/tinygo_0.35.0_amd64.deb && sudo dpkg -i tinygo_0.35.0_amd64.deb
- name: Setup Go
uses: actions/setup-go@v3
with:
go-version: 1.20

- name: Build WASM
run: cd web && cp $(tinygo env TINYGOROOT)/targets/wasm_exec.js . && tinygo build -o wasm.wasm -target wasm -no-debug --panic trap ../pkg/wasm/
run: |
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" web/
GOOS=js GOARCH=wasm go build -o web/wasm.wasm ./pkg/wasm/

- name: Deploy
uses: peaceiris/actions-gh-pages@v3
Expand Down
5 changes: 2 additions & 3 deletions examples/node/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ You can download the WASM build and `wasm_exec.js` from master build OR build yo
* `wget https://pe.pion.ly/wasm_exec.js`

### Build
* [Install TinyGo](https://tinygo.org/getting-started/install/)
* Copy wasm_exec - `cp $(tinygo env TINYGOROOT)/targets/wasm_exec.js .`
* Build - `tinygo build -o wasm.wasm -target wasm -no-debug --panic trap github.com/pion/explainer/pkg/wasm`
* Copy `wasm_exec.js`: `cp "$(go env GOROOT)/misc/wasm/wasm_exec_node.js" .`
* Build - `GOOS=js GOARCH=wasm go build -o wasm.wasm ../../pkg/wasm`

### Run
Run `node main.js`
56 changes: 32 additions & 24 deletions examples/node/main.js
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

/* global WebAssembly, TextDecoder, TextEncoder */

require('./wasm_exec.js')
const go = new global.Go()
const importObject = go.importObject

const remoteDescription = `{"type": "offer", "sdp": "v=0\r\no=- 0 0 IN IP4 127.0.0.1\r\ns=-\r\nc=IN IP4 127.0.0.1\r\nt=0 0\r\nm=audio 4000 RTP/AVP 111\r\na=rtpmap:111 OPUS/48000/2\r\nm=video 4002 RTP/AVP 96\r\na=rtpmap:96 VP8/90000"}`
const localDescription = `{"type": "answer", "sdp": "v=0\r\no=- 0 0 IN IP4 127.0.0.1\r\ns=-\r\nc=IN IP4 127.0.0.1\r\nt=0 0\r\nm=audio 4000 RTP/AVP 111\r\na=rtpmap:111 OPUS/48000/2\r\nm=video 4002 RTP/AVP 96\r\na=rtpmap:96 VP8/90000"}`

WebAssembly.instantiate(require('fs').readFileSync('wasm.wasm'), importObject).then(wasmModule => {
go.run(wasmModule.instance)
let exports = wasmModule.instance.exports

let wasmMemory = () => {
return new Uint8Array(exports.memory.buffer)
}
let memoryOffset = exports.getWasmMemoryBufferOffset()

wasmMemory().set((new TextEncoder().encode(remoteDescription)), memoryOffset)
exports.SetRemoteDescription(remoteDescription.length)

wasmMemory().set((new TextEncoder().encode(localDescription)), memoryOffset)
exports.SetLocalDescription(localDescription.length)

let explainSize = exports.Explain()
console.log(new TextDecoder().decode(wasmMemory().subarray(memoryOffset, memoryOffset + explainSize)))
})
globalThis.require = require;
globalThis.fs = require("fs");
globalThis.TextEncoder = require("util").TextEncoder;
globalThis.TextDecoder = require("util").TextDecoder;

globalThis.performance = {
now() {
const [sec, nsec] = process.hrtime();
return sec * 1000 + nsec / 1000000;
},
};

const crypto = require("crypto");
globalThis.crypto = {
getRandomValues(b) {
crypto.randomFillSync(b);
},
};

require("./wasm_exec");

const go = new Go();
WebAssembly.instantiate(fs.readFileSync('wasm.wasm'), go.importObject).then((result) => {
go.run(result.instance);

result_str = explain(localDescription, remoteDescription)
result = JSON.parse(result_str)
console.log(result)
}).catch((err) => {
console.error(err);
process.exit(1);
});
83 changes: 20 additions & 63 deletions pkg/wasm/main.go
Original file line number Diff line number Diff line change
@@ -1,90 +1,47 @@
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT

//go:build js
// +build js

// Package main implements a WASM example
package main

import (
"encoding/json"
"syscall/js"

"github.com/pion/explainer"
)

// nolint: deadcode, unused, revive
type (
Result = explainer.Result
SessionDetails = explainer.SessionDetails
PeerDetails = explainer.PeerDetails
)

const (
bufferSize int = 500000
)

// nolint: unused, golint, gochecknoglobals
//nolint:gochecknoglobals
var (
buffer [bufferSize]byte
peerConnectionExplainer explainer.PeerConnectionExplainer
exp explainer.PeerConnectionExplainer
)

func main() {}

//export getWasmMemoryBufferOffset
func getWasmMemoryBufferOffset() *[bufferSize]byte { //nolint: deadcode, unused
return &buffer
}

func maybeInitExplainer() { //nolint: deadcode, unused
if peerConnectionExplainer == nil {
peerConnectionExplainer = explainer.NewPeerConnectionExplainer()
func explain(_ js.Value, inputs []js.Value) interface{} {
if len(inputs) != 2 {
panic("invalid number of inputs") //nolint:forbidigo

Check warning on line 24 in pkg/wasm/main.go

View check run for this annotation

Codecov / codecov/patch

pkg/wasm/main.go#L22-L24

Added lines #L22 - L24 were not covered by tests
}
}

// SetLocalDescription updates the PeerConnectionExplainer with the provided SessionDescription
//
//export SetLocalDescription
func SetLocalDescription(length int) { //nolint: unused, deadcode
maybeInitExplainer()
peerConnectionExplainer.SetLocalDescription(string(buffer[:length]))
}
localDescription := inputs[0].String()
remoteDescription := inputs[1].String()

Check warning on line 28 in pkg/wasm/main.go

View check run for this annotation

Codecov / codecov/patch

pkg/wasm/main.go#L27-L28

Added lines #L27 - L28 were not covered by tests

// SetRemoteDescription updates the PeerConnectionExplainer with the provided SessionDescription
//
//export SetRemoteDescription
func SetRemoteDescription(length int) { //nolint: deadcode, unused, golint
maybeInitExplainer()
peerConnectionExplainer.SetRemoteDescription(string(buffer[:length]))
}
exp.SetLocalDescription(localDescription)
exp.SetRemoteDescription(remoteDescription)

Check warning on line 31 in pkg/wasm/main.go

View check run for this annotation

Codecov / codecov/patch

pkg/wasm/main.go#L30-L31

Added lines #L30 - L31 were not covered by tests

// Explain returns the result of the current PeerConnectionExplainer.
//
//export Explain
func Explain() int { //nolint: deadcode, unused
maybeInitExplainer()

result := peerConnectionExplainer.Explain()
j, err := json.Marshal(result)
out, err := json.Marshal(exp.Explain())

Check warning on line 33 in pkg/wasm/main.go

View check run for this annotation

Codecov / codecov/patch

pkg/wasm/main.go#L33

Added line #L33 was not covered by tests
if err != nil {
return 0
panic(err) //nolint:forbidigo

Check warning on line 35 in pkg/wasm/main.go

View check run for this annotation

Codecov / codecov/patch

pkg/wasm/main.go#L35

Added line #L35 was not covered by tests
}

return copy(buffer[:], j)
return string(out)

Check warning on line 38 in pkg/wasm/main.go

View check run for this annotation

Codecov / codecov/patch

pkg/wasm/main.go#L38

Added line #L38 was not covered by tests
}

// GetLocalDescription returns the current SDP we are using from SetLocalDescription
//
//export GetLocalDescription
func GetLocalDescription() int { //nolint: deadcode, unused
maybeInitExplainer()

return copy(buffer[:], peerConnectionExplainer.GetLocalDescription())
}
func main() {
exp = explainer.NewPeerConnectionExplainer()

Check warning on line 42 in pkg/wasm/main.go

View check run for this annotation

Codecov / codecov/patch

pkg/wasm/main.go#L41-L42

Added lines #L41 - L42 were not covered by tests

// GetRemoteDescription returns the current SDP we are using from GetRemoteDescription
//
//export GetRemoteDescription
func GetRemoteDescription() int { //nolint: deadcode, unused
maybeInitExplainer()
js.Global().Set("explain", js.FuncOf(explain))

Check warning on line 44 in pkg/wasm/main.go

View check run for this annotation

Codecov / codecov/patch

pkg/wasm/main.go#L44

Added line #L44 was not covered by tests

return copy(buffer[:], peerConnectionExplainer.GetRemoteDescription())
select {}

Check warning on line 46 in pkg/wasm/main.go

View check run for this annotation

Codecov / codecov/patch

pkg/wasm/main.go#L46

Added line #L46 was not covered by tests
}
5 changes: 2 additions & 3 deletions web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@ You can download the WASM build and `wasm_exec.js` from master build OR build yo
* `wget https://pe.pion.ly/wasm_exec.js`

### Build
* [Install TinyGo](https://tinygo.org/getting-started/install/)
* Copy wasm_exec - `cp $(tinygo env TINYGOROOT)/targets/wasm_exec.js .`
* Build - `tinygo build -o wasm.wasm -target wasm -no-debug --panic trap github.com/pion/explainer/pkg/wasm`
* Copy `wasm_exec.js`: `cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .`
* Build - `GOOS=js GOARCH=wasm go build -o wasm.wasm ../pkg/wasm`

### Run
You can now run using any HTTP server. If you have Python available `python -m SimpleHTTPServer` is a good option.
Expand Down
25 changes: 5 additions & 20 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -243,35 +243,22 @@ <h3> Parsed Local Session Description </h3>
}
}

let wasm, memoryOffset
let wasmMemory = () => {
return new Uint8Array(wasm.exports.memory.buffer)
}

let handleInput = () => {
const localDescription = document.querySelector('#local-description-div textarea').value
const remoteDescription = document.querySelector('#remote-description-div textarea').value

if (wasm === undefined) {
if (explain === undefined) {
return
} else if (document.querySelector('#remote-description-div input').checked && remoteDescription.length === 0) {
return
} else if (document.querySelector('#local-description-div input').checked && localDescription.length === 0) {
return
}

wasmMemory().set((new TextEncoder().encode(remoteDescription)), memoryOffset)
wasm.exports.SetRemoteDescription(remoteDescription.length)

wasmMemory().set((new TextEncoder().encode(localDescription)), memoryOffset)
wasm.exports.SetLocalDescription(localDescription.length)
result_str = explain(localDescription, remoteDescription)
result = JSON.parse(result_str)

let explainResult = wasm.exports.Explain()
renderOutput(
JSON.parse(new TextDecoder().decode(wasmMemory().subarray(memoryOffset, memoryOffset + explainResult))),
new TextDecoder().decode(wasmMemory().subarray(memoryOffset, memoryOffset + wasm.exports.GetLocalDescription())),
new TextDecoder().decode(wasmMemory().subarray(memoryOffset, memoryOffset + wasm.exports.GetRemoteDescription()))
)
renderOutput(result, localDescription, remoteDescription)
}

for (let i of document.querySelectorAll('input[type=checkbox]')) {
Expand All @@ -290,9 +277,7 @@ <h3> Parsed Local Session Description </h3>
resp.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, go.importObject).then(function (obj) {
wasm = obj.instance
memoryOffset = wasm.exports.getWasmMemoryBufferOffset()
go.run(wasm)
go.run(obj.instance)
})
)
</script>
Expand Down
Loading