Skip to content
Draft
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
4b66a39
add voice module, deps, wip models
llsc12 Feb 19, 2026
d49fcc1
more voice models
llsc12 Feb 19, 2026
f942d4d
clean up
llsc12 Feb 19, 2026
a820da1
added gateway actor, not ready yet tho
llsc12 Feb 20, 2026
4cf68cb
more work
llsc12 Feb 21, 2026
61a4263
Merge branch 'main' into voice
llsc12 Feb 21, 2026
8d412d3
test
llsc12 Feb 22, 2026
c9e96ae
fix builds
llsc12 Feb 22, 2026
15d959a
Squashed commit of the following:
llsc12 Feb 22, 2026
ef52d96
fix ios builds
llsc12 Feb 22, 2026
753c916
clean up, add dave work, tests
llsc12 Feb 23, 2026
5075107
max dave version
llsc12 Feb 23, 2026
1cf1c9a
more udp work
llsc12 Feb 23, 2026
2917dc6
add dave session handling
llsc12 Feb 23, 2026
8a767b5
i think my outbound code is wrong
llsc12 Feb 23, 2026
0e66982
wip app side voice stuff
llsc12 Feb 24, 2026
5645ece
dont forget to identify
llsc12 Feb 24, 2026
d4da406
connection doesnt always work
llsc12 Feb 24, 2026
368e7e4
voice gateway working
llsc12 Feb 24, 2026
d5aea9d
temporary leave button
llsc12 Feb 25, 2026
5be2f71
fix udp stuff, fix ip discovery
llsc12 Feb 25, 2026
bfe23ed
weird crash with libdave
llsc12 Feb 25, 2026
bf98f17
the crypto stuff is fixed
llsc12 Mar 3, 2026
9e6664f
Update VoiceGatewayManager.swift
llsc12 Mar 3, 2026
35a5599
forgot to encode opcode, works now
llsc12 Mar 3, 2026
6299376
fix a bunch of logical issues, fix sending audio packets, send silent…
llsc12 Mar 4, 2026
b8bcdf2
fix crypto
llsc12 Mar 5, 2026
dc7a63c
wip voice working
llsc12 Mar 5, 2026
8b20bbc
dont schedule buffers on main thread
llsc12 Mar 7, 2026
e3fade7
emit opus packets directly, emit fake speaking events
llsc12 Mar 7, 2026
56d79fa
voice states
llsc12 Mar 7, 2026
88aa05d
Update VoiceGatewayManager.swift
llsc12 Mar 7, 2026
6001c74
init decoder and player node per ssrc
llsc12 Mar 7, 2026
12ab4de
fix missing sendable payload
llsc12 Mar 7, 2026
3b6303f
add audio receive buffer
llsc12 Mar 7, 2026
e990997
fix encryption nonce, add additional data to chacha
llsc12 Mar 11, 2026
34f7ee4
paicordlib add dave ssrc codec info, better buffering impl, get rid o…
llsc12 Mar 11, 2026
c182f07
working bidirectional audio
llsc12 Mar 11, 2026
bde09a4
buffer per incoming stream
llsc12 Mar 11, 2026
5fe71f9
fix changing channels whilst in a channel
llsc12 Mar 11, 2026
7f7623f
Update VoiceConnectionStore.swift
llsc12 Mar 12, 2026
42ca30e
disconnect on another client connecting
llsc12 Mar 12, 2026
8b1e6ff
fix member row popout
llsc12 Mar 12, 2026
6f758a5
add voice states to guild
llsc12 Mar 12, 2026
7cdc426
expose guild and channel stores, voice channel members, call bar
llsc12 Mar 12, 2026
ddd4160
request member data
llsc12 Mar 12, 2026
d42b3d5
fix disconnection bug, fix weird voice channel spacing
llsc12 Mar 13, 2026
0525f9d
make call bar nicer
llsc12 Mar 14, 2026
65aaef7
change how navigation works
llsc12 Mar 16, 2026
90514e0
wip voice ui
llsc12 Mar 17, 2026
11f2c62
permissions
llsc12 Mar 17, 2026
a3d771a
fixes
llsc12 Mar 17, 2026
81e7b2c
fix dms button
llsc12 Mar 18, 2026
e7ccd8c
point links away from discordbm's issues
llsc12 Mar 18, 2026
ad0a4fb
discord can send no name for connected accounts
llsc12 Mar 18, 2026
de68d6c
Update VoiceGatewayManager.swift
llsc12 Mar 18, 2026
3c58754
ringing
llsc12 Mar 18, 2026
50a9be0
calls (dm vc) support, wip call ui
llsc12 Mar 18, 2026
ee443c1
fixes to channel order, dms ui wip
llsc12 Mar 23, 2026
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
14 changes: 14 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@ jobs:
restore-keys: |
deriveddata-macos

- name: Force Git to use HTTPS
run: |
# rewrite any git@github.com:... clones to https://github.com/...
git config --global url."https://github.com/".insteadOf "git@github.com:"
# optional: debug the rule
git config --get-regexp '^url\.' || true

- name: Build macOS .app
run: |
COMMIT_HASH=$(git rev-parse --short HEAD)
Expand Down Expand Up @@ -226,6 +233,13 @@ jobs:
restore-keys: |
deriveddata-ios

- name: Force Git to use HTTPS
run: |
# rewrite any git@github.com:... clones to https://github.com/...
git config --global url."https://github.com/".insteadOf "git@github.com:"
# optional: debug the rule
git config --get-regexp '^url\.' || true

- name: Build iOS .ipa
run: |
COMMIT_HASH=$(git rev-parse --short HEAD)
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/build_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ jobs:
deriveddata-macos-pr-${{ github.event.pull_request.number }}-
deriveddata-macos-pr-

- name: Force Git to use HTTPS
run: |
# rewrite any git@github.com:... clones to https://github.com/...
git config --global url."https://github.com/".insteadOf "git@github.com:"
# optional: debug the rule
git config --get-regexp '^url\.' || true

- name: Build macOS
id: build
run: |
Expand Down Expand Up @@ -77,6 +84,13 @@ jobs:
deriveddata-ios-pr-${{ github.event.pull_request.number }}-
deriveddata-ios-pr-

- name: Force Git to use HTTPS
run: |
# rewrite any git@github.com:... clones to https://github.com/...
git config --global url."https://github.com/".insteadOf "git@github.com:"
# optional: debug the rule
git config --get-regexp '^url\.' || true

- name: Build iOS
id: build
run: |
Expand Down
14 changes: 14 additions & 0 deletions .github/workflows/release_pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,13 @@ jobs:
restore-keys: |
pr-release-deriveddata-macos-

- name: Force Git to use HTTPS
run: |
# rewrite any git@github.com:... clones to https://github.com/...
git config --global url."https://github.com/".insteadOf "git@github.com:"
# optional: debug the rule
git config --get-regexp '^url\.' || true

- name: Build macOS
run: |
set -euo pipefail
Expand Down Expand Up @@ -194,6 +201,13 @@ jobs:
echo "ldid installed at: $(command -v ldid)"
fi

- name: Force Git to use HTTPS
run: |
# rewrite any git@github.com:... clones to https://github.com/...
git config --global url."https://github.com/".insteadOf "git@github.com:"
# optional: debug the rule
git config --get-regexp '^url\.' || true

- name: Build iOS
run: |
set -euo pipefail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<key>DiscordMarkdownParser.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
<integer>4</integer>
</dict>
</dict>
</dict>
Expand Down
15 changes: 12 additions & 3 deletions DiscordMarkdownParser/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ let package = Package(
// Products define the executables and libraries a package produces, making them visible to other packages.
.library(
name: "DiscordMarkdownParser",
targets: ["DiscordMarkdownParser"])
targets: ["DiscordMarkdownParser"]
)
],
dependencies: [
.package(path: "../PaicordLib")
Expand All @@ -24,9 +25,17 @@ let package = Package(
name: "DiscordMarkdownParser",
dependencies: [
"PaicordLib"
]),
],
swiftSettings: [
.interoperabilityMode(.Cxx)
]
),
.testTarget(
name: "DiscordMarkdownParserTests",
dependencies: ["DiscordMarkdownParser"]),
dependencies: ["DiscordMarkdownParser"],
swiftSettings: [
.interoperabilityMode(.Cxx)
]
),
]
)
6 changes: 6 additions & 0 deletions Paicord.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@
AAEEC71F2E65120000EB5FC9 /* TokenStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAEEC71E2E6511F800EB5FC9 /* TokenStore.swift */; };
AAEEC7222E6515C400EB5FC9 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = AAEEC7212E6515C400EB5FC9 /* KeychainAccess */; };
AAEEF5012E9900F60034FA04 /* Default.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAEEF5002E9900E50034FA04 /* Default.swift */; };
AAFBC52E2F4C946800C5B644 /* VoiceConnectionStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAFBC52D2F4C945F00C5B644 /* VoiceConnectionStore.swift */; };
AAFC9DDA2EB7DAE300BB8028 /* VariableBlurView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAFC9DD92EB7DAE200BB8028 /* VariableBlurView.swift */; };
AAFD41382E92FA43002BC9BE /* Array+safe.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAFD41372E92FA42002BC9BE /* Array+safe.swift */; };
/* End PBXBuildFile section */
Expand Down Expand Up @@ -297,6 +298,7 @@
AAEB3D942ED60812008BDD1D /* ImpactGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImpactGenerator.swift; sourceTree = "<group>"; };
AAEEC71E2E6511F800EB5FC9 /* TokenStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenStore.swift; sourceTree = "<group>"; };
AAEEF5002E9900E50034FA04 /* Default.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Default.swift; sourceTree = "<group>"; };
AAFBC52D2F4C945F00C5B644 /* VoiceConnectionStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VoiceConnectionStore.swift; sourceTree = "<group>"; };
AAFC9DD92EB7DAE200BB8028 /* VariableBlurView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VariableBlurView.swift; sourceTree = "<group>"; };
AAFD41372E92FA42002BC9BE /* Array+safe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+safe.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -978,6 +980,7 @@
AABED5A32E7F4DAE005BDD63 /* GuildStore.swift */,
AABED59D2E7F4637005BDD63 /* ChannelStore.swift */,
AA7B38F32EB50EFD00CA4A3C /* MessageDrainStore.swift */,
AAFBC52D2F4C945F00C5B644 /* VoiceConnectionStore.swift */,
AABED5A52E7F5148005BDD63 /* SettingsStore.swift */,
AAAF797F2ED1E9ED004B5B3F /* ExternalBadgeStore.swift */,
AA79479D2EDC7B9400B7A1EE /* PresenceStore.swift */,
Expand Down Expand Up @@ -1175,6 +1178,7 @@
AA47AF1F2EDEF04F008A50C9 /* AuthorisedAppsSection.swift in Sources */,
AA21D2802EAA220300C75093 /* MaskEdgesModifier.swift in Sources */,
57F5AF552E7CBDF400AD5674 /* MFAView.swift in Sources */,
AAFBC52E2F4C946800C5B644 /* VoiceConnectionStore.swift in Sources */,
AA7B38F22EB37F9B00CA4A3C /* PermsHelper.swift in Sources */,
AA63EB722EA711D000A5F21D /* EmbedsView.swift in Sources */,
AAB50A582E9AD4BB0048E8B0 /* Utilities.swift in Sources */,
Expand Down Expand Up @@ -1425,6 +1429,7 @@
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_INTEROP_MODE = objcxx;
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting SWIFT_OBJC_INTEROP_MODE to objcxx enables C++ interoperability which is required for some dependencies (likely DaveKit). However, this is a significant compiler mode change that affects the entire project. Ensure this is intentional and documented, as it may have implications for build times and compatibility with other dependencies.

Suggested change
SWIFT_OBJC_INTEROP_MODE = objcxx;
/* SWIFT_OBJC_INTEROP_MODE not forced to objcxx here; use default (objc) to avoid project-wide ObjC++ mode. */

Copilot uses AI. Check for mistakes.
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,7";
Expand Down Expand Up @@ -1488,6 +1493,7 @@
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_INTEROP_MODE = objcxx;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,7";
XROS_DEPLOYMENT_TARGET = 1.0;
Expand Down
33 changes: 30 additions & 3 deletions Paicord.xcworkspace/xcshareddata/swiftpm/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions Paicord/Stores/VoiceConnectionStore.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
//
// VoiceConnectionStore.swift
// Paicord
//
// Created by Lakhan Lothiyi on 23/02/2026.
// Copyright © 2026 Lakhan Lothiyi.
//

import PaicordLib

final class VoiceConnectionStore: DiscordDataStore {
var gateway: GatewayStore?
var voiceGateway: VoiceGatewayManager?

var eventTask: Task<Void, Never>?

func setupEventHandling() {
guard let gateway = gateway?.gateway else { return }

eventTask = Task { @MainActor in
for await event in await gateway.events {
switch event.data {
// capture and store voice events
default:
break
}
}
}
}


func cancelEventHandling() {
// overrides default impl of protocol
eventTask?.cancel()
eventTask = nil

// end networking session etc.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
<key>orderHint</key>
<integer>6</integer>
</dict>
<key>DiscordVoice.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>3</integer>
</dict>
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.swiftpm/xcode/xcuserdata/... is user-specific Xcode state and typically shouldn’t be committed (it causes noisy diffs and conflicts across developers/CI). Consider adding **/xcuserdata/ to .gitignore and removing this file from the repo unless there’s a strong reason to keep it.

Copilot uses AI. Check for mistakes.
<key>GenerateAPIEndpointsExec.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
Expand Down
43 changes: 38 additions & 5 deletions PaicordLib/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ let package = Package(
name: "DiscordGateway",
targets: ["DiscordGateway"]
),
.library(
name: "DiscordVoice",
targets: ["DiscordVoice"]
),
.library(
name: "DiscordModels",
targets: ["DiscordModels"]
Expand Down Expand Up @@ -74,6 +78,14 @@ let package = Package(
url: "https://github.com/apple/swift-crypto.git",
"1.0.0"..<"5.0.0"
),
.package(
url: "https://github.com/alta/swift-opus.git",
branch: "main"
),
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SwiftPM dependency on https://github.com/alta/swift-opus.git is pinned to the mutable main branch rather than an immutable tag or commit. If that upstream repository or branch is compromised, new builds will automatically pull and execute attacker-controlled code in your voice/audio pipeline. Pin this dependency to a specific version or commit SHA and only update it intentionally after reviewing upstream changes.

Copilot uses AI. Check for mistakes.
.package(
url: "https://github.com/llsc12/DaveKit.git",
branch: "main"
Comment on lines +81 to +83
Copy link

Copilot AI Feb 19, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The swift-opus dependency is pinned only to the mutable main branch, which makes your build pipeline dependent on whatever code is currently published there. If that repository is compromised or publishes a malicious change to main, the malicious code will be automatically fetched and executed with the same privileges as your application (e.g., access to tokens and user data). Pin this dependency to an immutable identifier (a specific released version or commit hash) instead of a branch name to reduce supply-chain compromise risk.

Copilot uses AI. Check for mistakes.
),
],
targets: [
.target(
Expand All @@ -82,6 +94,7 @@ let package = Package(
.target(name: "DiscordAuth"),
.target(name: "DiscordHTTP"),
.target(name: "DiscordCore"),
.target(name: "DiscordVoice"),
.target(name: "DiscordGateway"),
.target(name: "DiscordModels"),
.target(name: "DiscordUtilities"),
Expand Down Expand Up @@ -111,9 +124,22 @@ let package = Package(
.product(name: "AsyncHTTPClient", package: "async-http-client"),
.product(name: "WSClient", package: "swift-websocket"),
.product(name: "libzstd", package: "zstd"),
.target(name: "DiscordHTTP"),
.product(name: "Crypto", package: "swift-crypto"),
.product(name: "_CryptoExtras", package: "swift-crypto"),
.target(name: "DiscordHTTP"),
],
swiftSettings: swiftSettings
),
.target(
name: "DiscordVoice",
dependencies: [
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "AsyncHTTPClient", package: "async-http-client"),
.product(name: "WSClient", package: "swift-websocket"),
.product(name: "libzstd", package: "zstd"),
.product(name: "Opus", package: "swift-opus"),
.product(name: "DaveKit", package: "DaveKit"),
.target(name: "DiscordGateway"),
],
swiftSettings: swiftSettings
),
Expand All @@ -122,10 +148,11 @@ let package = Package(
dependencies: [
.product(name: "NIOFoundationCompat", package: "swift-nio"),
.product(name: "MultipartKit", package: "multipart-kit"),
.target(name: "DiscordCore"),
.target(name: "UnstableEnumMacro"),
.product(name: "SwiftProtobuf", package: "swift-protobuf"),
.product(name: "UInt128", package: "UInt128"),
.product(name: "DaveKit", package: "DaveKit"),
.target(name: "DiscordCore"),
.target(name: "UnstableEnumMacro"),
],
swiftSettings: swiftSettings
),
Expand All @@ -139,7 +166,12 @@ let package = Package(
.target(
name: "DiscordAuth",
dependencies: [
.target(name: "DiscordModels")
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "AsyncHTTPClient", package: "async-http-client"),
.product(name: "WSClient", package: "swift-websocket"),
.product(name: "Crypto", package: "swift-crypto"),
.product(name: "_CryptoExtras", package: "swift-crypto"),
.target(name: "DiscordGateway"),
],
swiftSettings: swiftSettings
),
Expand Down Expand Up @@ -211,9 +243,10 @@ let package = Package(

var featureFlags: [SwiftSetting] {
[
.interoperabilityMode(.Cxx),
/// https://github.com/apple/swift-evolution/blob/main/proposals/0335-existential-any.md
/// Require `any` for existential types.
.enableUpcomingFeature("ExistentialAny")
.enableUpcomingFeature("ExistentialAny"),
// .define("DISCORDBM_ENABLE_LOGGING_DURING_DECODE", .when(configuration: .debug)),
]
}
Expand Down
Loading