livekit-server-sdk 0.8.3 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -0
  3. data/.github/banner_dark.png +0 -0
  4. data/.github/banner_light.png +0 -0
  5. data/.github/workflows/generate-protobufs.yml +82 -0
  6. data/.github/workflows/test-api.yml +43 -0
  7. data/.github/workflows/test.yml +10 -7
  8. data/CHANGELOG.md +18 -0
  9. data/Gemfile.lock +70 -39
  10. data/README.md +7 -5
  11. data/Rakefile +8 -2
  12. data/bin/bootstrap.sh +1 -1
  13. data/lib/livekit/agent_dispatch_service_client.rb +11 -9
  14. data/lib/livekit/auth_mixin.rb +23 -8
  15. data/lib/livekit/connector_service_client.rb +87 -0
  16. data/lib/livekit/dial_timeout.rb +26 -0
  17. data/lib/livekit/egress_service_client.rb +41 -19
  18. data/lib/livekit/errors.rb +60 -0
  19. data/lib/livekit/failover.rb +215 -0
  20. data/lib/livekit/grants.rb +6 -2
  21. data/lib/livekit/ingress_service_client.rb +8 -6
  22. data/lib/livekit/livekit_api.rb +67 -0
  23. data/lib/livekit/proto/livekit_agent_dispatch_pb.rb +3 -1
  24. data/lib/livekit/proto/livekit_agent_dispatch_twirp.rb +1 -1
  25. data/lib/livekit/proto/livekit_agent_pb.rb +2 -1
  26. data/lib/livekit/proto/livekit_agent_twirp.rb +1 -1
  27. data/lib/livekit/proto/livekit_connector_pb.rb +20 -0
  28. data/lib/livekit/proto/livekit_connector_twilio_pb.rb +22 -0
  29. data/lib/livekit/proto/livekit_connector_twilio_twirp.rb +8 -0
  30. data/lib/livekit/proto/livekit_connector_twirp.rb +21 -0
  31. data/lib/livekit/proto/livekit_connector_whatsapp_pb.rb +32 -0
  32. data/lib/livekit/proto/livekit_connector_whatsapp_twirp.rb +8 -0
  33. data/lib/livekit/proto/livekit_egress_pb.rb +33 -16
  34. data/lib/livekit/proto/livekit_egress_twirp.rb +6 -5
  35. data/lib/livekit/proto/livekit_ingress_pb.rb +2 -1
  36. data/lib/livekit/proto/livekit_ingress_twirp.rb +1 -1
  37. data/lib/livekit/proto/livekit_metrics_pb.rb +3 -1
  38. data/lib/livekit/proto/livekit_metrics_twirp.rb +1 -1
  39. data/lib/livekit/proto/livekit_models_pb.rb +20 -1
  40. data/lib/livekit/proto/livekit_models_twirp.rb +1 -1
  41. data/lib/livekit/proto/livekit_room_pb.rb +8 -1
  42. data/lib/livekit/proto/livekit_room_twirp.rb +4 -1
  43. data/lib/livekit/proto/livekit_rtc_pb.rb +86 -0
  44. data/lib/livekit/proto/livekit_rtc_twirp.rb +8 -0
  45. data/lib/livekit/proto/livekit_sip_pb.rb +20 -1
  46. data/lib/livekit/proto/livekit_sip_twirp.rb +4 -1
  47. data/lib/livekit/proto/livekit_webhook_pb.rb +1 -1
  48. data/lib/livekit/proto/livekit_webhook_twirp.rb +1 -1
  49. data/lib/livekit/proto/logger/options_pb.rb +19 -0
  50. data/lib/livekit/proto/logger/options_twirp.rb +8 -0
  51. data/lib/livekit/room_service_client.rb +31 -13
  52. data/lib/livekit/sip_service_client.rb +147 -21
  53. data/lib/livekit/version.rb +1 -1
  54. data/lib/livekit.rb +3 -0
  55. data/livekit_server_sdk.gemspec +8 -8
  56. metadata +59 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1c0cc5485847e5c607b3d932f49dc765060cfed1c67dc87b4bd391fa814ebbcb
4
- data.tar.gz: 20328e28b682ae95762918dbb2d0992ea2ede14020ce9755f85ef3b539d0d05d
3
+ metadata.gz: 5ea2a9dbfe91bc5b18d22b6f5d7003e012f8b12cfbcc8888608a6caf17f2547f
4
+ data.tar.gz: 23b228981cd42c60a7126c069abb2cf0e5d32f0023e503dd245dcaada56597eb
5
5
  SHA512:
6
- metadata.gz: c91cb47f2cf90f3be008f2fcb6dc3d53326a9a5c15651331a556bdfa1349caf275af7745d9b7986cf1c8b2051cb948aacc968cc9eb05923a8dfe91ddba735de7
7
- data.tar.gz: f0d1a1f0fbb354d9ed05146e3ffa89c508664bd2316f34ef5fed6ca235842d31d1b20bc610ac0b1db753d9dd292dec0359b46a5060bedd325da6e2bf1c5c1500
6
+ metadata.gz: 9ace72abe5c36e81223b1da3039d0bee5bde9997c6321a78fbce561ec0a5e2a3c0e0bc4aa4cc54da18b2586d6ea9c0717329808298c06c9d0e64d8f281ad4d42
7
+ data.tar.gz: cad3174b5fa4d01280a943290bb0fc1688ec21eea1c33a09850ad75f8c38988de14715edec40ab4be23cab8f2cdfba0533ee5453d577fa6bbb8ee5448d013f75
@@ -0,0 +1 @@
1
+ * @livekit/cs-devs
Binary file
Binary file
@@ -0,0 +1,82 @@
1
+ # Copyright 2026 LiveKit, Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # Regenerates the vendored protobuf/Twirp stubs (lib/livekit/proto) from the
16
+ # `protocol` submodule and commits them back, so generated code is never
17
+ # produced on a developer's machine. Runs on PRs that bump the submodule (or
18
+ # change the generation task) and commits the regenerated files onto the PR
19
+ # branch; also available on demand.
20
+
21
+ name: Generate Protobufs
22
+
23
+ permissions:
24
+ contents: write
25
+
26
+ on:
27
+ workflow_dispatch:
28
+ pull_request:
29
+ branches: [main]
30
+ paths:
31
+ - "protocol"
32
+ - "Rakefile"
33
+ - ".github/workflows/generate-protobufs.yml"
34
+
35
+ concurrency:
36
+ group: generate-protobufs-${{ github.ref }}
37
+ cancel-in-progress: true
38
+
39
+ jobs:
40
+ generate:
41
+ runs-on: ubuntu-latest
42
+ # Actions cannot push to a fork's branch, so skip generation there. The
43
+ # checked-in files are still validated by the gem's test workflow.
44
+ if: github.event_name == 'workflow_dispatch' || github.event.pull_request.head.repo.full_name == github.repository
45
+ steps:
46
+ - name: Checkout code
47
+ uses: actions/checkout@v4
48
+ with:
49
+ submodules: recursive
50
+ # Commit regenerated files back onto the PR branch (or the dispatched branch).
51
+ ref: ${{ github.head_ref || github.ref_name }}
52
+
53
+ - name: Set up Ruby
54
+ uses: ruby/setup-ruby@v1.190.0
55
+ with:
56
+ ruby-version: "3.3"
57
+ bundler-cache: true
58
+
59
+ - name: Set up Go
60
+ uses: actions/setup-go@v5
61
+ with:
62
+ go-version: "1.23"
63
+
64
+ - name: Install protoc
65
+ uses: arduino/setup-protoc@v3
66
+ with:
67
+ version: "30.2"
68
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
69
+
70
+ - name: Install protoc-gen-twirp_ruby
71
+ run: go install github.com/arthurnn/twirp-ruby/protoc-gen-twirp_ruby@v1.14.1
72
+
73
+ - name: Generate protobufs
74
+ run: |
75
+ export PATH="$(go env GOPATH)/bin:$PATH"
76
+ bundle exec rake proto
77
+
78
+ - name: Commit regenerated protobufs
79
+ uses: stefanzweifel/git-auto-commit-action@v5
80
+ with:
81
+ commit_message: "chore: regenerate protobufs"
82
+ file_pattern: "lib/livekit/proto/**"
@@ -0,0 +1,43 @@
1
+ name: Test API
2
+
3
+ permissions:
4
+ contents: read
5
+
6
+ on:
7
+ workflow_dispatch:
8
+ push:
9
+ branches: [main]
10
+ pull_request:
11
+ branches: [main]
12
+
13
+ jobs:
14
+ failover:
15
+ runs-on: ubuntu-latest
16
+ services:
17
+ mock-server:
18
+ image: livekit/test-server:latest
19
+ ports:
20
+ - 9999:9999
21
+ - 10000:10000
22
+ - 10001:10001
23
+ - 10002:10002
24
+ steps:
25
+ - name: Checkout code
26
+ uses: actions/checkout@v4
27
+
28
+ - name: Setup Ruby
29
+ uses: ruby/setup-ruby@v1.190.0
30
+ with:
31
+ ruby-version: "3.3"
32
+ bundler-cache: true
33
+
34
+ - name: Wait for mock server
35
+ run: |
36
+ for i in $(seq 1 30); do
37
+ curl -sf http://127.0.0.1:9999/settings/regions >/dev/null && exit 0
38
+ sleep 1
39
+ done
40
+ echo "mock server did not become ready" && exit 1
41
+
42
+ - name: Run API tests
43
+ run: bundle exec rspec spec/api
@@ -1,4 +1,7 @@
1
- on: [push, pull_request]
1
+ on:
2
+ push:
3
+ branches: [main]
4
+ pull_request:
2
5
  name: Test
3
6
  jobs:
4
7
  test:
@@ -7,17 +10,17 @@ jobs:
7
10
  strategy:
8
11
  matrix:
9
12
  include:
10
- - { os: ubuntu-latest, ruby_version: "3.0" }
11
- - { os: ubuntu-latest, ruby_version: "3.3" }
13
+ # Ruby 3.1 is the floor (google-protobuf 4.x requires >= 3.1; 3.0 is EOL).
14
+ - { os: ubuntu-latest, ruby_version: "3.1" }
15
+ - { os: ubuntu-latest, ruby_version: "3.4" }
12
16
  - { os: ubuntu-latest, ruby_version: "jruby-9.4" }
13
17
  steps:
18
+ - name: Checkout code
19
+ uses: actions/checkout@v4
14
20
  - name: Setup Ruby, JRuby and TruffleRuby
15
- uses: ruby/setup-ruby@v1.190.0
21
+ uses: ruby/setup-ruby@v1.315.0
16
22
  with:
17
- bundler: 1
18
23
  ruby-version: ${{ matrix.ruby_version }}
19
- - name: Checkout code
20
- uses: actions/checkout@v2
21
24
  - name: Run tests
22
25
  run: |
23
26
  gem install bundler:2.3.7
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.0.0]
4
+
5
+ ### Added
6
+
7
+ - `LiveKit::LiveKitAPI`, a single entry point exposing every service through a reader (`room`, `egress`, `ingress`, `sip`, `agent_dispatch`, `connector`).
8
+ - Token authentication: construct clients (or `LiveKitAPI`) with a pre-signed `token:` that is sent verbatim, enabling client-side use without an API secret. Credentials fall back to `LIVEKIT_URL`, `LIVEKIT_TOKEN`, `LIVEKIT_API_KEY`, and `LIVEKIT_API_SECRET`.
9
+ - `LiveKit::SipCallError` (a `LiveKit::TwirpError`) raised by SIP dialing calls, exposing `sip_status_code` and `sip_status`.
10
+
11
+ ### Changed
12
+
13
+ - **Breaking:** service methods now return the response message directly and raise `LiveKit::TwirpError` on failure, instead of returning a `Twirp::ClientResp`. Replace `resp = client.create_room(...); resp.data` with `room = client.create_room(...)`, and rescue `LiveKit::TwirpError` for errors.
14
+ - `faraday` is now a declared runtime dependency.
15
+
16
+ ### Fixed
17
+
18
+ - `EgressServiceClient` no longer raises when a single output is passed to `start_participant_egress` (the request has no deprecated singular output field).
19
+ - `AgentDispatchServiceClient#get_dispatch` / `#list_dispatch` now return correctly (they previously assumed the RPC returned data directly).
20
+
3
21
  ## [0.1.0] - 2021-07-25
4
22
 
5
23
  - Initial release
data/Gemfile.lock CHANGED
@@ -1,60 +1,91 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- livekit-server-sdk (0.8.3)
5
- google-protobuf (>= 3.21.0, < 4.0)
4
+ livekit-server-sdk (1.0.0)
5
+ faraday (>= 2.0, < 3.0)
6
+ google-protobuf (~> 4.30, >= 4.30.2)
6
7
  jwt (>= 2.2.3, < 3.0)
7
- rack (>= 2.2.3)
8
- twirp (>= 1.10.0, < 2.0)
8
+ twirp (~> 1.13, >= 1.13.1)
9
9
 
10
10
  GEM
11
11
  remote: https://rubygems.org/
12
12
  specs:
13
- base64 (0.2.0)
13
+ base64 (0.3.0)
14
+ bigdecimal (4.1.2)
15
+ bigdecimal (4.1.2-java)
14
16
  coderay (1.1.3)
15
- diff-lcs (1.5.0)
16
- faraday (2.10.1)
17
- faraday-net_http (>= 2.0, < 3.2)
17
+ diff-lcs (1.6.2)
18
+ faraday (2.14.3)
19
+ faraday-net_http (>= 2.0, < 3.5)
20
+ json
18
21
  logger
19
- faraday-net_http (3.1.1)
20
- net-http
21
- google-protobuf (3.25.4)
22
- jwt (2.8.2)
22
+ faraday-net_http (3.4.4)
23
+ net-http (~> 0.5)
24
+ ffi (1.17.4-java)
25
+ ffi-compiler (1.4.2)
26
+ ffi (>= 1.15.5)
27
+ rake
28
+ google-protobuf (4.35.1)
29
+ bigdecimal
30
+ rake (~> 13.3)
31
+ google-protobuf (4.35.1-java)
32
+ bigdecimal
33
+ ffi (~> 1)
34
+ ffi-compiler (~> 1)
35
+ rake (~> 13.3)
36
+ google-protobuf (4.35.1-x86_64-linux-gnu)
37
+ bigdecimal
38
+ rake (~> 13.3)
39
+ io-console (0.8.2)
40
+ io-console (0.8.2-java)
41
+ json (2.20.0)
42
+ json (2.20.0-java)
43
+ jwt (2.10.3)
23
44
  base64
24
- logger (1.6.5)
25
- method_source (1.0.0)
26
- net-http (0.4.1)
27
- uri
28
- pry (0.14.2)
45
+ logger (1.7.0)
46
+ method_source (1.1.0)
47
+ net-http (0.9.1)
48
+ uri (>= 0.11.1)
49
+ pry (0.16.0)
50
+ coderay (~> 1.1)
51
+ method_source (~> 1.0)
52
+ reline (>= 0.6.0)
53
+ pry (0.16.0-java)
29
54
  coderay (~> 1.1)
30
55
  method_source (~> 1.0)
31
- pry-doc (1.4.0)
56
+ reline (>= 0.6.0)
57
+ spoon (~> 0.0)
58
+ pry-doc (1.7.0)
32
59
  pry (~> 0.11)
33
- yard (~> 0.9.11)
34
- rack (3.1.7)
35
- rake (13.0.6)
36
- rspec (3.12.0)
37
- rspec-core (~> 3.12.0)
38
- rspec-expectations (~> 3.12.0)
39
- rspec-mocks (~> 3.12.0)
40
- rspec-core (3.12.1)
41
- rspec-support (~> 3.12.0)
42
- rspec-expectations (3.12.2)
60
+ yard (~> 0.9.21)
61
+ rack (3.2.6)
62
+ rake (13.4.2)
63
+ reline (0.6.3)
64
+ io-console (~> 0.5)
65
+ rspec (3.13.2)
66
+ rspec-core (~> 3.13.0)
67
+ rspec-expectations (~> 3.13.0)
68
+ rspec-mocks (~> 3.13.0)
69
+ rspec-core (3.13.6)
70
+ rspec-support (~> 3.13.0)
71
+ rspec-expectations (3.13.5)
43
72
  diff-lcs (>= 1.2.0, < 2.0)
44
- rspec-support (~> 3.12.0)
45
- rspec-mocks (3.12.3)
73
+ rspec-support (~> 3.13.0)
74
+ rspec-mocks (3.13.8)
46
75
  diff-lcs (>= 1.2.0, < 2.0)
47
- rspec-support (~> 3.12.0)
48
- rspec-support (3.12.0)
49
- twirp (1.10.0)
76
+ rspec-support (~> 3.13.0)
77
+ rspec-support (3.13.7)
78
+ spoon (0.0.6)
79
+ ffi
80
+ twirp (1.13.1)
50
81
  faraday (< 3)
51
- google-protobuf (~> 3.0, >= 3.7.0)
52
- uri (0.13.0)
53
- webrick (1.7.0)
54
- yard (0.9.28)
55
- webrick (~> 1.7.0)
82
+ google-protobuf (>= 3.25, < 5.a)
83
+ rack (>= 2.2.3)
84
+ uri (1.1.1)
85
+ yard (0.9.44)
56
86
 
57
87
  PLATFORMS
88
+ java
58
89
  ruby
59
90
  x86_64-linux
60
91
 
@@ -67,4 +98,4 @@ DEPENDENCIES
67
98
  yard
68
99
 
69
100
  BUNDLED WITH
70
- 2.3.7
101
+ 2.6.9
data/README.md CHANGED
@@ -139,12 +139,14 @@ The gem is available as open source under the terms of Apache 2.0 License.
139
139
  <br/><table>
140
140
  <thead><tr><th colspan="2">LiveKit Ecosystem</th></tr></thead>
141
141
  <tbody>
142
- <tr><td>LiveKit SDKs</td><td><a href="https://github.com/livekit/client-sdk-js">Browser</a> · <a href="https://github.com/livekit/client-sdk-swift">iOS/macOS/visionOS</a> · <a href="https://github.com/livekit/client-sdk-android">Android</a> · <a href="https://github.com/livekit/client-sdk-flutter">Flutter</a> · <a href="https://github.com/livekit/client-sdk-react-native">React Native</a> · <a href="https://github.com/livekit/rust-sdks">Rust</a> · <a href="https://github.com/livekit/node-sdks">Node.js</a> · <a href="https://github.com/livekit/python-sdks">Python</a> · <a href="https://github.com/livekit/client-sdk-unity">Unity</a> · <a href="https://github.com/livekit/client-sdk-unity-web">Unity (WebGL)</a></td></tr><tr></tr>
142
+ <tr><td>Agents SDKs</td><td><a href="https://github.com/livekit/agents">Python</a> · <a href="https://github.com/livekit/agents-js">Node.js</a></td></tr><tr></tr>
143
+ <tr><td>LiveKit SDKs</td><td><a href="https://github.com/livekit/client-sdk-js">Browser</a> · <a href="https://github.com/livekit/client-sdk-swift">Swift</a> · <a href="https://github.com/livekit/client-sdk-android">Android</a> · <a href="https://github.com/livekit/client-sdk-flutter">Flutter</a> · <a href="https://github.com/livekit/client-sdk-react-native">React Native</a> · <a href="https://github.com/livekit/rust-sdks">Rust</a> · <a href="https://github.com/livekit/node-sdks">Node.js</a> · <a href="https://github.com/livekit/python-sdks">Python</a> · <a href="https://github.com/livekit/client-sdk-unity">Unity</a> · <a href="https://github.com/livekit/client-sdk-unity-web">Unity (WebGL)</a> · <a href="https://github.com/livekit/client-sdk-esp32">ESP32</a> · <a href="https://github.com/livekit/client-sdk-cpp">C++</a></td></tr><tr></tr>
144
+ <tr><td>Starter Apps</td><td><a href="https://github.com/livekit-examples/agent-starter-python">Python Agent</a> · <a href="https://github.com/livekit-examples/agent-starter-node">TypeScript Agent</a> · <a href="https://github.com/livekit-examples/agent-starter-react">React App</a> · <a href="https://github.com/livekit-examples/agent-starter-swift">SwiftUI App</a> · <a href="https://github.com/livekit-examples/agent-starter-android">Android App</a> · <a href="https://github.com/livekit-examples/agent-starter-flutter">Flutter App</a> · <a href="https://github.com/livekit-examples/agent-starter-react-native">React Native App</a> · <a href="https://github.com/livekit-examples/agent-starter-embed">Web Embed</a></td></tr><tr></tr>
145
+ <tr><td>UI Components</td><td><a href="https://github.com/livekit/components-js">React</a> · <a href="https://github.com/livekit/components-android">Android Compose</a> · <a href="https://github.com/livekit/components-swift">SwiftUI</a> · <a href="https://github.com/livekit/components-flutter">Flutter</a></td></tr><tr></tr>
143
146
  <tr><td>Server APIs</td><td><a href="https://github.com/livekit/node-sdks">Node.js</a> · <a href="https://github.com/livekit/server-sdk-go">Golang</a> · <b>Ruby</b> · <a href="https://github.com/livekit/server-sdk-kotlin">Java/Kotlin</a> · <a href="https://github.com/livekit/python-sdks">Python</a> · <a href="https://github.com/livekit/rust-sdks">Rust</a> · <a href="https://github.com/agence104/livekit-server-sdk-php">PHP (community)</a> · <a href="https://github.com/pabloFuente/livekit-server-sdk-dotnet">.NET (community)</a></td></tr><tr></tr>
144
- <tr><td>UI Components</td><td><a href="https://github.com/livekit/components-js">React</a> · <a href="https://github.com/livekit/components-android">Android Compose</a> · <a href="https://github.com/livekit/components-swift">SwiftUI</a></td></tr><tr></tr>
145
- <tr><td>Agents Frameworks</td><td><a href="https://github.com/livekit/agents">Python</a> · <a href="https://github.com/livekit/agents-js">Node.js</a> · <a href="https://github.com/livekit/agent-playground">Playground</a></td></tr><tr></tr>
146
- <tr><td>Services</td><td><a href="https://github.com/livekit/livekit">LiveKit server</a> · <a href="https://github.com/livekit/egress">Egress</a> · <a href="https://github.com/livekit/ingress">Ingress</a> · <a href="https://github.com/livekit/sip">SIP</a></td></tr><tr></tr>
147
- <tr><td>Resources</td><td><a href="https://docs.livekit.io">Docs</a> · <a href="https://github.com/livekit-examples">Example apps</a> · <a href="https://livekit.io/cloud">Cloud</a> · <a href="https://docs.livekit.io/home/self-hosting/deployment">Self-hosting</a> · <a href="https://github.com/livekit/livekit-cli">CLI</a></td></tr>
147
+ <tr><td>Resources</td><td><a href="https://docs.livekit.io">Docs</a> · <a href="https://docs.livekit.io/mcp">Docs MCP Server</a> · <a href="https://github.com/livekit/livekit-cli">CLI</a> · <a href="https://cloud.livekit.io">LiveKit Cloud</a></td></tr><tr></tr>
148
+ <tr><td>LiveKit Server OSS</td><td><a href="https://github.com/livekit/livekit">LiveKit server</a> · <a href="https://github.com/livekit/egress">Egress</a> · <a href="https://github.com/livekit/ingress">Ingress</a> · <a href="https://github.com/livekit/sip">SIP</a></td></tr><tr></tr>
149
+ <tr><td>Community</td><td><a href="https://community.livekit.io">Developer Community</a> · <a href="https://livekit.io/join-slack">Slack</a> · <a href="https://x.com/livekit">X</a> · <a href="https://www.youtube.com/@livekit_io">YouTube</a></td></tr>
148
150
  </tbody>
149
151
  </table>
150
152
  <!--END_REPO_NAV-->
data/Rakefile CHANGED
@@ -7,7 +7,7 @@ task default: %i[spec]
7
7
 
8
8
  desc "Generate protobuf stubs"
9
9
  task :proto do
10
- system("protoc",
10
+ ok = system("protoc",
11
11
  "--proto_path=protocol/protobufs",
12
12
  "--ruby_out=lib/livekit/proto",
13
13
  "--twirp_ruby_out=lib/livekit/proto",
@@ -20,5 +20,11 @@ task :proto do
20
20
  "./protocol/protobufs/livekit_metrics.proto",
21
21
  "./protocol/protobufs/livekit_models.proto",
22
22
  "./protocol/protobufs/livekit_room.proto",
23
- "./protocol/protobufs/livekit_webhook.proto")
23
+ "./protocol/protobufs/livekit_rtc.proto",
24
+ "./protocol/protobufs/livekit_webhook.proto",
25
+ "./protocol/protobufs/livekit_connector.proto",
26
+ "./protocol/protobufs/livekit_connector_twilio.proto",
27
+ "./protocol/protobufs/livekit_connector_whatsapp.proto",
28
+ "./protocol/protobufs/logger/options.proto")
29
+ abort("protoc failed to generate protobuf stubs") unless ok
24
30
  end
data/bin/bootstrap.sh CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  echo "Ensure protoc and Go are installed"
4
4
 
5
- go install github.com/github/twirp-ruby/protoc-gen-twirp_ruby@latest
5
+ go install github.com/arthurnn/twirp-ruby/protoc-gen-twirp_ruby@latest
@@ -1,6 +1,7 @@
1
1
  require "livekit/proto/livekit_agent_dispatch_twirp"
2
2
  require "livekit/auth_mixin"
3
3
  require 'livekit/utils'
4
+ require 'livekit/failover'
4
5
 
5
6
  module LiveKit
6
7
  # Client for LiveKit's Agent Dispatch Service, which manages agent assignments to rooms
@@ -10,10 +11,11 @@ module LiveKit
10
11
  include AuthMixin
11
12
  attr_accessor :api_key, :api_secret
12
13
 
13
- def initialize(base_url, api_key: nil, api_secret: nil)
14
- super(File.join(Utils.to_http_url(base_url), "/twirp"))
14
+ def initialize(base_url, api_key: nil, api_secret: nil, token: nil, failover: true, connection: nil)
15
+ super(connection || LiveKit::Failover.connection(base_url, failover))
15
16
  @api_key = api_key
16
17
  @api_secret = api_secret
18
+ @token = token
17
19
  end
18
20
 
19
21
  # Creates a new agent dispatch for a named agent
@@ -34,7 +36,7 @@ module LiveKit
34
36
  agent_name: agent_name,
35
37
  metadata: metadata,
36
38
  )
37
- self.rpc(
39
+ rpc!(
38
40
  :CreateDispatch,
39
41
  request,
40
42
  headers: auth_header(video_grant: VideoGrant.new(roomAdmin: true, room: room_name)),
@@ -50,10 +52,10 @@ module LiveKit
50
52
  dispatch_id: dispatch_id,
51
53
  room: room_name,
52
54
  )
53
- self.rpc(
55
+ rpc!(
54
56
  :DeleteDispatch,
55
57
  request,
56
- headers: auth_header(VideoGrant.new(roomAdmin: true, room: room_name)),
58
+ headers: auth_header(video_grant: VideoGrant.new(roomAdmin: true, room: room_name)),
57
59
  )
58
60
  end
59
61
 
@@ -66,10 +68,10 @@ module LiveKit
66
68
  dispatch_id: dispatch_id,
67
69
  room: room_name,
68
70
  )
69
- res = self.rpc(
71
+ res = rpc!(
70
72
  :ListDispatch,
71
73
  request,
72
- headers: auth_header(VideoGrant.new(roomAdmin: true, room: room_name)),
74
+ headers: auth_header(video_grant: VideoGrant.new(roomAdmin: true, room: room_name)),
73
75
  )
74
76
  if res.agent_dispatches.size > 0
75
77
  return res.agent_dispatches[0]
@@ -84,10 +86,10 @@ module LiveKit
84
86
  request = Proto::ListAgentDispatchRequest.new(
85
87
  room: room_name,
86
88
  )
87
- res = self.rpc(
89
+ res = rpc!(
88
90
  :ListDispatch,
89
91
  request,
90
- headers: auth_header(VideoGrant.new(roomAdmin: true, room: room_name)),
92
+ headers: auth_header(video_grant: VideoGrant.new(roomAdmin: true, room: room_name)),
91
93
  )
92
94
  res.agent_dispatches
93
95
  end
@@ -1,23 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "livekit/errors"
4
+
3
5
  module LiveKit
4
- # Create authenticated headers when keys are provided
6
+ # Shared behavior for the Twirp-based service clients: builds authenticated
7
+ # request headers and issues RPCs that raise on error.
5
8
  module AuthMixin
9
+ # Builds request headers. When a pre-signed token is set it is sent verbatim
10
+ # (the caller is responsible for its grants); otherwise a token is signed per
11
+ # call from the API key and secret.
6
12
  def auth_header(
7
13
  video_grant: nil,
8
14
  sip_grant: nil
9
15
  )
10
16
  headers = {}
11
- t = ::LiveKit::AccessToken.new(api_key: @api_key, api_secret: @api_secret)
12
- if video_grant != nil
13
- t.video_grant = video_grant
14
- end
15
- if sip_grant != nil
16
- t.sip_grant = sip_grant
17
+ if @token
18
+ headers["Authorization"] = "Bearer #{@token}"
19
+ return headers
17
20
  end
21
+
22
+ t = ::LiveKit::AccessToken.new(api_key: @api_key, api_secret: @api_secret)
23
+ t.video_grant = video_grant if video_grant != nil
24
+ t.sip_grant = sip_grant if sip_grant != nil
18
25
  headers["Authorization"] = "Bearer #{t.to_jwt}"
19
- headers["User-Agent"] = "LiveKit Ruby SDK"
20
26
  headers
21
27
  end
28
+
29
+ # Issues a Twirp RPC and returns the response message, raising a
30
+ # {LiveKit::ServerError} (or {LiveKit::SipCallError}) on failure.
31
+ def rpc!(rpc_method, input, headers:)
32
+ resp = rpc(rpc_method, input, headers: headers)
33
+ raise ::LiveKit::ServerError.from(resp.error) if resp.error
34
+
35
+ resp.data
36
+ end
22
37
  end
23
38
  end
@@ -0,0 +1,87 @@
1
+ require "livekit/proto/livekit_connector_twirp"
2
+ require "livekit/auth_mixin"
3
+ require 'livekit/utils'
4
+ require 'livekit/failover'
5
+ require 'livekit/dial_timeout'
6
+
7
+ module LiveKit
8
+ # Client for LiveKit's Connector service, bridging WhatsApp and Twilio calls
9
+ # into LiveKit rooms.
10
+ #
11
+ # The request types carry many fields, so each method takes a fully-built
12
+ # protobuf request and returns the protobuf response.
13
+ class ConnectorServiceClient < Twirp::Client
14
+ client_for Proto::ConnectorService
15
+ include AuthMixin
16
+ attr_accessor :api_key, :api_secret
17
+
18
+ def initialize(base_url, api_key: nil, api_secret: nil, token: nil, failover: true, connection: nil)
19
+ super(connection || LiveKit::Failover.connection(base_url, failover))
20
+ @api_key = api_key
21
+ @api_secret = api_secret
22
+ @token = token
23
+ end
24
+
25
+ # Initiates an outbound WhatsApp call.
26
+ # @param request [Proto::DialWhatsAppCallRequest]
27
+ # @return [Proto::DialWhatsAppCallResponse]
28
+ def dial_whatsapp_call(request)
29
+ rpc!(
30
+ :DialWhatsAppCall,
31
+ request,
32
+ headers: auth_header(video_grant: VideoGrant.new(roomCreate: true)),
33
+ )
34
+ end
35
+
36
+ # Accepts an inbound WhatsApp call.
37
+ # @param request [Proto::AcceptWhatsAppCallRequest]
38
+ # @param timeout [Numeric, nil] optional request timeout in seconds. When the
39
+ # request waits for the inbound party to join, it defaults to the standard
40
+ # ring window.
41
+ # @return [Proto::AcceptWhatsAppCallResponse]
42
+ def accept_whatsapp_call(request, timeout: nil)
43
+ headers = auth_header(video_grant: VideoGrant.new(roomCreate: true))
44
+ # Waiting for the inbound party to join can block, so default the request
45
+ # timeout to the standard ring window; otherwise honor any user timeout.
46
+ if request.wait_until_answered
47
+ headers[Failover::TIMEOUT_HEADER] = (timeout || DialTimeout::DEFAULT_RINGING_TIMEOUT).to_s
48
+ elsif timeout
49
+ headers[Failover::TIMEOUT_HEADER] = timeout.to_s
50
+ end
51
+ rpc!(:AcceptWhatsAppCall, request, headers: headers)
52
+ end
53
+
54
+ # Connects an established WhatsApp call (used for business-initiated calls).
55
+ # @param request [Proto::ConnectWhatsAppCallRequest]
56
+ # @return [Proto::ConnectWhatsAppCallResponse]
57
+ def connect_whatsapp_call(request)
58
+ rpc!(
59
+ :ConnectWhatsAppCall,
60
+ request,
61
+ headers: auth_header(video_grant: VideoGrant.new(roomCreate: true)),
62
+ )
63
+ end
64
+
65
+ # Disconnects an active WhatsApp call.
66
+ # @param request [Proto::DisconnectWhatsAppCallRequest]
67
+ # @return [Proto::DisconnectWhatsAppCallResponse]
68
+ def disconnect_whatsapp_call(request)
69
+ rpc!(
70
+ :DisconnectWhatsAppCall,
71
+ request,
72
+ headers: auth_header(video_grant: VideoGrant.new(roomCreate: true)),
73
+ )
74
+ end
75
+
76
+ # Connects a Twilio call to a LiveKit room.
77
+ # @param request [Proto::ConnectTwilioCallRequest]
78
+ # @return [Proto::ConnectTwilioCallResponse]
79
+ def connect_twilio_call(request)
80
+ rpc!(
81
+ :ConnectTwilioCall,
82
+ request,
83
+ headers: auth_header(video_grant: VideoGrant.new(roomCreate: true)),
84
+ )
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LiveKit
4
+ # Request-timeout handling shared by calls that may block until a call is
5
+ # answered (SIP CreateSIPParticipant/TransferSIPParticipant, WhatsApp
6
+ # AcceptWhatsAppCall). These take longer than a normal request, and the request
7
+ # must outlast the wait or it would abort before the call can be answered.
8
+ module DialTimeout
9
+ # Ring window (seconds) assumed when a request doesn't set a ringing timeout;
10
+ # matches the server default. A dialing request must outlast it.
11
+ DEFAULT_RINGING_TIMEOUT = 30
12
+ # Keep the request timeout at least this many seconds above the ringing
13
+ # timeout, so the request doesn't abort before the call can be answered.
14
+ RINGING_TIMEOUT_MARGIN = 2
15
+
16
+ # Request timeout (seconds): the ring window plus a margin, so the request
17
+ # doesn't abort before the call can be answered. The ring window is
18
+ # +ringing_timeout+ (seconds) when set, else DEFAULT_RINGING_TIMEOUT. A longer
19
+ # user-supplied +timeout+ is honored; a shorter one is raised to the floor.
20
+ def self.resolve(timeout, ringing_timeout)
21
+ ring = ringing_timeout || DEFAULT_RINGING_TIMEOUT
22
+ floor = ring + RINGING_TIMEOUT_MARGIN
23
+ [timeout || floor, floor].max
24
+ end
25
+ end
26
+ end