Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,14 @@ import java.io.Closeable
*/
class ChannelWithCloseableData<T>(
capacity: Int = RENDEZVOUS,
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND
onBufferOverflow: BufferOverflow = BufferOverflow.SUSPEND,
onUndeliveredElement: ((T) -> Unit) = {}
) : ReceiveChannel<ChannelWithCloseableData.CloseableData<T>> {
private val channel =
Channel<CloseableData<T>>(capacity, onBufferOverflow, onUndeliveredElement = { it.close() })
Channel<CloseableData<T>>(capacity, onBufferOverflow, onUndeliveredElement = {
it.close()
onUndeliveredElement(it.data)
})

/**
* Sends data along with a close action to the channel.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import io.github.thibaultbee.streampack.core.configuration.BitrateRegulatorConfi
*/
interface IBitrateRegulator {
/**
* Calls regularly to get new stats
* Calls regularly to get new metrics
*
* @param stats transmission stats
* @param metrics transmission metrics
* @param currentVideoBitrate current video bitrate target in bits/s.
* @param currentAudioBitrate current audio bitrate target in bits/s.
*/
fun update(stats: Any, currentVideoBitrate: Int, currentAudioBitrate: Int)
fun update(metrics: Any, currentVideoBitrate: Int, currentAudioBitrate: Int)

/**
* Factory interface you must use to create a [BitrateRegulator] object.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,27 +164,79 @@ class DataStoreRepository(
EndpointType.RTMP -> {
val url =
preferences[stringPreferencesKey(context.getString(R.string.rtmp_server_url_key))]
?: context.getString(R.string.default_rtmp_url)
?: context.getString(R.string.rtmp_default_url)
UriMediaDescriptor(context, url)
}
}
}.distinctUntilChanged()

val bitrateRegulatorConfigFlow: Flow<BitrateRegulatorConfig?> =
dataStore.data.map { preferences ->
val endpointTypeId =
preferences[stringPreferencesKey(context.getString(R.string.endpoint_type_key))]?.toInt()
?: EndpointType.SRT.id

val isBitrateRegulatorEnable =
preferences[booleanPreferencesKey(context.getString(R.string.srt_server_enable_bitrate_regulation_key))]
preferences[booleanPreferencesKey(
context.getString(
when (endpointTypeId) {
EndpointType.SRT.id -> {
R.string.srt_server_enable_bitrate_regulation_key
}

EndpointType.RTMP.id -> {
R.string.rtmp_server_enable_bitrate_regulation_key
}

else -> {
throw IllegalArgumentException("Unknown endpoint type")
}
}
)
)]
?: true
if (!isBitrateRegulatorEnable) {
return@map null
}

val videoMinBitrate =
preferences[intPreferencesKey(context.getString(R.string.srt_server_video_min_bitrate_key))]?.toInt()
preferences[intPreferencesKey(
context.getString(
when (endpointTypeId) {
EndpointType.SRT.id -> {
R.string.srt_server_video_min_bitrate_key
}

EndpointType.RTMP.id -> {
R.string.rtmp_server_video_min_bitrate_key
}

else -> {
throw IllegalArgumentException("Unknown endpoint type")
}
}
)
)]
?.times(1000)
?: 300000
val videoMaxBitrate =
preferences[intPreferencesKey(context.getString(R.string.srt_server_video_target_bitrate_key))]?.toInt()
preferences[intPreferencesKey(
context.getString(
when (endpointTypeId) {
EndpointType.SRT.id -> {
R.string.srt_server_video_target_bitrate_key
}

EndpointType.RTMP.id -> {
R.string.rtmp_server_video_target_bitrate_key
}

else -> {
throw IllegalArgumentException("Unknown endpoint type")
}
}
)
)]
?.times(1000)
?: 10000000
BitrateRegulatorConfig(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import io.github.thibaultbee.streampack.core.streamers.single.VideoOnlySingleStr
import io.github.thibaultbee.streampack.core.streamers.single.withAudio
import io.github.thibaultbee.streampack.core.streamers.single.withVideo
import io.github.thibaultbee.streampack.core.utils.extensions.isClosedException
import io.github.thibaultbee.streampack.ext.rtmp.regulator.controllers.simpleRtmpBitrateRegulatorControllerFactory
import io.github.thibaultbee.streampack.ext.srt.regulator.controllers.simpleSrtBitrateRegulatorControllerFactory
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
Expand All @@ -77,6 +78,7 @@ import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.sync.Mutex
Expand Down Expand Up @@ -312,16 +314,32 @@ class PreviewViewModel(private val application: Application) : ObservableViewMod
val descriptor = storageRepository.endpointDescriptorFlow.first()
streamer.startStream(descriptor)

if (descriptor.type.sinkType == MediaSinkType.SRT) {
if ((descriptor.type.sinkType == MediaSinkType.RTMP) || (descriptor.type.sinkType == MediaSinkType.SRT)) {
val bitrateRegulatorConfig =
storageRepository.bitrateRegulatorConfigFlow.first()
if (bitrateRegulatorConfig != null) {
Log.i(TAG, "Add bitrate regulator controller")
streamer.addBitrateRegulatorController(
simpleSrtBitrateRegulatorControllerFactory(
bitrateRegulatorConfig = bitrateRegulatorConfig
)
)
val controllerFactory =
when (descriptor.type.sinkType) {
MediaSinkType.RTMP -> {
simpleRtmpBitrateRegulatorControllerFactory(
bitrateRegulatorConfig = bitrateRegulatorConfig
)
}

MediaSinkType.SRT -> {
simpleSrtBitrateRegulatorControllerFactory(
bitrateRegulatorConfig = bitrateRegulatorConfig
)
}

else -> {
null
}
}
controllerFactory?.let {
streamer.addBitrateRegulatorController(it)
} ?: Log.e(TAG, "Controller factory is null")
}
}
} catch (e: CancellationException) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,30 @@ class SettingsFragment : PreferenceFragmentCompat() {
this.findPreference(getString(R.string.srt_server_port_key))!!
}

private val serverEnableBitrateRegulationPreference: SwitchPreference by lazy {
private val srtServerEnableBitrateRegulationPreference: SwitchPreference by lazy {
this.findPreference(getString(R.string.srt_server_enable_bitrate_regulation_key))!!
}

private val serverTargetVideoBitratePreference: SeekBarPreference by lazy {
private val srtServerTargetVideoBitratePreference: SeekBarPreference by lazy {
this.findPreference(getString(R.string.srt_server_video_target_bitrate_key))!!
}

private val serverMinVideoBitratePreference: SeekBarPreference by lazy {
private val srtServerMinVideoBitratePreference: SeekBarPreference by lazy {
this.findPreference(getString(R.string.srt_server_video_min_bitrate_key))!!
}

private val rtmpServerEnableBitrateRegulationPreference: SwitchPreference by lazy {
this.findPreference(getString(R.string.rtmp_server_enable_bitrate_regulation_key))!!
}

private val rtmpServerTargetVideoBitratePreference: SeekBarPreference by lazy {
this.findPreference(getString(R.string.rtmp_server_video_target_bitrate_key))!!
}

private val rtmpServerMinVideoBitratePreference: SeekBarPreference by lazy {
this.findPreference(getString(R.string.rtmp_server_video_min_bitrate_key))!!
}

private val fileNamePreference: EditTextPreference by lazy {
this.findPreference(getString(R.string.file_name_key))!!
}
Expand Down Expand Up @@ -417,26 +429,50 @@ class SettingsFragment : PreferenceFragmentCompat() {
editText.filters = arrayOf(InputFilter.LengthFilter(5))
}

serverTargetVideoBitratePreference.isVisible =
serverEnableBitrateRegulationPreference.isChecked
serverMinVideoBitratePreference.isVisible =
serverEnableBitrateRegulationPreference.isChecked
serverEnableBitrateRegulationPreference.setOnPreferenceChangeListener { _, newValue ->
serverTargetVideoBitratePreference.isVisible = newValue as Boolean
serverMinVideoBitratePreference.isVisible = newValue
srtServerTargetVideoBitratePreference.isVisible =
srtServerEnableBitrateRegulationPreference.isChecked
srtServerMinVideoBitratePreference.isVisible =
srtServerEnableBitrateRegulationPreference.isChecked
srtServerEnableBitrateRegulationPreference.setOnPreferenceChangeListener { _, newValue ->
srtServerTargetVideoBitratePreference.isVisible = newValue as Boolean
srtServerMinVideoBitratePreference.isVisible = newValue
true
}

srtServerTargetVideoBitratePreference.setOnPreferenceChangeListener { _, newValue ->
if ((newValue as Int) < srtServerMinVideoBitratePreference.value) {
srtServerMinVideoBitratePreference.value = newValue
}
true
}

srtServerMinVideoBitratePreference.setOnPreferenceChangeListener { _, newValue ->
if ((newValue as Int) > srtServerTargetVideoBitratePreference.value) {
srtServerTargetVideoBitratePreference.value = newValue
}
true
}

rtmpServerTargetVideoBitratePreference.isVisible =
rtmpServerEnableBitrateRegulationPreference.isChecked
rtmpServerMinVideoBitratePreference.isVisible =
rtmpServerEnableBitrateRegulationPreference.isChecked
rtmpServerEnableBitrateRegulationPreference.setOnPreferenceChangeListener { _, newValue ->
rtmpServerTargetVideoBitratePreference.isVisible = newValue as Boolean
rtmpServerMinVideoBitratePreference.isVisible = newValue
true
}

serverTargetVideoBitratePreference.setOnPreferenceChangeListener { _, newValue ->
if ((newValue as Int) < serverMinVideoBitratePreference.value) {
serverMinVideoBitratePreference.value = newValue
rtmpServerTargetVideoBitratePreference.setOnPreferenceChangeListener { _, newValue ->
if ((newValue as Int) < rtmpServerMinVideoBitratePreference.value) {
rtmpServerMinVideoBitratePreference.value = newValue
}
true
}

serverMinVideoBitratePreference.setOnPreferenceChangeListener { _, newValue ->
if ((newValue as Int) > serverTargetVideoBitratePreference.value) {
serverTargetVideoBitratePreference.value = newValue
rtmpServerMinVideoBitratePreference.setOnPreferenceChangeListener { _, newValue ->
if ((newValue as Int) > rtmpServerTargetVideoBitratePreference.value) {
rtmpServerTargetVideoBitratePreference.value = newValue
}
true
}
Expand All @@ -459,7 +495,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
// Update file extension
if (endpoint.hasFileCapabilities) {
// Remove previous extension
FileExtension.entries.forEach {
FileExtension.entries.forEach { _ ->
fileNamePreference.text = fileNamePreference.text?.substringBeforeLast(".")
}
// Add correct extension
Expand Down
9 changes: 8 additions & 1 deletion demos/camera/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,14 @@
<string name="rtmp_server_key">rtmp_server_key</string>
<string name="rtmp_server">RTMP Server</string>
<string name="rtmp_server_url_key">rtmp_server_url_key</string>
<string name="default_rtmp_url">rtmp://192.168.1.192/s/streamKey</string>
<string name="rtmp_default_url">rtmp://192.168.1.192/s/streamKey</string>
<string name="rtmp_server_enable_bitrate_regulation_key">rtmp_server_enable_bitrate_regulation_key</string>
<string name="rtmp_server_enable_bitrate_regulation">Enable bitrate regulation</string>
<string name="rtmp_server_video_target_bitrate_key">rtmp_server_video_target_bitrate_key</string>
<string name="rtmp_server_video_target_bitrate">Video target bitrate (kb/s)</string>
<string name="rtmp_server_video_min_bitrate_key">rtmp_server_video_min_bitrate_key</string>
<string name="rtmp_server_video_min_bitrate">Video minimum bitrate (kb/s)</string>

<string name="server_url">URL</string>

<string name="file_endpoint_key">file_endpoint_key</string>
Expand Down
24 changes: 23 additions & 1 deletion demos/camera/src/main/res/xml/root_preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,33 @@
app:title="@string/rtmp_server">

<EditTextPreference
app:defaultValue="@string/default_rtmp_url"
app:defaultValue="@string/rtmp_default_url"
app:key="@string/rtmp_server_url_key"
app:title="@string/server_url"
app:useSimpleSummaryProvider="true" />

<SwitchPreference
android:defaultValue="false"
app:key="@string/rtmp_server_enable_bitrate_regulation_key"
app:title="@string/srt_server_enable_bitrate_regulation" />

<SeekBarPreference
android:max="10000"
app:defaultValue="5000"
app:key="@string/rtmp_server_video_target_bitrate_key"
app:min="500"
app:showSeekBarValue="true"
app:title="@string/srt_server_video_target_bitrate"
app:useSimpleSummaryProvider="true" />

<SeekBarPreference
android:max="10000"
app:defaultValue="300"
app:key="@string/rtmp_server_video_min_bitrate_key"
app:min="100"
app:showSeekBarValue="true"
app:title="@string/srt_server_video_min_bitrate"
app:useSimpleSummaryProvider="true" />
</PreferenceCategory>

<PreferenceCategory
Expand Down
2 changes: 1 addition & 1 deletion extensions/rtmp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dependencies {
implementation(project(":streampack-core"))
implementation(project(":streampack-flv"))

implementation(libs.komedia.komuxer.rtmp)
api(libs.komedia.komuxer.rtmp)

implementation(libs.kotlinx.coroutines.android)
implementation(libs.androidx.core.ktx)
Expand Down
Loading
Loading