-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
5GMS Consumption reporting: Add support to Media Session Handler #38
Changes from 3 commits
16332c8
5468ef3
0b2ee54
fcb38c6
306a7dd
8f1190f
94b055f
13898d3
7e40dc9
87d9c2b
00daeec
66c8df7
0b94262
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,11 +19,15 @@ 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.ConsumptionReporting | ||
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 com.fivegmag.a5gmsmediasessionhandler.network.ConsumptionReportingApi | ||
|
||
import okhttp3.Headers | ||
import okhttp3.ResponseBody | ||
import okhttp3.OkHttpClient | ||
import retrofit2.Call | ||
import retrofit2.Response | ||
|
@@ -32,9 +36,12 @@ import retrofit2.converter.gson.GsonConverterFactory | |
import java.util.Timer | ||
import java.util.TimerTask | ||
|
||
import kotlin.random.Random | ||
|
||
const val TAG = "5GMS Media Session Handler" | ||
|
||
const val SamplePercentage_100 = 100; | ||
|
||
/** | ||
* Create a bound service when you want to interact with the service from activities and other components in your application | ||
* or to expose some of your application's functionality to other applications through interprocess communication (IPC). | ||
|
@@ -46,6 +53,14 @@ class MediaSessionHandlerMessengerService() : Service() { | |
*/ | ||
private lateinit var mMessenger: Messenger | ||
private var clientsSessionData = HashMap<Int, ClientSessionModel>() | ||
|
||
private lateinit var serviceAccessInformationApi: ServiceAccessInformationApi | ||
//private lateinit var currentServiceAccessInformation: ServiceAccessInformation | ||
private var currentServiceAccessInformation: ServiceAccessInformation? = null | ||
|
||
private lateinit var consumptionReportingApi: ConsumptionReportingApi | ||
private lateinit var serverAddressesForConsumpReport: String | ||
|
||
private val headerInterceptor = HeaderInterceptor() | ||
private val utils = Utils() | ||
private val okHttpClient = OkHttpClient() | ||
|
@@ -74,6 +89,7 @@ class MediaSessionHandlerMessengerService() : Service() { | |
) | ||
|
||
SessionHandlerMessageTypes.SET_M5_ENDPOINT -> setM5Endpoint(msg) | ||
SessionHandlerMessageTypes.CONSUMPTION_REPORTING_MESSAGE -> reportConsumption(msg) | ||
else -> super.handleMessage(msg) | ||
} | ||
} | ||
|
@@ -123,6 +139,15 @@ class MediaSessionHandlerMessengerService() : Service() { | |
val resource = | ||
handleServiceAccessResponse(response, sendingUid, provisioningSessionId) | ||
|
||
// initialize Retrofit for ConsumptionReporting | ||
currentServiceAccessInformation = resource | ||
if(currentServiceAccessInformation!!.clientConsumptionReportingConfiguration.serverAddresses.isNotEmpty()) | ||
{ | ||
val serverAddressesForConsumpReport: String = currentServiceAccessInformation!!.clientConsumptionReportingConfiguration.serverAddresses[0]; | ||
Log.i(TAG, ">>>shilin: clientConsumptionReportingConfiguration serverAddresses0: $serverAddressesForConsumpReport.") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove comment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
initializeRetrofitForConsumpReport(serverAddressesForConsumpReport) | ||
} | ||
|
||
// Trigger the playback by providing all available entry points | ||
val msgResponse: Message = Message.obtain( | ||
null, | ||
|
@@ -144,6 +169,7 @@ class MediaSessionHandlerMessengerService() : Service() { | |
} | ||
|
||
override fun onFailure(call: Call<ServiceAccessInformation?>, t: Throwable) { | ||
Log.i(TAG, ">>>shilin: debug onFailure") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove comment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
call.cancel() | ||
} | ||
}) | ||
|
@@ -302,5 +328,128 @@ class MediaSessionHandlerMessengerService() : Service() { | |
return mMessenger.binder | ||
} | ||
|
||
/* Refer to TS26.512 Clause 4.7.4 | ||
The Service Access Information indicating whether Consumption Reporting is provisioned for downlink streaming | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shorten this description |
||
sessions is described in clause 11.2.3. When the clientConsumptionReportingConfiguration.samplePercentage | ||
value is 100, the Media Session Handler shall activate the consumption reporting procedure. | ||
If the samplePercentage is less than 100, the Media Session Handler shall generate a random number | ||
which is uniformly distributed in the range of 0 to 100, and the Media Session Handler shall activate | ||
the consumption report procedure when the generated random number is of a lower value than | ||
the samplePercentage value.The Service Access Information indicating whether Consumption Reporting | ||
is provisioned for downlink streaming sessions is described in clause 11.2.3. When the | ||
clientConsumptionReportingConfiguration.samplePercentage value is 100, the Media Session Handler | ||
shall activate the consumption reporting procedure. If the samplePercentage is less than 100, | ||
the Media Session Handler shall generate a random number which is uniformly distributed in | ||
the range of 0 to 100, and the Media Session Handler shall activate the consumption report | ||
procedure when the generated random number is of a lower value than the samplePercentage value. | ||
The Service Access Information indicating whether Consumption Reporting is provisioned for downlink streaming sessions is described in clause 11.2.3. When the clientConsumptionReportingConfiguration.samplePercentage value is 100, the Media Session Handler shall activate the consumption reporting procedure. If the samplePercentage is less than 100, the Media Session Handler shall generate a random number which is uniformly distributed in the range of 0 to 100, and the Media Session Handler shall activate the consumption report procedure when the generated random number is of a lower value than the samplePercentage value. | ||
*/ | ||
private fun IsConsumptionReportingActivated(): Boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename function to |
||
//if(currentServiceAccessInformation.isInitialized) { | ||
if(currentServiceAccessInformation == null) { | ||
return false | ||
} | ||
|
||
var samplePercentage: UInt = currentServiceAccessInformation!!.clientConsumptionReportingConfiguration.samplePercentage; | ||
if(samplePercentage > SamplePercentage_100.toUInt()) | ||
{ | ||
Log.i(TAG, "shilin>>>Invaild samplePercentage $samplePercentage in currentServiceAccessInformation") | ||
return false; | ||
} | ||
|
||
if(SamplePercentage_100.toUInt() == samplePercentage) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use this function to check if reporting should be activated or not according to
|
||
{ | ||
return true; | ||
} | ||
|
||
val myRandomValue = Random.nextInt(0, SamplePercentage_100) | ||
if(myRandomValue.toUInt() >= samplePercentage) | ||
{ | ||
Log.i(TAG, "shilin>>>IsConsumptionReportingActivated true:myRandomValue[$myRandomValue],samplePercentage[$samplePercentage]") | ||
return true; | ||
} | ||
else | ||
{ | ||
Log.i(TAG, "shilin>>>IsConsumptionReportingActivated false:myRandomValue[$myRandomValue],samplePercentage[$samplePercentage]") | ||
return false; | ||
} | ||
} | ||
|
||
/* Refer to TS26.512 Clause 4.7.4 | ||
TS26.501 Clause 5.6.3*/ | ||
private fun NeedReportConsumption(): Boolean { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename function to |
||
// check IsConsumptionReportingActivated | ||
if (!IsConsumptionReportingActivated()) | ||
{ | ||
Log.i(TAG, "shilin>>>ReportConsumption not Activated") | ||
return false; | ||
} | ||
|
||
// Start/stop of consumption of a downlink streaming session | ||
// triggered when PlayerStates.PLAYING & PlayerStates.ENDED | ||
/*if( Start || stop) | ||
{ | ||
return true; | ||
}*/ | ||
|
||
// check clientConsumptionReportingConfiguration.reportingInterval, start a timer | ||
// reportConsumptionTimer() | ||
|
||
// check clientConsumptionReportingConfiguration.locationReporting | ||
// check clientConsumptionReportingConfiguration.accessReporting | ||
if(currentServiceAccessInformation!!.clientConsumptionReportingConfiguration.locationReporting | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is consumption reporting only send if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just follow clause 4.7.4, as below:
Did I misunderstand it? |
||
|| currentServiceAccessInformation!!.clientConsumptionReportingConfiguration.accessReporting) | ||
{ | ||
return true; | ||
} | ||
|
||
return false; | ||
} | ||
|
||
private fun reportConsumption(msg: Message) { | ||
if (!NeedReportConsumption()) | ||
{ | ||
Log.i(TAG, "shilin>>>Not need ReportConsumption") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove all There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
return | ||
} | ||
|
||
val bundle: Bundle = msg.data | ||
bundle.classLoader = ConsumptionReporting::class.java.classLoader | ||
//val data: String = bundle.getString("ConsumptionData", "") | ||
val dataReporting: ConsumptionReporting? = bundle.getParcelable("consumptionData") | ||
|
||
Log.i(TAG, "reportConsumption ClientId: ${dataReporting?.reportingClientId}.") | ||
Toast.makeText( | ||
applicationContext, | ||
"MSH recv Consumption-ID: ${dataReporting?.reportingClientId}", | ||
Toast.LENGTH_LONG | ||
).show() | ||
|
||
// call m5 report consumption to AF - TS26.512 Clause 4.7.4 | ||
val aspId: String = "2"; | ||
val call: Call<ResponseBody>? = consumptionReportingApi.postConsumptionReporting(aspId,dataReporting?.reportingClientId); | ||
|
||
call?.enqueue(object : retrofit2.Callback<ResponseBody> { | ||
override fun onResponse( | ||
call: Call<ResponseBody?>, | ||
response: Response<ResponseBody?> | ||
) { | ||
Log.i(TAG, "shilin>>resp from AF:"+ response.body()?.string()) | ||
//System.out.println(">>>>>>>>>>>>"+response.body()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove comment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
} | ||
|
||
override fun onFailure(call: Call<ResponseBody?>, t: Throwable) { | ||
Log.i(TAG, "shilin>>onFailure") | ||
call.cancel() | ||
} | ||
}) | ||
} | ||
|
||
private fun initializeRetrofitForConsumpReport(url: String) { | ||
val m5RetrofitConsump: Retrofit = Retrofit.Builder() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
.baseUrl(url) | ||
//.addConverterFactory(GsonConverterFactory.create()) | ||
.build() | ||
consumptionReportingApi = m5RetrofitConsump.create(ConsumptionReportingApi::class.java) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be bound to a specific client is as there are multiple applications connected to the same Media Session Handler. As an example for the Service Access Information:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,5 +9,18 @@ https://drive.google.com/file/d/1cinCiA778IErENZ3JN52VFW-1ffHpx7Z/view | |
|
||
package com.fivegmag.a5gmsmediasessionhandler.network | ||
|
||
import com.fivegmag.a5gmscommonlibrary.models.ConsumptionReporting | ||
import okhttp3.ResponseBody | ||
import retrofit2.Call | ||
import retrofit2.http.Path | ||
import retrofit2.http.Field; | ||
import retrofit2.http.FieldMap; | ||
import retrofit2.http.FormUrlEncoded; | ||
import retrofit2.http.POST | ||
|
||
interface ConsumptionReportingApi { | ||
@FormUrlEncoded | ||
@POST("consumption-reporting/{aspId}") | ||
fun postConsumptionReporting(@Path("aspId") aspId: String?, @Field("data") data: String?): Call<ResponseBody>? | ||
//fun postConsumptionReporting(@Path("aspId") aspId: String?, @Field("data") data: String ): Call<String>? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove comment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are maintaining multiple concurrent sessions in the Media Session Handler. This means that multiple applications can be connected to the same Media Session Handler (see handling in
handleServiceAccessResponse
). There is no need to define a variablecurrentServiceAccessInformation
, you can useresource
directly.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because in some Consumption reporting related methods such as IsConsumptionReportingActivated and NeedReportConsumption, clientConsumptionReportingConfiguration of ServiceAccessInformation is need. So I need to save it as a member of the class MediaSessionHandlerMessengerService. I can only use resource directly only in handleStartPlaybackByServiceListEntryMessage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is what
clientsSessionData
can be used for:clientsSessionData[sendingUid]?.serviceAccessInformation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks. Done