Skip to content

Commit f779467

Browse files
committed
Merge branch 'develop'
2 parents 91dd83f + 17ea968 commit f779467

File tree

34 files changed

+1000
-314
lines changed

34 files changed

+1000
-314
lines changed

README.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -123,29 +123,29 @@ Video roadmap and changelog is available [here](https://github.com/GetStream/pro
123123
### 0.4.0 milestone
124124

125125
- [X] Screensharing from mobile
126-
- [ ] Implement Chat overlay for Dogfooding
127-
- [ ] Add Dogfooding instructions + directs Google Play
128-
- [ ] Reaction dialog API for Compose
129-
- [ ] Complete Livestreaming APIs and Tutorials for hosting & watching
126+
- [X] Picture of the video stream at the highest resolution + docs on how to add a button for this (Daniel)
127+
- [X] Audio & Video filters. Support (Daniel)
128+
- [ ] Default livestream player UI + docs (Jaewoong/ Daniel)
129+
- [ ] Implement Chat overlay for Dogfooding (Jaewoong)
130+
- [ ] Add Dogfooding instructions + directs Google Play (Jaewoong)
131+
- [ ] Reaction dialog API for Compose (Jaewoong)
130132
- [ ] Android SDK development.md cleanup (Daniel)
131133
- [ ] Upgrade to more recent versions of webrtc (Kanat)
132-
- [ ] Picture of the video stream at highest resolution
133-
- [ ] Review foreground service vs backend for some things like screensharing etc
134-
- [ ] Audio & Video filters. Support (Daniel)
135-
- [ ] Dynascale 2.0
136-
- [ ] Support participant.custom field which was previously ignored. ParticipantState line 216
137-
- [ ] Call Analytics stateflow (Thierry)
138-
- [ ] Test coverage
139-
- [ ] Logging is too verbose (rtc is very noisy), clean it up to focus on the essential for info and higher
134+
- [ ] Review foreground service vs backend for audio rooms etc. (Daniel)
135+
- [ ] Support participant.custom field which was previously ignored. ParticipantState line 216 (Daniel)
136+
- [ ] Logging is too verbose (rtc is very noisy), clean it up to focus on the essential for info and higher (Daniel)
140137

141138
### 0.5.0 milestone
142139

143-
- [ ] Testing on more devices
144140
- [ ] Enable SFU switching
141+
- [ ] H264 workaround on Samsung 23? (see https://github.com/livekit/client-sdk-android/blob/main/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/SimulcastVideoEncoderFactoryWrapper.kt#L34 and
142+
- https://github.com/react-native-webrtc/react-native-webrtc/issues/983#issuecomment-975624906)
143+
- [ ] Test coverage
144+
- [ ] Dynascale 2.0 (depending backend support)
145+
- [ ] Testing on more devices
145146
- [ ] Camera controls
146147
- [ ] Tap to focus
147-
- [ ] H264 workaround on Samsung 23 (see https://github.com/livekit/client-sdk-android/blob/main/livekit-android-sdk/src/main/java/io/livekit/android/webrtc/SimulcastVideoEncoderFactoryWrapper.kt#L34 and
148-
- https://github.com/react-native-webrtc/react-native-webrtc/issues/983#issuecomment-975624906)
148+
149149

150150
### Dynascale 2.0
151151

docusaurus/docs/Android/06-advanced/05-apply-video-filters.mdx

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ How does this work? You can inject a filter through `Call.videoFilter`, you will
1111

1212
## Adding a Video Filter
1313

14-
Create a `BitmapVideoFilter` or `RawVideoFilter` instance in your project. Here is how the abstract classes look like:
14+
Create a `BitmapVideoFilter` or `RawVideoFilter` instance in your project. Here is how the abstract classes are defined:
1515

1616
```kotlin
1717
abstract class BitmapVideoFilter : VideoFilter() {
@@ -131,4 +131,65 @@ The result:
131131

132132
## Audio Filters
133133

134-
TODO
134+
The StreamVideo SDK also supports custom audio processing of the local track. This opens up possibilities for custom echo filtering, voice changing or other audio effects.
135+
136+
If you want to have custom audio processing, you need to provide your own implementation of the `AudioFilter` interface to `Call.audioFilter`.
137+
138+
The `AudioFilter` is defined like this:
139+
140+
```kotlin
141+
interface AudioFilter {
142+
/**
143+
* Invoked after an audio sample is recorded. Can be used to manipulate
144+
* the ByteBuffer before it's fed into WebRTC. Currently the audio in the
145+
* ByteBuffer is always PCM 16bit and the buffer sample size is ~10ms.
146+
*
147+
* @param audioFormat format in android.media.AudioFormat
148+
*/
149+
fun filter(audioFormat: Int, channelCount: Int, sampleRate: Int, sampleData: ByteBuffer)
150+
}
151+
```
152+
153+
In the following example, we will build a simple audio filter that gives the user's voice a robotic touch.
154+
155+
```kotlin
156+
// We assume that you already have a call instance (call is started)
157+
// Create a simple filter (pitch modification) and assign it to the call
158+
159+
call.audioFilter = object: AudioFilter {
160+
161+
override fun filter(audioFormat: Int, channelCount: Int, sampleRate: Int, sampleData: ByteBuffer) {
162+
// You can modify the pitch factor to achieve a bit different effect
163+
val pitchShiftFactor = 0.8f
164+
val inputBuffer = audioBuffer.duplicate()
165+
inputBuffer.order(ByteOrder.LITTLE_ENDIAN) // Set byte order for correct handling of PCM data
166+
167+
val numSamples = inputBuffer.remaining() / 2 // Assuming 16-bit PCM audio
168+
169+
val outputBuffer = ByteBuffer.allocate(inputBuffer.capacity())
170+
outputBuffer.order(ByteOrder.LITTLE_ENDIAN)
171+
172+
for (channel in 0 until numChannels) {
173+
val channelBuffer = ShortArray(numSamples)
174+
inputBuffer.asShortBuffer().get(channelBuffer)
175+
176+
for (i in 0 until numSamples) {
177+
val originalIndex = (i * pitchShiftFactor).toInt()
178+
179+
if (originalIndex >= 0 && originalIndex < numSamples) {
180+
outputBuffer.putShort(channelBuffer[originalIndex])
181+
} else {
182+
// Fill with silence if the index is out of bounds
183+
outputBuffer.putShort(0)
184+
}
185+
}
186+
}
187+
188+
outputBuffer.flip()
189+
audioBuffer.clear()
190+
audioBuffer.put(outputBuffer)
191+
audioBuffer.flip()
192+
}
193+
}
194+
```
195+
This is a simple algorithm that just does shifting of the indexes. For a more complex one, you can also use some voice processing library. The important part is that you update the `channelBuffer` with the filtered values.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
title: Screenshots
3+
description: How to take screenshots of VideoFrames
4+
---
5+
6+
## Screenshots
7+
8+
You can take a picture of a `VideoTrack` at highest possible resolution by using `Call.takeScreenshot(videoTrack): Bitmap`. This can be useful for example if you want to take a screenshot of a screenshare at full resolution.
9+
10+
You need to get the right `VideoTrack` to take the screenshot first - the selection depends on your use case. Let's for example take the first participant in the list of participants in a Call:
11+
12+
```kotlin
13+
val participant = call.state.participants.value[0]
14+
val participantVideoTrack = participant.videoTrack.value
15+
if (participantVideoTrack != null) {
16+
val bitmap = call.takeScreenshot(participantVideoTrack)
17+
// display, save or share the bitmap
18+
}
19+
```
20+
21+
:::note
22+
A `VideoTrack` can be null when the current participant video is not visible on the screen. Video is only streamed from participants that are currently visible.
23+
:::
24+
25+
Or for example if you specifically want to take a screenshot of a screenshare session:
26+
27+
```kotlin
28+
val screenshareSession = call.state.screenSharingSession.value
29+
val screenShareTrack = screenshareSession?.participant?.screenSharingTrack?.value
30+
if (screenShareTrack != null) {
31+
val bitmap = call.takeScreenshot(screenShareTrack)
32+
// display, save or share the bitmap
33+
}
34+
```

docusaurus/docs/Android/06-advanced/05-chat-with-video.mdx renamed to docusaurus/docs/Android/06-advanced/07-chat-with-video.mdx

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)