Skip to content

Commit 0d2509b

Browse files
committed
feat(*): initial version of AMF, FLV and RTMP
1 parent fa9b9bc commit 0d2509b

File tree

181 files changed

+12190
-2
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

181 files changed

+12190
-2
lines changed

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5+
6+
version: 2
7+
updates:
8+
- package-ecosystem: "gradle" # See documentation for possible values
9+
directory: "/" # Location of package manifests
10+
schedule:
11+
interval: "weekly"

.github/workflows/build.yml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: Assemble and Test
2+
3+
on:
4+
[ workflow_dispatch, push ]
5+
6+
jobs:
7+
build:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v4
11+
- uses: actions/setup-java@v4
12+
with:
13+
java-version: '21'
14+
distribution: 'adopt'
15+
- name: Cache Gradle packages
16+
uses: actions/cache@v4
17+
with:
18+
path: ~/.gradle/caches
19+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
20+
restore-keys: ${{ runner.os }}-gradle
21+
- name: Make gradlew executable
22+
working-directory: .
23+
run: chmod +x ./gradlew
24+
- name: Assemble
25+
working-directory: .
26+
run: ./gradlew assemble --info --stacktrace
27+
test:
28+
needs: build
29+
runs-on: ubuntu-latest
30+
steps:
31+
- uses: actions/checkout@v4
32+
- uses: actions/setup-java@v4
33+
with:
34+
java-version: '21'
35+
distribution: 'adopt'
36+
- name: Cache Gradle packages
37+
uses: actions/cache@v4
38+
with:
39+
path: ~/.gradle/caches
40+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
41+
restore-keys: ${{ runner.os }}-gradle
42+
- name: Make gradlew executable
43+
working-directory: .
44+
run: chmod +x ./gradlew
45+
- name: Test
46+
working-directory: .
47+
run: ./gradlew allTest --info --stacktrace
48+
kover:
49+
needs: test
50+
runs-on: ubuntu-latest
51+
steps:
52+
- uses: actions/checkout@v4
53+
- uses: actions/setup-java@v4
54+
with:
55+
java-version: '21'
56+
distribution: 'adopt'
57+
- name: Cache Gradle packages
58+
uses: actions/cache@v4
59+
with:
60+
path: ~/.gradle/caches
61+
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }}
62+
restore-keys: ${{ runner.os }}-gradle
63+
- name: Make gradlew executable
64+
working-directory: .
65+
run: chmod +x ./gradlew
66+
- name: Kover report
67+
working-directory: .
68+
run: ./gradlew koverHtmlReport --info --stacktrace
69+
- name: Upload Kover report
70+
uses: actions/upload-artifact@v4
71+
with:
72+
name: kover-report.zip
73+
path: build/reports/kover/html
74+
- name: Kover verify
75+
working-directory: .
76+
run: ./gradlew koverVerify --info --stacktrace
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Build and publish documentation
2+
3+
on:
4+
workflow_dispatch:
5+
release:
6+
types: [ published ]
7+
8+
jobs:
9+
update-api-documentation:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- name: Set up Java
14+
uses: actions/setup-java@v4
15+
with:
16+
java-version: '21'
17+
distribution: 'adopt'
18+
- name: Grant execute permission for gradlew
19+
run: chmod +x gradlew
20+
- name: Generate API documentation
21+
run: ./gradlew dokkaHtmlMultiModule
22+
- name: Deploy API documentation to Github Pages
23+
uses: JamesIves/github-pages-deploy-action@v4
24+
with:
25+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26+
BRANCH: gh-pages
27+
FOLDER: build/dokka/htmlMultiModule

.github/workflows/pull-request.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Measure coverage
2+
3+
on:
4+
pull_request:
5+
6+
jobs:
7+
report-coverage:
8+
runs-on: ubuntu-latest
9+
permissions:
10+
pull-requests: write
11+
steps:
12+
- uses: actions/checkout@v4
13+
- name: Set up JDK
14+
uses: actions/setup-java@v4
15+
with:
16+
java-version: '21'
17+
distribution: 'adopt'
18+
- name: Grant execute permission for gradlew
19+
run: chmod +x gradlew
20+
- name: Generate kover coverage report
21+
run: ./gradlew koverXmlReport
22+
- name: Add coverage report to PR
23+
id: kover
24+
uses: mi-kas/kover-report@v1
25+
with:
26+
path: |
27+
${{ github.workspace }}/build/reports/kover/report.xml
28+
title: Code Coverage
29+
update-comment: true
30+
min-coverage-overall: 80
31+
min-coverage-changed-files: 80
32+
coverage-counter-type: LINE

.github/workflows/release.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Publish package to Maven Central
2+
3+
on:
4+
release:
5+
types: [ published ]
6+
7+
jobs:
8+
release:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
- uses: actions/setup-java@v4
13+
with:
14+
java-version: '21'
15+
distribution: 'adopt'
16+
- name: Make gradlew executable
17+
run: chmod +x ./gradlew
18+
- name: Publish to Maven Central
19+
run: ./gradlew publishAllPublicationsToMavenCentral --no-configuration-cache
20+
env:
21+
ORG_GRADLE_PROJECT_signingInMemoryKey: ${{ secrets.SIGNING_IN_MEMORY_KEY }}
22+
ORG_GRADLE_PROJECT_signingInMemoryKeyId: ${{ secrets.SIGNING_KEY_ID }}
23+
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: ${{ secrets.SIGNING_PASSWORD }}
24+
ORG_GRADLE_PROJECT_mavenCentralUsername: ${{ secrets.OSSRH_USERNAME }}
25+
ORG_GRADLE_PROJECT_mavenCentralPassword: ${{ secrets.OSSRH_TOKEN }}
26+
- name: Generate documentation
27+
run: ./gradlew dokkaHtmlMultiModule
28+
- name: Deploy API documentation to Github Pages
29+
uses: JamesIves/github-pages-deploy-action@v4
30+
with:
31+
github_token: ${{ secrets.GITHUB_TOKEN }}
32+
branch: gh-pages
33+
folder: build/dokkaCustomMultiModuleOutput

.gitignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
*.iml
2+
.gradle
3+
.idea
4+
.DS_Store
5+
build
6+
captures
7+
.externalNativeBuild
8+
.cxx
9+
.kotlin
10+
local.properties
11+
xcuserdata

README.md

Lines changed: 191 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,191 @@
1-
# krtmp
2-
RTMP/FLV/AMF for Kotlin Multiplatform
1+
# krtmp: A RTMP/FLV/AMF library for Kotlin Multiplatform and Android
2+
3+
# RTMP
4+
5+
A RTMP client and server (soon) library for Kotlin Multiplatform.
6+
7+
Features:
8+
9+
- [x] RTMP publish client
10+
- [ ] RTMP play client
11+
- [ ] RTMP play2 client
12+
- [ ] RTMP server
13+
- [ ] Statistics
14+
15+
Supported protocols:
16+
17+
- [x] RTMP
18+
- [x] RTMPS
19+
- [x] RTMPT (partially)
20+
21+
## Installation
22+
23+
Adds the following dependency to your project:
24+
25+
```kotlin
26+
implementation("io.github.thibaultbee.krtmp:rtmp:1.0.0")
27+
```
28+
29+
## Usage
30+
31+
Creates a RTMP publish client with the Factory `RtmpClientConnectionFactory`:
32+
33+
```kotlin
34+
val client = RtmpPublishClientConnectionFactory().create(
35+
"rtmp://my.server.com/app/streamkey" // Your RTMP server URL (incl app name and stream key)
36+
)
37+
```
38+
39+
Then prepare your live by sending these messages to the server:
40+
41+
```kotlin
42+
client.connect()
43+
client.createStream()
44+
client.publish(Command.Publish.Type.LIVE)
45+
```
46+
47+
If you have raw audio and video frames, you need to mux them into FLV tag headers. You can use
48+
the `FlvMuxer` class for that.
49+
50+
```kotlin
51+
val flvMuxer = client.flvMuxer
52+
```
53+
54+
See [FLV](#flv) for more details to write audio and video frames..
55+
56+
If you already have FLV data, write your video/audio data:
57+
58+
```kotlin
59+
try {
60+
// Write metadata
61+
val metadata = OnMetadata.Metadata(...)
62+
client.writeSetDataFrame(metadata)
63+
64+
while (true) {
65+
// Write audio data. `audioData` are in `AudioTagHeader` format. See FLV specification for more details.
66+
client.writeAudio(audioTimestamp, audioData)
67+
// Write video data. `videoData` are in `VideoTagHeader` format. See FLV specification for more details.
68+
client.writeVideo(videoTimestamp, videoData)
69+
}
70+
} catch (e: Exception) {
71+
// Handle exception
72+
}
73+
```
74+
75+
For advanced configuration, see `RtmpClientSettings`.
76+
77+
# FLV
78+
79+
A muxer/demuxer for FLV.
80+
81+
Features:
82+
83+
- [x] Muxer for FLV
84+
- [x] Demuxer for FLV
85+
- [x] AMF0 metadata
86+
- [ ] AMF3 metadata
87+
- [x] Supported audio codec: AAC
88+
- [x] Supported video codec: AVC/H.264 and enhanced RTMP codecs: HEVC/H.265, VP9, AV1
89+
90+
## Installation
91+
92+
Adds the following dependencies to your project:
93+
94+
```kotlin
95+
implementation("io.github.thibaultbee.krtmp:flv:1.0.0")
96+
```
97+
98+
## Usage
99+
100+
Creates a FLV muxer and add audio/video data:
101+
102+
```kotlin
103+
val muxer = FlvMuxer()
104+
105+
// Register audio configurations (if any)
106+
val audioConfig = FlvAudioConfig(
107+
FlvAudioConfig.SoundFormat.AAC,
108+
FlvAudioConfig.SoundRate.KHZ44,
109+
FlvAudioConfig.SoundSize.SND8BIT,
110+
FlvAudioConfig.SoundType.STEREO
111+
)
112+
val audioId = muxer.addStream(audioConfig)
113+
114+
// Register audio configurations (if any)
115+
val videoConfig = FlvVideoConfig(
116+
117+
)
118+
val videoId = muxer.addStream(videoConfig)
119+
120+
// Start the muxer (write FlvTag (if needed) and onMetaData)
121+
muxer.startStream()
122+
123+
// Write audio/video data
124+
muxer.write(audioFrame)
125+
muxer.write(videoFrame)
126+
muxer.write(audioFrame)
127+
muxer.write(videoFrame)
128+
// till you're done
129+
130+
// Stop the muxer
131+
muxer.stopStream()
132+
133+
```
134+
135+
# AMF
136+
137+
A serializer/deserializer for AMF0 and AMF3.
138+
139+
Features:
140+
141+
- [x] Serializer for AMF0
142+
- [ ] Serializer for AMF3
143+
- [ ] Deserializer for AMF0
144+
- [ ] Deserializer for AMF3
145+
146+
## Installation
147+
148+
It requires `kotlinx.serialization` library.
149+
See [Setup](https://github.com/Kotlin/kotlinx.serialization?tab=readme-ov-file#setup) for more
150+
details.
151+
Then, adds the following dependencies to your project:
152+
153+
```kotlin
154+
implementation("io.github.thibaultbee.krtmp:amf:1.0.0")
155+
```
156+
157+
## Usage
158+
159+
Creates a class and make it serializable with `@Serializable` annotation:
160+
161+
```kotlin
162+
@Serializable
163+
class MyData(val a: Int, val b: String)
164+
```
165+
166+
Then you can serialize it to AMF0:
167+
168+
```kotlin
169+
val data = MyData(1, "Hello")
170+
val array = Amf.encodeToByteArray(MyData.serializer(), data)
171+
```
172+
173+
# TODO
174+
175+
- [x] A FLV/RTMP parameter for supported level: (legacy, enhanced v1, enhanced v2,...)
176+
177+
# Licence
178+
179+
Copyright 2023 Thibault B.
180+
181+
Licensed under the Apache License, Version 2.0 (the "License");
182+
you may not use this file except in compliance with the License.
183+
You may obtain a copy of the License at
184+
185+
http://www.apache.org/licenses/LICENSE-2.0
186+
187+
Unless required by applicable law or agreed to in writing, software
188+
distributed under the License is distributed on an "AS IS" BASIS,
189+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190+
See the License for the specific language governing permissions and
191+
limitations under the License.

0 commit comments

Comments
 (0)