10 Commits

Author SHA1 Message Date
1b84c7e7ba fix invalid errors. 2024-07-20 14:48:54 +02:00
21a4b2b797 autostart broadcast only if url is set. 2024-06-18 23:35:22 +02:00
5e96bca296 update readme. 2024-06-17 23:20:42 +02:00
c78d797fe7 fix typo. 2024-06-17 23:16:48 +02:00
57596315e9 broadcast_autostart as config option, #398. 2024-06-17 23:14:12 +02:00
0d7887e9d2 workaround for firefox read clipboard, #373.
Firefox 122+ incorrectly reports that it can read the clipboard but it can't instead it hangs when reading clipboard, until user clicks on the page and the click itself is not handled by the page at all, also the clipboard reads always fail with "Clipboard read operation is not allowed."
2024-06-16 22:55:13 +02:00
978fd8977d google does not archive chrome 111 anymore. 2024-06-16 22:28:32 +02:00
4ab5901ba9 sync clipboard only if in focus #373. 2024-06-16 22:27:46 +02:00
11a862f101 update docs. 2024-05-19 23:17:17 +02:00
b938a4e09e update docs. 2024-05-19 17:07:52 +02:00
15 changed files with 70 additions and 38 deletions

View File

@ -3,7 +3,9 @@ FROM $BASE_IMAGE
# latest working version with EGL: 111.0.5563.146, revert when resolved
# 112.0.5615.49 fails: https://github.com/VirtualGL/virtualgl/issues/229
ARG SRC_URL="https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_111.0.5563.146-1_amd64.deb"
# google does not provide a direct link to the deb file anymore
# ARG SRC_URL="https://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_111.0.5563.146-1_amd64.deb"
ARG SRC_URL="https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb"
#
# install google chrome

View File

@ -313,7 +313,15 @@
}
get clipboard_read_available() {
return 'clipboard' in navigator && typeof navigator.clipboard.readText === 'function'
return (
'clipboard' in navigator &&
typeof navigator.clipboard.readText === 'function' &&
// Firefox 122+ incorrectly reports that it can read the clipboard but it can't
// instead it hangs when reading clipboard, until user clicks on the page
// and the click itself is not handled by the page at all, also the clipboard
// reads always fail with "Clipboard read operation is not allowed."
navigator.userAgent.indexOf('Firefox') == -1
)
}
get clipboard_write_available() {
@ -630,7 +638,7 @@
}
async syncClipboard() {
if (this.clipboard_read_available) {
if (this.clipboard_read_available && window.document.hasFocus()) {
try {
const text = await navigator.clipboard.readText()
if (this.clipboard !== text) {

View File

@ -6,6 +6,7 @@
- Added nvidia support for firefox.
- Added `?lang=<lang>` parameter to the URL, which will set the language of the interface (by @mbattista).
- Added `?show_side=1` and `?mute_chat=1` parameter to the URL, for chat mute and show side (by @mbattista).
- Added `NEKO_BROADCAST_AUTOSTART` to automatically start or do not start broadcasting when the room is created. By default, it is set to `true` because it was the previous behavior.
### Bugs
- Fix incorrect version sorting for chromium, microsoft-edge, opera and ungoogledchromium.

View File

@ -107,9 +107,11 @@ nat1to1: <ip>
#### `NEKO_BROADCAST_PIPELINE`:
- Makes it possible to create custom gstreamer pipeline used for broadcasting, strings `{url}`, `{device}` and `{display}` will be replaced.
#### `NEKO_BROADCAST_URL`:
- Set a default URL for broadcast streams. Setting this value will automatically enable broadcasting when n.eko starts. It can be disabled/changed later by admins in the GUI.
- Set a default URL for broadcast streams. It can be disabled/changed later by admins in the GUI.
- e.g. `rtmp://<your-server>:1935/ingest/<stream-key>`
#### `NEKO_BROADCAST_AUTOSTART`:
- Automatically start broadcasting when neko starts and broadcast_url is set.
- e.g. `true`
### Server
#### `NEKO_BIND`:

View File

@ -4,15 +4,18 @@ Neko UI loads, but you don't see the screen, and it gives you `connection timeou
## Test your client
Some browser may block WebRTC access by default. You can check if it is enabled by going to `about:webrtc` or `chrome://webrtc-internals` in your browser.
Some browsers may block WebRTC access by default. You can check if it is enabled by going to `about:webrtc` or `chrome://webrtc-internals` in your browser.
Check if your extensions are not blocking WebRTC access. For example, Privacy Badger or Private Internet Access blocks WebRTC by default.
Check if your extensions are not blocking WebRTC access. Following extensions are known to block or does not work properly with WebRTC:
- Privacy Badger
- Private Internet Access
- PIA VPN (even if disabled)
Test whether your client [supports](https://www.webrtc-experiment.com/DetectRTC/) and can [connect to WebRTC](https://www.webcasts.com/webrtc/).
## Networking
Most problems are networking related.
If you are absolutely sure, that your client is working correctly, then most likely your networking is not set up correctly.
### Check if your ports are correctly exposed using docker
@ -59,6 +62,13 @@ Then try to type on one end, you should see characters on the other side.
If it does not work for you, then most likely your port forwarding is not working correctly. Or your ISP is blocking traffic.
If you get [`Command 'nc' not found.`](https://command-not-found.com/nc) error, you can install `netcat` package using:
```shell
sudo apt-get install netcat
```
### Check if your external IP was determined correctly
One of the first logs, when the server starts, writes down your external IP that will be sent to your clients to connect to.
@ -67,6 +77,8 @@ One of the first logs, when the server starts, writes down your external IP that
docker-compose logs neko | grep nat_ips
```
Note: Some newer versions of docker-compose use `docker compose` instead of `docker-compose`.
You should see this:
```

View File

@ -22,7 +22,7 @@ type BroacastManagerCtx struct {
started bool
}
func broadcastNew(pipelineFn func(url string) (string, error), defaultUrl string) *BroacastManagerCtx {
func broadcastNew(pipelineFn func(url string) (string, error), url string, started bool) *BroacastManagerCtx {
logger := log.With().
Str("module", "capture").
Str("submodule", "broadcast").
@ -31,8 +31,8 @@ func broadcastNew(pipelineFn func(url string) (string, error), defaultUrl string
return &BroacastManagerCtx{
logger: logger,
pipelineFn: pipelineFn,
url: defaultUrl,
started: defaultUrl != "",
url: url,
started: started && url != "",
}
}

View File

@ -31,7 +31,7 @@ func New(desktop types.DesktopManager, config *config.Capture) *CaptureManagerCt
// sinks
broadcast: broadcastNew(func(url string) (string, error) {
return NewBroadcastPipeline(config.AudioDevice, config.Display, config.BroadcastPipeline, url)
}, config.BroadcastUrl),
}, config.BroadcastUrl, config.BroadcastAutostart),
audio: streamSinkNew(config.AudioCodec, func() (string, error) {
return NewAudioPipeline(config.AudioCodec, config.AudioDevice, config.AudioPipeline, config.AudioBitrate)
}, "audio"),

View File

@ -34,8 +34,9 @@ type Capture struct {
AudioPipeline string
// broadcast
BroadcastPipeline string
BroadcastUrl string
BroadcastPipeline string
BroadcastUrl string
BroadcastAutostart bool
}
func (Capture) Init(cmd *cobra.Command) error {
@ -155,11 +156,16 @@ func (Capture) Init(cmd *cobra.Command) error {
return err
}
cmd.PersistentFlags().String("broadcast_url", "", "URL for broadcasting, setting this value will automatically enable broadcasting")
cmd.PersistentFlags().String("broadcast_url", "", "a default default URL for broadcast streams, can be disabled/changed later by admins in the GUI")
if err := viper.BindPFlag("broadcast_url", cmd.PersistentFlags().Lookup("broadcast_url")); err != nil {
return err
}
cmd.PersistentFlags().Bool("broadcast_autostart", true, "automatically start broadcasting when neko starts and broadcast_url is set")
if err := viper.BindPFlag("broadcast_autostart", cmd.PersistentFlags().Lookup("broadcast_autostart")); err != nil {
return err
}
return nil
}
@ -247,4 +253,5 @@ func (s *Capture) Set() {
s.BroadcastPipeline = viper.GetString("broadcast_pipeline")
s.BroadcastUrl = viper.GetString("broadcast_url")
s.BroadcastAutostart = viper.GetBool("broadcast_autostart")
}

View File

@ -46,9 +46,9 @@ const (
)
const (
BORADCAST_STATUS = "broadcast/status"
BORADCAST_CREATE = "broadcast/create"
BORADCAST_DESTROY = "broadcast/destroy"
BROADCAST_STATUS = "broadcast/status"
BROADCAST_CREATE = "broadcast/create"
BROADCAST_DESTROY = "broadcast/destroy"
)
const (

View File

@ -175,7 +175,7 @@ func (h *MessageHandler) adminGive(id string, session types.Session, payload *me
ID: id,
Target: payload.ID,
}, nil); err != nil {
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.CONTROL_LOCKED)
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.CONTROL_GIVE)
return err
}
@ -207,7 +207,7 @@ func (h *MessageHandler) adminMute(id string, session types.Session, payload *me
Target: target.ID(),
ID: id,
}, nil); err != nil {
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.ADMIN_UNMUTE)
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.ADMIN_MUTE)
return err
}

View File

@ -6,7 +6,7 @@ import (
"m1k1o/neko/internal/types/message"
)
func (h *MessageHandler) boradcastCreate(session types.Session, payload *message.BroadcastCreate) error {
func (h *MessageHandler) broadcastCreate(session types.Session, payload *message.BroadcastCreate) error {
broadcast := h.capture.Broadcast()
if !session.Admin() {
@ -44,14 +44,14 @@ func (h *MessageHandler) boradcastCreate(session types.Session, payload *message
}
}
if err := h.boradcastStatus(nil); err != nil {
if err := h.broadcastStatus(nil); err != nil {
return err
}
return nil
}
func (h *MessageHandler) boradcastDestroy(session types.Session) error {
func (h *MessageHandler) broadcastDestroy(session types.Session) error {
broadcast := h.capture.Broadcast()
if !session.Admin() {
@ -70,18 +70,18 @@ func (h *MessageHandler) boradcastDestroy(session types.Session) error {
broadcast.Stop()
if err := h.boradcastStatus(nil); err != nil {
if err := h.broadcastStatus(nil); err != nil {
return err
}
return nil
}
func (h *MessageHandler) boradcastStatus(session types.Session) error {
func (h *MessageHandler) broadcastStatus(session types.Session) error {
broadcast := h.capture.Broadcast()
msg := message.BroadcastStatus{
Event: event.BORADCAST_STATUS,
Event: event.BROADCAST_STATUS,
IsActive: broadcast.Started(),
URL: broadcast.Url(),
}
@ -89,7 +89,7 @@ func (h *MessageHandler) boradcastStatus(session types.Session) error {
// if no session, broadcast change
if session == nil {
if err := h.sessions.AdminBroadcast(msg, nil); err != nil {
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.BORADCAST_STATUS)
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.BROADCAST_STATUS)
return err
}
@ -102,7 +102,7 @@ func (h *MessageHandler) boradcastStatus(session types.Session) error {
}
if err := session.Send(msg); err != nil {
h.logger.Warn().Err(err).Msgf("sending event %s has failed", event.BORADCAST_STATUS)
h.logger.Warn().Err(err).Msgf("sending event %s has failed", event.BROADCAST_STATUS)
return err
}

View File

@ -17,7 +17,7 @@ func (h *MessageHandler) chat(id string, session types.Session, payload *message
Content: payload.Content,
ID: id,
}, nil); err != nil {
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.CONTROL_RELEASE)
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.CHAT_MESSAGE)
return err
}
return nil
@ -34,7 +34,7 @@ func (h *MessageHandler) chatEmote(id string, session types.Session, payload *me
Emote: payload.Emote,
ID: id,
}, nil); err != nil {
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.CONTROL_RELEASE)
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.CHAT_EMOTE)
return err
}
return nil

View File

@ -115,7 +115,7 @@ func (h *MessageHandler) controlGive(id string, session types.Session, payload *
ID: id,
Target: payload.ID,
}, nil); err != nil {
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.CONTROL_LOCKED)
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.CONTROL_GIVE)
return err
}

View File

@ -148,15 +148,15 @@ func (h *MessageHandler) Message(id string, raw []byte) error {
return h.screenSet(id, session, payload)
}), "%s failed", header.Event)
// Boradcast Events
case event.BORADCAST_CREATE:
// Broadcast Events
case event.BROADCAST_CREATE:
payload := &message.BroadcastCreate{}
return errors.Wrapf(
utils.Unmarshal(payload, raw, func() error {
return h.boradcastCreate(session, payload)
return h.broadcastCreate(session, payload)
}), "%s failed", header.Event)
case event.BORADCAST_DESTROY:
return errors.Wrapf(h.boradcastDestroy(session), "%s failed", header.Event)
case event.BROADCAST_DESTROY:
return errors.Wrapf(h.broadcastDestroy(session), "%s failed", header.Event)
// Admin Events
case event.ADMIN_LOCK:

View File

@ -30,7 +30,7 @@ func (h *MessageHandler) SessionCreated(id string, session types.Session) error
}
// send broadcast status if admin
if err := h.boradcastStatus(session); err != nil {
if err := h.broadcastStatus(session); err != nil {
return err
}
}
@ -78,7 +78,7 @@ func (h *MessageHandler) SessionConnected(id string, session types.Session) erro
Event: event.MEMBER_CONNECTED,
Member: session.Member(),
}, nil); err != nil {
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.CONTROL_RELEASE)
h.logger.Warn().Err(err).Msgf("broadcasting event %s has failed", event.MEMBER_CONNECTED)
return err
}