Skip to content

Commit 58b7dbf

Browse files
committedJul 28, 2024·
Pull in Blackmagic recording functionality from Sunset Showdown branch and tidy it up.
1 parent 7993bdb commit 58b7dbf

File tree

5 files changed

+83
-0
lines changed

5 files changed

+83
-0
lines changed
 

‎field/arena.go

+5
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type Arena struct {
5555
Plc plc.Plc
5656
TbaClient *partner.TbaClient
5757
NexusClient *partner.NexusClient
58+
BlackmagicClient *partner.BlackmagicClient
5859
AllianceStations map[string]*AllianceStation
5960
Displays map[string]*Display
6061
TeamSigns *TeamSigns
@@ -182,6 +183,7 @@ func (arena *Arena) LoadSettings() error {
182183
arena.Plc.SetAddress(settings.PlcAddress)
183184
arena.TbaClient = partner.NewTbaClient(settings.TbaEventCode, settings.TbaSecretId, settings.TbaSecret)
184185
arena.NexusClient = partner.NewNexusClient(settings.TbaEventCode)
186+
arena.BlackmagicClient = partner.NewBlackmagicClient(settings.BlackmagicAddresses)
185187

186188
game.MatchTiming.WarmupDurationSec = settings.WarmupDurationSec
187189
game.MatchTiming.AutoDurationSec = settings.AutoDurationSec
@@ -459,6 +461,7 @@ func (arena *Arena) AbortMatch() error {
459461
arena.AudienceDisplayModeNotifier.Notify()
460462
arena.AllianceStationDisplayMode = "logo"
461463
arena.AllianceStationDisplayModeNotifier.Notify()
464+
go arena.BlackmagicClient.StopRecording()
462465
return nil
463466
}
464467

@@ -550,6 +553,7 @@ func (arena *Arena) Update() {
550553
arena.AudienceDisplayModeNotifier.Notify()
551554
arena.AllianceStationDisplayMode = "match"
552555
arena.AllianceStationDisplayModeNotifier.Notify()
556+
go arena.BlackmagicClient.StartRecording()
553557
if game.MatchTiming.WarmupDurationSec > 0 {
554558
arena.MatchState = WarmupPeriod
555559
enabled = false
@@ -601,6 +605,7 @@ func (arena *Arena) Update() {
601605
auto = false
602606
enabled = false
603607
sendDsPacket = true
608+
go arena.BlackmagicClient.StopRecording()
604609
go func() {
605610
// Leave the scores on the screen briefly at the end of the match.
606611
time.Sleep(time.Second * matchEndScoreDwellSec)

‎model/event_settings.go

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type EventSettings struct {
4444
TeamSignBlue2Address string
4545
TeamSignBlue3Address string
4646
TeamSignBlueTimerAddress string
47+
BlackmagicAddresses string
4748
WarmupDurationSec int
4849
AutoDurationSec int
4950
PauseDurationSec int

‎partner/blackmagic.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2024 Team 254. All Rights Reserved.
2+
// Author: pat@patfairbank.com (Patrick Fairbank)
3+
//
4+
// Client for interfacing with one or more Blackmagic HyperDeck devices to automatically record matches.
5+
6+
package partner
7+
8+
import (
9+
"fmt"
10+
"log"
11+
"net"
12+
"strings"
13+
"time"
14+
)
15+
16+
const (
17+
blackmagicPort = 9993
18+
blackmagicConnectTimeoutMs = 100
19+
blackmagicStopDelaySec = 10
20+
)
21+
22+
type BlackmagicClient struct {
23+
deviceAddresses []string
24+
}
25+
26+
// Creates a new Blackmagic client with the given device addresses as a comma-separated string.
27+
func NewBlackmagicClient(addresses string) *BlackmagicClient {
28+
deviceAddresses := strings.Split(addresses, ",")
29+
for i, address := range deviceAddresses {
30+
deviceAddresses[i] = strings.TrimSpace(address)
31+
}
32+
return &BlackmagicClient{deviceAddresses: deviceAddresses}
33+
}
34+
35+
// Starts recording across all devices.
36+
func (client *BlackmagicClient) StartRecording() {
37+
client.sendCommand("record")
38+
}
39+
40+
// Stops recording across all devices after a delay.
41+
func (client *BlackmagicClient) StopRecording() {
42+
time.Sleep(blackmagicStopDelaySec * time.Second)
43+
client.sendCommand("stop")
44+
}
45+
46+
// Connects to all devices and executes the given command.
47+
func (client *BlackmagicClient) sendCommand(command string) {
48+
for _, address := range client.deviceAddresses {
49+
conn, err := net.DialTimeout(
50+
"tcp", fmt.Sprintf("%s:%d", address, blackmagicPort), blackmagicConnectTimeoutMs*time.Millisecond,
51+
)
52+
if err != nil {
53+
log.Printf("Failed to connect to Blackmagic device at %s: %v", address, err)
54+
continue
55+
}
56+
defer conn.Close()
57+
_, err = fmt.Fprint(conn, command+"\n")
58+
if err != nil {
59+
log.Printf("Failed to send '%s' command to Blackmagic device at %s: %v", command, address, err)
60+
}
61+
}
62+
}

‎templates/setup_settings.html

+14
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,20 @@
291291
</div>
292292
</div>
293293
</fieldset>
294+
<fieldset class="mb-4">
295+
<legend>Match Video Recording</legend>
296+
<p>
297+
If you are using a Blackmagic HyperDeck device to record match video, enter the device IP address(es) here
298+
to have Cheesy Arena automatically start and stop recording for each match. Separate multiple addresses with
299+
a comma.
300+
</p>
301+
<div class="row mb-3">
302+
<label class="col-lg-6 control-label">Blackmagic Addresses</label>
303+
<div class="col-lg-6">
304+
<input type="text" class="form-control" name="blackmagicAddresses" value="{{.BlackmagicAddresses}}">
305+
</div>
306+
</div>
307+
</fieldset>
294308
<fieldset class="mb-4">
295309
<legend>Game-Specific</legend>
296310
<div class="row mb-3">

‎web/setup_settings.go

+1
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ func (web *Web) settingsPostHandler(w http.ResponseWriter, r *http.Request) {
9696
eventSettings.TeamSignBlue2Address = r.PostFormValue("teamSignBlue2Address")
9797
eventSettings.TeamSignBlue3Address = r.PostFormValue("teamSignBlue3Address")
9898
eventSettings.TeamSignBlueTimerAddress = r.PostFormValue("teamSignBlueTimerAddress")
99+
eventSettings.BlackmagicAddresses = r.PostFormValue("blackmagicAddresses")
99100
eventSettings.WarmupDurationSec, _ = strconv.Atoi(r.PostFormValue("warmupDurationSec"))
100101
eventSettings.AutoDurationSec, _ = strconv.Atoi(r.PostFormValue("autoDurationSec"))
101102
eventSettings.PauseDurationSec, _ = strconv.Atoi(r.PostFormValue("pauseDurationSec"))

0 commit comments

Comments
 (0)
Please sign in to comment.