Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/development'
Browse files Browse the repository at this point in the history
  • Loading branch information
dsilhavy committed Aug 25, 2023
2 parents f2367f0 + cacc31d commit 19339ea
Show file tree
Hide file tree
Showing 10 changed files with 238 additions and 49 deletions.
2 changes: 1 addition & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 15 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ android {
minSdk 29
targetSdk 33
versionCode 1
versionName "1.0.1"
versionName "1.0.2"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down Expand Up @@ -43,10 +43,23 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

// 5GMAG
implementation 'com.fivegmag:a5gmscommonlibrary:1.0.1'
implementation 'com.fivegmag:a5gmscommonlibrary:1.0.2'

// Retrofit
def retrofit_version = "2.9.0"
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
}

task CaptureLibraryVersion {
def libDef = project.configurations.getByName('implementation').allDependencies.matching {
it.group.equals("com.fivegmag")
}
if (libDef.size() > 0) {
android.buildTypes.each {
libDef.forEach { item ->
it.buildConfigField 'String', "LIB_VERSION_" + item.name, "\"${item.version}\""
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,35 @@ https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view

package com.fivegmag.a5gmsmediasessionhandler

import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.TextView

const val TAG_MEDIA_SESSION_HANDLER = "5GMS Aware Application"

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setApplicationVersionNumber()
printDependenciesVersionNumbers()
}

private fun setApplicationVersionNumber() {
try {
val packageInfo = packageManager.getPackageInfo(packageName, 0)
val versionName = packageInfo.versionName
val versionTextView = findViewById<TextView>(R.id.versionNumber)
val versionText = getString(R.string.versionTextField, versionName)
versionTextView.text = versionText
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
}

private fun printDependenciesVersionNumbers() {
Log.d(TAG_MEDIA_SESSION_HANDLER, "5GMS Common Library Version: ${BuildConfig.LIB_VERSION_a5gmscommonlibrary}")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,21 @@ import android.os.*
import android.util.Log
import android.widget.Toast
import com.fivegmag.a5gmscommonlibrary.helpers.SessionHandlerMessageTypes
import com.fivegmag.a5gmscommonlibrary.helpers.Utils
import com.fivegmag.a5gmscommonlibrary.models.EntryPoint
import com.fivegmag.a5gmscommonlibrary.models.ServiceAccessInformation
import com.fivegmag.a5gmscommonlibrary.models.ServiceListEntry
import com.fivegmag.a5gmsmediasessionhandler.models.ClientSessionModel
import com.fivegmag.a5gmsmediasessionhandler.network.HeaderInterceptor
import com.fivegmag.a5gmsmediasessionhandler.network.ServiceAccessInformationApi
import okhttp3.Headers
import okhttp3.OkHttpClient
import retrofit2.Call
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.Timer
import java.util.TimerTask


const val TAG = "5GMS Media Session Handler"
Expand All @@ -40,11 +45,16 @@ class MediaSessionHandlerMessengerService() : Service() {
* Target we publish for clients to send messages to IncomingHandler.
*/
private lateinit var mMessenger: Messenger
private lateinit var serviceAccessInformationApi: ServiceAccessInformationApi
private lateinit var currentServiceAccessInformation: ServiceAccessInformation

/** Keeps track of all current registered clients. */
var mClients = ArrayList<Int>()
private var clientsSessionData = HashMap<Int, ClientSessionModel>()
private val headerInterceptor = HeaderInterceptor()
private val utils = Utils()
private val okHttpClient = OkHttpClient()
.newBuilder()
.addInterceptor(headerInterceptor)
.build()
private val retrofitBuilder = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)

/**
* Handler of incoming messages from clients.
Expand All @@ -69,11 +79,11 @@ class MediaSessionHandlerMessengerService() : Service() {
}

private fun registerClient(msg: Message) {
mClients.add(msg.sendingUid)
clientsSessionData[msg.sendingUid] = ClientSessionModel(msg.replyTo)
}

private fun unregisterClient(msg: Message) {
mClients.remove(msg.sendingUid)
clientsSessionData.remove(msg.sendingUid)
}

private fun handleStatusMessage(msg: Message) {
Expand All @@ -94,36 +104,43 @@ class MediaSessionHandlerMessengerService() : Service() {
bundle.classLoader = ServiceListEntry::class.java.classLoader
val serviceListEntry: ServiceListEntry? = bundle.getParcelable("serviceListEntry")
val responseMessenger: Messenger = msg.replyTo
val sendingUid = msg.sendingUid;
resetClientSession(sendingUid)

val provisioningSessionId: String = serviceListEntry!!.provisioningSessionId
val call: Call<ServiceAccessInformation>? =
serviceAccessInformationApi.fetchServiceAccessInformation(provisioningSessionId)

clientsSessionData[msg.sendingUid]?.serviceAccessInformationApi?.fetchServiceAccessInformation(
provisioningSessionId,
null,
null
)
call?.enqueue(object : retrofit2.Callback<ServiceAccessInformation?> {
override fun onResponse(
call: Call<ServiceAccessInformation?>,
response: Response<ServiceAccessInformation?>
) {
val resource: ServiceAccessInformation? = response.body()
if (resource != null) {
currentServiceAccessInformation = resource
}

val resource =
handleServiceAccessResponse(response, sendingUid, provisioningSessionId)

// Trigger the playback by providing all available entry points
val msgResponse: Message = Message.obtain(
null,
SessionHandlerMessageTypes.SESSION_HANDLER_TRIGGERS_PLAYBACK
)
var finalEntryPoints: ArrayList<EntryPoint>? = serviceListEntry.entryPoints
if (finalEntryPoints == null || finalEntryPoints.size == 0) {
if (resource != null && (finalEntryPoints == null || finalEntryPoints.size == 0)) {
finalEntryPoints =
currentServiceAccessInformation.streamingAccess.entryPoints
resource.streamingAccess.entryPoints
}


val bundle = Bundle()
val responseBundle = Bundle()
if (finalEntryPoints != null && finalEntryPoints.size > 0) {
bundle.putParcelableArrayList("entryPoints", finalEntryPoints)
msgResponse.data = bundle
responseBundle.putParcelableArrayList("entryPoints", finalEntryPoints)
msgResponse.data = responseBundle
responseMessenger.send(msgResponse)
}

}

override fun onFailure(call: Call<ServiceAccessInformation?>, t: Throwable) {
Expand All @@ -132,14 +149,136 @@ class MediaSessionHandlerMessengerService() : Service() {
})
}

/**
* Starts the timer task to re-request and saves the current state of the Service Access Information
*
* @param response
* @param sendingUid
* @param provisioningSessionId
* @return
*/
private fun handleServiceAccessResponse(
response: Response<ServiceAccessInformation?>,
sendingUid: Int,
provisioningSessionId: String
): ServiceAccessInformation? {
val headers = response.headers()


// Save the ServiceAccessInformation if it has changed
val resource: ServiceAccessInformation? = response.body()
if (resource != null && response.code() != 304 && utils.hasResponseChanged(
headers,
clientsSessionData[sendingUid]?.serviceAccessInformationResponseHeaders
)
) {
clientsSessionData[sendingUid]?.serviceAccessInformation = resource
}


// Start the re-requesting of the Service Access Information according to the max-age header
startServiceAccessInformationUpdateTimer(
headers,
sendingUid,
provisioningSessionId
)

// Save current headers
clientsSessionData[sendingUid]?.serviceAccessInformationResponseHeaders = headers

return clientsSessionData[sendingUid]?.serviceAccessInformation
}


/**
* Starts the timer task to re-request the the Service Access Information
*
* @param headers
* @param sendingUid
* @param provisioningSessionId
*/
private fun startServiceAccessInformationUpdateTimer(
headers: Headers,
sendingUid: Int,
provisioningSessionId: String
) {
val cacheControlHeader = headers.get("cache-control") ?: return
val cacheControlHeaderItems = cacheControlHeader.split(',');
val maxAgeHeader = cacheControlHeaderItems.filter { it.trim().startsWith("max-age=") }

if (maxAgeHeader.isEmpty()) {
return
}

val maxAgeValue = maxAgeHeader[0].trim().substring(8).toLong()
val timer = Timer()
clientsSessionData[sendingUid]?.serviceAccessInformationRequestTimer = timer

timer.schedule(
object : TimerTask() {
override fun run() {
val call: Call<ServiceAccessInformation>? =
clientsSessionData[sendingUid]?.serviceAccessInformationApi?.fetchServiceAccessInformation(
provisioningSessionId,
clientsSessionData[sendingUid]?.serviceAccessInformationResponseHeaders?.get("etag"),
clientsSessionData[sendingUid]?.serviceAccessInformationResponseHeaders?.get("last-modified")
)

call?.enqueue(object : retrofit2.Callback<ServiceAccessInformation?> {
override fun onResponse(
call: Call<ServiceAccessInformation?>,
response: Response<ServiceAccessInformation?>
) {

handleServiceAccessResponse(
response,
sendingUid,
provisioningSessionId
)
}

override fun onFailure(
call: Call<ServiceAccessInformation?>,
t: Throwable
) {
call.cancel()
}
})
}
},
maxAgeValue * 1000
)

}

/**
* Reset a client session once a new playback session is started. Remove the ServiceAccessInformation
* for the corresponding client id and reset all metric reporting timers.
*
* @param clientId
*/
private fun resetClientSession(clientId: Int) {
if (clientsSessionData[clientId] != null) {
Log.i(TAG, "Resetting information for client $clientId")
clientsSessionData[clientId]?.serviceAccessInformation = null
clientsSessionData[clientId]?.serviceAccessInformationRequestTimer?.cancel()
clientsSessionData[clientId]?.serviceAccessInformationRequestTimer = null
clientsSessionData[clientId]?.serviceAccessInformationResponseHeaders = null
}
}


private fun setM5Endpoint(msg: Message) {
try {
val bundle: Bundle = msg.data
val m5BaseUrl: String? = bundle.getString("m5BaseUrl")
Log.i(TAG, "Setting M5 endpoint to $m5BaseUrl")
if (m5BaseUrl != null) {
initializeRetrofitForServiceAccessInformation(m5BaseUrl)
val retrofit = retrofitBuilder
.baseUrl(m5BaseUrl)
.build()
clientsSessionData[msg.sendingUid]?.serviceAccessInformationApi =
retrofit.create(ServiceAccessInformationApi::class.java)
}
} catch (e: Exception) {
}
Expand All @@ -151,23 +290,6 @@ class MediaSessionHandlerMessengerService() : Service() {

}

private fun initializeRetrofitForServiceAccessInformation(url: String) {
val headerInterceptor = HeaderInterceptor()
val okHttpClient = OkHttpClient()
.newBuilder()
.addInterceptor(headerInterceptor)
.build()

val retrofitServiceAccessInformation: Retrofit = Retrofit.Builder()
.client(okHttpClient)
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.build()

serviceAccessInformationApi =
retrofitServiceAccessInformation.create(ServiceAccessInformationApi::class.java)
}

/**
* When binding to the service, we return an interface to our messenger
* for sending messages to the service. To create a bound service, you must define the interface that specifies
Expand All @@ -176,12 +298,9 @@ class MediaSessionHandlerMessengerService() : Service() {
*/
override fun onBind(intent: Intent): IBinder? {
Log.i("MediaSessionHandler-New", "Service bound new")
return initializeMessenger()
}

private fun initializeMessenger(): IBinder? {
mMessenger = Messenger(IncomingHandler(this))
return mMessenger.binder
}


}
Loading

0 comments on commit 19339ea

Please sign in to comment.