org.jitsi.mediajson.MediaJson.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jicoco-mediajson Show documentation
Show all versions of jicoco-mediajson Show documentation
Jitsi Common Components (Media JSON)
/*
* Copyright @ 2024 - present 8x8, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jitsi.mediajson
import com.fasterxml.jackson.annotation.JsonSubTypes
import com.fasterxml.jackson.annotation.JsonTypeInfo
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.fasterxml.jackson.databind.annotation.JsonSerialize
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
private val objectMapper = jacksonObjectMapper().apply {
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
}
/**
* This is based on the format used by VoxImplant here, hence the encoding of certain numeric fields as strings:
* https://voximplant.com/docs/guides/voxengine/websocket
*/
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "event")
@JsonSubTypes(
JsonSubTypes.Type(value = MediaEvent::class, name = "media"),
JsonSubTypes.Type(value = StartEvent::class, name = "start"),
)
sealed class Event(val event: String) {
fun toJson(): String = objectMapper.writeValueAsString(this)
companion object {
fun parse(s: String): Event = objectMapper.readValue(s, Event::class.java)
fun parse(s: List): List = s.map { objectMapper.readValue(it, Event::class.java) }
}
}
data class MediaEvent(
@JsonSerialize(using = Int2StringSerializer::class)
@JsonDeserialize(using = String2IntDeserializer::class)
val sequenceNumber: Int,
val media: Media
) : Event("media")
data class StartEvent(
@JsonSerialize(using = Int2StringSerializer::class)
@JsonDeserialize(using = String2IntDeserializer::class)
val sequenceNumber: Int,
val start: Start
) : Event("start")
data class MediaFormat(
val encoding: String,
val sampleRate: Int,
val channels: Int
)
data class Start(
val tag: String,
val mediaFormat: MediaFormat
)
data class Media(
val tag: String,
@JsonSerialize(using = Int2StringSerializer::class)
@JsonDeserialize(using = String2IntDeserializer::class)
val chunk: Int,
@JsonSerialize(using = Long2StringSerializer::class)
@JsonDeserialize(using = String2LongDeserializer::class)
val timestamp: Long,
val payload: String
)
class Int2StringSerializer : JsonSerializer() {
override fun serialize(value: Int, gen: JsonGenerator, p: SerializerProvider) {
gen.writeString(value.toString())
}
}
class String2IntDeserializer : JsonDeserializer() {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Int {
return p.readValueAs(Int::class.java).toInt()
}
}
class Long2StringSerializer : JsonSerializer() {
override fun serialize(value: Long, gen: JsonGenerator, p: SerializerProvider) {
gen.writeString(value.toString())
}
}
class String2LongDeserializer : JsonDeserializer() {
override fun deserialize(p: JsonParser, ctxt: DeserializationContext): Long {
return p.readValueAs(Long::class.java).toLong()
}
}