diff --git a/AAMP-UVE-API.md b/AAMP-UVE-API.md
index 7e81f1e..3e1caae 100644
--- a/AAMP-UVE-API.md
+++ b/AAMP-UVE-API.md
@@ -42,7 +42,7 @@ This document is targeted to application developers who are interested in evalu
@@ -79,7 +79,7 @@ Configuration options are passed to AAMP using the UVE initConfig method. This a
| abrCacheLength | Number | 3 | Length of abr cache for network bandwidth calculation. |
| abrCacheLife | Number | 5000 | Lifetime value for abr cache for network bandwidth calculation (in milliseconds). |
| abrCacheOutlier | Number | 5000000 | Outlier difference which will be ignored from network bandwidth calculation (default: 5 MB in bytes). |
-| abrNwConsistency | Number | 2 | Number of checks before profile incr/decr by 1. This is to avoid frequent profile switching with network change. |
+| abrNwConsistency | Number | 2 | Number of checks before profile increment/decrement by 1. This is to avoid frequent profile switching with network change. |
| abrSkipDuration | Number | 6 | Minimum duration of fragment to be downloaded before triggering abr (in secs). |
| audioOnlyPlayback | Boolean | False | Configuration to enable/disable Audio only Playback. |
| cdvrLiveOffset | Number | 30 | Live offset time in seconds for cdvr, aamp starts live playback this much time before the live point for inprogress cdvr. |
@@ -209,15 +209,14 @@ Configuration options are passed to AAMP using the UVE initConfig method. This a
Example:
```js
{
- // configuration setting for player
- var playerInitConfig = {
- initialBitrate: 2500000,
- offset: 0,
- networkTimeout: 10,
- preferredAudioLanguage: "en",
- };
- // Use valid URL instead of example
- var url = "https://example.com/multilang/sample.m3u8";
+ // configuration setting for player
+ var playerInitConfig = {
+ initialBitrate: 2500000,
+ offset: 0,
+ networkTimeout: 10,
+ preferredAudioLanguage: "en",
+ };
+ var url = "https://example.com/multilang/sample.m3u8"; // replace with valid URL!
var player = new AAMPMediaPlayer();
player.initConfig(playerInitConfig);
player.load(url);
@@ -240,14 +239,13 @@ DRM configuration options are passed to AAMP using the setDRMConfig method. Para
Example:
```js
{
- // configuration for DRM -Sample for Widevine
- var DrmConfig = {
- 'https://example.com/AcquireLicense', // Use valid URL instead of example
- 'preferredKeysystem':'com.widevine.alpha'
- };
- // Use valid URL instead of example
- var url = "https://example.com/multilang/sample.m3u8";
- var player = new AAMPMediaPlayer();
+ // configuration for DRM -Sample for Widevine
+ var DrmConfig = {
+ 'https://example.com/AcquireLicense', // replace with valid URL!
+ 'preferredKeysystem':'com.widevine.alpha'
+ };
+ var url = "https://example.com/multilang/sample.m3u8"; // replace with valid URL!
+ var player = new AAMPMediaPlayer();
player.setDRMConfig(DrmConfig);
player.load(url);
}
@@ -302,16 +300,15 @@ Example:
```js
{
var player = new AAMPMediaPlayer();
- var url = "https://example.com/multilang/sample.m3u8"; // Use valid URL instead of example
+ var url = "https://example.com/multilang/sample.m3u8"; // replace with valid URL!
player.load(url); // for autoplayback
}
// support for multiple player instances
{
var player1 = new AAMPMediaPlayer();
var player2 = new AAMPMediaPlayer();
- // Use valid URLs instead of example
- var url1 = "https://example.com/multilang/sample.m3u8";
- var url2 = "https://example.com/multilang/sample1.m3u8";
+ var url1 = "https://example.com/multilang/sample.m3u8"; // replace with valid URL!
+ var url2 = "https://example.com/multilang/sample1.m3u8"; // replace with valid URL!
player1.load(url1); // for immediate playback
player2.load(url2,false); // for background buffering,no playback.
}
@@ -319,9 +316,8 @@ Example:
{
var player1 = new AAMPMediaPlayer();
var player2 = new AAMPMediaPlayer();
- // Use valid URLs instead of example
- var url1 = "https://example.com/multilang/sample.m3u8";
- var url2 = "https://example.com/multilang/sample1.m3u8";
+ var url1 = "https://example.com/multilang/sample.m3u8"; // replace with valid URL!
+ var url2 = "https://example.com/multilang/sample1.m3u8"; // replace with valid URL!
var params_1 = { sessionId: "12192978-da71-4da7-8335-76fbd9ae2ae9" };
var params_2 = { sessionId: "6e3c49cb-6254-4324-9f5e-bddef465bdff" };
@@ -332,9 +328,9 @@ Example:
// support for preprocessed DASH manifest
{
var player = new AAMPMediaPlayer();
- // Use valid URL instead of example
- var url = "https://example.com/VideoTestStream/aamptest/streams/ads/stitched/sample_manifest.mpd"
- const xml = "\n\n tuneStartBaseUTCMS - when tune logically started from AAMP perspective
- mms -> ManifestDownloadStartTime - offset in milliseconds from tunestart when main manifest begins download
- mmt -> ManifestDownloadTotalTime - time (ms) taken for main manifest download, relative to ManifestDownloadStartTime
- - mme -> ManifestDownloadFailCount - errors/retries occured during this operation
- - vps -> video offset in milliseconds from tunestart when playlist subManifest begins download(in MS)
- - vpt -> time (ms) taken for video playlist subManifest download, relative to PlaylistDownloadStartTime(in MS)
- - vpe -> video playlist errors/retries occured during this operation
- - aps -> audio offset in milliseconds from tunestart when playlist subManifest begins download(in MS)
- - apt -> time (ms) taken for audio playlist subManifest download, relative to PlaylistDownloadStartTime(in MS)
- - ape -> audio playlist errors/retries occured during this operation
- - vis -> video init-segment relative start time(in MS)
- - vit -> video init-segment total duration(in MS)
- - vie -> video init-segment errors/retries occured during this operation
- - ais -> audio init-segment relative start time(in MS)
- - ait -> audio init-segment total duration(in MS)
- - aie -> audio init-segment errors/retries occured during this operation
- - vfs -> video fragment relative start time(in MS)
- - vft -> video fragment total duration(in MS)
- - vfe -> video fragment errors/retries occured during this operation
+ - mme -> ManifestDownloadFailCount - errors/retries occurred during this operation
+ - vps -> video offset in milliseconds from tunestart when playlist subManifest begins download(in ms)
+ - vpt -> time (ms) taken for video playlist subManifest download, relative to PlaylistDownloadStartTime(in ms)
+ - vpe -> video playlist errors/retries occurred during this operation
+ - aps -> audio offset in milliseconds from tunestart when playlist subManifest begins download(in ms)
+ - apt -> time (ms) taken for audio playlist subManifest download, relative to PlaylistDownloadStartTime(in ms)
+ - ape -> audio playlist errors/retries occurred during this operation
+ - vis -> video init-segment relative start time(in ms)
+ - vit -> video init-segment total duration(in ms)
+ - vie -> video init-segment errors/retries occurred during this operation
+ - ais -> audio init-segment relative start time(in ms)
+ - ait -> audio init-segment total duration(in ms)
+ - aie -> audio init-segment errors/retries occurred during this operation
+ - vfs -> video fragment relative start time(in ms)
+ - vft -> video fragment total duration(in ms)
+ - vfe -> video fragment errors/retries occurred during this operation
- vfb -> video bandwidth in bps
- - afs -> audio fragment relative start time(in MS)
- - aft -> audio fragment total duration(in MS)
- - afe -> audio fragment errors/retries occured during this operation
+ - afs -> audio fragment relative start time(in ms)
+ - aft -> audio fragment total duration(in ms)
+ - afe -> audio fragment errors/retries occurred during this operation
- afb -> audio bandwidth in bps
- las -> drmLicenseRequestStart - offset in milliseconds from tunestart
- lat ->drmLicenseRequestTotalTime -time (ms) for license acquisition relative to drmLicenseRequestStart
@@ -1939,8 +1932,8 @@ Example:
- Example:
stt for playready dash stream = 22 = 20 (DASH ) + 2 ( PlayReady Codec type )
- ftt -> firstTune - To identify the first tune after load
- - pbm -> If Player was in prebufferd mode
- - tpb -> time spent in prebufferd(BG) mode
+ - pbm -> If Player was in prebuffered mode
+ - tpb -> time spent in prebuffered(BG) mode
- dus -> Asset duration in seconds
- ifw -> Connection is wifi or not - wifi(1) ethernet(0)
- tat -> TuneAttempts
@@ -2277,9 +2270,9 @@ This feature can be enabled in two methods
* Video Engine Managed
* Application managing Multi Player instance
-### CDAI Mechanism#1 – Engine Managed CDAI
+### CDAI Mechanism #1 – Engine Managed CDAI
-Supported for DASH Linear, working with period structure and SCTE35 markers, with optional replacement for like-amount of content.
+Supported for DASH Linear, working with period structure and SCTE35 markers. Supports optional replacement for like-amount of content. Source may be left as-is, replaced with a single similar sized alternate ad, or replaced with multiple alternate ads whose total duration is expected to fill the ad break. If insufficient alternate content duration is provided, or ads manifests are unable to download, player falls back to original (non-DAI) content.
#### setSubscribedTags( tagNames )
- Supported UVE version 0.8 and above.
@@ -2318,7 +2311,7 @@ Supported UVE version 0.8 and above
---
-### CDAI Mechanism#2 – Multi player instance
+### CDAI Mechanism #2 – Multi player instance
Can be leveraged for quick stream transitions. Suitable for preroll, and midroll insertions. No limitations with respect to content type – can transition between DASH and HLS.
@@ -2372,6 +2365,9 @@ adPlayer2.detach();
player.play();
adPlayer2.stop();
```
+
+When a player instance is no longer needed, recommend to call explicit release() method rather than rely only on eventual garbage collection. However, player instances can be recycled and reused throughout an app's lifecycle.
+
---
diff --git a/AampCacheHandler.cpp b/AampCacheHandler.cpp
index c8dac20..dcb2917 100644
--- a/AampCacheHandler.cpp
+++ b/AampCacheHandler.cpp
@@ -73,7 +73,8 @@ bool AampCacheHandler::RetrieveFromPlaylistCache( const std::string &url, AampGr
}
buffer->Clear();
buffer->AppendBytes( cachedData->buffer->GetPtr(), cachedData->buffer->GetLen() );
- assert( mediaType == cachedData->mediaType );
+ // below fails when playing an HLS playlist directly, then seeking or retuning
+ // assert( mediaType == cachedData->mediaType );
AAMPLOG_TRACE( "%s %s found", GetMediaTypeName(cachedData->mediaType), url.c_str() );
ret = true;
}
diff --git a/AampConfig.cpp b/AampConfig.cpp
index 4765038..5ec043b 100644
--- a/AampConfig.cpp
+++ b/AampConfig.cpp
@@ -196,12 +196,6 @@ struct ConfigLookupEntryString
#define DEFAULT_VALUE_USE_SINGLE_PIPELINE false
#endif
-#ifdef DISABLE_MEDIA_PROCESSOR
-#define DEFAULT_VALUE_ENABLE_MEDIA_PROCESSOR false
-#else
-#define DEFAULT_VALUE_ENABLE_MEDIA_PROCESSOR true
-#endif
-
/**
* @brief AAMPConfigSettingString metadata
* note that order must match the actual order of the enum; this is enforced with asserts to catch any wrong/missing declarations
@@ -239,7 +233,6 @@ static const ConfigLookupEntryString mConfigLookupTableString[AAMPCONFIG_STRING_
{"","gstlevel", eAAMPConfig_GstDebugLevel,false},
{"","tsbType", eAAMPConfig_TsbType, false},
{DEFAULT_TSB_LOCATION,"tsbLocation",eAAMPConfig_TsbLocation, true},
- {AAMP_LOW_LATENCY_URL_KEYWORD,"lldUrlKeyword", eAAMPConfig_LLDUrlKeyword, true},
};
/**
@@ -360,7 +353,7 @@ static const ConfigLookupEntryBool mConfigLookupTableBool[AAMPCONFIG_BOOL_COUNT]
{false,"sendLicenseResponseHeaders", eAAMPConfig_SendLicenseResponseHeaders, false},
{false,"suppressDecode", eAAMPConfig_SuppressDecode, false},
{false,"reconfigPipelineOnDiscontinuity", eAAMPConfig_ReconfigPipelineOnDiscontinuity, false},
- {DEFAULT_VALUE_ENABLE_MEDIA_PROCESSOR,"enableMediaProcessor", eAAMPConfig_EnableMediaProcessor, true},
+ {true,"enableMediaProcessor", eAAMPConfig_EnableMediaProcessor, true},
{true,"mpdStichingSupport", eAAMPConfig_MPDStitchingSupport, true}, // FIXME - spelling
{false,"sendUserAgentInLicense", eAAMPConfig_SendUserAgent, false},
{false,"enablePTSReStamp", eAAMPConfig_EnablePTSReStamp, true},
@@ -452,8 +445,6 @@ static const ConfigLookupEntryInt mConfigLookupTableInt[AAMPCONFIG_INT_COUNT+CON
{0,"minBitrate",eAAMPConfig_MinBitrate,true},
{INT_MAX,"maxBitrate",eAAMPConfig_MaxBitrate,true},
{CURL_SSLVERSION_TLSv1_2,"supportTLS",eAAMPConfig_TLSVersion,true,eCONFIG_RANGE_CURL_SSL_VERSION},
- {MAX_GST_VIDEO_BUFFER_BYTES_FOG_LIVE,"gstVideoBufBytesForFogLive", eAAMPConfig_GstVideoBufBytesForFogLive,false},
- {MAX_GST_AUDIO_BUFFER_BYTES_FOG_LIVE,"gstAudioBufBytesForFogLive", eAAMPConfig_GstAudioBufBytesForFogLive,false},
{DEFAULT_DRM_NETWORK_TIMEOUT,"drmNetworkTimeout",eAAMPConfig_DrmNetworkTimeout,true,eCONFIG_RANGE_TIMEOUT},
{0,"drmStallTimeout",eAAMPConfig_DrmStallTimeout,true,eCONFIG_RANGE_TIMEOUT},
{0,"drmStartTimeout",eAAMPConfig_DrmStartTimeout,true,eCONFIG_RANGE_TIMEOUT},
@@ -1260,11 +1251,6 @@ bool AampConfig::ProcessConfigJson(const cJSON *cfgdata, ConfigPriority owner )
SetConfigValue(owner,eAAMPConfig_CKLicenseServerUrl,conv);
drmType = eDRM_ClearKey;
}
- if(strcasecmp("preferredKeysystem",subitem->string)==0)
- {
- AAMPLOG_MIL("Preferred key system received - %s", conv.c_str());
- SetConfigValue(owner,eAAMPConfig_PreferredDRM,(int)drmType);
- }
if(strcasecmp("customData",subitem->string)==0)
{
AAMPLOG_MIL("customData received - %s", conv.c_str());
@@ -1272,6 +1258,27 @@ bool AampConfig::ProcessConfigJson(const cJSON *cfgdata, ConfigPriority owner )
}
subitem = subitem->next;
}
+
+ // preferredKeysystem used to disambiguate DRM type to use when manifest advertises multiple supported systems.
+ cJSON *preferredKeySystemItem = cJSON_GetObjectItem(drmConfig, "preferredKeysystem");
+ if (preferredKeySystemItem && cJSON_IsString(preferredKeySystemItem))
+ {
+ const char * preferredKeySystem = preferredKeySystemItem->valuestring;
+ AAMPLOG_MIL("preferredKeySystem received - %s", preferredKeySystem );
+ if( strcmp(preferredKeySystem,"com.widevine.alpha")==0 )
+ {
+ drmType = eDRM_WideVine;
+ }
+ else if ( strcmp(preferredKeySystem,"com.microsoft.playready")==0 )
+ {
+ drmType = eDRM_PlayReady;
+ }
+ else if ( strcmp(preferredKeySystem,"org.w3.clearkey")==0 )
+ {
+ drmType = eDRM_ClearKey;
+ }
+ }
+ SetConfigValue(owner, eAAMPConfig_PreferredDRM, (int)drmType);
}
retval = true;
}
@@ -1691,21 +1698,19 @@ void AampConfig::ReadAampCfgFromEnv()
}
}
}
- else
+
+ // Now check for base64 based env, this is back up in case above string becomes big and becomes error prone, also base64 covers json format as well.
+ envConf = getenv("AAMP_CFG_BASE64");
+ if (NULL != envConf)
{
- // Now check for base64 based env, this is back up in case above string becomes big and becomes error prone, also base64 covers json format as well.
- envConf = getenv("AAMP_CFG_BASE64");
- if(NULL != envConf)
+ std::string strEnvConfig = envConf; // make sure we copy this as recommended by getEnv doc
+ size_t iConfigLen = strEnvConfig.length();
+ AAMPLOG_MIL("ReadAampCfgFromEnv:BASE64 ENV:%s len:%zu ", strEnvConfig.c_str(), iConfigLen);
+ char *strConfig = (char *)base64_Decode(strEnvConfig.c_str(), &iConfigLen);
+ if (NULL != strConfig)
{
- std::string strEnvConfig = envConf; // make sure we copy this as recommended by getEnv doc
- size_t iConfigLen = strEnvConfig.length();
- AAMPLOG_MIL("ReadAampCfgFromEnv:BASE64 ENV:%s len:%zu ",strEnvConfig.c_str(),iConfigLen);
- char * strConfig = (char * ) base64_Decode(strEnvConfig.c_str(),&iConfigLen);
- if( NULL != strConfig )
- {
- ProcessBase64AampCfg(strConfig, iConfigLen,AAMP_DEV_CFG_SETTING);
- free(strConfig); // free mem allocated by base64_Decode
- }
+ ProcessBase64AampCfg(strConfig, iConfigLen, AAMP_DEV_CFG_SETTING);
+ free(strConfig); // free mem allocated by base64_Decode
}
}
}
@@ -1769,7 +1774,6 @@ void AampConfig::ReadAllTR181Params()
}
}
}
- ConfigureLogSettings();
for( int i =0; i < AAMPCONFIG_STRING_COUNT; i++ )
{
@@ -1793,13 +1797,20 @@ void AampConfig::ReadAllTR181Params()
*/
void AampConfig::ReadOperatorConfiguration()
{
- // Not all parameters are supported as individual tr181 parameter hence keeping base64 version.
- ReadBase64TR181Param();
+ // Tr181 doesn't work in container environment hence ignore it if it is container
+ // this will improve load time of aamp in container environment
+ if(!IsContainerEnvironment() )
+ {
+ // Not all parameters are supported as individual tr181 parameter hence keeping base64 version.
+ ReadBase64TR181Param();
- // new way of reading RFC for each separate parameter it will override any parameter set before ReadBase64TR181Param
- // read all individual config parameters,
- ReadAllTR181Params();
+ // new way of reading RFC for each separate parameter it will override any parameter set before ReadBase64TR181Param
+ // read all individual config parameters,
+ ReadAllTR181Params();
+ }
+ // this required to set log settings based on configs either default or read from Tr181
+ ConfigureLogSettings();
///////////// Read environment variables set specific to Operator ///////////////////
const char *env_aamp_force_aac = getenv("AAMP_FORCE_AAC");
if(env_aamp_force_aac)
diff --git a/AampConfig.h b/AampConfig.h
index e820da1..eacd67e 100644
--- a/AampConfig.h
+++ b/AampConfig.h
@@ -293,8 +293,6 @@ typedef enum
eAAMPConfig_MinBitrate, /**< minimum bitrate filter for playback profiles */
eAAMPConfig_MaxBitrate, /**< maximum bitrate filter for playback profiles*/
eAAMPConfig_TLSVersion, /**< TLS Version value*/
- eAAMPConfig_GstVideoBufBytesForFogLive, /**< Gstreamer Max Video buffering bytes for fog linear*/
- eAAMPConfig_GstAudioBufBytesForFogLive, /**< Gstreamer Max Audio buffering bytes for fog linear*/
eAAMPConfig_DrmNetworkTimeout, /**< DRM license request timeout in sec*/
eAAMPConfig_DrmStallTimeout, /**< Stall Timeout for DRM license request*/
eAAMPConfig_DrmStartTimeout, /**< Start Timeout for DRM license request*/
@@ -375,7 +373,6 @@ typedef enum
eAAMPConfig_GstDebugLevel, /**< gstreamer debug level as you'd define in GST_DEBUG */
eAAMPConfig_TsbType,
eAAMPConfig_TsbLocation, /**< tsbType location for local TSB storage*/
- eAAMPConfig_LLDUrlKeyword, /** Keyword to identify the lld stream */
eAAMPConfig_StringMaxValue /**< Max value for string config always last element */
} AAMPConfigSettingString;
#define AAMPCONFIG_STRING_COUNT (eAAMPConfig_StringMaxValue)
diff --git a/AampDRMLicPreFetcher.cpp b/AampDRMLicPreFetcher.cpp
index 4176a34..a3b0805 100644
--- a/AampDRMLicPreFetcher.cpp
+++ b/AampDRMLicPreFetcher.cpp
@@ -442,12 +442,18 @@ void AampLicensePreFetcher::NotifyDrmFailure(LicensePreFetchObjectPtr fetchObj,
{
if (!selfAbort)
{
- isRetryEnabled = (failure != AAMP_TUNE_AUTHORIZATION_FAILURE)
- && (failure != AAMP_TUNE_LICENCE_REQUEST_FAILED)
- && (failure != AAMP_TUNE_LICENCE_TIMEOUT)
- && (failure != AAMP_TUNE_DEVICE_NOT_PROVISIONED)
- && (failure != AAMP_TUNE_HDCP_COMPLIANCE_ERROR);
-
+ //Set the isRetryEnabled flag to true if the failure is due to
+ //SEC_CLIENT_RESULT_HTTP_RESULT_FAILURE_TIMEOUT (error -7). This
+ //error is caused by a network failure, so the tune may succeed
+ //on a retry attempt.
+ //For other DRM failures, the flag should be set to false.
+ isRetryEnabled = ((failure == AAMP_TUNE_LICENCE_REQUEST_FAILED) && (event->getResponseCode() == SECCLIENT_RESULT_HTTP_FAILURE_TIMEOUT))
+ || ((failure != AAMP_TUNE_AUTHORIZATION_FAILURE)
+ && (failure != AAMP_TUNE_LICENCE_REQUEST_FAILED)
+ && (failure != AAMP_TUNE_LICENCE_TIMEOUT)
+ && (failure != AAMP_TUNE_DEVICE_NOT_PROVISIONED)
+ && (failure != AAMP_TUNE_HDCP_COMPLIANCE_ERROR));
+ AAMPLOG_WARN("Drm failure:%d response: %d isRetryEnabled:%d ",(int)failure,event->getResponseCode(),isRetryEnabled);
mPrivAAMP->SendDrmErrorEvent(event, isRetryEnabled);
mPrivAAMP->profiler.SetDrmErrorCode((int)failure);
mPrivAAMP->profiler.ProfileError(PROFILE_BUCKET_LA_TOTAL, (int)failure);
diff --git a/AampDRMLicPreFetcher.h b/AampDRMLicPreFetcher.h
index 9614de5..7c65850 100644
--- a/AampDRMLicPreFetcher.h
+++ b/AampDRMLicPreFetcher.h
@@ -33,6 +33,8 @@
#include "AampEvent.h"
#include "AampDRMLicPreFetcherInterface.h"
+#define SECCLIENT_RESULT_HTTP_FAILURE_TIMEOUT (-7) /**< License result is not returned to the device due to network failure */
+
class PrivateInstanceAAMP;
/**
diff --git a/AampDefine.h b/AampDefine.h
index 1076987..8ee075f 100644
--- a/AampDefine.h
+++ b/AampDefine.h
@@ -30,7 +30,7 @@
#define AAMP_CFG_PATH "/opt/aamp.cfg"
#define AAMP_JSON_PATH "/opt/aampcfg.json"
-#define AAMP_VERSION "7.02"
+#define AAMP_VERSION "7.03"
#define AAMP_TUNETIME_VERSION 5
//Stringification of Macro : use two levels of macros
@@ -166,9 +166,6 @@
#define MAX_GST_VIDEO_BUFFER_BYTES (GST_VIDEOBUFFER_SIZE_BYTES)
#define MAX_GST_AUDIO_BUFFER_BYTES (GST_AUDIOBUFFER_SIZE_BYTES)
-#define MAX_GST_VIDEO_BUFFER_BYTES_FOG_LIVE (2097152) /* GST Buffer for FOG Linear Video*/
-#define MAX_GST_AUDIO_BUFFER_BYTES_FOG_LIVE (256000) /* GST Buffer for FOG Linear Audio*/
-
#define DEFAULT_LATENCY_MONITOR_DELAY 9 /**< Latency Monitor Delay */
#define DEFAULT_LATENCY_MONITOR_INTERVAL 6 /**< Latency monitor Interval */
#define DEFAULT_MIN_LOW_LATENCY 3 /**< min Default Latency */
@@ -187,8 +184,6 @@
#define AAMP_BUFFER_MONITOR_GREEN_THRESHOLD 4 /**< 2 fragments for MSO specific linear streams. */
#define AAMP_BUFFER_MONITOR_GREEN_THRESHOLD_LLD 1 /**< LLD 1 sec minimum buffer to alert */
-#define AAMP_LOW_LATENCY_URL_KEYWORD "/low/" /**< AAMP expect this keyword in low latency URL to enable local TSB*/
-#define AAMP_LOW_LATENCY_URL_KEYWORD_ENCODED "%2Flow%2F" /**< AAMP expect this keyword in low latency URL to defog*/
#define AAMP_FOG_TSB_URL_KEYWORD "tsb?" /**< AAMP expect this keyword in URL to identify it is FOG url */
#define DEFAULT_INITIAL_RATE_CORRECTION_SPEED 1.000001f /**< Initial rate correction speed to avoid audio drop */
@@ -246,6 +241,7 @@
#define MAX_SESSION_ID_LENGTH 128 /** &metadata, const s
}
/**
- * @brief Get ID3 metdata
+ * @brief Get ID3 metadata
*
* @return ID3 metadata content
*/
@@ -1418,7 +1418,7 @@ const std::vector &ID3MetadataEvent::getMetadata() const
}
/**
- * @brief Get ID3 metdata size
+ * @brief Get ID3 metadata size
*
* @return ID3 metadata size
*/
diff --git a/AampLogManager.h b/AampLogManager.h
index 4ed88c6..e9399b4 100644
--- a/AampLogManager.h
+++ b/AampLogManager.h
@@ -257,84 +257,6 @@ class AampLogManager
}
}
- /**
- * @fn LogDRMError
- *
- * @param[in] major - drm major error code
- * @param[in] minor - drm minor error code
- * @return void
- */
- static void LogDRMError(int major, int minor)
- {
- std::string description;
- switch(major)
- {
- case 3307: /* Internal errors */
- if(minor == 268435462)
- {
- description = "Missing drm keys. Files are missing from /opt/drm. This could happen if socprovisioning fails to pull keys from fkps. This could also happen with a new box type that isn't registered with fkps. Check the /opt/logs/socprov.log for error. Contact ComSec for help.";
- }
- else if(minor == 570425352)
- {
- description = "Stale cache data. There is bad data in adobe cache at /opt/persistent/adobe. This can happen if the cache isn't cleared by /lib/rdk/cleanAdobe.sh after either an FKPS key update or a firmware update. This should not be happening in the field. For engineers, they can try a factory reset to fix the problem.";
- }
- else if(minor == 1000022)
- {
- description = "Local cache directory not readable. The Receiver running as non-root cannot access and read the adobe cache at /opt/persistent/adobe. This can happen if /lib/rdk/prepareChrootEnv.sh fails to set that folders privileges. Run ls -l /opt/persistent and check the access rights. Contact the SI team for help.";
- }
- break; /* 3307 */
-
- case 3321: /* Individualization errors */
- if(minor == 102)
- {
- description = "Invalid signature request on the Adobe individualization request. Expired certs can cause this, so the first course of action is to verify if the certs, temp baked in or production fkps, have not expired.";
- }
- else if(minor == 10100)
- {
- description = "Unknown Device class error from the Adobe individualization server. The drm certs may be been distributed to MSO security team for inclusion in fkps, but Adobe has not yet added the device info to their indi server.";
- }
- else if(minor == 1107296357)
- {
- description = "Failed to connect to individualization server. This can happen if the network goes down. This can also happen if bad proxy settings exist in /opt/xreproxy.conf. Check the receiver.log for the last HttpRequestBegin before the error occurs and check the host name in the url, then check your proxy conf";
- }
- if(minor == 1000595) /* RequiredSPINotAvailable */
- {
- /* This error doesn't tell us anything useful but points to some other underlying issue.
- * Don't report this error. Ensure a triage log is being create for the underlying issue
- */
-
- return;
- }
- break; /* 3321 */
-
- case 3322: /* Device binding failure */
- description = "Device binding failure. DRM data cached by the player at /opt/persistent/adobe, may be corrupt, missing, or inaccessible due to file permission. Please check this folder. A factory reset may be required to fix this and force a re-individualization of the box to reset that data.";
- break; /* 3322 */
-
- case 3328:
- if(minor == 1003532)
- {
- description = "Potential server issue. This could happen if drm keys are missing or bad. To attempt a quick fix: Back up /opt/drm and /opt/persistent/adobe, perform a factory reset, and see if that fixes the issue. Reach out to ComSec team for help diagnosing the error.";
- }
- break; /* 3328 */
-
- case 3329: /* Application errors (our consec errors) */
- description = "MSO license server error response. This could happen for various reasons: bad cache data, bad session token, any license related issue. To attempt a quick fix: Back up /opt/drm and /opt/persistent/adobe, perform a factory reset, and see if that fixes the issue. Reach out to ComSec team for help diagnosing the error.";
- break; /* 3329 */
-
- case 3338: /* Unknown connection type */
- description = "Unknown connection type. Rare issue related to output protection code not being implemented on certain branches or core or for new socs. See STBI-6542 for details. Reach out to Receiver IP-Video team for help.";
- break; /* 3338 */
- }
-
- if(description.empty())
- {
- description = "Unrecognized error. Please report this to the STB IP-Video team.";
- }
-
- logprintf( eLOGLEVEL_ERROR, __FUNCTION__, __LINE__, "AAMPLogDRMError error=%d.%d description='%s'", major, minor, description.c_str());
- }
-
/**
* @fn LogABRInfo
*
diff --git a/AampMPDDownloader.cpp b/AampMPDDownloader.cpp
index 1c8dcf5..4bac6f2 100755
--- a/AampMPDDownloader.cpp
+++ b/AampMPDDownloader.cpp
@@ -328,22 +328,6 @@ void AampMPDDownloader::Start()
{
AAMPLOG_WARN("Thread create failed for MPD Downloader1 : %s", e.what());
}
-
- #if 0 // downloader thread 2 is not required now . When Option 2 is considered , need to do parallel download
- // Following to be done after successful download of Main Manifest
- if(!mMPDDnldCfg->mStichUrl.empty())
- {
- try
- {
- mDownloaderThread_t2 = std::thread(&AampMPDDownloader::downloadMPDThread2, this);
- AAMPLOG_INFO("Thread created for MPD Downloader2 [%zu]", GetPrintableThreadID(mDownloaderThread_t2));
- }
- catch(std::exception &e)
- {
- AAMPLOG_WARN("Thread create failed for MPD Downloader2 : %s", e.what());
- }
- }
- #endif
}
else
{
@@ -357,13 +341,13 @@ void AampMPDDownloader::Start()
*/
void AampMPDDownloader::downloadMPDThread1()
{
+ UsingPlayerId playerId(mMPDDnldCfg->mPlayerId);
bool refreshNeeded = false;
std::string tuneUrl = mMPDDnldCfg->mTuneUrl;
bool firstDownload = true;
ManifestDownloadResponsePtr cachedBackupData = nullptr;
do
{
-
std::unordered_map> Headers = mMPDDnldCfg->mDnldConfig->sCustomHeaders;
bool doPush = true;
long long tStartTime = NOW_STEADY_TS_MS;
@@ -492,7 +476,6 @@ void AampMPDDownloader::downloadMPDThread1()
}
}
long long tEndTime = NOW_STEADY_TS_MS;
-
showDownloadMetrics(mMPDData->mMPDDownloadResponse, (int)(tEndTime - tStartTime));
if(doPush)
{
@@ -563,8 +546,6 @@ void AampMPDDownloader::harvestManifest()
} //CID:168113 - forward null
}
}
-
-
}
@@ -603,7 +584,6 @@ void AampMPDDownloader::stichToCachedManifest(ManifestDownloadResponsePtr mpdToA
*/
void AampMPDDownloader::showDownloadMetrics(DownloadResponsePtr dnldPtr, int totalPerformanceTime)
{
-
CURLcode res = static_cast(dnldPtr->curlRetValue);
int http_code = dnldPtr->iHttpRetValue;
double total = dnldPtr->downloadCompleteMetrics.total;
@@ -635,45 +615,6 @@ void AampMPDDownloader::showDownloadMetrics(DownloadResponsePtr dnldPtr, int tot
0, dnldPtr->sEffectiveUrl.c_str());
}
-
-/**
-* @fn downloadMPDThread2
-* @brief downloadMPDThread1 thread function to download the Manifest 2
-*/
-void AampMPDDownloader::downloadMPDThread2()
-{
- mDownloader2.Initialize(mMPDDnldCfg->mDnldConfig);
- do
- {
- long long tStartTime = NOW_STEADY_TS_MS;
- mDownloader2.Clear();
- AAMPLOG_INFO("aamp url:%d,%d,%d,%f,%s", eMEDIATYPE_TELEMETRY_MANIFEST, eMEDIATYPE_MANIFEST,eCURLINSTANCE_VIDEO,0.000000, mMPDDnldCfg->mStichUrl.c_str());
- ManifestDownloadResponsePtr tmpFullManifestData = std::make_shared ();
- mDownloader2.Download(mMPDDnldCfg->mStichUrl, tmpFullManifestData->mMPDDownloadResponse);
-
- if(tmpFullManifestData->mMPDDownloadResponse->curlRetValue == 0 && tmpFullManifestData->mMPDDownloadResponse->iHttpRetValue == 200)
- {
- tmpFullManifestData->parseMPD();
- // Update the effective url , so that next refresh uses the effective url
- mMPDDnldCfg->mStichUrl = tmpFullManifestData->mMPDDownloadResponse->sEffectiveUrl;
- AAMPLOG_INFO("Successfully parsed Full Manifest ...IsLive[%d]",tmpFullManifestData->mIsLiveManifest);
- mCachedMPDData = tmpFullManifestData;
- }
- else
- {
- // Failure in request
- AAMPLOG_ERR("curl request %s httpError[%u] curlError[%u]", mMPDDnldCfg->mStichUrl.c_str(), tmpFullManifestData->mMPDDownloadResponse->iHttpRetValue,tmpFullManifestData->mMPDDownloadResponse->curlRetValue);
- tmpFullManifestData->mMPDStatus = AAMPStatusType::eAAMPSTATUS_MANIFEST_DOWNLOAD_ERROR;
- }
- long long tEndTime = NOW_STEADY_TS_MS;
-
- showDownloadMetrics(tmpFullManifestData->mMPDDownloadResponse, (int)(tEndTime - tStartTime));
-
- }while(false);
- AAMPLOG_INFO("Out of Full Manifest Download ...");
-
-}
-
/**
* @fn pushDownloadDataToQueue
* @brief pushDownloadDataToQueue push the downloaded data to queue
@@ -1145,6 +1086,7 @@ void AampMPDDownloader::UnRegisterCallback()
*/
void AampMPDDownloader::downloadNotifierThread()
{
+ UsingPlayerId playerId(mMPDDnldCfg->mPlayerId);
std::unique_lock lck2(mMPDNotifierMtx);
// infinite wait for download notification
diff --git a/AampMPDDownloader.h b/AampMPDDownloader.h
index f1c29d5..2f9f5c6 100755
--- a/AampMPDDownloader.h
+++ b/AampMPDDownloader.h
@@ -65,7 +65,6 @@
#include "AampMPDUtils.h"
typedef void (*ManifestUpdateCallbackFunc)(void *);
-typedef std::shared_ptr AampMPDParseHelperPtr;
/**
* @struct _manifestDownloadConfig
@@ -87,19 +86,20 @@ typedef struct _manifestDownloadConfig
std::string mHarvestPathConfigured; // Harvest Path
AampCMCDCollector* mCMCDCollector; // new variable for cmcd header collector
std::string mPreProcessedManifest; // provided pre-processed manifest file
+ int mPlayerId;
- _manifestDownloadConfig() :mDnldConfig(std::make_shared ()),mTuneUrl(),mStichUrl(),
+ _manifestDownloadConfig( int playerId ) :mDnldConfig(std::make_shared ()),mTuneUrl(),mStichUrl(),
mIsLLDConfigEnabled(false), mCullManifestAtTuneStart(false),mTSBDuration(-1),
mStartPosnToTSB(-1),mCMCDCollector(nullptr),mMPDStichOption(OPT_1_FULL_MANIFEST_TUNE),
- mHarvestCountLimit(0),mHarvestConfig(0),mHarvestPathConfigured(),mPreProcessedManifest() {}
+ mHarvestCountLimit(0),mHarvestConfig(0),mHarvestPathConfigured(),mPreProcessedManifest(),mPlayerId(playerId) {}
_manifestDownloadConfig(const _manifestDownloadConfig& other): mDnldConfig(other.mDnldConfig),mTuneUrl(other.mTuneUrl),
mStichUrl(other.mStichUrl),mIsLLDConfigEnabled(other.mIsLLDConfigEnabled),
mCullManifestAtTuneStart(other.mCullManifestAtTuneStart), mTSBDuration(other.mTSBDuration),
mStartPosnToTSB(other.mStartPosnToTSB),mCMCDCollector(other.mCMCDCollector),
mMPDStichOption(other.mMPDStichOption),mHarvestCountLimit(other.mHarvestCountLimit),
- mHarvestConfig(other.mHarvestConfig),mHarvestPathConfigured(other.mHarvestPathConfigured),mPreProcessedManifest(other.mPreProcessedManifest) {}
+ mHarvestConfig(other.mHarvestConfig),mHarvestPathConfigured(other.mHarvestPathConfigured),mPreProcessedManifest(other.mPreProcessedManifest),mPlayerId(other.mPlayerId) {}
_manifestDownloadConfig& operator=(const _manifestDownloadConfig& other)
@@ -333,11 +333,7 @@ class AampMPDDownloader
* @brief Thread Function to download manifest file and refresh it if live
*/
void downloadMPDThread1();
- /**
- * @fn downloadMPDThread2
- * @brief Thread Function to download second manifest file for post stitching ( not supported now)
- */
- void downloadMPDThread2();
+
/**
* @fn downloadNotifierThread
* @brief Thread Function to notify the registered user fo manifest refresh. This will avoid any delays in
diff --git a/AampMPDParseHelper.h b/AampMPDParseHelper.h
index 4f83b57..ccff836 100644
--- a/AampMPDParseHelper.h
+++ b/AampMPDParseHelper.h
@@ -465,6 +465,13 @@ public :
* @return True if period has segment timeline for video otherwise false
*/
bool aamp_HasSegmentTimeline(IPeriod * period);
+
+ /**
+ * @brief Get the MPD instance.
+ *
+ * @return const dash::mpd::IMPD* A pointer to the MPD instance.
+ */
+ const dash::mpd::IMPD* getMPD() const { return mMPDInstance; }
private:
/**
@@ -509,5 +516,6 @@ public :
std::vector mMPDPeriodDetails;
};
+typedef std::shared_ptr AampMPDParseHelperPtr;
#endif
diff --git a/AampProfiler.cpp b/AampProfiler.cpp
index a56cea5..f1996a7 100644
--- a/AampProfiler.cpp
+++ b/AampProfiler.cpp
@@ -122,7 +122,7 @@ std::string ProfileEventAAMP::GetTuneTimeMetricAsJson(TuneEndMetrics tuneMetrics
cJSON_AddStringToObject(item, "frs", failureReason.c_str());
cJSON_AddStringToObject(item, "app", appName.c_str());
- cJSON_AddNumberToObject(item, "tsb", tuneMetricsData.mTSBEnabled);
+ cJSON_AddNumberToObject(item, "tsb", tuneMetricsData.mFogTSBEnabled);
cJSON_AddNumberToObject(item, "tot", tuneMetricsData.mTotalTime);
//lets use cJSON_PrintUnformatted , cJSON_Print is formated adds whitespace n hence takes more memory also eats up more logs if logged.
@@ -341,7 +341,7 @@ void ProfileEventAAMP::TuneEnd(TuneEndMetrics &mTuneEndMetrics,std::string appNa
playerPreBuffered,playerPreBuffered ? buckets[PROFILE_BUCKET_PLAYER_PRE_BUFFERED].tStart : 0,
durationSeconds,interfaceWifi,
mTuneEndMetrics.mTuneAttempts, mTuneEndMetrics.success,failureReason.c_str(),appName.c_str(),
- mTuneEndMetrics.mTimedMetadata,mTimedMetadataStartTime < 0 ? 0 : mTimedMetadataStartTime , mTuneEndMetrics.mTimedMetadataDuration,mTuneEndMetrics.mTSBEnabled,mTotalTime
+ mTuneEndMetrics.mTimedMetadata,mTimedMetadataStartTime < 0 ? 0 : mTimedMetadataStartTime , mTuneEndMetrics.mTimedMetadataDuration,mTuneEndMetrics.mFogTSBEnabled,mTotalTime
);
// Telemetry is generated in GetTuneTimeMetricAsJson hence calling always,
diff --git a/AampProfiler.h b/AampProfiler.h
index 3f18a52..0a17ac5 100644
--- a/AampProfiler.h
+++ b/AampProfiler.h
@@ -146,7 +146,7 @@ typedef struct
int mTimedMetadataDuration; /**< Time Taken to send TiedMetaData event*/
int mTuneAttempts; /**< No of tune attempts taken */
bool mFirstTune; /**< To identify the first tune after load.*/
- bool mTSBEnabled; /**< Flag to indicate TSB is enabled or not */
+ bool mFogTSBEnabled; /**< Flag to indicate TSB is enabled or not */
int mTotalTime;
ContentType contentType;
}TuneEndMetrics;
diff --git a/AampTSBSessionManager.cpp b/AampTSBSessionManager.cpp
index 63d70cd..0f5b0e0 100644
--- a/AampTSBSessionManager.cpp
+++ b/AampTSBSessionManager.cpp
@@ -204,8 +204,11 @@ std::shared_ptr AampTSBSessionManager::Read(TsbFragmentDataPtr f
std::size_t len = mTSBStore->GetSize(url);
if (len > 0)
{
- cachedFragment->position = fragment->GetPosition();
- cachedFragment->absPosition = fragment->GetPosition(); // AbsPosition is same as position for content from TSB
+ // PTS restamping must be enabled to use AAMP Local TSB.
+ // 'position' has the restamped PTS value, however, the PTS value in the ISO BMFF boxes
+ // (baseMediaDecodeTime) will be restamped later, in the injector thread.
+ cachedFragment->position = fragment->GetPTS() + fragment->GetPTSOffsetSec();
+ cachedFragment->absPosition = fragment->GetAbsPosition();
cachedFragment->duration = fragment->GetDuration();
cachedFragment->discontinuity = fragment->IsDiscontinuous();
cachedFragment->type = fragment->GetInitFragData()->GetMediaType();
@@ -213,7 +216,7 @@ std::shared_ptr AampTSBSessionManager::Read(TsbFragmentDataPtr f
cachedFragment->timeScale = fragment->GetTimeScale();
cachedFragment->uri = url;
pts = fragment->GetPTS();
- AAMPLOG_INFO("[%s] Read fragment from AAMP TSB: position %fs absPosition %fs pts %fs duration %fs discontinuity %d ptsOffset %fs timeScale %u url %s",
+ AAMPLOG_INFO("[%s] Read fragment from AAMP TSB: position (restamped PTS) %fs absPosition %fs pts %fs duration %fs discontinuity %d ptsOffset %fs timeScale %u url %s",
GetMediaTypeName(cachedFragment->type), cachedFragment->position, cachedFragment->absPosition, pts, cachedFragment->duration,
cachedFragment->discontinuity, cachedFragment->PTSOffsetSec, cachedFragment->timeScale, url.c_str());
@@ -265,6 +268,10 @@ void AampTSBSessionManager::EnqueueWrite(std::string url, std::shared_ptr guard(mWriteQueueMutex);
AampMediaType mediaType = ConvertMediaType(cachedFragment->type);
+ // Read the PTS from the ISOBMFF boxes (baseMediaDecodeTime / timescale) before applying the PTS offset.
+ // The PTS value will be restamped by the injector thread.
+ // This function is called in the context of the fetcher thread before the fragment is added to the list to be injected, to avoid
+ // any race conditions; so it cannot be moved to ProcessWriteQueue() or any other functions called from a different context.
double pts = RecalculatePTS(static_cast(cachedFragment->type), cachedFragment->fragment.GetPtr(), cachedFragment->fragment.GetLen(), mAamp);
// Get or create the datamanager for the mediatype
std::shared_ptr dataManager = GetTsbDataManager(mediaType);
@@ -285,6 +292,17 @@ void AampTSBSessionManager::EnqueueWrite(std::string url, std::shared_ptrRemoveFragment(deleteInit);
+ if (removedFragment && deleteInit)
+ {
+ mTSBStore->Delete(removedFragment->GetInitFragData()->GetUrl());
+ }
+ return removedFragment;
+}
+
/**
* @brief Monitors the write queue and writes any pending data to AAMP TSB
*/
@@ -396,13 +414,13 @@ void AampTSBSessionManager::ProcessWriteQueue()
}
else
{
- TsbFragmentDataPtr removedFragment = GetTsbDataManager(mediatype)->RemoveFragment();
+ TsbFragmentDataPtr removedFragment = RemoveFragmentDeleteInit(mediatype);
if (removedFragment)
{
UpdateTotalStoreDuration(mediatype, -removedFragment->GetDuration());
std::string removedFragmentUrl = removedFragment->GetUrl();
mTSBStore->Delete(removedFragmentUrl);
- AAMPLOG_INFO("[%s] Removed %.02lf sec, Position: %.02lf ,pts %.02lf, Url : %s", GetMediaTypeName(mediatype), removedFragment->GetDuration(), removedFragment->GetPosition(), removedFragment->GetPTS(), removedFragmentUrl.c_str());
+ AAMPLOG_INFO("[%s] Removed %.02lf sec, AbsPosition: %.02lfs ,pts %.02lf, Url : %s", GetMediaTypeName(mediatype), removedFragment->GetDuration(), removedFragment->GetAbsPosition(), removedFragment->GetPTS(), removedFragmentUrl.c_str());
}
}
UnlockReadMutex();
@@ -511,7 +529,7 @@ double AampTSBSessionManager::CullSegments()
if (!skip)
{
// Remove the oldest segment
- TsbFragmentDataPtr removedFragment = GetTsbDataManager(mediaTypeToRemove)->RemoveFragment();
+ TsbFragmentDataPtr removedFragment = RemoveFragmentDeleteInit(mediaTypeToRemove);
if (removedFragment)
{
double durationInSeconds = removedFragment->GetDuration();
@@ -521,7 +539,7 @@ double AampTSBSessionManager::CullSegments()
UnlockReadMutex();
mTSBStore->Delete(removedFragmentUrl);
LockReadMutex();
- AAMPLOG_INFO("[%s] Removed %lf fragment duration seconds, Url: %s, Position: %lf, pts %lf", GetMediaTypeName(mediaTypeToRemove), durationInSeconds, removedFragmentUrl.c_str(), removedFragment->GetPosition(), removedFragment->GetPTS());
+ AAMPLOG_INFO("[%s] Removed %lf fragment duration seconds, Url: %s, AbsPosition: %lf, pts %lf", GetMediaTypeName(mediaTypeToRemove), durationInSeconds, removedFragmentUrl.c_str(), removedFragment->GetAbsPosition(), removedFragment->GetPTS());
// Update total stored duration
UpdateTotalStoreDuration(mediaTypeToRemove, -durationInSeconds);
@@ -709,7 +727,7 @@ void AampTSBSessionManager::SkipFragment(std::shared_ptr& reader,
double skippedDuration = 0.0;
if(eMEDIATYPE_VIDEO == reader->GetMediaType())
{
- double startPos = nextFragmentData->GetPosition();
+ double startPos = nextFragmentData->GetAbsPosition();
int vodTrickplayFPS = mAamp->mConfig->GetConfigValue(eAAMPConfig_VODTrickPlayFPS);
float rate = reader->GetPlaybackRate();
double delta = 0.0;
@@ -736,7 +754,7 @@ void AampTSBSessionManager::SkipFragment(std::shared_ptr& reader,
if (nextFragmentData)
{
AAMPLOG_INFO("Skipped frames [rate=%.02f] from %.02lf to %.02lf total duration = %.02lf",
- rate, startPos, nextFragmentData->GetPosition(), skippedDuration);
+ rate, startPos, nextFragmentData->GetAbsPosition(), skippedDuration);
}
else
{
@@ -751,7 +769,7 @@ void AampTSBSessionManager::SkipFragment(std::shared_ptr& reader,
*
* @param[in] MediaStreamContext of appropriate track
* @return bool - true if success
- * @brief Fetches and caches audio fragment parallelly for video fragment.
+ * @brief Fetches and caches audio fragment in parallel with video fragment.
*/
bool AampTSBSessionManager::PushNextTsbFragment(MediaStreamContext *pMediaStreamContext)
{
@@ -777,9 +795,14 @@ bool AampTSBSessionManager::PushNextTsbFragment(MediaStreamContext *pMediaStream
ret = true;
TsbInitDataPtr initFragmentData = nextFragmentData->GetInitFragData();
double bandwidth = initFragmentData->GetBandWidth();
- AAMPLOG_INFO("Profile Changed : %d : CurrentBandwidth: %.02lf Previous Bandwidth: %.02lf",(bandwidth != reader->mCurrentBandwidth),bandwidth,reader->mCurrentBandwidth);
- if((reader->IsDiscontinuous()) || (reader->IsPeriodBoundary()) || isFirstDownload || bandwidth != reader->mCurrentBandwidth)
+ AAMPLOG_INFO("[%s] Inject init fragment: %d CurrentBandwidth: %.02lf Previous Bandwidth: %.02lf IsDiscontinuous: %d IsPeriodBoundary: %d IsFirstDownload: %d",
+ GetMediaTypeName(mediaType), (reader->mLastInitFragmentData.get() != initFragmentData.get()),
+ bandwidth, reader->mCurrentBandwidth, reader->IsDiscontinuous(), reader->IsPeriodBoundary(), isFirstDownload);
+ if (reader->mLastInitFragmentData != initFragmentData)
{
+ AAMPLOG_TRACE("[%s] Previous init fragment data is different from current init fragment data, injecting", GetMediaTypeName(mediaType));
+ reader->mLastInitFragmentData = initFragmentData;
+
CachedFragmentPtr initFragment = Read(initFragmentData);
if (initFragment)
{
@@ -799,6 +822,10 @@ bool AampTSBSessionManager::PushNextTsbFragment(MediaStreamContext *pMediaStream
reader->mCurrentBandwidth = bandwidth; // Update bandwidth
}
}
+ else
+ {
+ AAMPLOG_WARN("[%s] Failed to read next fragment", GetMediaTypeName(mediaType));
+ }
if (ret && nextFragmentData)
{
@@ -806,24 +833,22 @@ bool AampTSBSessionManager::PushNextTsbFragment(MediaStreamContext *pMediaStream
CachedFragmentPtr nextFragment = Read(nextFragmentData, pts);
if (nextFragment)
{
- pMediaStreamContext->downloadedDuration = mAamp->culledSeconds + ((nextFragmentData->GetPosition() - GetTsbDataManager(mediaType)->GetFirstFragmentPosition()) + nextFragmentData->GetDuration());
+ pMediaStreamContext->downloadedDuration = mAamp->culledSeconds + ((nextFragmentData->GetAbsPosition() - GetTsbDataManager(mediaType)->GetFirstFragmentPosition()) + nextFragmentData->GetDuration());
// Slow motion is like a normal playback with audio (volume set to 0) and handled in GST layer with SetPlaybackRate
if(mAamp->IsIframeExtractionEnabled() && AAMP_NORMAL_PLAY_RATE != rate && AAMP_RATE_PAUSE != rate && eMEDIATYPE_VIDEO == mediaType && AAMP_SLOWMOTION_RATE != rate )
{
if(!mIsoBmffHelper->ConvertToKeyFrame(nextFragment->fragment))
{
- AAMPLOG_ERR("Failed to generate iFrame track from video track at %lf", nextFragmentData->GetPosition());
+ AAMPLOG_ERR("Failed to generate iFrame track from video track at %lf", nextFragmentData->GetAbsPosition());
}
}
UnlockReadMutex();
- nextFragment->position = pts;/*Update the fragment absolute position as PTS for injection,as the PTS value is required for overriding events in qtdemux.*/
-
ret = pMediaStreamContext->CacheTsbFragment(nextFragment);
LockReadMutex();
}
else
{
- AAMPLOG_ERR("[%s] Failed to fetch fragment at %lf", GetMediaTypeName(mediaType), nextFragmentData->GetPosition());
+ AAMPLOG_ERR("[%s] Failed to fetch fragment at %lf", GetMediaTypeName(mediaType), nextFragmentData->GetAbsPosition());
ret = false;
}
}
diff --git a/AampTSBSessionManager.h b/AampTSBSessionManager.h
index 1f2058c..92f921d 100644
--- a/AampTSBSessionManager.h
+++ b/AampTSBSessionManager.h
@@ -254,6 +254,13 @@ class AampTSBSessionManager
mDataManagers[mediaType].second += durationInSeconds;
}
+ /**
+ * @brief Remove fragment from list and delete init fragment from TSB store if nolonger referenced
+ * @param[in] mediaType - track type
+ * @return shared ptr to fragment removed is any
+ */
+ TsbFragmentDataPtr RemoveFragmentDeleteInit(AampMediaType mediatype);
+
bool mInitialized_;
std::atomic_bool mStopThread_; // This variable is atomic because it can be accessed from multiple threads
diff --git a/AampTsbDataManager.cpp b/AampTsbDataManager.cpp
index 1c292f9..a030698 100644
--- a/AampTsbDataManager.cpp
+++ b/AampTsbDataManager.cpp
@@ -42,7 +42,7 @@ class DebugTimeData
{
auto endTime = std::chrono::steady_clock::now();
std::chrono::duration duration = endTime - creationTime;
- AAMPLOG_WARN("API: %s Taken time: %.02lf ", apiName.c_str(), duration.count() * 1000);
+ AAMPLOG_MIL("API: %s Taken time: %.02lf ", apiName.c_str(), duration.count() * 1000);
}
};
@@ -108,7 +108,7 @@ TsbFragmentDataPtr AampTsbDataManager::GetNearestFragment(double position)
/**
* @brief RemoveFragment - remove fragment from the top
*/
-TsbFragmentDataPtr AampTsbDataManager::RemoveFragment()
+TsbFragmentDataPtr AampTsbDataManager::RemoveFragment(bool &deleteInit)
{
TSB_DM_TIME_DATA();
TsbFragmentDataPtr deletedFragment = nullptr;
@@ -123,7 +123,8 @@ TsbFragmentDataPtr AampTsbDataManager::RemoveFragment()
initData->decrementUser();
if (initData->GetUsers() <= 0)
{
- AAMPLOG_INFO("Removing Init fragment of BW( %" BITSPERSECOND_FORMAT ") since no more cached fragment using it", initData->GetBandWidth());
+ AAMPLOG_INFO("Removing Init fragment of BW( %" BITSPERSECOND_FORMAT ")", initData->GetBandWidth());
+ deleteInit = true;
mTsbInitData.remove(initData);
}
if (deletedFragment->next)
@@ -257,7 +258,7 @@ double AampTsbDataManager::GetFirstFragmentPosition()
std::lock_guard lock(mTsbDataMutex);
if (!mTsbFragmentData.empty())
{
- pos = mTsbFragmentData.begin()->second->GetPosition();
+ pos = mTsbFragmentData.begin()->second->GetAbsPosition();
}
return pos;
}
@@ -305,7 +306,7 @@ double AampTsbDataManager::GetLastFragmentPosition()
std::lock_guard lock(mTsbDataMutex);
if (!mTsbFragmentData.empty())
{
- pos = (std::prev(mTsbFragmentData.end()))->second->GetPosition();
+ pos = (std::prev(mTsbFragmentData.end()))->second->GetAbsPosition();
}
return pos;
}
@@ -358,12 +359,11 @@ bool AampTsbDataManager::AddFragment(TSBWriteData &writeData, AampMediaType medi
AAMPLOG_WARN("Inserting fragment at %.02lf but init header information is missing !!!", position);
return ret;
}
- AAMPLOG_INFO("[%s] Adding fragment data: position %.02lfs duration %.02lfs pts %.02lfs relativePos %.02lfs bandwidth %" BITSPERSECOND_FORMAT " discontinuous %d periodId %s timeScale %u ptsOffset %fs fragmentUrl '%s' initHeaderUrl '%s'",
- GetMediaTypeName(media), position, duration, pts, mRelativePos, mCurrentInitData->GetBandWidth(), discont, periodId.c_str(), timeScale, PTSOffsetSec,
+ AAMPLOG_INFO("[%s] Adding fragment data: position %.02lfs duration %.02lfs pts %.02lfs bandwidth %" BITSPERSECOND_FORMAT " discontinuous %d periodId %s timeScale %u ptsOffset %fs fragmentUrl '%s' initHeaderUrl '%s'",
+ GetMediaTypeName(media), position, duration, pts, mCurrentInitData->GetBandWidth(), discont, periodId.c_str(), timeScale, PTSOffsetSec,
url.c_str(), mCurrentInitData->GetUrl().c_str());
mCurrentInitData->incrementUser();
- TsbFragmentDataPtr fragmentData = std::make_shared(url, media, position, duration, pts, discont, mRelativePos, periodId, mCurrentInitData, timeScale, PTSOffsetSec);
- mRelativePos += duration;
+ TsbFragmentDataPtr fragmentData = std::make_shared(url, media, position, duration, pts, discont, periodId, mCurrentInitData, timeScale, PTSOffsetSec);
if (mCurrHead != nullptr)
{
fragmentData->prev = mCurrHead;
@@ -398,8 +398,8 @@ bool AampTsbDataManager::DumpData()
{
TsbFragmentDataPtr fragmentData = it->second;
TsbInitDataPtr initdata = fragmentData->GetInitFragData();
- AAMPLOG_INFO("Fragment Meta Data: { Media [%d] position : %.02lf duration: %.02lf PTS : %.02lf bandwidth: %" BITSPERSECOND_FORMAT " discontinuous: %d fragmentUrl: '%s' initHeaderUrl: '%s' }",
- fragmentData->GetMediaType(), fragmentData->GetPosition(), fragmentData->GetDuration(), fragmentData->GetPTS(),
+ AAMPLOG_INFO("Fragment Meta Data: { Media [%d] absPosition : %.02lf duration: %.02lf PTS : %.02lf bandwidth: %" BITSPERSECOND_FORMAT " discontinuous: %d fragmentUrl: '%s' initHeaderUrl: '%s' }",
+ fragmentData->GetMediaType(), fragmentData->GetAbsPosition(), fragmentData->GetDuration(), fragmentData->GetPTS(),
initdata->GetBandWidth(), fragmentData->IsDiscontinuous(), fragmentData->GetUrl().c_str(), initdata->GetUrl().c_str());
}
}
@@ -451,11 +451,11 @@ TsbFragmentDataPtr AampTsbDataManager::GetNextDiscFragment(double position, bool
try
{
auto segment = mTsbFragmentData.lower_bound(position);
- if (!backwardSearch)
+ if (!backwardSearch)
{
while( segment != mTsbFragmentData.end())
{
- if (segment->second->IsDiscontinuous())
+ if (segment->second->IsDiscontinuous())
{
fragment = segment->second;
break;
diff --git a/AampTsbDataManager.h b/AampTsbDataManager.h
index 26f1a98..82e7662 100644
--- a/AampTsbDataManager.h
+++ b/AampTsbDataManager.h
@@ -94,12 +94,12 @@ class TsbInitData : public TsbSegment
public:
/**
* @fn incrementUser
- * @return Increment count of fragments used
+ * @brief Increment count of fragments used
*/
void incrementUser() { users++; };
/**
* @fn decrementUser
- * @return decrement count of fragments used
+ * @brief Decrement count of fragments used
*/
void decrementUser() { users--; };
/**
@@ -124,19 +124,22 @@ class TsbInitData : public TsbSegment
/**
* @fn GetBandWidth
- * @return double bandwidth information
+ * @brief Get the bandwidth information
+ * @return Bandwidth information in bits per second
*/
BitsPerSecond GetBandWidth() { return fragStreamInfo.bandwidthBitsPerSecond; }
/**
* @fn GetCacheFragStreamInfo
- * @return StreamInfo Fragment stream info
+ * @brief Get the cached fragment stream info
+ * @return Fragment stream info
*/
const StreamInfo& GetCacheFragStreamInfo() { return fragStreamInfo; }
/**
* @fn GetProfileIndex
- * @return int ABR profile index
+ * @brief Get ABR profile index
+ * @return ABR profile index
*/
int GetProfileIndex() { return profileIndex; }
@@ -155,11 +158,10 @@ class TsbInitData : public TsbSegment
class TsbFragmentData : public TsbSegment
{
private:
- double position; /**< absolute position of the current fragment, in seconds since 1970 */
+ double absolutePositionS; /**< absolute position of the current fragment, in seconds since 1970 */
double duration; /**< duration of the current fragment*/
- double mPTS; /**< PTS of the current fragment*/
+ double mPTS; /**< PTS of the current fragment in seconds before applying PTS offset, i.e. ISO BMFF baseMediaDecodeTime / timescale */
bool isDiscontinuous; /**< the current fragment is discontinuous*/
- double relativePosition; /**< Relative position from start*/
std::shared_ptr initFragData; /**< init Fragment of the current fragment*/
uint32_t timeScale; /**< timescale of the current fragment */
double PTSOffsetSec; /**< PTS offset of the current fragment */
@@ -172,20 +174,19 @@ class TsbFragmentData : public TsbSegment
* @fn constructor
* @param[in] url - Segment URL as string
* @param[in] media - Segment type as AampMediaType
- * @param[in] position - absolute position of the current fragment, in seconds since 1970
+ * @param[in] absolutePositionS - absolute position of the current fragment, in seconds since 1970
* @param[in] duration - duration of the current fragment
- * @param[in] pts - PTS of the current fragment
+ * @param[in] pts - PTS of the current fragment in seconds before applying PTS offset, i.e. ISO BMFF baseMediaDecodeTime / timescale
* @param[in] disc - discontinuity flag
- * @param[in] relativePos - Relative position
* @param[in] prId - Period Id of the fragment
* @param[in] initData - Pointer to initData
* @param[in] timeScale - timescale of the current fragment
* @param[in] PTSOffsetSec - PTS offset of the current fragment
*/
- TsbFragmentData(std::string url, AampMediaType media, double position, double duration, double pts, bool disc, double relativePos,
+ TsbFragmentData(std::string url, AampMediaType media, double absolutePositionS, double duration, double pts, bool disc,
std::string prId, std::shared_ptr initData, uint32_t timeScale, double PTSOffsetSec)
- : TsbSegment(url, media, prId), position(position), duration(duration), mPTS(pts), isDiscontinuous(disc), initFragData(initData),
- relativePosition(relativePos), timeScale(timeScale), PTSOffsetSec(PTSOffsetSec)
+ : TsbSegment(url, media, prId), absolutePositionS(absolutePositionS), duration(duration), mPTS(pts), isDiscontinuous(disc), initFragData(initData),
+ timeScale(timeScale), PTSOffsetSec(PTSOffsetSec)
{
}
@@ -203,11 +204,11 @@ class TsbFragmentData : public TsbSegment
std::shared_ptr GetInitFragData() const { return initFragData; }
/**
- * @fn GetPosition
+ * @fn GetAbsPosition
*
* @return absolute position of the current fragment, in seconds since 1970
*/
- double GetPosition() const { return position; }
+ double GetAbsPosition() const { return absolutePositionS; }
/**
* @fn GetPTS
@@ -216,13 +217,6 @@ class TsbFragmentData : public TsbSegment
*/
double GetPTS() const { return mPTS; }
- /**
- * @fn GetRelativePosition
- *
- * @return Query the relative position of fragment
- */
- double GetRelativePosition() const { return relativePosition; }
-
/**
* @fn GetDuration
*
@@ -336,9 +330,10 @@ class AampTsbDataManager
/**
* @fn RemoveFragment
+ * @param[in,out] deleteInit - True if init segment was removed as well
* @return Shared pointer to removed fragment
*/
- std::shared_ptr RemoveFragment();
+ std::shared_ptr RemoveFragment(bool &deleteInit);
/**
* @fn RemoveFragments
diff --git a/AampTsbReader.cpp b/AampTsbReader.cpp
index 03e57ef..917b6d0 100644
--- a/AampTsbReader.cpp
+++ b/AampTsbReader.cpp
@@ -36,7 +36,7 @@ AampTsbReader::AampTsbReader(PrivateInstanceAAMP *aamp, std::shared_ptrGetPosition() < startPosSec)
+ if (lastFragment->GetAbsPosition() < startPosSec)
{
// Handle seek out of range
- AAMPLOG_WARN("[%s] Seeking to the TSB End: %lfs (Requested:%lfs), Range:(%lfs-%lfs) tunetype:%d", GetMediaTypeName(mMediaType), lastFragment->GetPosition(), startPosSec, firstFragment->GetPosition(), lastFragment->GetPosition(), mActiveTuneType);
- requestedPosition = lastFragment->GetPosition();
+ AAMPLOG_WARN("[%s] Seeking to the TSB End: %lfs (Requested:%lfs), Range:(%lfs-%lfs) tunetype:%d", GetMediaTypeName(mMediaType), lastFragment->GetAbsPosition(), startPosSec, firstFragment->GetAbsPosition(), lastFragment->GetAbsPosition(), mActiveTuneType);
+ requestedPosition = lastFragment->GetAbsPosition();
}
else
{
@@ -115,7 +115,7 @@ AAMPStatusType AampTsbReader::Init(double &startPosSec, float rate, TuneType tun
}
if (nullptr != firstFragmentToFetch)
{
- mStartPosition = firstFragmentToFetch->GetPosition();
+ mStartPosition = firstFragmentToFetch->GetAbsPosition();
// Assign upcoming position as start position
mUpcomingFragmentPosition = mStartPosition;
mCurrentRate = rate;
@@ -130,9 +130,9 @@ AAMPStatusType AampTsbReader::Init(double &startPosSec, float rate, TuneType tun
}
// Save First PTS
mFirstPTS = firstFragmentToFetch->GetPTS();
- AAMPLOG_INFO("[%s] startPosition:%lfs rate:%f pts:%lfs Range:(%lfs-%lfs)", GetMediaTypeName(mMediaType), mStartPosition, mCurrentRate, mFirstPTS, firstFragment->GetPosition(), lastFragment->GetPosition());
+ AAMPLOG_INFO("[%s] startPosition:%lfs rate:%f pts:%lfs Range:(%lfs-%lfs)", GetMediaTypeName(mMediaType), mStartPosition, mCurrentRate, mFirstPTS, firstFragment->GetAbsPosition(), lastFragment->GetAbsPosition());
mInitialized_ = true;
- startPosSec = firstFragmentToFetch->GetPosition();
+ startPosSec = firstFragmentToFetch->GetAbsPosition();
}
else
{
@@ -187,7 +187,7 @@ std::shared_ptr AampTsbReader::ReadNext()
}
// Error Handling
// We are skipping one fragment if not found based on the rate
- if (mCurrentRate > 0 && (ret->GetPosition() + FLOATING_POINT_EPSILON) < mUpcomingFragmentPosition)
+ if (mCurrentRate > 0 && (ret->GetAbsPosition() + FLOATING_POINT_EPSILON) < mUpcomingFragmentPosition)
{
// Forward rate
// Nearest fragment behind mUpcomingFragmentPosition calculated based of last fragment info
@@ -195,7 +195,7 @@ std::shared_ptr AampTsbReader::ReadNext()
// Therefore, retrieve the next fragment from the linked list if it exists, otherwise, return nullptr.
ret = ret->next;
}
- else if (mCurrentRate < 0 && (ret->GetPosition() - FLOATING_POINT_EPSILON) > mUpcomingFragmentPosition)
+ else if (mCurrentRate < 0 && (ret->GetAbsPosition() - FLOATING_POINT_EPSILON) > mUpcomingFragmentPosition)
{
// Rewinding
// Nearest fragment ahead of mUpcomingFragmentPosition calculated based of last fragment info
@@ -232,15 +232,15 @@ std::shared_ptr AampTsbReader::ReadNext()
CheckPeriodBoundary(ret);
}
mUpcomingFragmentPosition += (mCurrentRate >= 0) ? ret->GetDuration() : -ret->GetDuration();
- AAMPLOG_INFO("[%s] Returning fragment: pos %lfs pts %lfs relativePos %lfs next %lfs eos %d initWaiting %d discontinuity %d mIsPeriodBoundary %d period %s timeScale %u ptsOffset %fs url %s",
- GetMediaTypeName(mMediaType), ret->GetPosition(), ret->GetPTS(), ret->GetRelativePosition(), mUpcomingFragmentPosition, mEosReached, mNewInitWaiting, mIsNextFragmentDisc, mIsPeriodBoundary, ret->GetPeriodId().c_str(), ret->GetTimeScale(), ret->GetPTSOffsetSec(), ret->GetUrl().c_str());
+ AAMPLOG_INFO("[%s] Returning fragment: absPos %lfs pts %lfs next %lfs eos %d initWaiting %d discontinuity %d mIsPeriodBoundary %d period %s timeScale %u ptsOffset %fs url %s",
+ GetMediaTypeName(mMediaType), ret->GetAbsPosition(), ret->GetPTS(), mUpcomingFragmentPosition, mEosReached, mNewInitWaiting, mIsNextFragmentDisc, mIsPeriodBoundary, ret->GetPeriodId().c_str(), ret->GetTimeScale(), ret->GetPTSOffsetSec(), ret->GetUrl().c_str());
return ret;
}
/**
* @fn CheckPeriodBoundary
- *
+ *
* @param[in] currFragment - Current fragment
*/
void AampTsbReader::CheckPeriodBoundary(TsbFragmentDataPtr currFragment)
@@ -264,27 +264,6 @@ void AampTsbReader::CheckPeriodBoundary(TsbFragmentDataPtr currFragment)
}
}
-/**
- * @fn GetStartPosition
- *
- * @return startPosition
- */
-double AampTsbReader::GetStartPosition()
-{
- double ret = 0.0;
- if (mStartPosition >= 0)
- {
- // Take the relative start position based on data manager start
- TsbFragmentDataPtr firstFragmentToFetch = mDataMgr->GetNearestFragment((mStartPosition - FLOATING_POINT_EPSILON));
- if (firstFragmentToFetch)
- {
- ret = firstFragmentToFetch->GetRelativePosition();
- AAMPLOG_INFO("[%s] Data manager current start : %lf, returing start position as %lf", GetMediaTypeName(mMediaType), mDataMgr->GetFirstFragmentPosition(), ret);
- }
- }
- return ret;
-}
-
/**
* @fn Term - function to clear TsbReader states
*/
@@ -301,6 +280,7 @@ void AampTsbReader::Term()
mActiveTuneType = eTUNETYPE_NEW_NORMAL;
mIsPeriodBoundary = false;
mIsEndFragmentInjected.store(false);
+ mLastInitFragmentData = nullptr;
AAMPLOG_INFO("mediaType : %s", GetMediaTypeName(mMediaType));
}
@@ -331,3 +311,21 @@ void AampTsbReader::AbortCheckForWaitIfReaderDone()
mEosCVWait.notify_one();
}
}
+
+ /**
+ * @fn IsFirstDownload
+ * @return True if first download
+ */
+ bool AampTsbReader::IsFirstDownload()
+ {
+ return (mStartPosition == mUpcomingFragmentPosition);
+ }
+
+ /**
+ * @fn GetPlaybackRate
+ * @return Playback rate
+ */
+ float AampTsbReader::GetPlaybackRate()
+ {
+ return mCurrentRate;
+ }
diff --git a/AampTsbReader.h b/AampTsbReader.h
index da7a4cd..1d28ba7 100644
--- a/AampTsbReader.h
+++ b/AampTsbReader.h
@@ -109,7 +109,7 @@ class AampTsbReader
*
* @return bool - true if first download
*/
- bool IsFirstDownload() { return (mStartPosition == mUpcomingFragmentPosition); }
+ bool IsFirstDownload();
/**
* @fn TrackEnabled
@@ -137,7 +137,7 @@ class AampTsbReader
*
* @return float - Playback rate
*/
- float GetPlaybackRate() { return mCurrentRate; }
+ float GetPlaybackRate();
/**
* @fn IsDiscontinuous
@@ -206,6 +206,7 @@ class AampTsbReader
bool mTrackEnabled;
std::shared_ptr mDataMgr;
double mCurrentBandwidth;
+ TsbInitDataPtr mLastInitFragmentData;
};
#endif // AAMP_TSBREADER_H
diff --git a/AampUtils.cpp b/AampUtils.cpp
index 7f35b13..7b62b4e 100644
--- a/AampUtils.cpp
+++ b/AampUtils.cpp
@@ -1314,17 +1314,22 @@ double RecalculatePTS(AampMediaType mediaType, const void *ptr, size_t len, Priv
{
double ret = 0;
uint32_t timeScale = 0;
-
- if(mediaType == eMEDIATYPE_VIDEO)
+ switch( mediaType )
{
+ case eMEDIATYPE_VIDEO:
timeScale = aamp->GetVidTimeScale();
- }
- else if(mediaType == eMEDIATYPE_AUDIO || mediaType == eMEDIATYPE_AUX_AUDIO)
- {
+ break;
+ case eMEDIATYPE_AUDIO:
+ case eMEDIATYPE_AUX_AUDIO:
timeScale = aamp->GetAudTimeScale();
+ break;
+ case eMEDIATYPE_SUBTITLE:
+ timeScale = aamp->GetSubTimeScale();
+ break;
+ default:
+ AAMPLOG_WARN("Invalid media type %d", mediaType);
+ break;
}
-
-
IsoBmffBuffer isobuf;
isobuf.setBuffer((uint8_t *)ptr, len);
bool bParse = false;
@@ -1351,7 +1356,6 @@ double RecalculatePTS(AampMediaType mediaType, const void *ptr, size_t len, Priv
if (bParse)
{
ret = fPts/(timeScale*1.0);
- AAMPLOG_TRACE("restamped PTS : %lf", ret);
}
}
return ret;
@@ -1487,6 +1491,33 @@ bool parseAndValidateSCTE35(const std::string &scte35Data)
}
return isValidDAIEvent;
}
+
+/**
+ * Hack to check if code is running in container environment.
+ * @return True if running in container environment, false otherwise.
+ */
+bool IsContainerEnvironment(void)
+{
+ static bool isContainer;
+ static bool isValid;
+ if( !isValid )
+ {
+ struct stat buffer;
+ if (stat("/etc/device.properties", &buffer) == 0)
+ { // if we can access file, infer that are are NOT running in container
+ AAMPLOG_MIL("not running in container environment");
+ isContainer = false;
+ }
+ else
+ { // if we cannot access file, infer that we ARE running in container
+ AAMPLOG_WARN("detected container environment");
+ isContainer = true;
+ }
+ isValid = true;
+ }
+ return isContainer;
+}
+
/**
* EOF
*/
diff --git a/AampUtils.h b/AampUtils.h
index f11983d..dfc7af9 100644
--- a/AampUtils.h
+++ b/AampUtils.h
@@ -377,5 +377,13 @@ std::string aamp_GetConfigPath( const std::string &filename );
*/
bool parseAndValidateSCTE35(const std::string &scte35Data);
+/**
+ * Temp function to check if code is running in container environment.
+ * This needs to be removed proper support for functions in container Environment available.
+ *
+ * @param None
+ * @return True if running in container environment, false otherwise.
+ */
+bool IsContainerEnvironment(void);
#endif /* __AAMP_UTILS_H__ */
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c5c8b2a..def6708 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -384,7 +384,7 @@ if(CMAKE_USE_SECMANAGER)
endif()
endif()
-execute_process(COMMAND bash "-c" "${CMAKE_SOURCE_DIR}/buildinfo.sh" OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE buildinfo)
+execute_process(COMMAND bash "-c" "${CMAKE_SOURCE_DIR}/buildinfo.sh" WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_VARIABLE buildinfo)
string(REGEX REPLACE "\n" "-" buildinfo "${buildinfo}")
message("build: ${buildinfo}")
set(LIBAAMP_DEFINES "${LIBAAMP_DEFINES} -DAAMP_VANILLA_AES_SUPPORT ${USE_MAC_FOR_RANDOM_GEN}")
diff --git a/MediaStreamContext.cpp b/MediaStreamContext.cpp
index 5c57dcd..16515de 100644
--- a/MediaStreamContext.cpp
+++ b/MediaStreamContext.cpp
@@ -83,17 +83,18 @@ bool MediaStreamContext::CacheFragment(std::string fragmentUrl, unsigned int cur
{
// apply pts offset to position which ends up getting put into gst_buffer in sendHelper
position += GetContext()->mPTSOffset.inSeconds();
+ AAMPLOG_INFO("Type[%d] position after restamp = %fs", type, position);
}
AampTSBSessionManager *tsbSessionManager = aamp->GetTSBSessionManager();
auto CheckEos = [this, &tsbSessionManager, &actualType]() {
- return tsbSessionManager &&
- aamp->IsLocalAAMPTsbInjection() &&
- IsLocalTSBInjection() &&
- AAMP_NORMAL_PLAY_RATE == aamp->rate &&
- eTUNETYPE_SEEKTOLIVE == context->mTuneType &&
- tsbSessionManager->GetTsbReader((AampMediaType)type) &&
- tsbSessionManager->GetTsbReader((AampMediaType)type)->IsEos();
+ return IsLocalTSBInjection() &&
+ AAMP_NORMAL_PLAY_RATE == aamp->rate &&
+ !aamp->pipeline_paused &&
+ eTUNETYPE_SEEKTOLIVE == context->mTuneType &&
+ tsbSessionManager &&
+ tsbSessionManager->GetTsbReader((AampMediaType)type) &&
+ tsbSessionManager->GetTsbReader((AampMediaType)type)->IsEos();
};
if(initSegment && discontinuity )
@@ -380,14 +381,12 @@ bool MediaStreamContext::CacheFragment(std::string fragmentUrl, unsigned int cur
CacheTsbFragment(fragmentToTsbSessionMgr);
SetLocalTSBInjection(false);
}
- else if(fragmentToTsbSessionMgr->initFragment && !IsLocalTSBInjection())
+ else if(fragmentToTsbSessionMgr->initFragment && !IsLocalTSBInjection() && !aamp->pipeline_paused)
{
// Insert init fragment through chunk injector
CacheTsbFragment(fragmentToTsbSessionMgr);
}
}
- fragmentToTsbSessionMgr->position = posInAbsTimeline; // Need to store the fragment with absolute position
-
tsbSessionManager->EnqueueWrite(fragmentUrl, fragmentToTsbSessionMgr, context->GetPeriod()->GetId());
}
// Added the duplicate conditional statements, to log only for localAAMPTSB cases.
@@ -407,14 +406,26 @@ bool MediaStreamContext::CacheFragment(std::string fragmentUrl, unsigned int cur
fragmentToTsbSessionMgr->cacheFragStreamInfo.bandwidthBitsPerSecond = fragmentDescriptor.Bandwidth;
CacheTsbFragment(fragmentToTsbSessionMgr);
}
- UpdateTSAfterFetch(initSegment);
- // When injection is from the CachedFragmentChunks buffer, need to update cachedFragments here to remove
- // the fragment from the buffer.
- if(IsInjectionFromCachedFragmentChunks())
+ // If playing back from local TSB, or pending playing back from local TSB as paused
+ if (tsbSessionManager && (IsLocalTSBInjection() || aamp->pipeline_paused))
+ {
+ AAMPLOG_TRACE("Skip notifying fragment fetch");
+ // Free the memory
+ cachedFragment->fragment.Free();
+ }
+ else
{
- UpdateTSAfterInject();
+ // Update buffer index after fetch for injection
+ UpdateTSAfterFetch(initSegment);
+
+ // If injection is from chunk buffer, remove the fragment for injection
+ if(IsInjectionFromCachedFragmentChunks())
+ {
+ UpdateTSAfterInject();
+ }
}
+
ret = true;
}
return ret;
diff --git a/README.md b/README.md
index 9660bac..e5b4832 100644
--- a/README.md
+++ b/README.md
@@ -162,7 +162,7 @@ bufferHealthMonitorInterval Override for buffer health monitor interval(in secs)
abrCacheLife Lifetime value (ms) for abr cache for network bandwidth calculation. Default: 5000ms
abrCacheLength Length of abr cache for network bandwidth calculation (# of segments. Default 3
abrCacheOutlier Outlier difference which will be ignored from network bandwidth calculation. Default: 5MB (in bytes)
-abrNwConsistency Number of checks before profile incr/decr by 1.This is to avoid frequent profile switching with network change: Default 2
+abrNwConsistency Number of checks before profile increment/decrement by 1.This is to avoid frequent profile switching with network change: Default 2
abrSkipDuration Minimum duration of fragment to be downloaded before triggering abr. Default: 6s
progressReportingInterval Interval (seconds) for progress reporting(in seconds. Default: 1
licenseRetryWaitTime License retry wait (ms) interval. Default: 500
@@ -347,12 +347,11 @@ bps Set video bitrate in bps
fog 'fog url' tune to arbitrary locator via fog. 'fog host=ip:port' set fog location (default: 127.0.0.1:9080)
adtesting Toggle indexed ad insertion that does NOT check for any duration match
advert
- advert add (index and duration optional -> index of adbreak , possible to add multiple ads to same index to insert multiple into same adbreak)
- advert add ( index and duration optional , add a url from the virtual channel map, if given channel number exists , at index)
- advert rm (remove a matching url)
- advert rm (remove the url at the given index)
- advert clear (clear current ad map)
- advert list (display the advert list)
+ advert map
+ specify ad locator to present instead of source content during specified ad break
+ note: multiple sequential ads can be mapped to fill a single ad break by calling advert map multiple times with same adBreakId
+ advert clear (clear current advert map)
+ advert list (display the advert list)
new create a new player instance with optional name
select move player val or name to foreground. With no option list all players
detach move current foreground player to background
@@ -428,11 +427,11 @@ in version 1.0,
in version 2.0
S = Session summary
200 = http success
- 18(0) - Curl 18 occured, network connectivity is down
- 18(1) = Curl 18 occured, network connectivity is up
- 28(0) - Curl 28 occured, network connectivity is down
- 28(1) = Curl 28 occured, network connectivity is up
- 404, 42, 7, etc.. = http/curl error code occured during download.
+ 18(0) - Curl 18 occurred, network connectivity is down
+ 18(1) = Curl 18 occurred, network connectivity is up
+ 28(0) - Curl 28 occurred, network connectivity is down
+ 28(1) = Curl 28 occurred, network connectivity is up
+ 404, 42, 7, etc.. = http/curl error code occurred during download.
Example : "S":{"200":341,"404":6} - 341 success attempts and 4 attempts with 404
"S":{"200":116,"28(1)":1,"404":114} - 115 success attempts, 114 attempts with 404 and 1 attempt with curl-28
T0
diff --git a/StreamAbstractionAAMP.h b/StreamAbstractionAAMP.h
index 21f4efc..9a490f3 100644
--- a/StreamAbstractionAAMP.h
+++ b/StreamAbstractionAAMP.h
@@ -220,7 +220,6 @@ class IsoBmffHelper;
class MediaTrack
{
public:
-
/**
* @fn MediaTrack
*
@@ -339,11 +338,11 @@ class MediaTrack
virtual std::string& GetEffectivePlaylistUrl() = 0;
/**
- * @fn SetEffectivePlaylistUrl
- *
- * @param string - original playlist URL
- */
- virtual void SetEffectivePlaylistUrl(std::string url) = 0;
+ * @fn SetEffectivePlaylistUrl
+ *
+ * @param string - original playlist URL
+ */
+ virtual void SetEffectivePlaylistUrl(std::string url) = 0;
/**
* @fn GetLastPlaylistDownloadTime
@@ -401,7 +400,7 @@ class MediaTrack
/**
* @fn Enabled
- * @retval true if enabled, false if disabled
+ * @retval true if enabled, false if disabled
*/
bool Enabled();
@@ -514,7 +513,7 @@ class MediaTrack
* @fn abortWaitForVideoPTS
* @return void
*/
- virtual void abortWaitForVideoPTS() = 0;
+ virtual void abortWaitForVideoPTS() = 0;
/**
* @fn resetPTSOnAudioSwitch
@@ -559,12 +558,12 @@ class MediaTrack
*/
void SetCurrentBandWidth(int bandwidthBps);
- /**
- * @fn GetProfileIndexForBW
- * @param mTsbBandwidth - bandwidth to identify profile index from list
- * @retval profile index of the current bandwidth
- */
- int GetProfileIndexForBW(BitsPerSecond mTsbBandwidth);
+ /**
+ * @fn GetProfileIndexForBW
+ * @param mTsbBandwidth - bandwidth to identify profile index from list
+ * @retval profile index of the current bandwidth
+ */
+ int GetProfileIndexForBW(BitsPerSecond mTsbBandwidth);
/**
* @fn GetCurrentBandWidth
@@ -580,12 +579,12 @@ class MediaTrack
*/
double GetTotalFetchedDuration() { return totalFetchedDuration; };
- /**
- * @brief Get total duration of fetched fragments
- *
- * @return Total duration in seconds
- */
- double GetTotalInjectedChunksDuration() { return totalInjectedChunksDuration; };
+ /**
+ * @brief Get total duration of fetched fragments
+ *
+ * @return Total duration in seconds
+ */
+ double GetTotalInjectedChunksDuration() { return totalInjectedChunksDuration; };
/**
* @brief Check if discontinuity is being processed
@@ -661,6 +660,12 @@ class MediaTrack
*/
void OnSinkBufferFull();
+ /**
+ * @fn FlushFetchedFragments
+ * @return void
+ */
+ void FlushFetchedFragments();
+
/**
* @fn FlushFragments
* @return void
@@ -691,7 +696,7 @@ class MediaTrack
*/
void LoadNewSubtitle(bool val);
-/**
+ /**
* @brief To set Track's Fetch and Inject duration after playlist update
*/
void OffsetTrackParams(double deltaFetchedDuration, double deltaInjectedDuration, int deltaFragmentsDownloaded);
@@ -744,8 +749,13 @@ class MediaTrack
*/
void FlushSubtitlePositionDuringTrackSwitch( CachedFragment* cachedFragment );
-protected:
+ /**
+ * @fn ResetTrickModePtsRestamping
+ * @brief Reset trick mode PTS restamping
+ */
+ void ResetTrickModePtsRestamping(void);
+protected:
/**
* @fn UpdateTSAfterInject
*
@@ -916,7 +926,7 @@ class MediaTrack
std::condition_variable fragmentInjected; /**< Signaled after a fragment is injected*/
std::thread fragmentInjectorThreadID; /**< Fragment injector thread id*/
std::condition_variable fragmentChunkInjected; /**< Signaled after a fragment is injected*/
- std::thread bufferMonitorThreadID; /**< Buffer Monitor thread id */
+ std::thread bufferMonitorThreadID; /**< Buffer Monitor thread id */
std::thread subtitleClockThreadID; /**< subtitle clock synchronisation thread id */
int totalFragmentsDownloaded; /**< Total fragments downloaded since start by track*/
int totalFragmentChunksDownloaded; /**< Total fragments downloaded since start by track*/
@@ -1070,12 +1080,12 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
return 0.0;
}
- /**
- * @brief Returns AvailabilityStartTime from the manifest
- *
- * @retval double . AvailabilityStartTime
- */
- virtual double GetAvailabilityStartTime()
+ /**
+ * @brief Returns AvailabilityStartTime from the manifest
+ *
+ * @retval double . AvailabilityStartTime
+ */
+ virtual double GetAvailabilityStartTime()
{
return 0.0;
}
@@ -1216,7 +1226,7 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
return -1.0;
}
- /**
+ /**
* @fn IsLowestProfile
*
* @param currentProfileIndex - current profile index to be checked.
@@ -1232,7 +1242,7 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
*/
int getOriginalCurlError(int http_error);
- /**
+ /**
* @fn CheckForRampDownProfile
*
* @param http_error - Http error code
@@ -1394,6 +1404,12 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
*/
void SetTrickplayMode(float rate) { trickplayMode = (rate != AAMP_NORMAL_PLAY_RATE); }
+ /**
+ * @fn ResetTrickModePtsRestamping
+ * @brief Reset trick mode PTS restamping
+ */
+ void ResetTrickModePtsRestamping(void);
+
/**
* @fn SetVideoPlaybackRate
* @brief Set the Video playback rate
@@ -1453,14 +1469,15 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
return aamp->mhAbrManager.getProfileCount();
}
- /**
- * @brief Get profile index for TsbBandwidth
- * @param mTsbBandwidth - bandwidth to identify profile index from list
- * @retval profile index of the current bandwidth
- */
- virtual int GetProfileIndexForBandwidth( BitsPerSecond mTsbBandwidth) {
- return aamp->mhAbrManager.getBestMatchedProfileIndexByBandWidth((int)mTsbBandwidth);
- }
+ /**
+ * @brief Get profile index for TsbBandwidth
+ * @param mTsbBandwidth - bandwidth to identify profile index from list
+ * @retval profile index of the current bandwidth
+ */
+ virtual int GetProfileIndexForBandwidth(BitsPerSecond mTsbBandwidth)
+ {
+ return aamp->mhAbrManager.getBestMatchedProfileIndexByBandWidth((int)mTsbBandwidth);
+ }
BitsPerSecond GetCurProfIdxBW(){
return aamp->mhAbrManager.getBandwidthOfProfile(this->currentProfileIndex);
@@ -1716,33 +1733,32 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
return std::vector();
}
- /**
- * @brief Get available thumbnail bitrates.
- *
- * @return available thumbnail bitrates.
- */
- virtual std::vector GetAvailableThumbnailTracks(void)
- { // STUB
- return std::vector();
- }
-
+ /**
+ * @brief Get available thumbnail bitrates.
+ *
+ * @return available thumbnail bitrates.
+ */
+ virtual std::vector GetAvailableThumbnailTracks(void)
+ { // STUB
+ return std::vector();
+ }
- /**
- * @brief Set thumbnail bitrate.
- *
- * @return none.
- */
+ /**
+ * @brief Set thumbnail bitrate.
+ *
+ * @return none.
+ */
virtual bool SetThumbnailTrack(int thumbnailIndex)
{
(void) thumbnailIndex; /* unused */
return false;
}
- /**
- * @brief Get thumbnail data for duration value.
- *
- * @return thumbnail data.
- */
+ /**
+ * @brief Get thumbnail data for duration value.
+ *
+ * @return thumbnail data.
+ */
virtual std::vector GetThumbnailRangeData(double start, double end, std::string *baseurl, int *raw_w, int *raw_h, int *width, int *height)
{
(void)start;
@@ -1756,36 +1772,35 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
return std::vector();
}
+ /**
+ * @brief SetAudioTrack set the audio track using index value. [currently for OTA]
+ *
+ * @param[in] index - Index of audio track
+ * @return void
+ */
+ virtual void SetAudioTrack(int index) {}
- /**
- * @brief SetAudioTrack set the audio track using index value. [currently for OTA]
- *
- * @param[in] index - Index of audio track
- * @return void
- */
- virtual void SetAudioTrack (int index) {}
-
- /**
- * @brief SetAudioTrackByLanguage set the audio language. [currently for OTA]
- *
- * @param[in] lang Language to be set
- * @param[in]
- */
- virtual void SetAudioTrackByLanguage(const char* lang) {}
-
- /**
- * @brief SetPreferredAudioLanguages set the preferred audio languages and rendition. [currently for OTA]
- *
- * @param[in]
- * @param[in]
- */
- virtual void SetPreferredAudioLanguages() {}
-
- /**
- * @fn MuteSubtitles
- *
- * @param[in] mute mute/unmute
- */
+ /**
+ * @brief SetAudioTrackByLanguage set the audio language. [currently for OTA]
+ *
+ * @param[in] lang Language to be set
+ * @param[in]
+ */
+ virtual void SetAudioTrackByLanguage(const char *lang) {}
+
+ /**
+ * @brief SetPreferredAudioLanguages set the preferred audio languages and rendition. [currently for OTA]
+ *
+ * @param[in]
+ * @param[in]
+ */
+ virtual void SetPreferredAudioLanguages() {}
+
+ /**
+ * @fn MuteSubtitles
+ *
+ * @param[in] mute mute/unmute
+ */
void MuteSubtitles(bool mute);
/**
@@ -1796,15 +1811,14 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
void WaitForVideoTrackCatchupForAux();
/**
- * @brief Set Content Restrictions
- * @param[in] restrictions - restrictions to be applied
- *
- * @return void
- */
+ * @brief Set Content Restrictions
+ * @param[in] restrictions - restrictions to be applied
+ *
+ * @return void
+ */
virtual void ApplyContentRestrictions(std::vector restrictions){};
-
- /**
+ /**
* @brief Disable Content Restrictions - unlock
* @param[in] grace - seconds from current time, grace period, grace = -1 will allow an unlimited grace period
* @param[in] time - seconds from current time,time till which the channel need to be kept unlocked
@@ -1814,9 +1828,9 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
virtual void DisableContentRestrictions(long grace, long time, bool eventChange){};
/**
- * @brief Enable Content Restrictions - lock
- * @return void
- */
+ * @brief Enable Content Restrictions - lock
+ * @return void
+ */
virtual void EnableContentRestrictions(){};
/**
@@ -1868,51 +1882,51 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
//Apis for sidecar caption support
/**
- * @brief Initialize subtitle parser for sidecar support
- *
- * @param data - subtitle data received from application
- * @return void
- */
- virtual void InitSubtitleParser(char *data) { };
+ * @brief Initialize subtitle parser for sidecar support
+ *
+ * @param data - subtitle data received from application
+ * @return void
+ */
+ virtual void InitSubtitleParser(char *data) {};
/**
- * @brief reset subtitle parser created for sidecar support
- *
- * @return void
- */
- virtual void ResetSubtitle() { };
+ * @brief reset subtitle parser created for sidecar support
+ *
+ * @return void
+ */
+ virtual void ResetSubtitle() {};
/**
- * @brief mute subtitles on pause
- *
- * @return void
- */
- virtual void MuteSubtitleOnPause() { };
+ * @brief mute subtitles on pause
+ *
+ * @return void
+ */
+ virtual void MuteSubtitleOnPause() {};
/**
- * @brief resume subtitles on play
- *
- * @param mute - mute status
- * @param data - subtitle data received from application
- * @return void
- */
- virtual void ResumeSubtitleOnPlay(bool mute, char *data) { };
+ * @brief resume subtitles on play
+ *
+ * @param mute - mute status
+ * @param data - subtitle data received from application
+ * @return void
+ */
+ virtual void ResumeSubtitleOnPlay(bool mute, char *data) {};
/**
- * @brief mute/unmute sidecar subtitles
- * @param mute - mute/unmute
- *
- * @return void
- */
+ * @brief mute/unmute sidecar subtitles
+ * @param mute - mute/unmute
+ *
+ * @return void
+ */
virtual void MuteSidecarSubtitles(bool mute) { };
/**
- * @brief resume subtitles after trickplay
- *
- * @param mute - mute status
- * @param data - subtitle data received from application
- * @return void
- */
+ * @brief resume subtitles after trickplay
+ *
+ * @param mute - mute status
+ * @param data - subtitle data received from application
+ * @return void
+ */
virtual void ResumeSubtitleAfterSeek(bool mute, char *data) { };
/**
@@ -1988,7 +2002,7 @@ class StreamAbstractionAAMP : public AampLicenseFetcher
// abr variables
long mCurrentBandwidth; /**< stores current bandwidth*/
- int mLastVideoFragCheckedforABR; /**< Last video fragment for which ABR is checked*/
+ int mLastVideoFragCheckedForABR; /**< Last video fragment for which ABR is checked*/
long mTsbBandwidth; /**< stores bandwidth when TSB is involved*/
bool mNwConsistencyBypass; /**< Network consistency bypass**/
int mABRHighBufferCounter; /**< ABR High buffer counter */
diff --git a/aampgstplayer.cpp b/aampgstplayer.cpp
index 35de98c..c0a644f 100644
--- a/aampgstplayer.cpp
+++ b/aampgstplayer.cpp
@@ -89,7 +89,6 @@ static void InitializePlayerConfigs(AAMPGstPlayer *_this, void *playerInstance)
interfacePlayer->m_gstConfigParam->enablePTSReStamp = config->IsConfigSet(eAAMPConfig_EnablePTSReStamp);
interfacePlayer->m_gstConfigParam->seamlessAudioSwitch = config->IsConfigSet(eAAMPConfig_SeamlessAudioSwitch);
interfacePlayer->m_gstConfigParam->videoBufBytes = config->GetConfigValue(eAAMPConfig_GstVideoBufBytes);
- interfacePlayer->m_gstConfigParam->videoBufBytesForFog = config->GetConfigValue(eAAMPConfig_GstVideoBufBytesForFogLive);
interfacePlayer->m_gstConfigParam->platformType = config->GetConfigValue(eAAMPConfig_PlatformType);
interfacePlayer->m_gstConfigParam->noNativeAV = config->IsConfigSet(eAAMPConfig_NoNativeAV);
interfacePlayer->m_gstConfigParam->enableDisconnectSignals = config->IsConfigSet(eAAMPConfig_enableDisconnectSignals);
@@ -97,7 +96,6 @@ static void InitializePlayerConfigs(AAMPGstPlayer *_this, void *playerInstance)
interfacePlayer->m_gstConfigParam->vodTrickModeFPS = config->GetConfigValue(eAAMPConfig_VODTrickPlayFPS);
interfacePlayer->m_gstConfigParam->enableGstPosQuery = config->IsConfigSet(eAAMPConfig_EnableGstPositionQuery);
interfacePlayer->m_gstConfigParam->audioBufBytes = config->GetConfigValue(eAAMPConfig_GstAudioBufBytes);
- interfacePlayer->m_gstConfigParam->audioBufBytesForFog = config->GetConfigValue(eAAMPConfig_GstAudioBufBytesForFogLive);
interfacePlayer->m_gstConfigParam->progressTimer = config->GetConfigValue(eAAMPConfig_ReportProgressInterval);
interfacePlayer->m_gstConfigParam->gstreamerBufferingBeforePlay = config->IsConfigSet(eAAMPConfig_GStreamerBufferingBeforePlay);
interfacePlayer->m_gstConfigParam->seiTimeCode = config->IsConfigSet(eAAMPConfig_SEITimeCode);
@@ -109,7 +107,6 @@ static void InitializePlayerConfigs(AAMPGstPlayer *_this, void *playerInstance)
interfacePlayer->m_gstConfigParam->framesToQueue = config->GetConfigValue(eAAMPConfig_RequiredQueuedFrames);
interfacePlayer->m_gstConfigParam->monitorAV = config->IsConfigSet(eAAMPConfig_MonitorAV);
interfacePlayer->m_gstConfigParam->disableUnderflow = config->IsConfigSet(eAAMPConfig_DisableUnderflow);
- interfacePlayer->m_gstConfigParam->tsbEnabled = _this->aamp->mTSBEnabled;
interfacePlayer->m_gstConfigParam->audioDecoderStreamSync = _this->aamp->mAudioDecoderStreamSync;
interfacePlayer->m_gstConfigParam->audioOnlyMode = _this->aamp->mAudioOnlyPb;
interfacePlayer->m_gstConfigParam->gstreamerSubsEnabled = _this->aamp->IsGstreamerSubsEnabled();
@@ -1252,7 +1249,7 @@ bool AAMPGstPlayer::SetTextStyle(const std::string &options)
bool AAMPGstPlayer::SignalSubtitleClock( void )
{
bool signalSent=false;
- signalSent = playerInstance->SignalSubtitleClock(aamp->GetVideoPTS(), aamp->GetBufUnderFlowStatus());
+ signalSent = playerInstance->SignalSubtitleClock(GetVideoPTS(), aamp->GetBufUnderFlowStatus());
return signalSent;
}
diff --git a/admanager_mpd.cpp b/admanager_mpd.cpp
index b218435..349d4b7 100644
--- a/admanager_mpd.cpp
+++ b/admanager_mpd.cpp
@@ -59,7 +59,7 @@ void CDAIObjectMPD::SetAlternateContents(const std::string &periodId, const std:
* @brief PrivateCDAIObjectMPD constructor
*/
PrivateCDAIObjectMPD::PrivateCDAIObjectMPD(PrivateInstanceAAMP* aamp) : mAamp(aamp),mDaiMtx(), mIsFogTSB(false), mAdBreaks(), mPeriodMap(), mCurPlayingBreakId(), mAdObjThreadID(), mCurAds(nullptr),
- mCurAdIdx(-1), mContentSeekOffset(0), mAdState(AdState::OUTSIDE_ADBREAK),mPlacementObj(), mAdFulfillObj(),mAdObjThreadStarted(false),mImmediateNextAdbreakAvailable(false),currentAdPeriodClosed(false),mAdtoInsertInNextBreakVec(),
+ mCurAdIdx(-1), mContentSeekOffset(0), mAdState(AdState::OUTSIDE_ADBREAK),mPlacementObj(), mAdFulfillObj(),mAdObjThreadStarted(false),currentAdPeriodClosed(false),mAdtoInsertInNextBreakVec(),
mAdBrkVecMtx(), mAdFulfillMtx(), mAdFulfillCV(), mAdFulfillQ(), mExitFulfillAdLoop(false), mAdPlacementMtx(), mAdPlacementCV()
{
StartFulfillAdLoop();
@@ -130,7 +130,7 @@ void PrivateCDAIObjectMPD::PrunePeriodMaps(std::vector &newPeriodId
SAFE_DELETE(ad.mpd);
}
}
- ErasefrmAdBrklist(it->first);
+ RemovePlacementObj(it->first);
it = mAdBreaks.erase(it);
}
else
@@ -191,15 +191,20 @@ void PrivateCDAIObjectMPD::ClearMaps()
}
/**
- * @brief Method to create a bidirectional between the ads and the underlying content periods
+ * @brief Places ads using the provided AampMPDParseHelper object.
+ * This function is responsible for placing ads using the provided AampMPDParseHelper object.
+ *
+ * @param AampMPDParseHelperPtr shared_ptr to the AampMPDParseHelper object.
*/
-void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
+void PrivateCDAIObjectMPD::PlaceAds(AampMPDParseHelperPtr adMPDParseHelper)
{
- AampMPDParseHelper *adMPDParseHelper = nullptr;
- adMPDParseHelper = new AampMPDParseHelper();
- adMPDParseHelper->Initialize(mpd);
- //Populate the map to specify the period boundaries
- if(mpd && (-1 != mPlacementObj.curAdIdx) && "" != mPlacementObj.pendingAdbrkId && isAdBreakObjectExist(mPlacementObj.pendingAdbrkId) && !mAdBreaks[mPlacementObj.pendingAdbrkId].mSrcPeriodOffsetGTthreshold) //Some Ad is still waiting for the placement
+ //Some Ad is still waiting for the placement
+ const dash::mpd::IMPD* mpd = nullptr;
+ if (adMPDParseHelper)
+ {
+ mpd = adMPDParseHelper->getMPD();
+ }
+ if(mpd && (-1 != mPlacementObj.curAdIdx) && "" != mPlacementObj.pendingAdbrkId && isAdBreakObjectExist(mPlacementObj.pendingAdbrkId))
{
AdBreakObject &abObj = mAdBreaks[mPlacementObj.pendingAdbrkId];
vector periods = mpd->GetPeriods();
@@ -269,11 +274,18 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
if(openPrdFound && -1 != mPlacementObj.curAdIdx && (mPlacementObj.openPeriodId == periodId))
{
double periodDelta = adMPDParseHelper->GetPeriodNewContentDurationMs(period, mPlacementObj.curEndNumber);
- double currperioddur = adMPDParseHelper->aamp_GetPeriodDuration(iter, 0);
- double nextperioddur = -1;
- if((iter+1) < periods.size())
+ double currPeriodDur = adMPDParseHelper->aamp_GetPeriodDuration(iter, 0);
+ double nextPeriodDur = -1;
+ int nextPeriodIter = iter+1;
+ // Find the next non-empty period if available
+ for (; nextPeriodIter < periods.size(); nextPeriodIter++)
{
- nextperioddur = adMPDParseHelper->aamp_GetPeriodDuration(iter+1, 0);
+ double duration = adMPDParseHelper->aamp_GetPeriodDuration(nextPeriodIter, 0);
+ if (duration > 0)
+ {
+ nextPeriodDur = duration;
+ break;
+ }
}
Period2AdData& p2AdData = mPeriodMap[periodId];
@@ -284,19 +296,19 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
p2AdData.offset2Ad[0] = AdOnPeriod{mPlacementObj.curAdIdx,mPlacementObj.adNextOffset};
}
p2AdData.duration += periodDelta;
- double diffInDurationMs = currperioddur - p2AdData.duration;
+ double diffInDurationMs = currPeriodDur - p2AdData.duration;
if(diffInDurationMs > 0)
{
AAMPLOG_WARN("[CDAI] Resetting p2AdData.duration!! periodId:%s diff:%lf periodDuration:%f p2AdData.duration:%" PRIu64 ,
- periodId.c_str(), diffInDurationMs, currperioddur, p2AdData.duration);
+ periodId.c_str(), diffInDurationMs, currPeriodDur, p2AdData.duration);
periodDelta += diffInDurationMs;
p2AdData.duration += diffInDurationMs;
}
AAMPLOG_INFO("periodDelta = %f p2AdData.duration = [%" PRIu64 "] mPlacementObj.adNextOffset = %u periodId = %s",periodDelta,p2AdData.duration,mPlacementObj.adNextOffset, periodId.c_str());
bool isSrcdurnotequalstoaddur = false;
- if ((periodDelta == 0) && (nextperioddur > 0))
+ if ((periodDelta == 0) && (nextPeriodDur > 0))
{
- IPeriod* nextPeriod = periods.at(iter+1);
+ IPeriod* nextPeriod = periods.at(nextPeriodIter);
if (nextPeriod)
{
// Next period was not available earlier when the adIdx was incremented, now the next period is present
@@ -312,47 +324,52 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
}
// Mark the current ad as placed.
abObj.ads->at(mPlacementObj.curAdIdx).placed = true;
- // Player ready to process next period
+ // Player ready to process next period
currentAdPeriodClosed = true;
// Getting the next valid ad to get placed by iterating through the ad break
if (true == GetNextAdInBreakToPlace())
{
+ // curAdIdx is updated in GetNextAdInBreakToPlace
AdNode &currAd = abObj.ads->at(mPlacementObj.curAdIdx);
const std::string &nextPeriodId = nextPeriod->GetId();
UpdateNextPeriodAdPlacement(nextPeriod, 0);
if("" == currAd.basePeriodId)
{
- //Next ad started placing from the beginning
+ //This ad started placing from the beginning
currAd.basePeriodId = nextPeriodId;
currAd.basePeriodOffset = 0;
AAMPLOG_INFO("[CDAI]currAd.basePeriodId:%s, currAd.basePeriodOffset:%d", currAd.basePeriodId.c_str(), currAd.basePeriodOffset);
- // offset2Ad is already updated above
}
- // We have already moved into new period. Logging split period marker now.
+ // The ad placement has moved to the next period, set split period marker.
abObj.mSplitPeriod = true;
}
else
{
AAMPLOG_ERR("[CDAI] Reached the end of ads[size:%zu] in adbreak[%s], not expected", abObj.ads->size(), mPlacementObj.pendingAdbrkId.c_str());
}
+ // Re-run the loop to start placing ad in the next period.
continue;
}
- AAMPLOG_INFO("nextPeriod:%s nextperioddur:%lf currperioddur:%lf adDuration:%" PRIu64 "", nextPeriod->GetId().c_str(), nextperioddur, currperioddur, abObj.ads->at(mPlacementObj.curAdIdx).duration);
- // Ad duration remaining to be placed in this break
- // adStartOffset signifies some portion of the current ad is already placed in a previous period
+ AAMPLOG_INFO("nextPeriod:%s nextPeriodDur:%lf currPeriodDur:%lf adDuration:%" PRIu64 "", nextPeriod->GetId().c_str(), nextPeriodDur, currPeriodDur, abObj.ads->at(mPlacementObj.curAdIdx).duration);
+
+ // Ad duration remaining to be placed for this ad break. adStartOffset signifies the starting offset of ad in the current period
double adDurationToPlaceInBreak = GetRemainingAdDurationInBreak(mPlacementObj.pendingAdbrkId, mPlacementObj.curAdIdx, mPlacementObj.adStartOffset);
- // This is the duration that is available in the current period, after deducting already placed ads if any.
- // If that duration not reaching the adDurationToPlaceInBreak, then its a split period case
- double periodDurationAvailable = (currperioddur - abObj.ads->at(mPlacementObj.curAdIdx).basePeriodOffset);
- if((nextperioddur > 0) && ((periodDurationAvailable >= 0) && (periodDurationAvailable <= adDurationToPlaceInBreak)))
+ // This is the duration that is available in the current period, after deducting already placed duration of ads if any.
+ // If periodDurationAvailable is not matching adDurationToPlaceInBreak, then its a split period case
+ double periodDurationAvailable = 0;
+ if( abObj.ads )
{
- AAMPLOG_INFO("nextperioddur = %f currperioddur = %f curAd.duration = [%" PRIu64 "] periodDurationAvailable:%lf adDurationToPlaceInBreak:%lf",
- nextperioddur,currperioddur,abObj.ads->at(mPlacementObj.curAdIdx).duration, periodDurationAvailable, adDurationToPlaceInBreak);
+ periodDurationAvailable = (currPeriodDur - abObj.ads->at(mPlacementObj.curAdIdx).basePeriodOffset);
+ }
+ if((nextPeriodDur > 0) && ((periodDurationAvailable >= 0) && (periodDurationAvailable <= adDurationToPlaceInBreak)))
+ {
+ AAMPLOG_INFO("nextPeriodDur = %f currPeriodDur = %f curAd.duration = [%" PRIu64 "] periodDurationAvailable:%lf adDurationToPlaceInBreak:%lf",
+ nextPeriodDur,currPeriodDur,abObj.ads->at(mPlacementObj.curAdIdx).duration, periodDurationAvailable, adDurationToPlaceInBreak);
isSrcdurnotequalstoaddur = true;
// An ad exceeding the current period duration by more than 2 seconds is considered a split period
// Source period duration should be more than tiny period to be treated as split period
// If the tiny period just happens to be within a split period, then split period marker will be set which is expected as of now
- if ((currperioddur > THRESHOLD_TOIGNORE_TINYPERIOD) && ((periodDurationAvailable + OFFSET_ALIGN_FACTOR) < adDurationToPlaceInBreak))
+ if ((currPeriodDur > THRESHOLD_TOIGNORE_TINYPERIOD) && ((periodDurationAvailable + OFFSET_ALIGN_FACTOR) < adDurationToPlaceInBreak))
{
abObj.mSplitPeriod = true;
}
@@ -361,22 +378,28 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
}
while(periodDelta > 0 || isSrcdurnotequalstoaddur)
{
+ if( !abObj.ads )
+ {
+ AAMPLOG_WARN("abObj.ads=nullptr");
+ break;
+ }
AdNode &curAd = abObj.ads->at(mPlacementObj.curAdIdx);
AAMPLOG_INFO("curAd.duration = [%" PRIu64 "]",curAd.duration);
if(periodDelta < (curAd.duration - mPlacementObj.adNextOffset))
{
mPlacementObj.adNextOffset += periodDelta;
if(isSrcdurnotequalstoaddur)
- { // check if the current source period duration < current period ad duration and it is lest than offset factor
- AAMPLOG_INFO("nextperiod : %s with valid duration available",periods.at(iter+1)->GetId().c_str());
- AAMPLOG_INFO("currperioddur : [%f] curAd.duration : %" PRIu64 " periodDelta : %f mPlacementObj.adNextOffset:%u diff : %" PRIu64 ,
- currperioddur, curAd.duration, periodDelta, mPlacementObj.adNextOffset, (curAd.duration - mPlacementObj.adNextOffset));
-
- currentAdPeriodClosed = true;//Player ready to process next period
- // This is a split period case, so we need to update nextperiod as the open period, so that we can continue placement
+ {
+ IPeriod* nextPeriod = periods.at(nextPeriodIter);
+ // check if the current source period duration < current period ad duration and it is lest than offset factor
+ AAMPLOG_INFO("nextperiod : %s with valid duration available",nextPeriod->GetId().c_str());
+ AAMPLOG_INFO("currPeriodDur : [%f] curAd.duration : %" PRIu64 " periodDelta : %f mPlacementObj.adNextOffset:%u diff : %" PRIu64 ,
+ currPeriodDur, curAd.duration, periodDelta, mPlacementObj.adNextOffset, (curAd.duration - mPlacementObj.adNextOffset));
+ //Player ready to process next period
+ currentAdPeriodClosed = true;
+ // If this is a split period case, we need to update nextperiod as the open period, so that we can continue placement
if(abObj.mSplitPeriod)
{
- IPeriod* nextPeriod = periods.at(iter+1);
UpdateNextPeriodAdPlacement(nextPeriod, mPlacementObj.adNextOffset);
}
else
@@ -387,18 +410,18 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
setAdMarkers(p2AdData.duration,periodDelta);
if (p2AdData.duration > THRESHOLD_TOIGNORE_TINYPERIOD)
{
- AAMPLOG_INFO("[CDAI] Source Ad duration is less than CDAI Ad. Mark as placed.end period:%s end period offset:%" PRIu64 " adjustEndPeriodOffset:%d",
- periodId.c_str(), abObj.endPeriodOffset, abObj.adjustEndPeriodOffset);
+ AAMPLOG_INFO("[CDAI] Source period[%s] duration is less than CDAI Ad. Mark as placed, end period:%s end period offset:%" PRIu64 " adjustEndPeriodOffset:%d",
+ periodId.c_str(), nextPeriod->GetId().c_str(), abObj.endPeriodOffset, abObj.adjustEndPeriodOffset);
}
else
{
AAMPLOG_WARN("[CDAI] Detected tiny period[id:%s dur:%" PRIu64 "] with ad[numads:%zu adsdur:%" PRIu32 "], not expected, setting ads to invalid",
periodId.c_str(), p2AdData.duration, abObj.ads->size(), abObj.adsDuration);
- // Mark all the ads in the break as invalid, so that we don't play this break anymore
- // This will not be called if the first period is not a split period
+ // Mark all the ads in the break as invalid, so that we don't play this break.
+ // Split period case will not enter here!
for (int idx = 0; idx < abObj.ads->size(); idx++)
{
- // We need to delete the ad entries once we fix FetcherLoop to pick tiny period
+ // We need not invalidate the ad entries once we fix FetcherLoop to pick tiny period
abObj.ads->at(idx).placed = true;
abObj.ads->at(idx).invalid = true;
}
@@ -411,12 +434,10 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
periodDelta = 0;
}
}
- //if we check period delta > OFFSET_ALIGN_FACTOR(previous logic), Player won't mark the ad as completely placed if delta is less than OFFSET_ALIGN_FACTOR(2000ms).This is a
- //corner case and player may fail to switch to next period
- //Player should mark the ad as placed if delta is greater than or equal to the difference of the ad duration and offset.
- else if((mPlacementObj.curAdIdx < (abObj.ads->size()-1)) //If it is not the last Ad, we can start placement immediately.
- || periodDelta >= curAd.duration - mPlacementObj.adNextOffset) //current ad completely placed.
+ //Player should mark the ad as placed if delta is greater than or equal to the difference of the ad duration and offset.
+ else if(periodDelta >= curAd.duration - mPlacementObj.adNextOffset)
{
+ // Find the duration to be placed for the current ad (not adbreaks duration)
int64_t remainingAdDuration = (curAd.duration - mPlacementObj.adNextOffset);
if (remainingAdDuration >= 0)
{
@@ -430,7 +451,7 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
remainingAdDuration, curAd.duration, mPlacementObj.adNextOffset);
}
isSrcdurnotequalstoaddur = false;
- // If another ad exists in this break
+ // If another ad exists in this ad break
if(mPlacementObj.curAdIdx+1 < abObj.ads->size())
{
// This case is added as part of split period. If periodDelta reaches zero, after the current ad is placed
@@ -439,9 +460,9 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
if (periodDelta > 0)
{
// Current Ad completely placed. But more space available in the current period for next Ad
- // Once marked as placed, we need to update the basePeriodOffset of next ad, otherwise fragmentTime calculation will go wrong
+ // Once marked as placed, we need to update the basePeriodOffset of next ad.
curAd.placed = true;
- // Getting the next valid ad to get placed by iterating through the max ad size
+ // Getting the next valid ad to be placed by iterating through the ads
if (true == GetNextAdInBreakToPlace())
{
AdNode &nextAd = abObj.ads->at(mPlacementObj.curAdIdx);
@@ -469,9 +490,11 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
else
{
curAd.placed = true;
- currentAdPeriodClosed = true;//Player ready to process next period
- mPlacementObj.curAdIdx++; // basically a no-op
- mPlacementObj.adNextOffset = 0; //basically a no-op
+ //Player ready to process next period
+ currentAdPeriodClosed = true;
+ // basically a no-op
+ mPlacementObj.curAdIdx++;
+ mPlacementObj.adNextOffset = 0;
// No ads left to place. lets mark the adbreak as complete
setAdMarkers(p2AdData.duration,periodDelta);
AAMPLOG_INFO("[CDAI] Current Ad completely placed.end period:%s end period offset:%" PRIu64 " adjustEndPeriodOffset:%d",periodId.c_str(),abObj.endPeriodOffset,abObj.adjustEndPeriodOffset);
@@ -487,7 +510,8 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
}
}
}
- if(abObj.adjustEndPeriodOffset) // make endPeriodOffset adjustment
+ // Make endPeriodOffset adjustment
+ if(abObj.adjustEndPeriodOffset)
{
bool endPeriodFound = false;
int iter =0;
@@ -503,67 +527,78 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
break;
}
}
- if(false == endPeriodFound) // something wrong keep the end-period positions same and proceed.
+ // something wrong keep the end-period positions same and proceed.
+ if(false == endPeriodFound)
{
abObj.adjustEndPeriodOffset = false;
abObj.mAdBreakPlaced = true;
- AAMPLOG_WARN("[CDAI] Couldn't adjust offset [endPeriodNotFound] ");
+ AAMPLOG_WARN("[CDAI] Couldn't adjust offset [endPeriodNotFound]");
}
else
{
//Inserted Ads finishes in < 4 seconds of new period (inside the adbreak) : Play-head goes to the period’s beginning.
if(abObj.endPeriodOffset < 2*OFFSET_ALIGN_FACTOR)
{
- abObj.adjustEndPeriodOffset = false; // done with Adjustment
- abObj.endPeriodOffset = 0;//Aligning the last period
+ // done with Adjustment
+ abObj.adjustEndPeriodOffset = false;
+ //Aligning the last period
+ abObj.endPeriodOffset = 0;
abObj.mAdBreakPlaced = true;
- mPeriodMap[abObj.endPeriodId] = Period2AdData(); //Resetting the period with small out-lier.
+ //Resetting the period with small out-lier.
+ mPeriodMap[abObj.endPeriodId] = Period2AdData();
AAMPLOG_INFO("[CDAI] Adjusted endperiodOffset");
}
else
{
// get current period duration
uint64_t currPeriodDuration = adMPDParseHelper->aamp_GetPeriodDuration(iter, 0);
-
- // Are we too close to current period end?
- //--> Inserted Ads finishes < 2 seconds behind new period : Channel play-back starts from new period.
int diff = (int)(currPeriodDuration - abObj.endPeriodOffset);
- // if diff is negative or < OFFSET_ALIGN_FACTOR we have to wait for it to catch up
- // and either period will end with diff < OFFSET_ALIGN_FACTOR then adjust to next period start
- // or diff will be more than OFFSET_ALIGN_FACTOR then don't do any adjustment
- if (diff < OFFSET_ALIGN_FACTOR)
+ //--> Inserted Ads finishes < 2 seconds in new period : Channel play-back starts from new period.
+ if (diff < OFFSET_ALIGN_FACTOR)
{
- //check if next period available
- iter++;
- if( iter < periods.size() && adMPDParseHelper->aamp_GetPeriodDuration(iter, 0) > 0)
+ // If the current period is not closed, we have to wait for it.
+ // This is because in following iterations, the current period could be updated such that
+ // diff > OFFSET_ALIGN_FACTOR, in which case its a partial ad.
+ // diff < OFFSET_ALIGN_FACTOR, in which case we have to align to next period.
+ // So check if next period available with valid duration
+ for (iter = iter+1; iter < periods.size(); iter++)
+ {
+ if (adMPDParseHelper->aamp_GetPeriodDuration(iter, 0) > 0)
+ {
+ break;
+ }
+ }
+ if (iter < periods.size())
{
auto nextPeriod = periods.at(iter);
- abObj.adjustEndPeriodOffset = false; // done with Adjustment
- abObj.endPeriodOffset = 0;//Aligning to next period start
+ // done with Adjustment
+ abObj.adjustEndPeriodOffset = false;
+ // Aligning to next period start
+ abObj.endPeriodOffset = 0;
abObj.endPeriodId = nextPeriod->GetId();
abObj.mAdBreakPlaced = true;
AAMPLOG_INFO("[CDAI] diff [%d] close to period end [%" PRIu64 "],Aligning to next-period:%s",
- diff,currPeriodDuration,abObj.endPeriodId.c_str());
+ diff, currPeriodDuration, abObj.endPeriodId.c_str());
}
else
{
- AAMPLOG_INFO("[CDAI] diff [%d] close to period end [%" PRIu64 "],but next period not available,waiting",
- diff,currPeriodDuration);
+ AAMPLOG_INFO("[CDAI] diff [%d] close to period end [%" PRIu64 "], but next period not available, waiting",
+ diff, currPeriodDuration);
}
- }// --> Inserted Ads finishes >= 2 seconds behind new period : Channel playback starts from that position in the current period.
- // OR //--> Inserted Ads finishes in >= 4 seconds of new period (inside the adbreak) : Channel playback starts from that position in the period.
+ }
+ // --> Inserted Ads finishes >= 2 seconds in current period : Channel playback starts from that position in the current period.
else
{
AAMPLOG_INFO("[CDAI] diff [%d] NOT close to period end, period:%s duration[%" PRIu64 "]", diff, mPlacementObj.pendingAdbrkId.c_str(), currPeriodDuration);
-
- abObj.adjustEndPeriodOffset = false; // done with Adjustment
- abObj.mAdBreakPlaced = true; // adbrk duration not equal to src period duration continue to play source period remaining duration
- abObj.mSrcPeriodOffsetGTthreshold = true;
+ // done with Adjustment
+ abObj.adjustEndPeriodOffset = false;
+ // adbrk duration not equal to src period duration continue to play source period for remaining duration
+ abObj.mAdBreakPlaced = true;
}
}
}
-
- if(!abObj.adjustEndPeriodOffset) // placed all ads now print the placement data and set mPlacementObj.curAdIdx = -1;
+ // Finished placing all ads, now print the placement data and update mPlacementObj.
+ if(!abObj.adjustEndPeriodOffset)
{
mPlacementObj.curAdIdx = -1;
if (abObj.mSplitPeriod)
@@ -607,7 +642,7 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
}
}
ss<<"]}";
- AAMPLOG_WARN("[CDAI] Placement Done: %s.", ss.str().c_str());
+ AAMPLOG_MIL("[CDAI] Placement Done: %s.", ss.str().c_str());
}
}
@@ -619,23 +654,22 @@ void PrivateCDAIObjectMPD::PlaceAds(dash::mpd::IMPD *mpd)
mPlacementObj.openPeriodId = "";
mPlacementObj.curEndNumber = 0;
mPlacementObj.adNextOffset = 0;
- mImmediateNextAdbreakAvailable = false;
}
else
{
- //Current ad break finished and the next ad break is available.
- //So need to call onAdEvent again from fetcher loop
+ // Current ad break finished and the next ad break is available.
+ // Remove the placementObj, as it is completely placed
+ std::string adBreakIdToRemove = mPlacementObj.pendingAdbrkId;
if(!mAdtoInsertInNextBreakVec.empty())
{
mPlacementObj = setPlacementObj(mPlacementObj.pendingAdbrkId,abObj.endPeriodId);
+ // Remove the placement object that was placed completely
+ RemovePlacementObj(adBreakIdToRemove);
}
- AAMPLOG_INFO("[CDAI] num of adbrks avail: %zu ",mAdtoInsertInNextBreakVec.size());
-
- mImmediateNextAdbreakAvailable = true;
+ AAMPLOG_INFO("[CDAI] num of adbrks avail: %zu",mAdtoInsertInNextBreakVec.size());
}
}
}
- SAFE_DELETE(adMPDParseHelper);
}
/**
@@ -648,7 +682,7 @@ void PrivateCDAIObjectMPD::UpdateNextPeriodAdPlacement(IPeriod* nextPeriod, uint
if (nextPeriod)
{
const std::string &nextPeriodId = nextPeriod->GetId();
- // If adbreak object exist for next period in split period with valid ads duration, log an error. This is not expected
+ // In split period, if an adbreak object exist for next period with valid ad duration, log an error. This is not expected
if (isAdBreakObjectExist(nextPeriodId) && mAdBreaks[nextPeriodId].adsDuration > 0)
{
// Lock the mutex, so we can delete this entry
@@ -693,16 +727,9 @@ int PrivateCDAIObjectMPD::CheckForAdStart(const float &rate, bool init, const st
{
int adIdx = -1;
auto pit = mPeriodMap.find(periodId);
- Period2AdData &curP2Ad = pit->second;
if(mPeriodMap.end() != pit && !(pit->second.adBreakId.empty()))
{
- //mBasePeriodId belongs to an Adbreak. Now we need to see whether any Ad is placed in the offset.
- // This condition may hit if the player is in TSB and if there is an abreak to place at live point. Possible?
- if(mPlacementObj.pendingAdbrkId != curP2Ad.adBreakId)
- {
- AAMPLOG_INFO("[CDAI] PlacementObj open adbreak(%s) and current period's(%s) adbreak(%s) not equal ... may be BUG ",
- mPlacementObj.pendingAdbrkId.c_str(), periodId.c_str(), curP2Ad.adBreakId.c_str());
- }
+ Period2AdData &curP2Ad = pit->second;
if(isAdBreakObjectExist(curP2Ad.adBreakId))
{
breakId = curP2Ad.adBreakId;
@@ -761,30 +788,35 @@ int PrivateCDAIObjectMPD::CheckForAdStart(const float &rate, bool init, const st
if(rate >= AAMP_NORMAL_PLAY_RATE && (-1 == adIdx) && (abObj.endPeriodId == periodId) && (uint64_t)(offSet*1000) >= abObj.endPeriodOffset)
{
- breakId = ""; //AdState should not stick to IN_ADBREAK after Adbreak ends.
+ //AdState should not stick to IN_ADBREAK after Adbreak ends.
+ breakId = "";
+ }
+ }
+ else
+ {
+ AAMPLOG_INFO("[CDAI] AdBreak not found for periodId:%s adBreakId:%s", periodId.c_str(), curP2Ad.adBreakId.c_str());
+ }
+ //reset the placementObj to current playing AdBreakId if it is not placed
+ if((adIdx != -1 && !breakId.empty()) && (mPlacementObj.pendingAdbrkId != curP2Ad.adBreakId))
+ {
+ AAMPLOG_INFO("[CDAI] PlacementObj pendingAdbrkId(%s) and current period's(%s) adbreak(%s) not equal",
+ mPlacementObj.pendingAdbrkId.c_str(), periodId.c_str(), curP2Ad.adBreakId.c_str());
+ AdBreakObject &abObj = mAdBreaks[curP2Ad.adBreakId];
+ AdNode &curAd = abObj.ads->at(adIdx);
+ if(!curAd.placed)
+ {
+ for(auto placementObj: mAdtoInsertInNextBreakVec)
+ {
+ if(curP2Ad.adBreakId == placementObj.pendingAdbrkId)
+ {
+ mPlacementObj = placementObj;
+ AAMPLOG_INFO("[CDAI] change in pending AdBrkId to (%s) ",mPlacementObj.pendingAdbrkId.c_str());
+ break;
+ }
+ }
}
}
}
- //reset the placementObj to current playing AdBreakId if it is not placed
- if((adIdx != -1 && !breakId.empty()) && (mPlacementObj.pendingAdbrkId != curP2Ad.adBreakId))
- {
- AAMPLOG_INFO("[CDAI] PlacementObj pendingAdbrkId(%s) and current period's(%s) adbreak(%s) not equal",
- mPlacementObj.pendingAdbrkId.c_str(), periodId.c_str(), curP2Ad.adBreakId.c_str());
- AdBreakObject &abObj = mAdBreaks[curP2Ad.adBreakId];
- AdNode &curAd = abObj.ads->at(adIdx);
- if(!curAd.placed)
- {
- for(auto placementObj: mAdtoInsertInNextBreakVec)
- {
- if(curP2Ad.adBreakId == placementObj.pendingAdbrkId)
- {
- mPlacementObj = placementObj;
- AAMPLOG_INFO("[CDAI] change in pending AdBrkId to (%s) ",mPlacementObj.pendingAdbrkId.c_str());
- break;
- }
- }
- }
- }
return adIdx;
}
@@ -805,9 +837,7 @@ bool PrivateCDAIObjectMPD::CheckForAdTerminate(double currOffset)
}
}
}
-
return false;
-
}
/**
@@ -961,7 +991,7 @@ MPD* PrivateCDAIObjectMPD::GetAdMPD(std::string &manifestUrl, bool &finalManifes
}
else
{
- AAMPLOG_WARN("Could not create root node");
+ AAMPLOG_ERR("Could not create root node");
}
}
else
@@ -1020,7 +1050,7 @@ bool PrivateCDAIObjectMPD::FulFillAdObject()
uint32_t availSpace = (uint32_t)(adbreakObj.brkDuration - startMS);
if(availSpace < durationMs)
{
- AAMPLOG_WARN("Adbreak's available space[%u] < Ad's Duration[%u]. Trimming the Ad.", availSpace, durationMs);
+ AAMPLOG_MIL("Adbreak's available space[%u] < Ad's Duration[%u]. Trimming the Ad.", availSpace, durationMs);
durationMs = availSpace;
}
adbreakObj.adsDuration += durationMs;
@@ -1031,8 +1061,9 @@ bool PrivateCDAIObjectMPD::FulFillAdObject()
//First Ad placement is doing now.
mPeriodMap[periodId].offset2Ad[0] = AdOnPeriod{0,0};
}
- // Add entry to mAdtoInsertInNextBreakVec
- if(!HasDaiAd(periodId))
+ // Add entry to mAdtoInsertInNextBreakVec if not already present
+ auto placementIter = std::find_if(mAdtoInsertInNextBreakVec.begin(), mAdtoInsertInNextBreakVec.end(), [periodId](const PlacementObj &obj) { return obj.pendingAdbrkId == periodId; });
+ if (placementIter == mAdtoInsertInNextBreakVec.end())
{
//If current ad index is -1 (that is no ads are pushed into the map yet), current ad placement can take place from here itself.
//Otherwise, the Player need to wait until the current ad placement is done.
@@ -1093,12 +1124,12 @@ bool PrivateCDAIObjectMPD::FulFillAdObject()
AAMPLOG_WARN("AdBreakAssets is empty. Adding new Ad, May be a BUG in fulfill queue.");
adBreakAssets->emplace_back(AdNode{false, false, true, mAdFulfillObj.adId, mAdFulfillObj.url, durationMs, periodId, 0, ad});
}
- AAMPLOG_WARN("New Ad successfully for periodId : %s added[Id=%s, url=%s, durationMs=%" PRIu32 "].",periodId.c_str(),mAdFulfillObj.adId.c_str(),mAdFulfillObj.url.c_str(), durationMs);
+ AAMPLOG_MIL("New Ad successfully for periodId : %s added[Id=%s, url=%s, durationMs=%" PRIu32 "].",periodId.c_str(),mAdFulfillObj.adId.c_str(),mAdFulfillObj.url.c_str(), durationMs);
adStatus = true;
}
else
{
- AAMPLOG_WARN("AdBreakId[%s] not existing. Dropping the Ad.", periodId.c_str());
+ AAMPLOG_ERR("AdBreakId[%s] not existing. Dropping the Ad.", periodId.c_str());
SAFE_DELETE(ad);
}
}
@@ -1106,7 +1137,7 @@ bool PrivateCDAIObjectMPD::FulFillAdObject()
{
if(CURLE_ABORTED_BY_CALLBACK == http_error)
{
- AAMPLOG_WARN("Ad MPD[%s] download aborted.", mAdFulfillObj.url.c_str());
+ AAMPLOG_ERR("Ad MPD[%s] download aborted.", mAdFulfillObj.url.c_str());
ret = false;
}
else
@@ -1204,7 +1235,7 @@ void PrivateCDAIObjectMPD::SetAlternateContents(const std::string &periodId, con
PlacementObj PrivateCDAIObjectMPD::setPlacementObj(std::string adBrkId,std::string endPeriodId)
{
PlacementObj nxtPlacementObj = PlacementObj();
- mAdBrkVecMtx.lock();
+ std::lock_guard guard(mAdBrkVecMtx);
if(adBrkId == endPeriodId)
{
// If adBrkId and endPeriodId are same, then the current ad break is completely placed but the period is not filled.
@@ -1259,23 +1290,22 @@ PlacementObj PrivateCDAIObjectMPD::setPlacementObj(std::string adBrkId,std::stri
}
}
AAMPLOG_INFO("[CDAI] Placed AdBrkId = %s curAdIx = %d",nxtPlacementObj.pendingAdbrkId.c_str(),nxtPlacementObj.curAdIdx);
- mAdBrkVecMtx.unlock();
return nxtPlacementObj;
}
/**
- * @fn ErasefrmAdBrklist
- * @brief Function to erase the current PlayingAdBrkId from next AdBreak Vector
+ * @fn RemovePlacementObj
+ * @brief Function to erase the PlacementObj matching the adBreakId from mAdtoInsertInNextBreakVec Vector
* @param[in] adBrkId Ad break id to be erased
*/
-void PrivateCDAIObjectMPD::ErasefrmAdBrklist(const std::string adBrkId)
+void PrivateCDAIObjectMPD::RemovePlacementObj(const std::string adBreakId)
{
- mAdBrkVecMtx.lock();
+ std::lock_guard guard(mAdBrkVecMtx);
for(auto it = mAdtoInsertInNextBreakVec.begin();it != mAdtoInsertInNextBreakVec.end();)
{
- if(it->pendingAdbrkId == adBrkId)
+ if(it->pendingAdbrkId == adBreakId)
{
- AAMPLOG_WARN("Period Id : %s state : %s processed remove from the DAI adbrk list ",it->pendingAdbrkId.c_str(),ADSTATE_STR[static_cast(mAdState)]);
+ AAMPLOG_WARN("Period Id: %s state : %s processed remove from the mAdtoInsertInNextBreakVec list ",it->pendingAdbrkId.c_str(),ADSTATE_STR[static_cast(mAdState)]);
it = mAdtoInsertInNextBreakVec.erase(it);
break;
}
@@ -1284,35 +1314,31 @@ void PrivateCDAIObjectMPD::ErasefrmAdBrklist(const std::string adBrkId)
++it;
}
}
- mAdBrkVecMtx.unlock();
}
/**
* @fn HasDaiAd
- * @brief Function Verify if the current period has DAI Ad
+ * @brief Function Verify if the current period has a possibility that it might have DAI Ad
+ * mPeriodMap[periodId].adBreakId is not empty, means that the period has a valid SCTE35 signal
+ * It could be filled or not, depending on the ad schedule
* @param[in] periodId Base period ID
* @return true if DAI Ad is present
*/
bool PrivateCDAIObjectMPD::HasDaiAd(const std::string periodId)
{
bool adFound = false;
- mAdBrkVecMtx.lock();
- if( !mAdtoInsertInNextBreakVec.empty() )
+ if (isPeriodExist(periodId))
{
- for(auto it = mAdtoInsertInNextBreakVec.begin();it != mAdtoInsertInNextBreakVec.end(); )
+ Period2AdData &curP2Ad = mPeriodMap[periodId];
+ if (!curP2Ad.adBreakId.empty())
{
- if(it->pendingAdbrkId == periodId)
- {
- adFound = true;
- break;
- }
- it++;
+ adFound = true;
}
}
- mAdBrkVecMtx.unlock();
return adFound;
}
+
/**
* @fn setAdMarkers
* @brief Update ad markers for the current ad break being placed
@@ -1323,8 +1349,10 @@ void PrivateCDAIObjectMPD::setAdMarkers(uint64_t p2AdDataduration,double periodD
{
AdBreakObject &abObj = mAdBreaks[mPlacementObj.pendingAdbrkId];
abObj.endPeriodOffset = p2AdDataduration - periodDelta;
- abObj.endPeriodId = mPlacementObj.openPeriodId; //if it is the exact period boundary, end period will be the next one
- abObj.adjustEndPeriodOffset = true; // marked for later adjustment
+ // If it is the exact period boundary, end period will be the next one
+ abObj.endPeriodId = mPlacementObj.openPeriodId;
+ // Marked for later adjustment
+ abObj.adjustEndPeriodOffset = true;
}
/**
@@ -1333,7 +1361,7 @@ void PrivateCDAIObjectMPD::setAdMarkers(uint64_t p2AdDataduration,double periodD
void PrivateCDAIObjectMPD::FulfillAdLoop()
{
AAMPLOG_INFO("Enter");
- // Start tread
+ // Start thread
do
{
std::unique_lock lock(mAdFulfillMtx);
@@ -1394,10 +1422,8 @@ void PrivateCDAIObjectMPD::StopFulfillAdLoop()
*/
void PrivateCDAIObjectMPD::NotifyAdLoopWait()
{
- {
- std::lock_guard lock(mAdFulfillMtx);
- AAMPLOG_INFO("Aborting fulfill ad loop wait.");
- }
+ std::lock_guard lock(mAdFulfillMtx);
+ AAMPLOG_INFO("Aborting fulfill ad loop wait.");
mAdFulfillCV.notify_one();
}
@@ -1412,7 +1438,7 @@ void PrivateCDAIObjectMPD::CacheAdData(const std::string &periodId, const std::s
{
bool notify = false;
{
- std::lock_guard lock(mAdFulfillMtx);
+ std::lock_guard guard(mAdFulfillMtx);
if(isAdBreakObjectExist(periodId))
{
mAdBreaks[periodId].ads->emplace_back(AdNode{false, false, false, adId, url, 0, "", 0, NULL});
@@ -1498,10 +1524,8 @@ bool PrivateCDAIObjectMPD::WaitForNextAdResolved(int timeoutMs, std::string peri
*/
void PrivateCDAIObjectMPD::AbortWaitForNextAdResolved()
{
- {
- std::lock_guard lock(mAdPlacementMtx);
- AAMPLOG_INFO("Aborting wait for next ad placement.");
- }
+ std::lock_guard lock(mAdPlacementMtx);
+ AAMPLOG_INFO("Aborting wait for next ad placement.");
mAdPlacementCV.notify_one();
}
@@ -1514,16 +1538,19 @@ void PrivateCDAIObjectMPD::AbortWaitForNextAdResolved()
uint64_t PrivateCDAIObjectMPD::GetRemainingAdDurationInBreak(const std::string &breakId, int adIdx, uint32_t startOffset)
{
uint64_t duration = 0;
- if (!breakId.empty())
+ if (!breakId.empty() )
{
AdBreakObject &abObj = mAdBreaks[breakId];
- for (int idx = adIdx; idx < abObj.ads->size(); idx++)
- {
- duration += abObj.ads->at(idx).duration;
- }
- if (duration > startOffset)
+ if( abObj.ads!=nullptr )
{
- duration -= startOffset;
+ for (int idx = adIdx; idx < abObj.ads->size(); idx++)
+ {
+ duration += abObj.ads->at(idx).duration;
+ }
+ if (duration > startOffset)
+ {
+ duration -= startOffset;
+ }
}
}
return duration;
diff --git a/admanager_mpd.h b/admanager_mpd.h
index 591fc47..343225d 100644
--- a/admanager_mpd.h
+++ b/admanager_mpd.h
@@ -32,6 +32,7 @@
#include "libdash/IDASHManager.h"
#include "libdash/xml/Node.h"
#include "libdash/IMPD.h"
+#include "AampMPDParseHelper.h"
using namespace dash;
using namespace std;
@@ -144,8 +145,8 @@ struct AdNode {
* @param[in] mpd - Pointer to the MPD object
*/
AdNode(bool invalid, bool placed, bool resolved, std::string adId, std::string url, uint64_t duration,
- std::string basePeriodId, int basePeriodOffset, MPD* mpd)
- : invalid(invalid), placed(placed), resolved(resolved), adId(adId), url(url), duration(duration), basePeriodId(basePeriodId),
+ std::string basePeriodId, int basePeriodOffset, MPD* mpd)
+ : invalid(invalid), placed(placed), resolved(resolved), adId(adId), url(url), duration(duration), basePeriodId(basePeriodId),
basePeriodOffset(basePeriodOffset), mpd(mpd)
{
@@ -156,9 +157,10 @@ struct AdNode {
*
* @param[in] adNode - Reference to the source AdNode
*/
- AdNode(const AdNode& adNode) : invalid(adNode.invalid), placed(adNode.placed), resolved(adNode.resolved), adId(adNode.adId),
- url(adNode.url), duration(adNode.duration), basePeriodId(adNode.basePeriodId),
- basePeriodOffset(adNode.basePeriodOffset), mpd(adNode.mpd)
+ AdNode(const AdNode& adNode)
+ : invalid(adNode.invalid), placed(adNode.placed), resolved(adNode.resolved), adId(adNode.adId),
+ url(adNode.url), duration(adNode.duration), basePeriodId(adNode.basePeriodId),
+ basePeriodOffset(adNode.basePeriodOffset), mpd(adNode.mpd)
{
}
@@ -184,14 +186,15 @@ struct AdBreakObject{
bool adjustEndPeriodOffset; /**< endPeriodOffset needs be re-adjusted or not */
bool mAdBreakPlaced; /**< flag marks if the adbreak is completely placed */
bool mAdFailed; /** Current Ad playback failed flag */
- bool mSrcPeriodOffsetGTthreshold;/*The flag will be set if the difference between the source period and the total ad duration exceeds the 2-second threshold.*/
bool mSplitPeriod; /**< To identify whether the ad is split period ad or not */
- bool invalid; /**< flag marks if the adbreak is invalid or not */
+ bool invalid; /**< flag marks if the adbreak is invalid or not */
/**
* @brief AdBreakObject default constructor
*/
- AdBreakObject() : brkDuration(0), ads(), endPeriodId(), endPeriodOffset(0), adsDuration(0), adjustEndPeriodOffset(false), mAdBreakPlaced(false), mAdFailed(false),mSrcPeriodOffsetGTthreshold(false), mSplitPeriod(false), invalid(false)
+ AdBreakObject()
+ : brkDuration(0), ads(), endPeriodId(), endPeriodOffset(0), adsDuration(0), adjustEndPeriodOffset(false),
+ mAdBreakPlaced(false), mAdFailed(false), mSplitPeriod(false), invalid(false)
{
}
@@ -205,8 +208,9 @@ struct AdBreakObject{
* @param[in] _adsDuration - Ads' duration in the Adbreak in milliseconds
*/
AdBreakObject(uint32_t _duration, AdNodeVectorPtr _ads, std::string _endPeriodId,
- uint64_t _endPeriodOffset, uint32_t _adsDuration)
- : brkDuration(_duration), ads(_ads), endPeriodId(_endPeriodId), endPeriodOffset(_endPeriodOffset), adsDuration(_adsDuration), adjustEndPeriodOffset(false), mAdBreakPlaced(false), mAdFailed(false),mSrcPeriodOffsetGTthreshold(false),mSplitPeriod(false)
+ uint64_t _endPeriodOffset, uint32_t _adsDuration)
+ : brkDuration(_duration), ads(_ads), endPeriodId(_endPeriodId), endPeriodOffset(_endPeriodOffset),
+ adsDuration(_adsDuration), adjustEndPeriodOffset(false), mAdBreakPlaced(false), mAdFailed(false), mSplitPeriod(false), invalid(false)
{
}
};
@@ -306,7 +310,7 @@ struct PlacementObj {
/**
* @brief PlacementObj constructor
*/
- PlacementObj(): pendingAdbrkId(), openPeriodId(), curEndNumber(0), curAdIdx(-1), adNextOffset(0), adStartOffset(0), waitForNextPeriod(false)
+ PlacementObj() : pendingAdbrkId(), openPeriodId(), curEndNumber(0), curAdIdx(-1), adNextOffset(0), adStartOffset(0), waitForNextPeriod(false)
{
}
@@ -320,7 +324,8 @@ struct PlacementObj {
* @param adNextOffset The current ad's offset to be placed in the next iteration of PlaceAds in milliseconds
* @param adStartOffset The current ad's start offset in milliseconds
*/
- PlacementObj(const std::string& pendingAdbrkId, const std::string& openPeriodId, uint64_t curEndNumber, int curAdIdx, uint32_t adNextOffset, uint32_t adStartOffset, bool waitForNextPeriod)
+ PlacementObj(const std::string& pendingAdbrkId, const std::string& openPeriodId, uint64_t curEndNumber,
+ int curAdIdx, uint32_t adNextOffset, uint32_t adStartOffset, bool waitForNextPeriod)
: pendingAdbrkId(pendingAdbrkId), openPeriodId(openPeriodId), curEndNumber(curEndNumber),
curAdIdx(curAdIdx), adNextOffset(adNextOffset), adStartOffset(adStartOffset), waitForNextPeriod(waitForNextPeriod)
{
@@ -351,7 +356,6 @@ class PrivateCDAIObjectMPD
PlacementObj mPlacementObj; /**< Temporary object for Ad placement over period */
double mContentSeekOffset; /**< Seek offset after the Ad playback */
AdState mAdState; /**< Current state of the CDAI state machine */
- bool mImmediateNextAdbreakAvailable;/**< Next ad break(immediate/back to back) need to be placed if the value is true*/
bool currentAdPeriodClosed;/**< The very next open period should be processed only when the flag is true*/
std::vector mAdtoInsertInNextBreakVec;/** /dev/null 2>&1; then
+ git describe --tags --exact-match HEAD
+else
+ echo "No-Tag"
+fi
diff --git a/dash/mpd/MPDSegmenter.cpp b/dash/mpd/MPDSegmenter.cpp
index 5d06ad6..bca0b58 100644
--- a/dash/mpd/MPDSegmenter.cpp
+++ b/dash/mpd/MPDSegmenter.cpp
@@ -36,12 +36,6 @@
using namespace std;
-#if defined(WIN32) && defined(_MSC_VER)
-#ifndef snprintf
-#define snprintf _snprintf
-#endif
-#endif
-
/**
* @typedef TemplateContext
* @brief
diff --git a/dash/utils/Path.cpp b/dash/utils/Path.cpp
index be6e123..f8fc635 100644
--- a/dash/utils/Path.cpp
+++ b/dash/utils/Path.cpp
@@ -164,7 +164,7 @@ bool Path::isRoot() const {
/**
* @brief Relative Path
- * @retval true if path doesnt start with '/'
+ * @retval true if path doesn't start with '/'
*/
bool Path::isRelative() const {
return path[0] != '/';
diff --git a/dash/utils/Utils.cpp b/dash/utils/Utils.cpp
index fd81c22..e7804ee 100644
--- a/dash/utils/Utils.cpp
+++ b/dash/utils/Utils.cpp
@@ -106,16 +106,9 @@ bool epochSecondsToIsoDateTime(double seconds, std::string& isoDateTime) {
std::ostringstream ss;
auto utc = (time_t) seconds;
tm *time = std::gmtime(&utc);
-#ifdef WIN32
- if (!time) {
- return false;
- }
- ss << std::put_time(time, "%Y-%m-%dT%H:%M:%SZ");
-#else
char buffer[80];
strftime(buffer,80,"%Y-%m-%dT%H:%M:%SZ", time);
ss << buffer;
-#endif
isoDateTime = ss.str();
return true;
}
diff --git a/drm/AampDrmInfo.h b/drm/AampDrmInfo.h
index 261ce03..b9d018e 100755
--- a/drm/AampDrmInfo.h
+++ b/drm/AampDrmInfo.h
@@ -27,7 +27,9 @@
#include
#include "AampDrmMediaFormat.h"
+#include
+#define DRM_IV_LEN 16
/**
* @enum DrmMethod
@@ -39,14 +41,13 @@ typedef enum
eMETHOD_AES_128, /**< encrypted using Advanced Encryption Standard 128-bit key and PKCS7 padding */
} DrmMethod;
-
/**
* @struct DrmInfo
* @brief DRM information required to decrypt
*/
struct DrmInfo
{
- DrmInfo() : method(eMETHOD_NONE), mediaFormat(eMEDIAFORMAT_HLS), useFirst16BytesAsIV(false), iv(nullptr),
+ DrmInfo() : method(eMETHOD_NONE), mediaFormat(eMEDIAFORMAT_HLS), useFirst16BytesAsIV(false), iv(),
masterManifestURL(), manifestURL(), keyURI(), keyFormat(), systemUUID(), initData(), bPropagateUriParams(true),
bUseMediaSequenceIV(true), bDecryptClearSamplesRequired(true)
{};
@@ -55,11 +56,10 @@ struct DrmInfo
DrmInfo(const DrmInfo& other) : method(other.method), mediaFormat(other.mediaFormat),
useFirst16BytesAsIV(other.useFirst16BytesAsIV), masterManifestURL(other.masterManifestURL),
manifestURL(other.manifestURL), keyURI(other.keyURI), keyFormat(other.keyFormat),
- systemUUID(other.systemUUID), initData(other.initData), iv(), bPropagateUriParams(other.bPropagateUriParams),
+ systemUUID(other.systemUUID), initData(other.initData), bPropagateUriParams(other.bPropagateUriParams),
bUseMediaSequenceIV(other.bUseMediaSequenceIV), bDecryptClearSamplesRequired(other.bDecryptClearSamplesRequired)
{
- // copying same iv, releases memory allocated after deleting any of these objects.
- iv = other.iv;
+ memcpy( iv, other.iv, DRM_IV_LEN );
}
DrmInfo& operator=(const DrmInfo& other)
{
@@ -74,7 +74,7 @@ struct DrmInfo
systemUUID = other.systemUUID;
initData = other.initData;
// copying same iv, releases memory allocated after deleting any of these objects.
- iv = other.iv;
+ memcpy( iv, other.iv, DRM_IV_LEN );
return *this;
}
DrmMethod method; /**< Encryption method */
@@ -83,7 +83,7 @@ struct DrmInfo
bool bPropagateUriParams; /**< Propagate Manifest uri params in DRM */
bool bUseMediaSequenceIV; /**< To create IV using media sequence number */
bool bDecryptClearSamplesRequired; /**< Process call to decrypt clear samples */
- unsigned char *iv; /**< [16] Initialisation vector */
+ unsigned char iv[DRM_IV_LEN]; /**< [16] Initialisation vector */
std::string masterManifestURL; /**< URL of the master manifest */
std::string manifestURL; /**< URL of playlist the DRM info was taken from. May be the same as the masterManifestURL */
std::string keyURI; /**< URI to fetch key. May be relative to the manifest URL */
diff --git a/drm/AampSecManager.cpp b/drm/AampSecManager.cpp
index 0a545e1..35fa44f 100644
--- a/drm/AampSecManager.cpp
+++ b/drm/AampSecManager.cpp
@@ -133,14 +133,14 @@ AampSecManager::~AampSecManager()
UnRegisterAllEvents();
}
-static std::size_t getInputSummaryHash(const char* moneyTraceMetdata[][2], const char* contentMetdata,
+static std::size_t getInputSummaryHash(const char* moneyTraceMetadata[][2], const char* contentMetadata,
size_t contMetaLen, const char* licenseRequest, const char* keySystemId,
const char* mediaUsage, const char* accessToken, bool isVideoMuted)
{
std::stringstream ss;
- ss<< moneyTraceMetdata[0][1]<
diff --git a/fragmentcollector_hls.cpp b/fragmentcollector_hls.cpp
index 4ccaecb..ea1832d 100755
--- a/fragmentcollector_hls.cpp
+++ b/fragmentcollector_hls.cpp
@@ -71,24 +71,6 @@
#include "AampVanillaDrmHelper.h"
#include "AampCCManager.h"
-/**
- * @struct DrmMetadata
- * @brief AVE drm metadata extracted from EXT-X-FAXS-CM
- */
-struct DrmMetadata
-{ // from EXT-X-FAXS-CM
- unsigned char * metadataPtr;
- size_t metadataSize;
-};
-struct DrmMetadataNode
-{
- DrmMetadata metaData;
- int deferredInterval ;
- long long drmKeyReqTime;
- char* sha1Hash;
-};
-#define DRM_SHA1_HASH_LEN 40
-
static const int DEFAULT_STREAM_WIDTH = 720;
static const int DEFAULT_STREAM_HEIGHT = 576;
static const double DEFAULT_STREAM_FRAMERATE = 25.0;
@@ -137,7 +119,7 @@ static void ParseKeyAttributeCallback(lstring attrName, lstring valuePtr, void*
}
}
ts->fragmentEncrypted = false;
- ts->UpdateDrmCMSha1Hash(NULL);
+ ts->UpdateDrmCMSha1Hash("");
}
ts->mDrmMethod = eDRM_KEY_METHOD_NONE;
}
@@ -224,7 +206,7 @@ static void ParseKeyAttributeCallback(lstring attrName, lstring valuePtr, void*
if( valuePtr.removePrefix("0x") || valuePtr.removePrefix("0X") )
{
std::string temp = valuePtr.tostring();
- ts->UpdateDrmIV(temp.c_str());
+ ts->UpdateDrmIV(temp);
ts->mDrmInfo.bUseMediaSequenceIV = false;
}
}
@@ -233,7 +215,7 @@ static void ParseKeyAttributeCallback(lstring attrName, lstring valuePtr, void*
if( valuePtr.removePrefix("0x") || valuePtr.removePrefix("0X") )
{
std::string temp = valuePtr.tostring();
- ts->UpdateDrmCMSha1Hash(temp.c_str());
+ ts->UpdateDrmCMSha1Hash(temp);
}
}
}
@@ -743,136 +725,130 @@ AAMPStatusType StreamAbstractionAAMP_HLS::ParseMainManifest()
lstring TrackState::GetIframeFragmentUriFromIndex(bool &bSegmentRepeated)
{
lstring uri;
- const IndexNode *index = (IndexNode *) this->index.GetPtr();
- const IndexNode *idxNode = NULL;
- int idx;
- if (context->rate > 0)
- {
- const IndexNode *lastIndexNode = &index[indexCount - 1];
- AampTime seekWindowEnd{lastIndexNode->completionTimeSecondsFromStart - aamp->mLiveOffset};
- if (IsLive() && playTarget > seekWindowEnd)
- {
- AAMPLOG_WARN("rate - %f playTarget(%f) > seekWindowEnd(%f), forcing EOS",
- context->rate, playTarget.inSeconds(), seekWindowEnd.inSeconds());
- return uri;
- }
-
- if (currentIdx == -1)
- { // search forward from beginning
- currentIdx = 0;
- }
- for (idx = currentIdx; idx < indexCount; idx++)
- { // search in direction until out-of-bounds
- const IndexNode *node = &index[idx];
- //AAMPLOG_WARN("rate %f completionTimeSecondsFromStart %f playTarget %f", rate, node->completionTimeSecondsFromStart, playTarget);
- if (node->completionTimeSecondsFromStart >= playTarget)
- { // found target iframe
- idxNode = node;
- break;
- }
- }
- }
- else
- {
- if (-1 == currentIdx)
- { // search backward from end
- currentIdx = indexCount - 1;
- }
- for (idx = currentIdx; idx >= 0; idx--)
- { // search in direction until out-of-bounds
- const IndexNode *node = &index[idx];
- if (node->completionTimeSecondsFromStart <= playTarget)
- { // found target iframe
- idxNode = node;
- break;
+ auto count = index.size();
+ if( count>0 )
+ {
+ const IndexNode *idxNode = NULL;
+ if( context->rate > 0 )
+ {
+ const IndexNode &lastIndexNode = index[count - 1];
+ AampTime seekWindowEnd{lastIndexNode.completionTimeSecondsFromStart - aamp->mLiveOffset};
+ if (IsLive() && playTarget > seekWindowEnd)
+ {
+ AAMPLOG_WARN("rate - %f playTarget(%f) > seekWindowEnd(%f), forcing EOS",
+ context->rate, playTarget.inSeconds(), seekWindowEnd.inSeconds());
+ return uri;
+ }
+ if( currentIdx == -1 )
+ { // search forward from beginning
+ currentIdx = 0;
+ }
+ for( int idx = currentIdx; idx < count; idx++ )
+ { // search in direction until out-of-bounds
+ if( index[idx].completionTimeSecondsFromStart >= playTarget )
+ { // found target iframe
+ currentIdx = idx;
+ idxNode = &index[idx];
+ break;
+ }
}
}
- }
- if (idxNode)
- {
- // For Fragmented MP4 check if initFragment injection is required
- if ( !idxNode->initFragmentPtr.empty() &&
- (mInitFragmentInfo.empty() || !mInitFragmentInfo.equal(idxNode->initFragmentPtr)) )
- {
- mInitFragmentInfo = idxNode->initFragmentPtr;
- mInjectInitFragment = true;
- }
-
- currentIdx = idx;
- byteRangeOffset = 0;
- byteRangeLength = 0;
- //AAMPLOG_WARN("fragmentinfo %s", idxNode->pFragmentInfo);
- lstring fragmentInfo = idxNode->pFragmentInfo;
- fragmentDurationSeconds = idxNode->completionTimeSecondsFromStart.inSeconds();
- if (idx > 0)
- {
- fragmentDurationSeconds -= index[idx - 1].completionTimeSecondsFromStart.inSeconds();
- }
-
- if(lastDownloadedIFrameTarget != -1.0 && idxNode->completionTimeSecondsFromStart == lastDownloadedIFrameTarget)
- {
- // found playtarget and lastdownloaded target on same segment .
- bSegmentRepeated = true;
- }
else
- { // diff segment
- bSegmentRepeated = false;
- lastDownloadedIFrameTarget = idxNode->completionTimeSecondsFromStart;
- }
-
- while (fragmentInfo.startswith('#'))
{
- IsExtXByteRange(fragmentInfo, &byteRangeLength, &byteRangeOffset);
- size_t offs = fragmentInfo.getPtr() - playlist.GetPtr();
- lstring iter( fragmentInfo.getPtr(), playlist.GetLen() - offs );
- fragmentInfo = iter.mystrpbrk(); // #EXTINF
- fragmentInfo = iter.mystrpbrk(); // url
+ if(-1 == currentIdx)
+ { // search backward from end
+ currentIdx = (int)(count - 1);
+ }
+ for( int idx = currentIdx; idx >= 0; idx-- )
+ { // search in direction until out-of-bounds
+ if( index[idx].completionTimeSecondsFromStart <= playTarget )
+ { // found target iframe
+ currentIdx = idx;
+ idxNode = &index[idx];
+ break;
+ }
+ }
}
-
+ if( idxNode )
{
- mFragmentURIFromIndex = fragmentInfo;
- uri = mFragmentURIFromIndex;
-
- //The EXT-X-TARGETDURATION tag specifies the maximum Media Segment duration.
- //The EXTINF duration of each Media Segment in the Playlist file, when rounded to the nearest integer,
- //MUST be less than or equal to the target duration
- if(!uri.empty() && std::round(fragmentDurationSeconds) > targetDurationSeconds)
+ // For Fragmented MP4 check if initFragment injection is required
+ if ( !idxNode->initFragmentPtr.empty() &&
+ (mInitFragmentInfo.empty() || !mInitFragmentInfo.equal(idxNode->initFragmentPtr)) )
{
- AAMPLOG_WARN("WARN - Fragment duration[%f] > TargetDuration[%f] for URI:%.*s",fragmentDurationSeconds, targetDurationSeconds.inSeconds(), uri.getLen(), uri.getPtr() );
+ mInitFragmentInfo = idxNode->initFragmentPtr;
+ mInjectInitFragment = true;
}
- }
-
- if (-1 == idxNode->drmMetadataIdx)
- {
- fragmentEncrypted = false;
- }
- else
- {
- fragmentEncrypted = true;
- // for each iframe , need to see if KeyTag changed and get the drminfo .
- // Get the key Index position .
- int keyIndexPosn = idxNode->drmMetadataIdx;
- if(keyIndexPosn != mLastKeyTagIdx)
+ byteRangeOffset = 0;
+ byteRangeLength = 0;
+ lstring fragmentInfo = idxNode->pFragmentInfo;
+ fragmentDurationSeconds = idxNode->completionTimeSecondsFromStart.inSeconds();
+ if( currentIdx > 0 )
+ {
+ fragmentDurationSeconds -= index[currentIdx - 1].completionTimeSecondsFromStart.inSeconds();
+ }
+ if(lastDownloadedIFrameTarget != -1.0 && idxNode->completionTimeSecondsFromStart == lastDownloadedIFrameTarget)
+ { // found playtarget and lastdownloaded target on same segment .
+ bSegmentRepeated = true;
+ }
+ else
+ { // diff segment
+ bSegmentRepeated = false;
+ lastDownloadedIFrameTarget = idxNode->completionTimeSecondsFromStart;
+ }
+ while (fragmentInfo.startswith('#'))
+ {
+ IsExtXByteRange(fragmentInfo, &byteRangeLength, &byteRangeOffset);
+ size_t offs = fragmentInfo.getPtr() - playlist.GetPtr();
+ lstring iter( fragmentInfo.getPtr(), playlist.GetLen() - offs );
+ fragmentInfo = iter.mystrpbrk(); // #EXTINF
+ fragmentInfo = iter.mystrpbrk(); // url
+ }
+
+ {
+ mFragmentURIFromIndex = fragmentInfo;
+ uri = mFragmentURIFromIndex;
+
+ //The EXT-X-TARGETDURATION tag specifies the maximum Media Segment duration.
+ //The EXTINF duration of each Media Segment in the Playlist file, when rounded to the nearest integer,
+ //MUST be less than or equal to the target duration
+ if(!uri.empty() && std::round(fragmentDurationSeconds) > targetDurationSeconds)
+ {
+ AAMPLOG_WARN("WARN - Fragment duration[%f] > TargetDuration[%f] for URI:%.*s",fragmentDurationSeconds, targetDurationSeconds.inSeconds(), uri.getLen(), uri.getPtr() );
+ }
+ }
+
+ if (-1 == idxNode->drmMetadataIdx)
+ {
+ fragmentEncrypted = false;
+ }
+ else
{
- AAMPLOG_WARN("[%d] KeyTable Size [%d] keyIndexPosn[%d] lastKeyIdx[%d]",type, (int)mKeyHashTable.size(), keyIndexPosn, mLastKeyTagIdx);
- if(keyIndexPosn < mKeyHashTable.size() )
+ fragmentEncrypted = true;
+ // for each iframe , need to see if KeyTag changed and get the drminfo .
+ // Get the key Index position .
+ int keyIndexPosn = idxNode->drmMetadataIdx;
+ if(keyIndexPosn != mLastKeyTagIdx)
{
- std::string &keyStr = mKeyHashTable[keyIndexPosn].mKeyTagStr;
- lstring key = lstring( keyStr.c_str(), keyStr.size() );
- if( !key.empty() )
+ AAMPLOG_WARN("[%d] KeyTable Size [%d] keyIndexPosn[%d] lastKeyIdx[%d]",type, (int)mKeyHashTable.size(), keyIndexPosn, mLastKeyTagIdx);
+ if(keyIndexPosn < mKeyHashTable.size() )
{
- key.ParseAttrList( ParseKeyAttributeCallback, this );
+ std::string &keyStr = mKeyHashTable[keyIndexPosn].mKeyTagStr;
+ lstring key = lstring( keyStr.c_str(), keyStr.size() );
+ if( !key.empty() )
+ {
+ key.ParseAttrList( ParseKeyAttributeCallback, this );
+ }
}
+ mKeyTagChanged = true;
+ mLastKeyTagIdx = keyIndexPosn;
}
- mKeyTagChanged = true;
- mLastKeyTagIdx = keyIndexPosn;
}
}
- }
- else
- {
- AAMPLOG_WARN("Couldn't find node - rate %f playTarget %f",
- context->rate, playTarget.inSeconds());
+ else
+ {
+ AAMPLOG_WARN("Couldn't find node - rate %f playTarget %f",
+ context->rate, playTarget.inSeconds());
+ }
}
return uri;
}
@@ -1024,14 +1000,14 @@ lstring TrackState::GetNextFragmentUriFromPlaylist(bool& reloadUri, bool ignoreD
AAMPLOG_WARN("#EXT-X-ENDLIST");
mReachedEndListTag = true;
}
- else if (ptr.removePrefix("-X-DISCONTINUITY"))
+ else if ( ptr.removePrefix("-X-DISCONTINUITY"))
{
discontinuity = true;
}
else
{
static const char *ignoreList[] = {
- "-X-PLAYLIST-TYPE:" "-X-DISCONTINUITY-SEQUENCE", "-X-I-FRAMES-ONLY", "-X-VERSION:", "-X-FAXS-CM:", "-X-FAXS-PACKAGINGCERT", "-X-FAXS-SIGNATURE", "-X-CUE", "-X-CM-SEQUENCE", "-X-MARKER", "-X-MAP", "-X-MEDIA-TIME", "-X-END-TOP-TAGS", "-X-CONTENT-IDENTIFIER", "-X-TRICKMODE-RESTRICTION", "-X-INDEPENDENT-SEGMENTS", "-X-BITRATE", "-X-FOG", "-UPLYNK-LIVE", "-X-START:", "-X-XCAL-CONTENTMETADATA", "-NOM-I-FRAME-DISTANCE", "-X-ADVERTISING", "-X-SOURCE-STREAM", "-X-X1-LIN-CK", "-X-SCTE35", "-X-ASSET", "-X-CUE-OUT", "-X-CUE-IN", "-X-DATERANGE", "-X-SPLICEPOINT-SCTE35" };
+ "-X-PLAYLIST-TYPE:", "-X-I-FRAMES-ONLY", "-X-VERSION:", "-X-FAXS-CM:", "-X-FAXS-PACKAGINGCERT", "-X-FAXS-SIGNATURE", "-X-CUE", "-X-CM-SEQUENCE", "-X-MARKER", "-X-MAP", "-X-MEDIA-TIME", "-X-END-TOP-TAGS", "-X-CONTENT-IDENTIFIER", "-X-TRICKMODE-RESTRICTION", "-X-INDEPENDENT-SEGMENTS", "-X-BITRATE", "-X-FOG", "-UPLYNK-LIVE", "-X-START:", "-X-XCAL-CONTENTMETADATA", "-NOM-I-FRAME-DISTANCE", "-X-ADVERTISING", "-X-SOURCE-STREAM", "-X-X1-LIN-CK", "-X-SCTE35", "-X-ASSET", "-X-CUE-OUT", "-X-CUE-IN", "-X-DATERANGE", "-X-SPLICEPOINT-SCTE35" };
LogUnknownTag( ptr, ARRAY_SIZE(ignoreList), ignoreList );
}
}
@@ -1399,7 +1375,7 @@ bool TrackState::FetchFragmentHelper(int &http_error, bool &decryption_error, bo
playTargetBufferCalc += fragmentDurationSeconds;
}
- if((eTRACK_VIDEO == type) && (aamp->IsTSBSupported()))
+ if((eTRACK_VIDEO == type) && (aamp->IsFogTSBSupported()))
{
std::size_t pos = fragmentUrl.find(FOG_FRAG_BW_IDENTIFIER);
if (pos != std::string::npos)
@@ -1440,15 +1416,9 @@ bool TrackState::FetchFragmentHelper(int &http_error, bool &decryption_error, bo
*/
if ( eMETHOD_AES_128 == mDrmInfo.method && true == mDrmInfo.bUseMediaSequenceIV )
{
- if ( true == CreateInitVectorByMediaSeqNo( nextMediaSequenceNumber-1 ) )
- {
- // Set this flag to seed the newly created IV to corresponding DRM instance
- mKeyTagChanged = true;
- }
- else
- {
- AAMPLOG_WARN ( "FetchFragmentHelper : Create Init Vector failed");
- }
+ CreateInitVectorByMediaSeqNo( nextMediaSequenceNumber-1 );
+ // seed the newly created IV to corresponding DRM instance
+ mKeyTagChanged = true;
}
AAMPLOG_TRACE(" [%s] uri %s - calling DrmDecrypt()",name, fragmentUrl.c_str());
@@ -1647,7 +1617,7 @@ void TrackState::FetchFragment()
// in case of tsb, GetCurrentBandWidth does not return correct bandwidth as it is updated after this point
// hence getting from context which is updated in FetchFragmentHelper
- long lbwd = aamp->IsTSBSupported() ? context->GetTsbBandwidth() : this->GetCurrentBandWidth();
+ long lbwd = aamp->IsFogTSBSupported() ? context->GetTsbBandwidth() : this->GetCurrentBandWidth();
//update videoend info
aamp->UpdateVideoEndMetrics((IS_FOR_IFRAME(iCurrentRate, type) ? eMEDIATYPE_IFRAME : (AampMediaType)(type)),
lbwd,
@@ -1696,7 +1666,7 @@ void TrackState::FetchFragment()
cachedFragment->absPosition = playlistPosition.inSeconds();
// in case of tsb, GetCurrentBandWidth does not return correct bandwidth as it is updated after this point
// hence getting from context which is updated in FetchFragmentHelper
- long lbwd = aamp->IsTSBSupported() ? context->GetTsbBandwidth() : this->GetCurrentBandWidth();
+ long lbwd = aamp->IsFogTSBSupported() ? context->GetTsbBandwidth() : this->GetCurrentBandWidth();
// update videoend info
aamp->UpdateVideoEndMetrics( (IS_FOR_IFRAME(iCurrentRate,type)? eMEDIATYPE_IFRAME:(AampMediaType)(type) ),
@@ -1803,7 +1773,7 @@ void TrackState::InjectFragmentInternal(CachedFragment* cachedFragment, bool &fr
static AampTime GetCompletionTimeForFragment(const TrackState *trackState, long long mediaSequenceNumber)
{
AampTime rc{};
- int indexCount = trackState->indexCount; // number of fragments
+ int indexCount = (int)trackState->index.size(); // number of fragments
if (indexCount>0)
{
int idx = (int)(mediaSequenceNumber - trackState->indexFirstMediaSequenceNumber);
@@ -1813,8 +1783,8 @@ static AampTime GetCompletionTimeForFragment(const TrackState *trackState, long
{ // clamp
idx = indexCount - 1;
}
- const IndexNode *node = &((IndexNode *)trackState->index.GetPtr())[idx];
- rc = node->completionTimeSecondsFromStart; // pick up from indexed playlist
+ const IndexNode &node = trackState->index[idx];
+ rc = node.completionTimeSecondsFromStart; // pick up from indexed playlist
}
else
{
@@ -1829,47 +1799,29 @@ static AampTime GetCompletionTimeForFragment(const TrackState *trackState, long
*/
void TrackState::FlushIndex()
{
- index.Free();
+ index.clear();
indexFirstMediaSequenceNumber = 0;
mProgramDateTime = 0.0; // new member - stored first program date time (if any) from playlist
- indexCount = 0;
currentIdx = -1;
mDrmKeyTagCount = 0;
mLastKeyTagIdx = -1;
mDeferredDrmKeyMaxTime = 0;
mKeyHashTable.clear();
- mDiscontinuityIndexCount = 0;
- mDiscontinuityIndex.Free();
- if (mDrmMetaDataIndexCount)
+ mDiscontinuityIndex.clear();
+ int drmMetaDataIndexCount = (int)mDrmMetaDataIndex.size();
+ if( drmMetaDataIndexCount )
{
- AAMPLOG_TRACE("TrackState::[%s]mDrmMetaDataIndexCount %d", name,
- mDrmMetaDataIndexCount);
- DrmMetadataNode* drmMetadataNode = (DrmMetadataNode*) mDrmMetaDataIndex.GetPtr();
- assert(NULL != drmMetadataNode);
- for (int i = 0; i < mDrmMetaDataIndexCount; i++)
+ AAMPLOG_TRACE("TrackState::[%s]mDrmMetaDataIndexCount %d", name, drmMetaDataIndexCount);
+ for (int i = 0; i < drmMetaDataIndexCount; i++)
{
- AAMPLOG_TRACE("TrackState::drmMetadataNode[%d].metaData.metadataPtr %p",i,
- drmMetadataNode[i].metaData.metadataPtr);
-
- if ((NULL == drmMetadataNode[i].metaData.metadataPtr || NULL == drmMetadataNode[i].sha1Hash) && mDrmMetaDataIndexCount)
+ DrmMetadataNode &drmMetadataNode = mDrmMetaDataIndex[i];
+ if( drmMetadataNode.sha1Hash.empty() )
{
- AAMPLOG_WARN ("TrackState: **** metadataPtr/sha1Hash is NULL, give attention and analyze it... mDrmMetaDataIndexCount[%d]", mDrmMetaDataIndexCount);
- }
-
- if (drmMetadataNode[i].metaData.metadataPtr)
- {
- free(drmMetadataNode[i].metaData.metadataPtr);
- drmMetadataNode[i].metaData.metadataPtr = NULL;
- }
-
- if (drmMetadataNode[i].sha1Hash)
- {
- free(drmMetadataNode[i].sha1Hash);
- drmMetadataNode[i].sha1Hash = NULL;
+ AAMPLOG_ERR("TrackState: **** metadataPtr/sha1Hash is NULL, give attention and analyze it... mDrmMetaDataIndexCount[%d]", drmMetaDataIndexCount);
}
+ drmMetadataNode.sha1Hash.clear();
}
- mDrmMetaDataIndex.Free();
- mDrmMetaDataIndexCount = 0;
+ mDrmMetaDataIndex.clear();
mDrmMetaDataIndexPosition = 0;
}
mInitFragmentInfo.clear();
@@ -1883,7 +1835,7 @@ void TrackState::SetDrmContext()
// Set the appropriate DrmContext for Decryption
// This function need to be called where KeyMethod != None is found after indexplaylist
// or when new KeyMethod is found , None to AES or between AES with different Method
- // or between KeyMethond when IV or URL changes (for Vanilla AES)
+ // or between KeyMethod when IV or URL changes (for Vanilla AES)
//CID:93939 - Removed the drmContextUpdated variable which is initialized but not used
mDrmInfo.bPropagateUriParams = ISCONFIGSET(eAAMPConfig_PropagateURIParam);
@@ -1928,6 +1880,7 @@ void TrackState::IndexPlaylist(bool IsRefresh, AampTime &culledSec)
long long commonPlayPosition = nextMediaSequenceNumber - 1;
AampTime prevSecondsBeforePlayPoint{};
lstring initFragmentPtr;
+ uint64_t discontinuitySequenceIndex = 0;
if(IsRefresh && !UseProgramDateTimeIfAvailable())
{
@@ -1975,7 +1928,8 @@ void TrackState::IndexPlaylist(bool IsRefresh, AampTime &culledSec)
if (discontinuity)
{
DiscontinuityIndexNode discontinuityIndexNode;
- discontinuityIndexNode.fragmentIdx = indexCount;
+ discontinuityIndexNode.discontinuitySequenceIndex = discontinuitySequenceIndex;
+ discontinuityIndexNode.fragmentIdx = (int)index.size();
discontinuityIndexNode.position = totalDuration.inSeconds();
discontinuityIndexNode.discontinuityPDT = 0.0;
if (programDateTimeIdxOfFragment)
@@ -1983,14 +1937,12 @@ void TrackState::IndexPlaylist(bool IsRefresh, AampTime &culledSec)
discontinuityIndexNode.discontinuityPDT = ISO8601DateTimeToUTCSeconds(programDateTimeIdxOfFragment);
}
discontinuityIndexNode.fragmentDuration = ptr.atof();
- mDiscontinuityIndex.AppendBytes(&discontinuityIndexNode, sizeof(DiscontinuityIndexNode));
- mDiscontinuityIndexCount++;
+ mDiscontinuityIndex.push_back(discontinuityIndexNode);
discontinuity = false;
}
programDateTimeIdxOfFragment = NULL;
node.pFragmentInfo = prev; //Point back to beginning of #EXTINF
fragDuration = ptr.atof();
- indexCount++;
totalDuration += fragDuration;
node.completionTimeSecondsFromStart = totalDuration.inSeconds();
node.drmMetadataIdx = drmMetadataIdx;
@@ -1999,7 +1951,7 @@ void TrackState::IndexPlaylist(bool IsRefresh, AampTime &culledSec)
{
node.mediaSequenceNumber++;
}
- index.AppendBytes( &node, sizeof(node) );
+ index.push_back(node);
}
else if(ptr.removePrefix("-X-MEDIA-SEQUENCE:"))
{
@@ -2040,16 +1992,17 @@ void TrackState::IndexPlaylist(bool IsRefresh, AampTime &culledSec)
{
// AVE DRM Not supported
}
- else if(ptr.removePrefix("-X-DISCONTINUITY-SEQUENCE"))
+ else if(ptr.removePrefix("-X-DISCONTINUITY-SEQUENCE:"))
{
- // ignore sequence
+ discontinuitySequenceIndex = ptr.atoll();
}
- else if(ptr.removePrefix("-X-DISCONTINUITY"))
+ else if( ptr.removePrefix("-X-DISCONTINUITY"))
{
+ discontinuitySequenceIndex++;
discontinuity = true;
if(ISCONFIGSET(eAAMPConfig_StreamLogging))
{
- AAMPLOG_WARN("%s [%d] Discontinuity Posn : %f ",name,indexCount,totalDuration.inSeconds());
+ AAMPLOG_MIL("%s [%zu] Discontinuity Posn : %f, discontinuitySequenceIndex=%" PRIu64, name, index.size(), totalDuration.inSeconds(), discontinuitySequenceIndex );
}
}
else if (ptr.removePrefix("-X-PROGRAM-DATE-TIME:"))
@@ -2062,7 +2015,7 @@ void TrackState::IndexPlaylist(bool IsRefresh, AampTime &culledSec)
if(!pdtAtTopAvailable)
{
// Fix : mProgramDateTime to be updated only for playlist at top of playlist , not with each segment of Discontinuity
- if(indexCount)
+ if(index.size())
{
// Found PDT in between , not at the top . Need to extrapolate and find the ProgramDateTime of first segment
AampTime tmppdt{ISO8601DateTimeToUTCSeconds(ptr.getPtr())};
@@ -2132,14 +2085,13 @@ void TrackState::IndexPlaylist(bool IsRefresh, AampTime &culledSec)
if(!fragmentEncrypted || mDrmMethod == eDRM_KEY_METHOD_SAMPLE_AES_CTR)
{
drmMetadataIdx = -1;
- AAMPLOG_TRACE("Not encrypted - fragmentEncrypted %d mCMSha1Hash %p mDrmMethod %d", fragmentEncrypted, mCMSha1Hash, mDrmMethod);
+ AAMPLOG_TRACE("Not encrypted - fragmentEncrypted %d mCMSha1Hash %s mDrmMethod %d", fragmentEncrypted, mCMSha1Hash.c_str(), mDrmMethod);
}
// mCMSha1Hash is populated after ParseAttrList , hence added here
- if(mCMSha1Hash)
+ if( !mCMSha1Hash.empty() )
{
- keyinfo.mShaID.resize(DRM_SHA1_HASH_LEN);
- memcpy((char*)keyinfo.mShaID.data(), mCMSha1Hash, DRM_SHA1_HASH_LEN);
+ keyinfo.mShaID = mCMSha1Hash;
}
mKeyHashTable.push_back(keyinfo);
mKeyTagChanged = false;
@@ -2150,7 +2102,6 @@ void TrackState::IndexPlaylist(bool IsRefresh, AampTime &culledSec)
initFragmentPtr = ptr;
if (mCheckForInitialFragEnc)
{
-// AAMPLOG_TRACE("fragmentEncrypted-%d drmMethod-%d and ptr - %s", fragmentEncrypted, mDrmMethod, ptr);
// Map tag present indicates ISOBMFF fragments. We need to store an encrypted fragment's init header
// Ensure order of tags 1. EXT-X-KEY, 2. EXT-X-MAP
if (fragmentEncrypted && mDrmMethod == eDRM_KEY_METHOD_SAMPLE_AES_CTR && mFirstEncInitFragmentInfo == NULL)
@@ -2241,7 +2192,7 @@ void TrackState::IndexPlaylist(bool IsRefresh, AampTime &culledSec)
}
firstIndexDone = true;
mIndexingInProgress = false;
- AAMPLOG_TRACE("Exit indexCount %d mDrmMetaDataIndexCount %d", indexCount, mDrmMetaDataIndexCount);
+ AAMPLOG_TRACE("Exit indexCount %zu mDrmMetaDataIndexCount %zu", index.size(), mDrmMetaDataIndex.size() );
mDuration = totalDuration.inSeconds();
if(IsRefresh)
@@ -2739,31 +2690,30 @@ bool StreamAbstractionAAMP_HLS::IsLive()
* @brief Function to update play target based on audio video exact discontinuity positions.
*/
void StreamAbstractionAAMP_HLS::CheckDiscontinuityAroundPlaytarget(void)
-{
+{ // FIXME!
TrackState *audio = trackState[eMEDIATYPE_AUDIO];
TrackState *video = trackState[eMEDIATYPE_VIDEO];
- DiscontinuityIndexNode* videoDiscontinuityIndex = (DiscontinuityIndexNode*) video->mDiscontinuityIndex.GetPtr();
- DiscontinuityIndexNode* audioDiscontinuityIndex = (DiscontinuityIndexNode*) audio->mDiscontinuityIndex.GetPtr();
-
- for (int i = 0; i < video->mDiscontinuityIndexCount; i++)
+ for( DiscontinuityIndexNode &videoDiscontinuity : video->mDiscontinuityIndex )
{
- if (videoDiscontinuityIndex[i].position.seconds() == video->playTarget.seconds())
+ if (videoDiscontinuity.position.seconds() == video->playTarget.seconds())
{
- if (videoDiscontinuityIndex[i].position < audioDiscontinuityIndex[i].position)
+ for( DiscontinuityIndexNode &audioDiscontinuity : audio->mDiscontinuityIndex )
{
- AAMPLOG_WARN("video->playTarget %f -> %f audio->playTarget %f -> %f",
- video->playTarget.inSeconds(), videoDiscontinuityIndex[i].position.inSeconds(), audio->playTarget.inSeconds(), audioDiscontinuityIndex[i].position.inSeconds());
- video->playTarget = videoDiscontinuityIndex[i].position;
- audio->playTarget = audioDiscontinuityIndex[i].position;
- }
- else
- {
- AAMPLOG_WARN("video->playTarget %f -> %" PRIi64 "audio->playTarget %f -> %" PRIi64,
- video->playTarget.inSeconds(), audioDiscontinuityIndex[i].position.seconds(), audio->playTarget.inSeconds(), audioDiscontinuityIndex[i].position.seconds());
- video->playTarget = audio->playTarget = audioDiscontinuityIndex[i].position.seconds();
+ if (videoDiscontinuity.position < audioDiscontinuity.position)
+ {
+ AAMPLOG_WARN("video->playTarget %f -> %f audio->playTarget %f -> %f",
+ video->playTarget.inSeconds(), videoDiscontinuity.position.inSeconds(), audio->playTarget.inSeconds(), audioDiscontinuity.position.inSeconds());
+ video->playTarget = videoDiscontinuity.position;
+ audio->playTarget = audioDiscontinuity.position;
+ }
+ else
+ {
+ AAMPLOG_WARN("video->playTarget %f -> %" PRIi64 "audio->playTarget %f -> %" PRIi64,
+ video->playTarget.inSeconds(), audioDiscontinuity.position.seconds(), audio->playTarget.inSeconds(), audioDiscontinuity.position.seconds());
+ video->playTarget = audio->playTarget = audioDiscontinuity.position.seconds();
+ }
+ return;
}
-
- break;
}
}
}
@@ -2772,7 +2722,7 @@ void StreamAbstractionAAMP_HLS::CheckDiscontinuityAroundPlaytarget(void)
* @brief Function to synchronize time between audio & video for VOD stream with discontinuities and uneven track length
*/
AAMPStatusType StreamAbstractionAAMP_HLS::SyncTracksForDiscontinuity()
-{
+{ // FIXME!
TrackState *audio = trackState[eMEDIATYPE_AUDIO];
TrackState *video = trackState[eMEDIATYPE_VIDEO];
TrackState *subtitle = trackState[eMEDIATYPE_SUBTITLE];
@@ -2807,18 +2757,18 @@ AAMPStatusType StreamAbstractionAAMP_HLS::SyncTracksForDiscontinuity()
if (video->playTarget !=0)
{
/*If video playTarget is just before a discontinuity, move playTarget to the discontinuity position*/
- DiscontinuityIndexNode* videoDiscontinuityIndex = (DiscontinuityIndexNode*) video->mDiscontinuityIndex.GetPtr();
- DiscontinuityIndexNode* audioDiscontinuityIndex = (DiscontinuityIndexNode*) audio->mDiscontinuityIndex.GetPtr();
-
- for (int i = 0; i < video->mDiscontinuityIndexCount; i++)
+ for( auto i=0; imDiscontinuityIndex.size(); i++ )
{
- AampTime roundedIndexPosition{(double)videoDiscontinuityIndex[i].position.nearestSecond()};
- AampTime roundedFragDuration{(double)videoDiscontinuityIndex[i].fragmentDuration.nearestSecond()};
+ DiscontinuityIndexNode &videoDiscontinuity = video->mDiscontinuityIndex[i];
+ AampTime roundedIndexPosition{(double)videoDiscontinuity.position.nearestSecond()};
+ AampTime roundedFragDuration{(double)videoDiscontinuity.fragmentDuration.nearestSecond()};
// check if playtarget is on discontinuity , around it or away from discontinuity
AampTime diff{roundedIndexPosition - roundedPlayTarget};
- videoPeriodStartCurrentPeriod = videoDiscontinuityIndex[i].position;
- audioPeriodStartCurrentPeriod = audioDiscontinuityIndex[i].position;
+ videoPeriodStartCurrentPeriod = videoDiscontinuity.position;
+
+ DiscontinuityIndexNode &audioDiscontinuity = audio->mDiscontinuityIndex[i];
+ audioPeriodStartCurrentPeriod = audioDiscontinuity.position;
// if play position is same as start of discontinuity , just start there , no checks
// if play position is within fragmentduration window , just start at discontinuity
@@ -2834,7 +2784,7 @@ AAMPStatusType StreamAbstractionAAMP_HLS::SyncTracksForDiscontinuity()
// this case : playtarget is after the discontinuity , but not sure if this is within
// current period .
offsetVideoToAdd = (roundedPlayTarget - roundedIndexPosition);
- offsetAudioToAdd = (roundedPlayTarget - audioDiscontinuityIndex[i].position.nearestSecond());
+ offsetAudioToAdd = (roundedPlayTarget - audioDiscontinuity.position.nearestSecond());
// Not sure if this is last period or not ,so update the Offset
}
else if(diff > 0 )
@@ -3439,7 +3389,7 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
else
{
// Set Default init bitrate according to last PersistBandwidth
- if((ISCONFIGSET(eAAMPConfig_PersistLowNetworkBandwidth)|| ISCONFIGSET(eAAMPConfig_PersistHighNetworkBandwidth)) && !aamp->IsTSBSupported())
+ if((ISCONFIGSET(eAAMPConfig_PersistLowNetworkBandwidth)|| ISCONFIGSET(eAAMPConfig_PersistHighNetworkBandwidth)) && !aamp->IsFogTSBSupported())
{
long persistbandwidth = aamp->mhAbrManager.getPersistBandwidth();
long TimeGap = aamp_GetCurrentTimeMS() - ABRManager::mPersistBandwidthUpdatedTime;
@@ -3648,7 +3598,7 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
if (rate != AAMP_NORMAL_PLAY_RATE)
{
trickplayMode = true;
- if(aamp->IsTSBSupported())
+ if(aamp->IsFogTSBSupported())
{
mTrickPlayFPS = GETCONFIGVALUE(eAAMPConfig_LinearTrickPlayFPS);
}
@@ -3695,7 +3645,7 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
SeekPosUpdate(seekPosition.inSeconds() - culled.inSeconds());
}
}
- if(ts->mDrmMetaDataIndexCount > 0)
+ if(ts->mDrmMetaDataIndex.size() > 0)
{
AAMPLOG_ERR("TrackState: Sending Error event DRM unsupported");
return eAAMPSTATUS_UNSUPPORTED_DRM_ERROR;
@@ -4038,7 +3988,7 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
else
{
this->trickplayMode = true;
- if(aamp->IsTSBSupported())
+ if(aamp->IsFogTSBSupported())
{
mTrickPlayFPS = GETCONFIGVALUE(eAAMPConfig_LinearTrickPlayFPS);
}
@@ -4198,8 +4148,9 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
{
if(!ISCONFIGSET(eAAMPConfig_AudioOnlyPlayback))
{
- if (!liveAdjust && video->mDiscontinuityIndexCount && (video->mDiscontinuityIndexCount == other->mDiscontinuityIndexCount))
- {
+ auto count = video->mDiscontinuityIndex.size();
+ if (!liveAdjust && count>0 && count == other->mDiscontinuityIndex.size() )
+ { // FIXME
SyncTracksForDiscontinuity();
}
}
@@ -4282,10 +4233,10 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
if ((audio->enabled || aux->enabled) && (aamp->IsLive()) && !ISCONFIGSET(eAAMPConfig_AudioOnlyPlayback))
{
TrackState *otherTrack = audio->enabled ? audio : aux;
- int discontinuityIndexCount = video->mDiscontinuityIndexCount;
+ auto discontinuityIndexCount = video->mDiscontinuityIndex.size();
if (discontinuityIndexCount > 0)
{
- if (discontinuityIndexCount == otherTrack->mDiscontinuityIndexCount)
+ if (discontinuityIndexCount == otherTrack->mDiscontinuityIndex.size())
{
if (liveAdjust)
{
@@ -4295,14 +4246,14 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
AampTime audioPrevDiscontinuity{};
AampTime videoNextDiscontinuity{};
AampTime audioNextDiscontinuity{};
- DiscontinuityIndexNode* videoDiscontinuityIndex = (DiscontinuityIndexNode*)video->mDiscontinuityIndex.GetPtr();
- DiscontinuityIndexNode* audioDiscontinuityIndex = (DiscontinuityIndexNode*)otherTrack->mDiscontinuityIndex.GetPtr();
- for (int i = 0; i <= discontinuityIndexCount; i++)
+ for (auto i = 0; i <= video->mDiscontinuityIndex.size(); i++)
{
+ DiscontinuityIndexNode & videoDiscontinuity = video->mDiscontinuityIndex[i];
+ DiscontinuityIndexNode & audioDiscontinuity = audio->mDiscontinuityIndex[i];
if (i < discontinuityIndexCount)
{
- videoNextDiscontinuity = videoDiscontinuityIndex[i].position;
- audioNextDiscontinuity = audioDiscontinuityIndex[i].position;
+ videoNextDiscontinuity = videoDiscontinuity.position;
+ audioNextDiscontinuity = audioDiscontinuity.position;
}
else
{
@@ -4310,9 +4261,8 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
audioNextDiscontinuity = videoNextDiscontinuity;
}
if ((videoNextDiscontinuity > (video->playTarget + 5))
- && (audioNextDiscontinuity > (otherTrack->playTarget + 5)))
+ && (audioNextDiscontinuity > (otherTrack->playTarget + 5)))
{
-
AAMPLOG_WARN( "StreamAbstractionAAMP_HLS: video->playTarget %f videoPrevDiscontinuity %f videoNextDiscontinuity %f",
video->playTarget.inSeconds(), videoPrevDiscontinuity.inSeconds(), videoNextDiscontinuity.inSeconds());
AAMPLOG_WARN( "StreamAbstractionAAMP_HLS: %s->playTarget %f audioPrevDiscontinuity %f audioNextDiscontinuity %f",
@@ -4339,8 +4289,8 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
}
else
{
- AAMPLOG_WARN("StreamAbstractionAAMP_HLS: videoPeriodPositionIndex.size %d audioPeriodPositionIndex.size %d",
- video->mDiscontinuityIndexCount, otherTrack->mDiscontinuityIndexCount);
+ AAMPLOG_WARN("StreamAbstractionAAMP_HLS: videoPeriodPositionIndex.size %zu audioPeriodPositionIndex.size %zu",
+ video->mDiscontinuityIndex.size(), otherTrack->mDiscontinuityIndex.size());
}
}
else
@@ -4375,7 +4325,7 @@ AAMPStatusType StreamAbstractionAAMP_HLS::Init(TuneType tuneType)
}
// To avoid audio loss while seeking HLS/TS AV of different duration w/o affecting VOD Discontinuities
- if(iTrack == 0 && ISCONFIGSET(eAAMPConfig_SyncAudioFragments) && !(ISCONFIGSET(eAAMPConfig_MidFragmentSeek) || audio->mDiscontinuityIndexCount))
+ if(iTrack == 0 && ISCONFIGSET(eAAMPConfig_SyncAudioFragments) && !(ISCONFIGSET(eAAMPConfig_MidFragmentSeek) || audio->mDiscontinuityIndex.size()))
{
AAMPLOG_TRACE("Setting audio playtarget %f to video playtarget %f", audio->playTarget.inSeconds(), ts->playTarget.inSeconds());
audio->playTarget = ts->playTarget;
@@ -4853,14 +4803,14 @@ void TrackState::RunFetchLoop()
}
// reached end of vod stream
//teststreamer_EndOfStreamReached();
- if(!abortedDownload && context->aamp->IsTSBSupported() && eosReached)
+ if(!abortedDownload && context->aamp->IsFogTSBSupported() && eosReached)
{
AbortWaitForCachedAndFreeFragment(false);
/* Make the aborted variable to true to avoid
* further fragment fetch loop running and abort sending multiple time */
abortedDownload = true;
}
- else if ((eosReached && !context->aamp->IsTSBSupported()) || mReachedEndListTag || !context->aamp->DownloadsAreEnabled())
+ else if ((eosReached && !context->aamp->IsFogTSBSupported()) || mReachedEndListTag || !context->aamp->DownloadsAreEnabled())
{
/* Check whether already aborted or not */
if(!abortedDownload)
@@ -4967,7 +4917,7 @@ TrackState::TrackState(TrackType type, StreamAbstractionAAMP_HLS* parent, Privat
ptsoffset_update_t ptsUpdate
) :
MediaTrack(type, aamp, name),
- indexCount(0), currentIdx(0), indexFirstMediaSequenceNumber(0), fragmentURI(), lastPlaylistDownloadTimeMS(0), lastPlaylistIndexedTimeMS(0),
+ currentIdx(0), indexFirstMediaSequenceNumber(0), fragmentURI(), lastPlaylistDownloadTimeMS(0), lastPlaylistIndexedTimeMS(0),
byteRangeLength(0), byteRangeOffset(0), nextMediaSequenceNumber(0), playlistPosition(0), playTarget(0),playTargetBufferCalc(0),lastDownloadedIFrameTarget(-1),
streamOutputFormat(FORMAT_INVALID),
playTargetOffset(0),
@@ -4975,14 +4925,14 @@ TrackState::TrackState(TrackType type, StreamAbstractionAAMP_HLS* parent, Privat
refreshPlaylist(false), fragmentCollectorThreadID(), isFirstFragmentAfterABR(false),
fragmentCollectorThreadStarted(false),
manifestDLFailCount(0),
- mCMSha1Hash(NULL), mDrmTimeStamp(0), mDrmMetaDataIndexCount(0),firstIndexDone(false), mDrm(NULL), mDrmLicenseRequestPending(false),
+ mCMSha1Hash(), mDrmTimeStamp(0), firstIndexDone(false), mDrm(NULL), mDrmLicenseRequestPending(false),
mInjectInitFragment(false), mInitFragmentInfo(), mDrmKeyTagCount(0), mIndexingInProgress(false), mForceProcessDrmMetadata(false),
mDuration(0), mLastMatchedDiscontPosition(-1), mCulledSeconds(0),mCulledSecondsOld(0),
mEffectiveUrl(""), mPlaylistUrl(""), mFragmentURIFromIndex(),
- mDiscontinuityIndexCount(0), mSyncAfterDiscontinuityInProgress(false), playlist("playlist"),
- index("playlist-index"), targetDurationSeconds(1), mDeferredDrmKeyMaxTime(0), startTimeForPlaylistSync(0.0),
+ mSyncAfterDiscontinuityInProgress(false), playlist("playlist"),
+ index(), targetDurationSeconds(1), mDeferredDrmKeyMaxTime(0), startTimeForPlaylistSync(0.0),
context(parent), fragmentEncrypted(false), mKeyTagChanged(false), mIVKeyChanged(false), mLastKeyTagIdx(0), mDrmInfo(),
- mDrmMetaDataIndexPosition(0), mDrmMetaDataIndex("drm-metadata-index"), mDiscontinuityIndex("discontinuity-index"), mKeyHashTable(), mPlaylistMutex(),
+ mDrmMetaDataIndexPosition(0), mDrmMetaDataIndex(), mDiscontinuityIndex(), mKeyHashTable(), mPlaylistMutex(),
mPlaylistIndexed(), mTrackDrmMutex(), mPlaylistType(ePLAYLISTTYPE_UNDEFINED), mReachedEndListTag(false),
mByteOffsetCalculation(false),mSkipAbr(false),
mCheckForInitialFragEnc(false), mFirstEncInitFragmentInfo(NULL), mDrmMethod(eDRM_KEY_METHOD_NONE)
@@ -4993,12 +4943,10 @@ TrackState::TrackState(TrackType type, StreamAbstractionAAMP_HLS* parent, Privat
,fragmentEncChange(false)
{
playlist.Clear();
- index.Clear();
+ index.clear();
startTimeForPlaylistSync = 0.0;
-// assert( sizeof(startTimeForPlaylistSync) == sizeof(struct timeval));
- //memset(&startTimeForPlaylistSync, 0, sizeof(struct timeval));
- mDrmMetaDataIndex.Clear();
- mDiscontinuityIndex.Clear();
+ mDrmMetaDataIndex.clear();
+ mDiscontinuityIndex.clear();
mCulledSecondsAtStart = aamp->culledSeconds;
mProgramDateTime = aamp->mProgramDateTime;
AAMPLOG_INFO("Restore PDT (%f) ",mProgramDateTime.inSeconds());
@@ -5019,17 +4967,7 @@ TrackState::~TrackState()
mCachedFragment[j].fragment.Free();
}
FlushIndex();
-
- if (mCMSha1Hash)
- {
- free(mCMSha1Hash);
- mCMSha1Hash = NULL;
- }
- if (mDrmInfo.iv)
- {
- free(mDrmInfo.iv);
- mDrmInfo.iv = NULL;
- }
+ memset( mDrmInfo.iv, 0, sizeof(mDrmInfo.iv) );
}
@@ -5571,25 +5509,8 @@ DrmReturn TrackState::DrmDecrypt( CachedFragment * cachedFragment, ProfilerBucke
/**
* @brief Function to create init vector using current media sequence number
*/
-bool TrackState::CreateInitVectorByMediaSeqNo ( long long seqNo )
+void TrackState::CreateInitVectorByMediaSeqNo ( long long seqNo )
{
- unsigned char *pui8IV=NULL;
- if (mDrmInfo.iv)
- {
- // Re-use memory if allocated from earlier call, instead of multiple malloc & free for every fragment.
- pui8IV = mDrmInfo.iv;
- }
- else
- {
- pui8IV = (unsigned char*)malloc(DRM_IV_LEN);
- if ( NULL == pui8IV )
- {
- AAMPLOG_WARN("IV MemAlloc error, Size:%d",DRM_IV_LEN);
- return false;
- }
-
- mDrmInfo.iv = pui8IV;
- }
/* From RFC8216 - Section 5.2,
* Keeping the Media Sequence Number's big-endian binary
* representation into a 16-octet (128-bit) buffer and padding
@@ -5600,11 +5521,9 @@ bool TrackState::CreateInitVectorByMediaSeqNo ( long long seqNo )
int idx = DRM_IV_LEN;
while( idx>0 )
{
- pui8IV[--idx] = seqNo&0xff;
+ mDrmInfo.iv[--idx] = seqNo&0xff;
seqNo >>= 8;
}
-
- return true;
}
/**
@@ -5626,37 +5545,23 @@ MediaTrack* StreamAbstractionAAMP_HLS::GetMediaTrack(TrackType type)
/**
* @brief Function to Update SHA1 Id for DRM Metadata
*/
-void TrackState::UpdateDrmCMSha1Hash(const char *ptr)
+void TrackState::UpdateDrmCMSha1Hash( const std::string &newSha1Hash )
{
bool drmDataChanged = false;
- if (NULL == ptr)
+ if( newSha1Hash.empty() )
{
- if (mCMSha1Hash)
- {
- free(mCMSha1Hash);
- mCMSha1Hash = NULL;
- }
+ mCMSha1Hash.clear();
}
- else if (mCMSha1Hash)
+ else if( !mCMSha1Hash.empty() )
{
- if (0 != memcmp(ptr, mCMSha1Hash, DRM_SHA1_HASH_LEN))
+ if( mCMSha1Hash != newSha1Hash )
{
if (!mIndexingInProgress)
{
- AAMPLOG_WARN("[%s] Different DRM metadata hash. old - ", name);
- for (int i = 0; i< DRM_SHA1_HASH_LEN; i++)
- {
- printf("%c", mCMSha1Hash[i]);
- }
- printf(" new - ");
- for (int i = 0; i< DRM_SHA1_HASH_LEN; i++)
- {
- printf("%c", ptr[i]);
- }
- printf("\n");
+ AAMPLOG_MIL("[%s] Different DRM metadata hash. old=%s new=%s", name, mCMSha1Hash.c_str(), newSha1Hash.c_str() );
}
drmDataChanged = true;
- memcpy(mCMSha1Hash, ptr, DRM_SHA1_HASH_LEN);
+ mCMSha1Hash = newSha1Hash;
}
else if (!mIndexingInProgress)
{
@@ -5667,72 +5572,42 @@ void TrackState::UpdateDrmCMSha1Hash(const char *ptr)
{
if (!mIndexingInProgress)
{
- AAMPLOG_WARN("[%s] New DRM metadata hash - ",name);
- for (int i = 0; i < DRM_SHA1_HASH_LEN; i++)
- {
- printf("%c", ptr[i]);
- }
- printf("\n");
- }
- mCMSha1Hash = (char*)malloc(DRM_SHA1_HASH_LEN);
- if(!mCMSha1Hash)
- {
- AAMPLOG_WARN("mCMSha1Hash is null"); //CID:84607 - Null Returns
- }
- else
- {
- memcpy(mCMSha1Hash, ptr, DRM_SHA1_HASH_LEN);
- drmDataChanged = true;
+ AAMPLOG_WARN("[%s] New DRM metadata hash - %s", name, newSha1Hash.c_str() );
}
+ mCMSha1Hash = newSha1Hash;
+ drmDataChanged = true;
}
if(drmDataChanged)
{
- int i;
- DrmMetadataNode* drmMetadataNode = (DrmMetadataNode*)mDrmMetaDataIndex.GetPtr();
- for (i = 0; i < mDrmMetaDataIndexCount; i++)
+ size_t i = 0;
+ while( i < mDrmMetaDataIndex.size() )
{
- if(drmMetadataNode[i].sha1Hash)
+ DrmMetadataNode &drmMetadataNode = mDrmMetaDataIndex[i];
+ if( !drmMetadataNode.sha1Hash.empty() )
{
- if (0 == memcmp(mCMSha1Hash, drmMetadataNode[i].sha1Hash, DRM_SHA1_HASH_LEN))
+ if( mCMSha1Hash == drmMetadataNode.sha1Hash )
{
if (!mIndexingInProgress)
{
- AAMPLOG_INFO("mDrmMetaDataIndexPosition %d->%d", mDrmMetaDataIndexPosition, i);
+ AAMPLOG_INFO("mDrmMetaDataIndexPosition %d->%zu", mDrmMetaDataIndexPosition, i);
}
- mDrmMetaDataIndexPosition = i;
+ mDrmMetaDataIndexPosition = (int)i;
break;
}
}
+ i++;
}
- if (i == mDrmMetaDataIndexCount)
+ if( i == mDrmMetaDataIndex.size() )
{
- AAMPLOG_WARN("[%s] Couldn't find matching hash mDrmMetaDataIndexCount %d ",
- name, mDrmMetaDataIndexCount);
- for (int j = 0; j < mDrmMetaDataIndexCount; j++)
+ AAMPLOG_WARN("[%s] Couldn't find matching hash mDrmMetaDataIndexCount %zu", name, mDrmMetaDataIndex.size() );
+ for( auto j = 0; j < mDrmMetaDataIndex.size(); j++ )
{
- if (drmMetadataNode[j].sha1Hash)
- {
- AAMPLOG_WARN("drmMetadataNode[%d].sha1Hash", j);
- for (int i = 0; i < DRM_SHA1_HASH_LEN; i++)
- {
- printf("%c", drmMetadataNode[j].sha1Hash[i]);
- }
- printf("\n");
- }
- else
- {
- AAMPLOG_WARN("drmMetadataNode[%d].sha1Hash NULL", j);
- }
- }
- for (int i = 0; i < playlist.GetLen(); i++)
- {
- char temp = playlist.GetPtr()[i];
- if (temp == '\0')
- {
- temp = '\n';
- }
- putchar(temp);
+ DrmMetadataNode &drmMetadataNode = mDrmMetaDataIndex[j];
+ AAMPLOG_MIL("drmMetadataNode[%d].sha1Hash = %s", j, drmMetadataNode.sha1Hash.c_str() );
}
+ playlist.AppendNulTerminator(); // make safe for cstring operations
+ // use printf to avoid 2048 char syslog limitation
+ printf("***playlist***:\n\n%s\n************\n", playlist.GetPtr());
assert(false);
}
}
@@ -5742,39 +5617,20 @@ void TrackState::UpdateDrmCMSha1Hash(const char *ptr)
/**
* @brief Function to update IV from DRM
*/
-void TrackState::UpdateDrmIV(const char *ptr)
+void TrackState::UpdateDrmIV(const std::string &ptr)
{
- size_t len;
- unsigned char *iv = base16_Decode(ptr, (DRM_IV_LEN*2), &len); // 32 characters encoding 128 bits (16 bytes)
- assert(len == DRM_IV_LEN);
- if(mDrmInfo.iv)
+ size_t len = 0;
+ unsigned char *iv = base16_Decode(ptr.c_str(), (DRM_IV_LEN*2), &len); // 32 characters encoding 128 bits (16 bytes)
+ if( iv )
{
+ assert(len == DRM_IV_LEN);
if(0 != memcmp(mDrmInfo.iv, iv, DRM_IV_LEN))
{
- free(mDrmInfo.iv);
- mDrmInfo.iv = iv;
+ memcpy( mDrmInfo.iv, iv, DRM_IV_LEN );
mIVKeyChanged = true;
}
- else
- {
- AAMPLOG_TRACE(" Same DRM IV");
- }
+ free( iv );
}
- else
- {
- mDrmInfo.iv = iv;
- mIVKeyChanged = true;
- }
-
-#ifdef AAMP_VANILLA_AES_SUPPORT
- //Update iv address in AesDec class
- std::shared_ptr aesdec = std::dynamic_pointer_cast (mDrm);
- if(aesdec)
- {
-// Set all the key info in the fetcher loop so IV and URI keep in sync
-// aesdec->SetIV(mDrmInfo.iv);
- }
-#endif
AAMPLOG_TRACE(" [%s] Exit mDrmInfo.iv %p", name, mDrmInfo.iv);
}
@@ -5860,7 +5716,6 @@ int StreamAbstractionAAMP_HLS::GetBWIndex(BitsPerSecond bitrate)
*/
void TrackState::GetNextFragmentPeriodInfo(int &periodIdx, AampTime &offsetFromPeriodStart, int &fragmentIdx)
{
- const IndexNode *index = (IndexNode *) this->index.GetPtr();
const IndexNode *idxNode = NULL;
periodIdx = -1;
fragmentIdx = -1;
@@ -5868,17 +5723,17 @@ void TrackState::GetNextFragmentPeriodInfo(int &periodIdx, AampTime &offsetFromP
int idx;
AampTime prevCompletionTimeSecondsFromStart{};
assert(context->rate > 0);
- for (idx = 0; idx < indexCount; idx++)
+ for (idx = 0; idx < index.size(); idx++)
{
- const IndexNode *node = &index[idx];
- if (node->completionTimeSecondsFromStart > playTarget)
+ const IndexNode &node = index[idx];
+ if (node.completionTimeSecondsFromStart > playTarget)
{
AAMPLOG_WARN("(%s) Found node - rate %f completionTimeSecondsFromStart %f playTarget %f", name,
- context->rate, node->completionTimeSecondsFromStart.inSeconds(), playTarget.inSeconds());
- idxNode = node;
+ context->rate, node.completionTimeSecondsFromStart.inSeconds(), playTarget.inSeconds());
+ idxNode = &index[idx];
break;
}
- prevCompletionTimeSecondsFromStart = node->completionTimeSecondsFromStart;
+ prevCompletionTimeSecondsFromStart = node.completionTimeSecondsFromStart;
}
if (idxNode)
{
@@ -5886,21 +5741,20 @@ void TrackState::GetNextFragmentPeriodInfo(int &periodIdx, AampTime &offsetFromP
{
offsetFromPeriodStart = prevCompletionTimeSecondsFromStart;
AampTime periodStartPosition{};
- DiscontinuityIndexNode* discontinuityIndex = (DiscontinuityIndexNode*)mDiscontinuityIndex.GetPtr();
- for (int i = 0; i < mDiscontinuityIndexCount; i++)
+ for( auto i = 0; i < mDiscontinuityIndex.size(); i++ )
{
- AAMPLOG_TRACE("TrackState:: [%s] Loop periodItr %d idx %d first %d second %f", name, i, idx,
- discontinuityIndex[i].fragmentIdx, discontinuityIndex[i].position.inSeconds());
- if (discontinuityIndex[i].fragmentIdx > idx)
+ DiscontinuityIndexNode &discontinuity = mDiscontinuityIndex[i];
+ AAMPLOG_TRACE("TrackState:: [%s] Loop periodItr %d idx %d first %d second %f", name, i, idx, discontinuity.fragmentIdx, discontinuity.position.inSeconds());
+ if (discontinuity.fragmentIdx > idx)
{
AAMPLOG_WARN("TrackState: [%s] Found periodItr %d idx %d first %d offsetFromPeriodStart %f",
- name, i, idx, discontinuityIndex[i].fragmentIdx, periodStartPosition.inSeconds());
+ name, i, idx, discontinuity.fragmentIdx, periodStartPosition.inSeconds());
- fragmentIdx = discontinuityIndex[i].fragmentIdx;
+ fragmentIdx = discontinuity.fragmentIdx;
break;
}
periodIdx = i;
- periodStartPosition = discontinuityIndex[i].position;
+ periodStartPosition = discontinuity.position;
}
offsetFromPeriodStart -= periodStartPosition;
}
@@ -5920,19 +5774,17 @@ void TrackState::GetNextFragmentPeriodInfo(int &periodIdx, AampTime &offsetFromP
AampTime TrackState::GetPeriodStartPosition(int periodIdx)
{
AampTime offset{};
- AAMPLOG_WARN("TrackState: [%s] periodIdx %d periodCount %d", name, periodIdx,
- (int) mDiscontinuityIndexCount);
- if (periodIdx < mDiscontinuityIndexCount)
+ AAMPLOG_MIL("TrackState: [%s] periodIdx %d periodCount %zu", name, periodIdx, mDiscontinuityIndex.size() );
+ if (periodIdx < mDiscontinuityIndex.size() )
{
int count = 0;
- DiscontinuityIndexNode* discontinuityIndex = (DiscontinuityIndexNode*)mDiscontinuityIndex.GetPtr();
- for (int i = 0; i < mDiscontinuityIndexCount; i++)
+ for( auto i = 0; i < mDiscontinuityIndex.size(); i++ )
{
if (count == periodIdx)
- {
- offset = discontinuityIndex[i].position;
- AAMPLOG_WARN("TrackState: [%s] offset %f periodCount %d", name, offset.inSeconds(),
- (int) mDiscontinuityIndexCount);
+ { // FIXME
+ offset = mDiscontinuityIndex[i].position;
+ AAMPLOG_MIL("TrackState: [%s] offset %f periodCount %zu", name, offset.inSeconds(),
+ mDiscontinuityIndex.size() );
break;
}
else
@@ -5943,8 +5795,8 @@ AampTime TrackState::GetPeriodStartPosition(int periodIdx)
}
else
{
- AAMPLOG_WARN("TrackState: [%s] WARNING periodIdx %d periodCount %d", name, periodIdx,
- mDiscontinuityIndexCount);
+ AAMPLOG_WARN("TrackState: [%s] WARNING periodIdx %d periodCount %zu", name, periodIdx,
+ mDiscontinuityIndex.size() );
}
return offset;
}
@@ -5955,7 +5807,7 @@ AampTime TrackState::GetPeriodStartPosition(int periodIdx)
*/
int TrackState::GetNumberOfPeriods()
{
- return mDiscontinuityIndexCount;
+ return (int)mDiscontinuityIndex.size();
}
@@ -5976,18 +5828,18 @@ bool TrackState::HasDiscontinuityAroundPosition(AampTime position, bool useDisco
{
// No condition to check DiscontinuityCount.Possible that in next refresh it will be available,
// Case where one discontinuity in one track ,but other track not having it
- DiscontinuityIndexNode* discontinuityIndex = (DiscontinuityIndexNode*)mDiscontinuityIndex.GetPtr();
AampTime deltaCulledSec{inputCulledSec - mCulledSeconds};
bool foundmatchingdisc = false;
- for (int i = 0; i < mDiscontinuityIndexCount; i++)
+ for( auto i = 0; i < mDiscontinuityIndex.size(); i++ )
{
+ const DiscontinuityIndexNode &discontinuity = mDiscontinuityIndex[i];
// Live is complicated lets finish that
- AampTime discdatetime{discontinuityIndex[i].discontinuityPDT};
+ AampTime discdatetime{discontinuity.discontinuityPDT};
if (IsLive())
{
- AAMPLOG_WARN("[%s] Host loop %d mDiscontinuityIndexCount %d discontinuity-pos %f mCulledSeconds %f playlistRefreshTime:%f discdatetime=%f",name, i,
- mDiscontinuityIndexCount, discontinuityIndex[i].position.inSeconds(), mCulledSeconds.inSeconds(), mProgramDateTime.inSeconds(), discdatetime.inSeconds());
+ AAMPLOG_WARN("[%s] Host loop %d mDiscontinuityIndexCount %zu discontinuity-pos %f mCulledSeconds %f playlistRefreshTime:%f discdatetime=%f",name, i,
+ mDiscontinuityIndex.size(), discontinuity.position.inSeconds(), mCulledSeconds.inSeconds(), mProgramDateTime.inSeconds(), discdatetime.inSeconds());
AAMPLOG_WARN("Visitor loop %d Input track position:%f useDateTime:%d CulledSeconds :%f playlistRefreshTime :%f DeltaCulledSec:%f", i,
position.inSeconds(), useDiscontinuityDateTime, inputCulledSec.inSeconds(), inputProgramDateTime.inSeconds(), deltaCulledSec.inSeconds());
@@ -6010,8 +5862,8 @@ bool TrackState::HasDiscontinuityAroundPosition(AampTime position, bool useDisco
// No PDT , now compare the position based on culled delta
// Additional fragmentDuration is considered as rounding with decimal is missing the position when culled delta is same
// Ignore millisecond accuracy
- AampTime tempLimit1 = (discontinuityIndex[i].position - abs(deltaCulledSec) - targetDurationSeconds - 1.0);
- AampTime tempLimit2 = (discontinuityIndex[i].position + abs(deltaCulledSec) + targetDurationSeconds + 1.0);
+ AampTime tempLimit1 = (discontinuity.position - abs(deltaCulledSec) - targetDurationSeconds - 1.0);
+ AampTime tempLimit2 = (discontinuity.position + abs(deltaCulledSec) + targetDurationSeconds + 1.0);
int64_t limit1 = tempLimit1.seconds();
int64_t limit2 = tempLimit2.seconds();
// Due to increase in fragment duration and mismatch between audio and video,
@@ -6034,11 +5886,11 @@ bool TrackState::HasDiscontinuityAroundPosition(AampTime position, bool useDisco
roundedPosn = position.nearestSecond();
}
- AAMPLOG_WARN("Comparing position input posn:%" PRIi64 " index[%d] position:%d deltaCulled:%f limit1:%" PRIi64" limit2:%" PRIi64, roundedPosn, i, (int)(discontinuityIndex[i].position.inSeconds()), deltaCulledSec.inSeconds(), limit1, limit2);
+ AAMPLOG_WARN("Comparing position input posn:%" PRIi64 " index[%d] position:%d deltaCulled:%f limit1:%" PRIi64" limit2:%" PRIi64, roundedPosn, i, (int)(discontinuity.position.inSeconds()), deltaCulledSec.inSeconds(), limit1, limit2);
if(roundedPosn >= limit1 && roundedPosn <= limit2 )
{
foundmatchingdisc = true;
- AAMPLOG_WARN("[%s] Found the matching discontinuity at position:%f for position:%f", name, discontinuityIndex[i].position.inSeconds(), position.inSeconds());
+ AAMPLOG_WARN("[%s] Found the matching discontinuity at position:%f for position:%f", name, discontinuity.position.inSeconds(), position.inSeconds());
break;
}
}
@@ -6053,7 +5905,7 @@ bool TrackState::HasDiscontinuityAroundPosition(AampTime position, bool useDisco
{
int maxPlaylistRefreshCount;
bool liveNoTSB;
- if (aamp->IsTSBSupported() || aamp->IsInProgressCDVR())
+ if (aamp->IsFogTSBSupported() || aamp->IsInProgressCDVR())
{
maxPlaylistRefreshCount = MAX_PLAYLIST_REFRESH_FOR_DISCONTINUITY_CHECK_EVENT;
liveNoTSB = false;
@@ -6672,7 +6524,7 @@ void StreamAbstractionAAMP_HLS::ConfigureVideoProfiles()
break;
}
}
- if (!aamp->IsTSBSupported() && iProfileCapped)
+ if (!aamp->IsFogTSBSupported() && iProfileCapped)
{
aamp->mProfileCappedStatus = true;
}
@@ -6950,7 +6802,7 @@ void StreamAbstractionAAMP_HLS::ConfigureVideoProfiles()
AAMPLOG_INFO("Adding image track, userData=%d BW = %ld ", j, streamInfo.bandwidthBitsPerSecond);
}
}
- if (!aamp->IsTSBSupported() && iProfileCapped)
+ if (!aamp->IsFogTSBSupported() && iProfileCapped)
{
aamp->mProfileCappedStatus = true;
}
@@ -7422,7 +7274,7 @@ StreamAbstractionAAMP::ABRMode StreamAbstractionAAMP_HLS::GetABRMode()
{
ABRMode mode;
- if (aamp->IsTSBSupported())
+ if (aamp->IsFogTSBSupported())
{
// Fog manages ABR.
mode = ABRMode::FOG_TSB;
diff --git a/fragmentcollector_hls.h b/fragmentcollector_hls.h
index 40f2db6..4e279dd 100755
--- a/fragmentcollector_hls.h
+++ b/fragmentcollector_hls.h
@@ -41,12 +41,9 @@
#include "HlsDrmBase.h"
#include
#include "AampDRMLicPreFetcher.h"
-
#include "ID3Metadata.hpp"
#include "MetadataProcessor.hpp"
-
#include "AampTime.h"
-
#include
#include
#include
@@ -158,10 +155,11 @@ struct KeyTagStruct
*/
struct DiscontinuityIndexNode
{
- int fragmentIdx; /**< Idx of fragment in index table*/
- AampTime position; /**< Time of index from start */
- AampTime fragmentDuration; /**< Fragment duration of current discontinuity index */
- AampTime discontinuityPDT; /**< Program Date time value */
+ uint64_t discontinuitySequenceIndex; /**< period index, useful for discontinuity synchronization across tracks */
+ int fragmentIdx; /**< index of fragment in index table*/
+ AampTime position; /**< Time of index from start */
+ AampTime fragmentDuration; /**< Fragment duration of current discontinuity index */
+ AampTime discontinuityPDT; /**< Program Date time value */
};
/**
@@ -177,9 +175,12 @@ typedef enum
eDRM_KEY_METHOD_UNKNOWN /**< DRM key is unknown method */
} DrmKeyMethod;
-/**
- * @}
- */
+struct DrmMetadataNode
+{
+ int deferredInterval;
+ long long drmKeyReqTime;
+ std::string sha1Hash;
+};
/// Function to call to update the local PTS record
using ptsoffset_update_t = std::function;
@@ -297,14 +298,14 @@ class TrackState : public MediaTrack
* @param[in] ptr IV string from DRM attribute
* @return void
***************************************************************************/
- void UpdateDrmIV(const char *ptr);
+ void UpdateDrmIV(const std::string &ptr);
/***************************************************************************
* @fn UpdateDrmCMSha1Hash
*
* @param[in] ptr ShaID string from DRM attribute
* @return void
***************************************************************************/
- void UpdateDrmCMSha1Hash(const char *ptr);
+ void UpdateDrmCMSha1Hash( const std::string &newSha1Hash );
/***************************************************************************
* @fn DrmDecrypt
*
@@ -319,7 +320,7 @@ class TrackState : public MediaTrack
* @param[in] ui32Seqno Current fragment's sequence number
* @return bool true if successfully created, false otherwise.
***************************************************************************/
- bool CreateInitVectorByMediaSeqNo( long long ui32Seqno );
+ void CreateInitVectorByMediaSeqNo( long long ui32Seqno );
/***************************************************************************
* @fn FetchPlaylist
*
@@ -597,8 +598,7 @@ class TrackState : public MediaTrack
AampGrowableBuffer playlist; /**< downloaded playlist contents */
AampTime mProgramDateTime;
- AampGrowableBuffer index; /**< packed IndexNode records for associated playlist */
- int indexCount; /**< number of indexed fragments in currently indexed playlist */
+ std::vector index;
int currentIdx; /**< index for currently-presenting fragment used during FF/REW (-1 if undefined) */
lstring mFragmentURIFromIndex; /**< storage for uri generated by GetIframeFragmentUriFromIndex */
long long indexFirstMediaSequenceNumber; /**< first media sequence number from indexed manifest */
@@ -626,15 +626,13 @@ class TrackState : public MediaTrack
bool mIVKeyChanged; /**< Flag to indicate Key info got changed (may be able to use existing flag with some restructuring) */
int mLastKeyTagIdx ; /**< Variable to hold the last keyTag index,to check if key tag changed */
struct DrmInfo mDrmInfo; /**< Structure variable to hold Drm Information */
- char* mCMSha1Hash; /**< variable to store ShaID*/
+ std::string mCMSha1Hash; /**< variable to store ShaID*/
long long mDrmTimeStamp; /**< variable to store Drm Time Stamp */
int mDrmMetaDataIndexPosition; /**< Variable to store Drm Meta data Index position*/
- AampGrowableBuffer mDrmMetaDataIndex; /**< DrmMetadata records for associated playlist */
- int mDrmMetaDataIndexCount; /**< number of DrmMetadata records in currently indexed playlist */
+ std::vector mDrmMetaDataIndex; /**< DrmMetadata records for associated playlist */
int mDrmKeyTagCount; /**< number of EXT-X-KEY tags present in playlist */
bool mIndexingInProgress; /**< indicates if indexing is in progress*/
- AampGrowableBuffer mDiscontinuityIndex; /**< discontinuity start position mapping of associated playlist */
- int mDiscontinuityIndexCount; /**< number of records in discontinuity position index */
+ std::vector mDiscontinuityIndex;
AampTime mDuration; /** Duration of the track*/
typedef std::vector KeyHashTable;
typedef std::vector::iterator KeyHashTableIter;
diff --git a/fragmentcollector_mpd.cpp b/fragmentcollector_mpd.cpp
index 60fbb86..2eb69c9 100644
--- a/fragmentcollector_mpd.cpp
+++ b/fragmentcollector_mpd.cpp
@@ -904,19 +904,20 @@ bool StreamAbstractionAAMP_MPD::FetchFragment(MediaStreamContext *pMediaStreamCo
{
AAMPLOG_WARN("StreamAbstractionAAMP_MPD: failed. fragmentUrl %s fragmentTime %f %d %d", fragmentUrl.c_str(), pMediaStreamContext->fragmentTime,isInitializationSegment, pMediaStreamContext->type);
//Added new check to avoid marking ad as failed if the http code is not worthy.
- if(mCdaiObject->mAdState == AdState::IN_ADBREAK_AD_PLAYING && (pMediaStreamContext->httpErrorCode!=CURLE_WRITE_ERROR && pMediaStreamContext->httpErrorCode!= CURLE_ABORTED_BY_CALLBACK) && (isInitializationSegment || pMediaStreamContext->segDLFailCount >= MAX_AD_SEG_DOWNLOAD_FAIL_COUNT))
+ if (isInitializationSegment && mCdaiObject->mAdState == AdState::IN_ADBREAK_AD_PLAYING &&
+ (pMediaStreamContext->httpErrorCode!=CURLE_WRITE_ERROR && pMediaStreamContext->httpErrorCode!= CURLE_ABORTED_BY_CALLBACK))
{
- AAMPLOG_WARN("StreamAbstractionAAMP_MPD: [CDAI] Ad fragment not available. Playback failed.");
+ AAMPLOG_WARN("StreamAbstractionAAMP_MPD: [CDAI] Ad init fragment not available. Playback failed.");
mCdaiObject->mAdBreaks[mBasePeriodId].mAdFailed = true;
}
}
- if( discontinuity && isInitializationSegment)
+ if (discontinuity && isInitializationSegment)
{
if(eTRACK_VIDEO == pMediaStreamContext->type)
{
isVidDiscInitFragFail = true;
AAMPLOG_WARN("StreamAbstractionAAMP_MPD: failed. isInit: %d IsTrackVideo: %s isDisc: %d vidInitFail: %d",
- isInitializationSegment, GetMediaTypeName(AampMediaType(pMediaStreamContext->type) ), isInitializationSegment, isVidDiscInitFragFail );
+ isInitializationSegment, GetMediaTypeName(AampMediaType(pMediaStreamContext->type) ), isInitializationSegment, isVidDiscInitFragFail);
}
if(mCdaiObject->mAdState == AdState::IN_ADBREAK_AD_PLAYING)
{
@@ -961,11 +962,11 @@ bool StreamAbstractionAAMP_MPD::FetchFragment(MediaStreamContext *pMediaStreamCo
retval = false;
}
- if( discontinuity && ( isInitializationSegment && eTRACK_VIDEO == pMediaStreamContext->type ) && (retval && isVidDiscInitFragFail ) )
- {
- isVidDiscInitFragFail = false;
- AAMPLOG_WARN("StreamAbstractionAAMP_MPD: rampdown init download success. isInit: %d IsTrackVideo: %s isDisc: %d vidInitFail: %d",
- isInitializationSegment, GetMediaTypeName(AampMediaType(pMediaStreamContext->type) ), isInitializationSegment, isVidDiscInitFragFail );
+ if (discontinuity && (isInitializationSegment && eTRACK_VIDEO == pMediaStreamContext->type ) && (retval && isVidDiscInitFragFail))
+{
+ isVidDiscInitFragFail = false;
+ AAMPLOG_WARN("StreamAbstractionAAMP_MPD: rampdown init download success. isInit: %d IsTrackVideo: %s isDisc: %d vidInitFail: %d",
+ isInitializationSegment, GetMediaTypeName(AampMediaType(pMediaStreamContext->type) ), isInitializationSegment, isVidDiscInitFragFail);
}
/**In the case of ramp down same fragment will be retried
@@ -1412,6 +1413,10 @@ bool StreamAbstractionAAMP_MPD::PushNextFragment( class MediaStreamContext *pMed
if(firstStartTime < presentationTimeOffset)
{
firstSegStartTime = (double)(firstStartTime/tScale);
+ // Period end time also needs to be updated based on the PTO.
+ // Otherwise, there is a chance to skip the last few fragments from the period if there is a large delta between the start time available in the manifest and the PTO.
+ endTime = (firstSegStartTime+(mPeriodDuration/1000));
+
AAMPLOG_INFO(" PTO ::(startTime < PTO) firstStartTime %" PRIu64 " tScale : %d presentationTimeOffset[%" PRIu64 "] positionInPeriod = %f startTime = %f endTime : %f mPeriodStartTime = %f mPeriodDuration = %f ",
firstStartTime, tScale, presentationTimeOffset, positionInPeriod, firstSegStartTime, endTime, mPeriodStartTime, mPeriodDuration);
}
@@ -1435,8 +1440,8 @@ bool StreamAbstractionAAMP_MPD::PushNextFragment( class MediaStreamContext *pMed
}
else
{
- AAMPLOG_WARN("Type[%d] Skipping Fetchfragment, Number(%" PRIu64 ") fragment beyond duration. fragmentPosition: %lf periodEndTime : %lf", pMediaStreamContext->type
- , pMediaStreamContext->fragmentDescriptor.Number, positionInPeriod , endTime);
+ AAMPLOG_WARN("Type[%d] Skipping Fetchfragment, Number(%" PRIu64 ") fragment beyond duration. fragmentPosition: %lf starttime:%lf periodEndTime : %lf ", pMediaStreamContext->type
+ , pMediaStreamContext->fragmentDescriptor.Number, positionInPeriod , firstSegStartTime, endTime);
}
if(fcsContent)
{
@@ -3007,7 +3012,7 @@ AAMPStatusType StreamAbstractionAAMP_MPD::GetMPDFromManifest( std::shared_ptrPlaceAds(mpd);
+ mCdaiObject->PlaceAds(mMPDParseHelper);
}
ret = AAMPStatusType::eAAMPSTATUS_OK;
@@ -3440,7 +3445,7 @@ AAMPStatusType StreamAbstractionAAMP_MPD::InitTsbReader(TuneType tuneType)
{
seekPosition = position;
mFirstPTS = tsbSessionManager->GetTsbReader(eMEDIATYPE_VIDEO)->GetFirstPTS();
- AAMPLOG_WARN("Updated position: %lfs, pts:%lfs", seekPosition, mFirstPTS);
+ AAMPLOG_MIL("Updated position: %lfs, pts:%lfs", seekPosition, mFirstPTS);
}
else
{
@@ -4455,7 +4460,7 @@ AAMPStatusType StreamAbstractionAAMP_MPD::FetchDashManifest()
else if (http_error == 512 )
{
// check if any response available to search
- if(mManifestDnldRespPtr->mMPDDownloadResponse->mResponseHeader.size() && aamp->mTSBEnabled)
+ if(mManifestDnldRespPtr->mMPDDownloadResponse->mResponseHeader.size() && aamp->mFogTSBEnabled)
{
for ( std::string header : mManifestDnldRespPtr->mMPDDownloadResponse->mResponseHeader )
{
@@ -4478,9 +4483,9 @@ AAMPStatusType StreamAbstractionAAMP_MPD::FetchDashManifest()
}
}
//When Fog is having tsb write error , then it will respond back with 302 with direct CDN url,In this case alone TSB should be disabled
- else if (aamp->mTSBEnabled && http_error == 302)
+ else if (aamp->mFogTSBEnabled && http_error == 302)
{
- aamp->mTSBEnabled = false;
+ aamp->mFogTSBEnabled = false;
}
else
@@ -4623,7 +4628,7 @@ void StreamAbstractionAAMP_MPD::MPDUpdateCallbackExec()
{
if (http_error == 512 )
{
- if(tmpManifestDnldRespPtr->mMPDDownloadResponse->mResponseHeader.size() && aamp->mTSBEnabled)
+ if(tmpManifestDnldRespPtr->mMPDDownloadResponse->mResponseHeader.size() && aamp->mFogTSBEnabled)
{
for ( std::string header : tmpManifestDnldRespPtr->mMPDDownloadResponse->mResponseHeader )
{
@@ -6636,7 +6641,7 @@ AAMPStatusType StreamAbstractionAAMP_MPD::UpdateMediaTrackInfo(AampMediaType typ
pMediaStreamContext->fragmentRepeatCount = 0;
pMediaStreamContext->fragmentOffset = 0;
pMediaStreamContext->periodStartOffset = pMediaStreamContext->fragmentTime;
- if (0 == pMediaStreamContext->fragmentDescriptor.Bandwidth || !aamp->IsTSBSupported())
+ if (0 == pMediaStreamContext->fragmentDescriptor.Bandwidth || !aamp->IsFogTSBSupported())
{
pMediaStreamContext->fragmentDescriptor.Bandwidth = pMediaStreamContext->representation->GetBandwidth();
}
@@ -7774,7 +7779,7 @@ AAMPStatusType StreamAbstractionAAMP_MPD::UpdateTrackInfo(bool modifyDefaultBW,
{
// For NewTune
// Set Default init bitrate according to last PersistBandwidth
- if((ISCONFIGSET(eAAMPConfig_PersistLowNetworkBandwidth)|| ISCONFIGSET(eAAMPConfig_PersistHighNetworkBandwidth)) && !aamp->IsTSBSupported())
+ if((ISCONFIGSET(eAAMPConfig_PersistLowNetworkBandwidth)|| ISCONFIGSET(eAAMPConfig_PersistHighNetworkBandwidth)) && !aamp->IsFogTSBSupported())
{
long persistbandwidth = aamp->mhAbrManager.getPersistBandwidth();
long TimeGap = aamp_GetCurrentTimeMS() - ABRManager::mPersistBandwidthUpdatedTime;
@@ -7853,7 +7858,7 @@ AAMPStatusType StreamAbstractionAAMP_MPD::UpdateTrackInfo(bool modifyDefaultBW,
pMediaStreamContext->representationIndex = 0; //Fog custom mpd has single representation
}
}
- //The logic is added to avoid a crash in AAMP due to stream issue in charter HEVC stream.
+ //The logic is added to avoid a crash in AAMP due to stream issue in HEVC stream.
//Player will be able to end the playback gracefully with the fix.
if(pMediaStreamContext->representationIndex < pMediaStreamContext->adaptationSet->GetRepresentation().size())
{
@@ -7884,7 +7889,7 @@ AAMPStatusType StreamAbstractionAAMP_MPD::UpdateTrackInfo(bool modifyDefaultBW,
pMediaStreamContext->fragmentRepeatCount = 0;
pMediaStreamContext->fragmentOffset = 0;
pMediaStreamContext->periodStartOffset = pMediaStreamContext->fragmentTime;
- if(0 == pMediaStreamContext->fragmentDescriptor.Bandwidth || !aamp->IsTSBSupported())
+ if(0 == pMediaStreamContext->fragmentDescriptor.Bandwidth || !aamp->IsFogTSBSupported())
{
pMediaStreamContext->fragmentDescriptor.Bandwidth = pMediaStreamContext->representation->GetBandwidth();
}
@@ -8925,7 +8930,8 @@ void StreamAbstractionAAMP_MPD::AdvanceTrack(int trackIdx, bool trickPlay, doubl
{
if((pMediaStreamContext->numberOfFragmentsCached != maxCachedFragmentsPerTrack) && !(pMediaStreamContext->profileChanged) &&
(!lowLatency || aamp->TrackDownloadsAreEnabled(static_cast(trackIdx))))
- { // profile not changed and Cache not full scenario
+ {
+ // profile not changed and Cache not full scenario
if (!pMediaStreamContext->eos)
{
if(trickPlay && pMediaStreamContext->mDownloadedFragment.GetPtr() == NULL && !pMediaStreamContext->freshManifest)
@@ -8980,6 +8986,7 @@ void StreamAbstractionAAMP_MPD::AdvanceTrack(int trackIdx, bool trickPlay, doubl
{
pMediaStreamContext->GetContext()->CheckForPlaybackStall(false);
}
+
//Determining the current position within the period by calculating the difference between
//the fragmentTime and the periodStartOffset (both in absolute terms).
//If this difference exceeds the total duration of the ad, the period is considered to have ended.
@@ -9190,7 +9197,8 @@ bool StreamAbstractionAAMP_MPD::SelectSourceOrAdPeriod(bool &periodChanged, bool
vector adaptationSets = newPeriod->GetAdaptationSets();
int adaptationSetCount = (int)adaptationSets.size();
// skip tiny periods (used for audio codec changes) as workaround for soc-specific issue
- if (0 == adaptationSetCount || (mMPDParseHelper->IsEmptyPeriod(mIterPeriodIndex, (rate != AAMP_NORMAL_PLAY_RATE))) || (mMPDParseHelper->GetPeriodDuration(mIterPeriodIndex, mLastPlaylistDownloadTimeMs, (rate != AAMP_NORMAL_PLAY_RATE), aamp->IsUninterruptedTSB()) < THRESHOLD_TOIGNORE_TINYPERIOD))
+ if (0 == adaptationSetCount || (mMPDParseHelper->IsEmptyPeriod(mIterPeriodIndex, (rate != AAMP_NORMAL_PLAY_RATE))) ||
+ (mMPDParseHelper->GetPeriodDuration(mIterPeriodIndex, mLastPlaylistDownloadTimeMs, (rate != AAMP_NORMAL_PLAY_RATE), aamp->IsUninterruptedTSB()) < THRESHOLD_TOIGNORE_TINYPERIOD))
{
/*To Handle non fog scenarios where empty periods are
* present after mpd update causing issues
@@ -9202,30 +9210,11 @@ bool StreamAbstractionAAMP_MPD::SelectSourceOrAdPeriod(bool &periodChanged, bool
continue;
}
- if (mBasePeriodId != newPeriod->GetId() && AdState::OUTSIDE_ADBREAK == mCdaiObject->mAdState)
- {
- mBasePeriodOffset = 0; // Not considering the delta from previous period's duration.
- }
- if (rate > 0)
- {
- if (AdState::OUTSIDE_ADBREAK != mCdaiObject->mAdState) // If Adbreak (somehow) goes beyond the designated periods, period outside adbreak will have +ve duration. Avoiding catastrophic cases.
- {
- mBasePeriodOffset -= ((double)mCdaiObject->mPeriodMap[mBasePeriodId].duration) / 1000.00;
- }
- }
- else
- {
- //Setting the end period offset as the base offset since the DAI ad break duration is shorter than the source period duration.
- if( rate < 0 && (mCdaiObject->isAdBreakObjectExist( newPeriod->GetId()) && mCdaiObject->mAdBreaks[newPeriod->GetId()].mSrcPeriodOffsetGTthreshold) )
- {
- AAMPLOG_INFO("[CDAI] Setting end period as offset, mBasePeriodOffset :%f endPeriodOffset:%" PRIu64 ,mBasePeriodOffset,mCdaiObject->mAdBreaks[newPeriod->GetId()].endPeriodOffset);
- mBasePeriodOffset += mCdaiObject->mAdBreaks[newPeriod->GetId()].endPeriodOffset/1000.000;
- }
- else
- {
- mBasePeriodOffset += (mMPDParseHelper->GetPeriodDuration(mIterPeriodIndex, mLastPlaylistDownloadTimeMs, (rate != AAMP_NORMAL_PLAY_RATE), aamp->IsUninterruptedTSB()) / 1000.00); // Already reached -ve. Subtracting from current period duration
- }
- }
+ // This is bit controversial to simplify setting of mBasePeriodOffset.
+ // But on a period change, would expect the periodOffset to align to either start or end of new period
+ // This could have some regressions, need to test thoroughly
+ mBasePeriodOffset = (rate > AAMP_RATE_PAUSE) ? 0 : (mMPDParseHelper->GetPeriodDuration(mIterPeriodIndex, mLastPlaylistDownloadTimeMs, (rate != AAMP_NORMAL_PLAY_RATE), aamp->IsUninterruptedTSB()) / 1000.00);
+
// Update period gaps for playback stats
if (mIsLiveStream)
{
@@ -9238,15 +9227,17 @@ bool StreamAbstractionAAMP_MPD::SelectSourceOrAdPeriod(bool &periodChanged, bool
}
mCurrentPeriodIdx = mIterPeriodIndex;
mBasePeriodId = newPeriod->GetId();
- periodChanged = false; // If the playing period changes, it will be detected below [if(currentPeriodId != mCurrentPeriod->GetId())]
+ // If the playing period changes, it will be detected below [if(currentPeriodId != mCurrentPeriod->GetId())]
+ periodChanged = false;
}
// Calling the function to play ads from first ad break(existing logic).
- adStateChanged = onAdEvent(AdEvent::DEFAULT); // TODO: Vinod, We can optimize here.
+ adStateChanged = onAdEvent(AdEvent::DEFAULT);
if(adStateChanged && AdState::OUTSIDE_ADBREAK_WAIT4ADS == mCdaiObject->mAdState)
{
- // Adbreak was available, so waited for fulfillment. Now, need to play the ad.
+ // Adbreak was available, but ads were not available and waited for fulfillment. Now, check if ads are available.
adStateChanged = onAdEvent(AdEvent::DEFAULT);
}
+ // endPeriod for the ad break is not available, so wait for the ad break to complete
if (AdState::IN_ADBREAK_WAIT2CATCHUP == mCdaiObject->mAdState)
{
waitForAdBreakCatchup = true;
@@ -9254,44 +9245,38 @@ bool StreamAbstractionAAMP_MPD::SelectSourceOrAdPeriod(bool &periodChanged, bool
break;
}
- // OUTSIDE_ADBREAK means the current ad break playback completed.
- bool ProcessNextAd = true;
- //If the source period duration exceeds the total ad duration by more than 2 seconds,
- //the player should switch back to the same base period instead of checking the
- //availability of the next ad break
- if(mCdaiObject->isAdBreakObjectExist(mBasePeriodId) && (mCdaiObject->mAdBreaks[mBasePeriodId].mSrcPeriodOffsetGTthreshold))
+ // If adStateChanged is true with OUTSIDE_ADBREAK, it means the current ad break playback completed.
+ // We need to check if the new period is also having ads.
+ if (adStateChanged && AdState::OUTSIDE_ADBREAK == mCdaiObject->mAdState)
{
- ProcessNextAd = false;
- }
- if (adStateChanged && AdState::OUTSIDE_ADBREAK == mCdaiObject->mAdState && ProcessNextAd)
- {
- // If the next ad break is available,need to call onAdEvent again to play DAI ads from the next immediate ad break.
- // Otherwise, player will switch to base period(source) of second ad break
- bool adPlaced = PlacenextAdBrkifAvail(mpd);
- // Just came out from the Adbreak. Need to search the right period
for (mIterPeriodIndex = 0; mIterPeriodIndex < mNumberOfPeriods; mIterPeriodIndex++)
{
if (mBasePeriodId == mpd->GetPeriods().at(mIterPeriodIndex)->GetId())
{
- mCurrentPeriodIdx = getValidperiodIdx(mIterPeriodIndex);
+ mCurrentPeriodIdx = GetValidPeriodIdx(mIterPeriodIndex);
mIterPeriodIndex = mCurrentPeriodIdx;
mBasePeriodId = mpd->GetPeriods().at(mCurrentPeriodIdx)->GetId();
if (mMPDParseHelper->IsEmptyPeriod(mCurrentPeriodIdx, (rate != AAMP_NORMAL_PLAY_RATE)))
{
AAMPLOG_WARN("Empty period(%s) at the end of manifest BasePeriodId (%s)", mpd->GetPeriods().at(mCurrentPeriodIdx)->GetId().c_str(), mpd->GetPeriods().at(mIterPeriodIndex)->GetId().c_str());
- /*empty periods are at live edge or no valid next period available
- all next periods are empty)wait for the manifest refresh to land at valid period */
}
break;
}
}
- if (adPlaced && rate < 0)
+ // Set the period offset to the boundaries of new period after ad playback
+ mBasePeriodOffset = (rate > AAMP_RATE_PAUSE) ? 0 : (mMPDParseHelper->GetPeriodDuration(mIterPeriodIndex, mLastPlaylistDownloadTimeMs, (rate != AAMP_NORMAL_PLAY_RATE), aamp->IsUninterruptedTSB()) / 1000.00);
+
{
- // When the ad is placed and rate is less than zero, we need to update mBasePeriodOffset
- // Otherwise, it will exit the fetch loop after single fragment download, since mBasePeriodOffset is set to zero initially
- // This will cause the fragment collector to exit without pushing EOS if the first period in TSB is DAI ad
- mBasePeriodOffset += (mMPDParseHelper->GetPeriodDuration(mCurrentPeriodIdx, mLastPlaylistDownloadTimeMs, (rate != AAMP_NORMAL_PLAY_RATE), aamp->IsUninterruptedTSB()) / 1000.00);
+ std::lock_guard lock(mCdaiObject->mDaiMtx);
+ if (mCdaiObject->mContentSeekOffset > 0)
+ {
+ // Set mBasePeriodOffset as mContentSeekOffset to handle cases of partial ads.
+ // mContentSeekOffset will be endPeriodOffset for partial ads and ensures the same ad is not selected again.
+ mBasePeriodOffset = mCdaiObject->mContentSeekOffset;
+ }
}
+ // Check if the new period is having ads
+ adStateChanged = onAdEvent(AdEvent::DEFAULT);
}
if (AdState::IN_ADBREAK_AD_PLAYING != mCdaiObject->mAdState)
@@ -9695,7 +9680,7 @@ void StreamAbstractionAAMP_MPD::FetcherLoop()
UpdatePtsOffset(periodChanged);
// Indexing success case
DetectDiscontinuityAndFetchInit(periodChanged, nextSegmentTime);
- if (mCdaiObject->HasDaiAd(mBasePeriodId))
+ if (AdState::IN_ADBREAK_AD_PLAYING == mCdaiObject->mAdState)
{
if (mCdaiObject->mAdBreaks[mBasePeriodId].mAdFailed)
{
@@ -9783,7 +9768,7 @@ void StreamAbstractionAAMP_MPD::FetcherLoop()
}
// -- Exit from fetch loop for period to be done only after audio and video fetch
- // While playing CDVR with EAC3 audio , durations doesnt match and only video downloads are seen leaving audio behind
+ // While playing CDVR with EAC3 audio, durations don't match and only video downloads are seen leaving audio behind
// Audio cache is always full and need for data is not received for more fetch.
// So after video downloads loop was exiting without audio fetch causing audio drop .
// Now wait for both video and audio to reach EOS before moving to next period or exit.
@@ -9844,8 +9829,8 @@ void StreamAbstractionAAMP_MPD::FetcherLoop()
}
// EOS from both tracks for dynamic (live) manifests for all periods.
// If ad state is not IN_ADBREAK_WAIT2CATCHUP, go for the manifest update, otherwise break the loop.
- bool exitFromloop = mCdaiObject->isAdBreakObjectExist(mBasePeriodId) && mCdaiObject->mAdBreaks[mBasePeriodId].mSrcPeriodOffsetGTthreshold;
- if (mIsLiveManifest && (rate > 0 && !exitFromloop) && (mIterPeriodIndex == mMPDParseHelper->mUpperBoundaryPeriod) && (AdState::IN_ADBREAK_WAIT2CATCHUP != mCdaiObject->mAdState))
+ if (mIsLiveManifest && (rate > 0) && (mIterPeriodIndex == mMPDParseHelper->mUpperBoundaryPeriod) &&
+ (AdState::IN_ADBREAK_WAIT2CATCHUP != mCdaiObject->mAdState))
{
aamp->interruptibleMsSleep(500);
}
@@ -9910,7 +9895,10 @@ void StreamAbstractionAAMP_MPD::FetcherLoop()
}
// Skip iterator reset and continue with appropriate period based on rate or ad state
resetIterator = false;
- if (AdState::IN_ADBREAK_WAIT2CATCHUP == mCdaiObject->mAdState)
+ // If we moved into an ad within the period mostly happens during rewind on partial ads, advance without incrementing the iterator.
+ // Added check for IN_ADBREAK_AD_PLAYING to confirm this particular case.
+ if (AdState::IN_ADBREAK_WAIT2CATCHUP == mCdaiObject->mAdState ||
+ (AdState::IN_ADBREAK_AD_PLAYING == mCdaiObject->mAdState && adStateChanged))
{
continue; // Need to finish all the ads in current before period change
}
@@ -10021,7 +10009,7 @@ void StreamAbstractionAAMP_MPD::TsbReader()
double delta = 0;
//bool adStateChanged = false;
- AAMPLOG_WARN("aamp: ready to read fragments");
+ AAMPLOG_MIL("aamp: ready to read fragments");
/*
* Ready to collect fragments
*/
@@ -10030,8 +10018,6 @@ void StreamAbstractionAAMP_MPD::TsbReader()
// playback
std::arraycacheFullStatus;
cacheFullStatus.fill(false);
- std::arraytrackEnabled;
- trackEnabled.fill(true);
AampTSBSessionManager* tsbSessionManager = aamp->GetTSBSessionManager();
if(NULL != tsbSessionManager)
{
@@ -10040,7 +10026,7 @@ void StreamAbstractionAAMP_MPD::TsbReader()
for (int trackIdx = (mNumberOfTracks - 1); trackIdx >= 0; trackIdx--)
{
cacheFullStatus[trackIdx] = true;
- if (!tsbSessionManager->GetTsbReader((AampMediaType) trackIdx)->IsEos() && trackEnabled[trackIdx])
+ if (!tsbSessionManager->GetTsbReader((AampMediaType) trackIdx)->IsEos())
{
AdvanceTsbFetch(trackIdx, trickPlay, delta, &waitForFreeFrag, &cacheFullStatus[trackIdx]);
}
@@ -10052,8 +10038,6 @@ void StreamAbstractionAAMP_MPD::TsbReader()
}
tsbSessionManager->LockReadMutex();
bool vEOS = tsbSessionManager->GetTsbReader(eMEDIATYPE_VIDEO)->IsEos();
- bool vPeriodEnd = tsbSessionManager->GetTsbReader(eMEDIATYPE_VIDEO)->IsPeriodBoundary();
- bool aPeriodEnd = tsbSessionManager->GetTsbReader(eMEDIATYPE_AUDIO)->IsPeriodBoundary();
bool aEOS = tsbSessionManager->GetTsbReader(eMEDIATYPE_AUDIO)->IsEos();
tsbSessionManager->UnlockReadMutex();
if(vEOS || aEOS)
@@ -10081,32 +10065,6 @@ void StreamAbstractionAAMP_MPD::TsbReader()
AAMPLOG_TRACE("EOS from both tracks - Wait for next fragment");
aamp->interruptibleMsSleep(500);
}
- if (vPeriodEnd && aPeriodEnd && (aamp->rate == AAMP_NORMAL_PLAY_RATE))
- {
- for (int trackIdx = (mNumberOfTracks - 1); trackIdx >= 0; trackIdx--)
- {
- trackEnabled[trackIdx] = true;
- AAMPLOG_TRACE("Reset Track [%d] Enabled:%d", trackIdx, trackEnabled[trackIdx]);
- }
-
- if(aamp->GetIsPeriodChangeMarked())
- {
- AAMPLOG_TRACE("Waiting to complete previous discontinuity!!");
- aamp->WaitForDiscontinuityProcessToComplete();
- }
- aamp->SetIsPeriodChangeMarked(true);
- //double firstPTS = tsbSessionManager->GetTsbReader(eMEDIATYPE_VIDEO)->GetFirstPTS();
- }
- else if(aamp->GetIsPeriodChangeMarked())
- {
- tsbSessionManager->LockReadMutex();
- for (int trackIdx = (mNumberOfTracks - 1); trackIdx >= 0; trackIdx--)
- {
- trackEnabled[trackIdx] = !tsbSessionManager->GetTsbReader((AampMediaType)trackIdx)->IsPeriodBoundary();
- AAMPLOG_TRACE("Track [%d] Enabled:%d", trackIdx, trackEnabled[trackIdx]);
- }
- tsbSessionManager->UnlockReadMutex();
- }
if(cacheFullStatus[eMEDIATYPE_VIDEO] || (vEOS && !aEOS))
{
// play cache is full , wait until cache is available to inject next, max wait of 1sec
@@ -10128,7 +10086,7 @@ void StreamAbstractionAAMP_MPD::TsbReader()
}
}
while (!exitLoop);
- AAMPLOG_WARN("TsbReader done");
+ AAMPLOG_MIL("TsbReader done");
}
/**
@@ -10418,94 +10376,106 @@ StreamAbstractionAAMP_MPD::~StreamAbstractionAAMP_MPD()
mManifestDnldRespPtr = nullptr;
}
-/**
- * @brief Starts streaming.
- */
-void StreamAbstractionAAMP_MPD::Start(void)
+void StreamAbstractionAAMP_MPD::StartFromOtherThanAampLocalTsb(void)
{
- if(!aamp->IsLocalAAMPTsb() || !aamp->IsLocalAAMPTsbInjection())
- {
#ifdef AAMP_MPD_DRM
- aamp->mDRMSessionManager->setSessionMgrState(SessionMgrState::eSESSIONMGR_ACTIVE);
+ aamp->mDRMSessionManager->setSessionMgrState(SessionMgrState::eSESSIONMGR_ACTIVE);
#endif
- // Start the worker threads for each track
- InitializeWorkers();
- try{
- fragmentCollectorThreadID = std::thread(&StreamAbstractionAAMP_MPD::FetcherLoop, this);
- fragmentCollectorThreadStarted = true;
- AAMPLOG_INFO("Thread created for FetcherLoop [%zx]", GetPrintableThreadID(fragmentCollectorThreadID));
- }
- catch (std::exception &e)
- {
- AAMPLOG_ERR("Thread allocation failed for FetcherLoop : %s ", e.what());
- }
+ // Start the worker threads for each track
+ InitializeWorkers();
+ try{
+ fragmentCollectorThreadID = std::thread(&StreamAbstractionAAMP_MPD::FetcherLoop, this);
+ fragmentCollectorThreadStarted = true;
+ AAMPLOG_INFO("Thread created for FetcherLoop [%zx]", GetPrintableThreadID(fragmentCollectorThreadID));
+ }
+ catch (std::exception &e)
+ {
+ AAMPLOG_ERR("Thread allocation failed for FetcherLoop : %s ", e.what());
+ }
+
+ if(aamp->IsPlayEnabled())
+ {
for (int i = 0; i < mNumberOfTracks; i++)
{
- if(aamp->IsPlayEnabled())
+ aamp->ResumeTrackInjection((AampMediaType) i);
+ // TODO: This could be moved to StartInjectLoop, but due to lack of testing will keep it here for now
+ if(mMediaStreamContext[i]->playContext)
{
- aamp->ResumeTrackInjection((AampMediaType) i);
- // TODO: This could be moved to StartInjectLoop, but due to lack of testing will keep it here for now
- if(mMediaStreamContext[i]->playContext)
- {
- mMediaStreamContext[i]->playContext->reset();
- }
- mMediaStreamContext[i]->StartInjectLoop();
+ mMediaStreamContext[i]->playContext->reset();
}
- }
- if( (mLowLatencyMode && ISCONFIGSET( eAAMPConfig_EnableLowLatencyCorrection ) ) && \
- (true == aamp->GetLLDashAdjustSpeed() ) )
- {
- StartLatencyMonitorThread();
+ mMediaStreamContext[i]->StartInjectLoop();
}
}
- else
+}
+
+void StreamAbstractionAAMP_MPD::StartFromAampLocalTsb(void)
+{
+ aamp->ResetTrackDiscontinuityIgnoredStatus();
+ aamp->UnblockWaitForDiscontinuityProcessToComplete();
+ mTrackState = eDISCONTINUITY_FREE;
+ for (int i = 0; i < mNumberOfTracks; i++)
{
- aamp->ResetTrackDiscontinuityIgnoredStatus();
- aamp->UnblockWaitForDiscontinuityProcessToComplete();
- mTrackState = eDISCONTINUITY_FREE;
- for (int i = 0; i < mNumberOfTracks; i++)
+ // Flush fragments from mCachedFragment, potentially cached during Live SLD
+ if (!mMediaStreamContext[i]->IsLocalTSBInjection())
{
- mMediaStreamContext[i]->SetLocalTSBInjection(true);
- mMediaStreamContext[i]->FlushFragments();
- // For seek to live, we will employ chunk cache and hence size has to be increased to max
- // For other tune types, we don't need chunks so revert to max cache fragment size
- if (mTuneType == eTUNETYPE_SEEKTOLIVE)
- {
- mMediaStreamContext[i]->SetCachedFragmentChunksSize(size_t(GETCONFIGVALUE(eAAMPConfig_MaxFragmentChunkCached)));
- }
- else
- {
- mMediaStreamContext[i]->SetCachedFragmentChunksSize(size_t(GETCONFIGVALUE(eAAMPConfig_MaxFragmentCached)));
- }
- mMediaStreamContext[i]->eosReached = false;
- if(aamp->IsPlayEnabled())
- {
- aamp->ResumeTrackInjection((AampMediaType) i);
- // TODO: This could be moved to StartInjectLoop, but due to lack of testing will keep it here for now
- if(mMediaStreamContext[i]->playContext)
- {
- mMediaStreamContext[i]->playContext->reset();
- }
- mMediaStreamContext[i]->StartInjectLoop(); ///TBD
- }
+ mMediaStreamContext[i]->FlushFetchedFragments();
}
- try
+ mMediaStreamContext[i]->SetLocalTSBInjection(true);
+
+ // Flush fragments from mCachedFragmentChunks
+ mMediaStreamContext[i]->FlushFragments();
+
+ // For seek to live, we will employ chunk cache and hence size has to be increased to max
+ // For other tune types, we don't need chunks so revert to max cache fragment size
+ if (mTuneType == eTUNETYPE_SEEKTOLIVE)
{
- abortTsbReader = false;
- tsbReaderThreadID = std::thread(&StreamAbstractionAAMP_MPD::TsbReader, this);
- tsbReaderThreadStarted = true;
- AAMPLOG_INFO("Thread created for TsbReader [%zx]", GetPrintableThreadID(tsbReaderThreadID));
+ mMediaStreamContext[i]->SetCachedFragmentChunksSize(size_t(GETCONFIGVALUE(eAAMPConfig_MaxFragmentChunkCached)));
}
- catch(const std::exception& e)
+ else
{
- AAMPLOG_ERR("Thread allocation failed for TsbReader : %s ", e.what());
+ mMediaStreamContext[i]->SetCachedFragmentChunksSize(size_t(GETCONFIGVALUE(eAAMPConfig_MaxFragmentCached)));
}
- if( (mLowLatencyMode && ISCONFIGSET( eAAMPConfig_EnableLowLatencyCorrection ) ) && \
- (true == aamp->GetLLDashAdjustSpeed() ) )
+ mMediaStreamContext[i]->eosReached = false;
+ if(aamp->IsPlayEnabled())
{
- StartLatencyMonitorThread();
+ aamp->ResumeTrackInjection((AampMediaType) i);
+ // TODO: This could be moved to StartInjectLoop, but due to lack of testing will keep it here for now
+ if(mMediaStreamContext[i]->playContext)
+ {
+ mMediaStreamContext[i]->playContext->reset();
+ }
+ mMediaStreamContext[i]->StartInjectLoop(); ///TBD
}
}
+ try
+ {
+ abortTsbReader = false;
+ tsbReaderThreadID = std::thread(&StreamAbstractionAAMP_MPD::TsbReader, this);
+ tsbReaderThreadStarted = true;
+ AAMPLOG_INFO("Thread created for TsbReader [%zx]", GetPrintableThreadID(tsbReaderThreadID));
+ }
+ catch(const std::exception& e)
+ {
+ AAMPLOG_ERR("Thread allocation failed for TsbReader : %s ", e.what());
+ }
+}
+
+void StreamAbstractionAAMP_MPD::Start(void)
+{
+ if (aamp->IsLocalAAMPTsbInjection())
+ {
+ StartFromAampLocalTsb();
+ }
+ else
+ {
+ StartFromOtherThanAampLocalTsb();
+ }
+
+ if( (mLowLatencyMode && ISCONFIGSET( eAAMPConfig_EnableLowLatencyCorrection ) ) && \
+ (true == aamp->GetLLDashAdjustSpeed() ) )
+ {
+ StartLatencyMonitorThread();
+ }
}
/**
@@ -10734,7 +10704,7 @@ void StreamAbstractionAAMP_MPD::GetStreamFormat(StreamOutputFormat &primaryOutpu
//TODO - check whether the ugly hack above is in operation
// This is again a dirty hack, the check for PTS restamp enabled. TODO: We need to remove this in future
// For cases where subtitles is enabled mid-playback, we need to configure the pipeline at the beginning. FORMAT_SUBTITLE_MP4 will be set
- if (mMediaStreamContext[eMEDIATYPE_SUBTITLE] && (mMediaStreamContext[eMEDIATYPE_SUBTITLE]->enabled || ISCONFIGSET(eAAMPConfig_EnablePTSReStamp))
+ if (mMediaStreamContext[eMEDIATYPE_SUBTITLE] && (mMediaStreamContext[eMEDIATYPE_SUBTITLE]->enabled || (ISCONFIGSET(eAAMPConfig_EnablePTSReStamp) && (!(ISCONFIGSET(eAAMPConfig_useRialtoSink)))))
&& mMediaStreamContext[eMEDIATYPE_SUBTITLE]->type != eTRACK_AUX_AUDIO)
{
AAMPLOG_WARN("Entering GetCurrentMimeType");
@@ -10869,7 +10839,7 @@ StreamInfo* StreamAbstractionAAMP_MPD::GetStreamInfo(int idx)
{
int userData = 0;
- if (GetProfileCount() && !aamp->IsTSBSupported()) // avoid calling getUserDataOfProfile() for playlist only URL playback.
+ if (GetProfileCount() && !aamp->IsFogTSBSupported()) // avoid calling getUserDataOfProfile() for playlist only URL playback.
{
userData = GetABRManager().getUserDataOfProfile(idx);
}
@@ -10924,7 +10894,6 @@ double StreamAbstractionAAMP_MPD::GetStartTimeOfFirstPTS()
if (tsbSessionManager && video && video->IsLocalTSBInjection())
{
startTime = 0;
- //startTime = tsbSessionManager->GetTsbReader(eMEDIATYPE_VIDEO)->GetStartPosition();
}
return startTime;
}
@@ -11687,21 +11656,26 @@ bool StreamAbstractionAAMP_MPD::onAdEvent(AdEvent evt, double &adOffset)
// Getting called from StreamAbstractionAAMP_MPD::Init or from FetcherLoop
std::string brkId = "";
int adIdx = mCdaiObject->CheckForAdStart(rate, (AdEvent::INIT == evt), mBasePeriodId, mBasePeriodOffset, brkId, adOffset);
- if(!brkId.empty() && adIdx >= 0)
+ // If an adbreak is found for period
+ if(!brkId.empty())
{
- AAMPLOG_INFO("[CDAI] CheckForAdStart found Adbreak. adIdx[%d] mBasePeriodOffset[%lf] adOffset[%lf] SeekOffset:%f.", adIdx, mBasePeriodOffset, adOffset,mCdaiObject->mContentSeekOffset);
- //Setting mContentSeekOffset as 0 if player is going to play DAI ad.
- //Otherwise, player will skip initial fragments of DAI ad sometimes due to the seekoffset.
- //Dai ad playback should start from first fragment.
-
- mCdaiObject->mContentSeekOffset = 0;
+ AAMPLOG_INFO("[CDAI] CheckForAdStart found Adbreak[%s] adIdx[%d] mBasePeriodOffset[%lf] adOffset[%lf] SeekOffset:%f.", brkId.c_str(), adIdx, mBasePeriodOffset, adOffset,mCdaiObject->mContentSeekOffset);
mCdaiObject->mCurPlayingBreakId = brkId;
+
+ // If an ad is found, for the periodOffset
if(-1 != adIdx && mCdaiObject->mAdBreaks[brkId].ads)
{
- // Wait for some time if the ad is not ready yet.
+ //Setting mContentSeekOffset as 0 if player is going to play DAI ad.
+ //Otherwise, player will skip initial fragments of DAI ad sometimes due to the seekoffset.
+ //Dai ad playback should start from first fragment.
+ mCdaiObject->mContentSeekOffset = 0;
+
lock.unlock();
+ // Check if ad is resolved, if not wait
CheckAdResolvedStatus(mCdaiObject->mAdBreaks[brkId].ads, adIdx);
lock.lock();
+
+ // If the ad is not invalid (failed to reserve), start the ad playback
if(!(mCdaiObject->mAdBreaks[brkId].ads->at(adIdx).invalid))
{
AAMPLOG_WARN("[CDAI]: STARTING ADBREAK[%s] AdIdx[%d] Found at Period[%s].", brkId.c_str(), adIdx, mBasePeriodId.c_str());
@@ -11711,7 +11685,9 @@ bool StreamAbstractionAAMP_MPD::onAdEvent(AdEvent evt, double &adOffset)
mCdaiObject->mAdState = AdState::IN_ADBREAK_AD_PLAYING;
for(int i=0; imCurAds->at(i).duration;
+ }
}
else
{
@@ -11719,48 +11695,70 @@ bool StreamAbstractionAAMP_MPD::onAdEvent(AdEvent evt, double &adOffset)
}
reservationEvt2Send = AAMP_EVENT_AD_RESERVATION_START;
adbreakId2Send = brkId;
- if(AdEvent::INIT == evt) sendImmediate = true;
- }
-
- if(AdState::IN_ADBREAK_AD_PLAYING != mCdaiObject->mAdState)
- {
- AAMPLOG_WARN("[CDAI]: BasePeriodId in Adbreak. But Ad not available. BasePeriodId[%s],Adbreak[%s]", mBasePeriodId.c_str(), brkId.c_str());
- mCdaiObject->mAdState = AdState::IN_ADBREAK_AD_NOT_PLAYING;
+ if(AdEvent::INIT == evt)
+ {
+ sendImmediate = true;
+ }
+ if(AdState::IN_ADBREAK_AD_PLAYING != mCdaiObject->mAdState)
+ {
+ AAMPLOG_WARN("[CDAI]: BasePeriodId in Adbreak. But Ad not available. BasePeriodId[%s],Adbreak[%s]", mBasePeriodId.c_str(), brkId.c_str());
+ mCdaiObject->mAdState = AdState::IN_ADBREAK_AD_NOT_PLAYING;
+ }
+ stateChanged = true;
}
- stateChanged = true;
- }
- else
- {
- if (mCdaiObject->isAdBreakObjectExist(mBasePeriodId))
+ else
{
- AAMPLOG_WARN("[CDAI] Got adIdx[%d] for adBreakId[%s] but adBreak object exist", adIdx, brkId.c_str());
-
- if ((mCdaiObject->mAdState != AdState::OUTSIDE_ADBREAK_WAIT4ADS) && !mCdaiObject->mAdBreaks[mBasePeriodId].invalid)
+ // On rewind, if the ad is not found at the offset, it could also be a partial ads
+ if (rate < AAMP_RATE_PAUSE)
{
- if(!brkId.empty() && mCdaiObject->mAdBreaks[brkId].ads->size() > 0)
- {
- AAMPLOG_WARN("[CDAI] ads.size() = %zu breakId = %s mBasePeriodId = %s", mCdaiObject->mAdBreaks[brkId].ads->size(), brkId.c_str(), mBasePeriodId.c_str());
- }
- else
- {
- lock.unlock();
- CheckAdResolvedStatus(mCdaiObject->mAdBreaks[mBasePeriodId].ads, -1, mBasePeriodId);
- lock.lock();
- }
- mCdaiObject->mAdState = AdState::OUTSIDE_ADBREAK_WAIT4ADS;
+ // This will ensure that we play the ads once the offset reaches a position where ad is available
+ mCdaiObject->mAdState = AdState::IN_ADBREAK_AD_NOT_PLAYING;
stateChanged = true;
}
- else
+ // If an adbreak exists for this basePeriodId, then ads might be available.
+ // Only for scenarios where mBasePeriodOffset is zero, we have to wait for the ads to be added by application.
+ // Otherwise for partial ad fill, once the ads are played, we will wait as adIdx will be -1 from CheckForAdStart().
+ else if (mBasePeriodOffset == 0)
{
- AAMPLOG_WARN("[CDAI] AdBreak[%s] is invalidated. Skipping.", mBasePeriodId.c_str());
- if(AdState::OUTSIDE_ADBREAK_WAIT4ADS == mCdaiObject->mAdState)
+ // If the adbreak is not invalidated, wait for ads to be added and resolved
+ if ((mCdaiObject->mAdState != AdState::OUTSIDE_ADBREAK_WAIT4ADS) && !mCdaiObject->mAdBreaks[mBasePeriodId].invalid)
{
+ mCdaiObject->mAdState = AdState::OUTSIDE_ADBREAK_WAIT4ADS;
stateChanged = true;
- mCdaiObject->mAdState = AdState::OUTSIDE_ADBREAK;
+ if(mCdaiObject->mAdBreaks[brkId].ads && mCdaiObject->mAdBreaks[brkId].ads->size() > 0)
+ {
+ AAMPLOG_WARN("[CDAI] ads.size() = %zu breakId = %s mBasePeriodId = %s", mCdaiObject->mAdBreaks[brkId].ads->size(), brkId.c_str(), mBasePeriodId.c_str());
+ // We failed to get an ad as its invalid, so we can switch to source content now
+ if (mCdaiObject->mAdBreaks[brkId].ads->at(0).invalid)
+ {
+ mCdaiObject->mAdState = AdState::OUTSIDE_ADBREAK;
+ }
+ }
+ else
+ {
+ lock.unlock();
+ // Wait for some time for the ads to be added
+ CheckAdResolvedStatus(mCdaiObject->mAdBreaks[mBasePeriodId].ads, -1, mBasePeriodId);
+ lock.lock();
+ }
+ }
+ else
+ {
+ // Ads are not added or ads failed to resolve, invalidate the adbreak
+ AAMPLOG_WARN("[CDAI] AdBreak[%s] is invalidated. Skipping.", mBasePeriodId.c_str());
+ if(AdState::OUTSIDE_ADBREAK_WAIT4ADS == mCdaiObject->mAdState)
+ {
+ stateChanged = true;
+ mCdaiObject->mAdState = AdState::OUTSIDE_ADBREAK;
+ }
}
}
}
}
+ else
+ {
+ AAMPLOG_INFO("[CDAI] No AdBreak found for period[%s] at offset:%lf", mBasePeriodId.c_str(), mBasePeriodOffset);
+ }
}
break;
case AdState::IN_ADBREAK_AD_NOT_PLAYING:
@@ -11770,15 +11768,13 @@ bool StreamAbstractionAAMP_MPD::onAdEvent(AdEvent evt, double &adOffset)
int adIdx = mCdaiObject->CheckForAdStart(rate, false, mBasePeriodId, mBasePeriodOffset, brkId, adOffset);
if(-1 != adIdx && mCdaiObject->mAdBreaks[brkId].ads)
{
- if(0 == adIdx && 0 != mBasePeriodOffset)
+ if (rate >= AAMP_NORMAL_PLAY_RATE)
{
- //Ad is ready; but it is late. Invalidate.
- mCdaiObject->mAdBreaks[brkId].ads->at(0).invalid = true;
+ // Wait for some time if the ad is not ready yet.
+ lock.unlock();
+ CheckAdResolvedStatus(mCdaiObject->mAdBreaks[brkId].ads, adIdx);
+ lock.lock();
}
- // Wait for some time if the ad is not ready yet.
- lock.unlock();
- CheckAdResolvedStatus(mCdaiObject->mAdBreaks[brkId].ads, adIdx);
- lock.lock();
if(!(mCdaiObject->mAdBreaks[brkId].ads->at(adIdx).invalid))
{
AAMPLOG_WARN("[CDAI]: AdIdx[%d] Found at Period[%s].", adIdx, mBasePeriodId.c_str());
@@ -11788,7 +11784,9 @@ bool StreamAbstractionAAMP_MPD::onAdEvent(AdEvent evt, double &adOffset)
mCdaiObject->mAdState = AdState::IN_ADBREAK_AD_PLAYING;
for(int i=0; imCurAds->at(i).duration;
+ }
stateChanged = true;
}
if(adIdx == (mCdaiObject->mAdBreaks[brkId].ads->size() -1)) //Rewind case only.
@@ -11925,11 +11923,6 @@ bool StreamAbstractionAAMP_MPD::onAdEvent(AdEvent evt, double &adOffset)
break;
}
- //If both IDs are the same, it indicates that the source period has content to play.
- if( mBasePeriodId == mCdaiObject->mAdBreaks[mCdaiObject->mCurPlayingBreakId].endPeriodId)
- {
- checkSrcAdisGreaterThanAdbreak();
- }
mBasePeriodId = mCdaiObject->mAdBreaks[mCdaiObject->mCurPlayingBreakId].endPeriodId;
mCdaiObject->mContentSeekOffset = (double)(mCdaiObject->mAdBreaks[mCdaiObject->mCurPlayingBreakId].endPeriodOffset)/ 1000;
}
@@ -12084,49 +12077,6 @@ bool StreamAbstractionAAMP_MPD::onAdEvent(AdEvent evt, double &adOffset)
return stateChanged;
}
-/**
- * @brief Checking whether the source period is greater than the ad break.
- * Play the remaining source content if applicable.
- *
- * @return void
- */
-void StreamAbstractionAAMP_MPD::checkSrcAdisGreaterThanAdbreak()
-{
- size_t sizeOfSrcPeriod = mpd->GetPeriods().size();
- int IterPeriodIndex =0;
- for(IterPeriodIndex=0; IterPeriodIndex < sizeOfSrcPeriod ; IterPeriodIndex++)
- {
- const std::string &pId = mpd->GetPeriods().at(IterPeriodIndex)->GetId();
- AAMPLOG_INFO("IterPeriodIndex: %d sizeOfSrcPeriod:%zu baseperiod:%s pid:%s",IterPeriodIndex,sizeOfSrcPeriod,mBasePeriodId.c_str(),pId.c_str());
- if(mBasePeriodId == pId)
- {
- break;
- }
- }
- //Source period duration
- double basePeriodDuration = mMPDParseHelper->aamp_GetPeriodDuration(IterPeriodIndex, 0);
- //ad break duration
- double baseperiodOffset = (double)(mCdaiObject->mAdBreaks[mCdaiObject->mCurPlayingBreakId].endPeriodOffset);
- AAMPLOG_INFO("mBasePeriodId:%s basePeriodDuration:%f baseperiodOffset:%f diff:%f",mBasePeriodId.c_str(),basePeriodDuration,baseperiodOffset,basePeriodDuration - baseperiodOffset);
- //The base PeriodOffset should be 0 if the ad break duration matches the source.
- ////If not, and the delta is more than 2 seconds, mSrcPeriodOffsetGTthreshold
- // needs to be set, indicating that the source period has content that needs
- // to be played after the ad playback.
- if( (baseperiodOffset > 0) && ((basePeriodDuration - baseperiodOffset) > OFFSET_ALIGN_FACTOR))
- {
- if(mCdaiObject->isAdBreakObjectExist(mBasePeriodId))
- {
- //The player should switch to the same base period to play the remaining content if the flag is true.
- mCdaiObject->mAdBreaks[mBasePeriodId].mSrcPeriodOffsetGTthreshold = true;
- AAMPLOG_INFO("Src period[%s] is greater than the ad break by %f ms",mBasePeriodId.c_str(),basePeriodDuration - baseperiodOffset);
- }
- else
- {
- AAMPLOG_INFO("Adbreak object does not exists for base period:%s",mBasePeriodId.c_str());
- }
- }
-}
-
/**
* @brief Print the current the track information
*
@@ -13706,64 +13656,37 @@ void StreamAbstractionAAMP_MPD::setNextRangeRequest(std::string fragmentUrl,std:
}
/**
- * @fn PlacenextAdBrkifAvail
- * @brief Function to verify if the next period contains ad break and place it
- * @param[in] mpd
- * @retval true if adstate changes.
- */
-
-bool StreamAbstractionAAMP_MPD::PlacenextAdBrkifAvail(IMPD *mpd)
-{
- bool adStateChanged = false;
- bool adFound = mCdaiObject->HasDaiAd(mBasePeriodId);
- if(adFound)
- {
- int basePeriodIdx = mMPDParseHelper->getPeriodIdx(mBasePeriodId);
- mBasePeriodOffset = 0;
- {
- std::lock_guard lock(mCdaiObject->mDaiMtx);
- if (mCdaiObject->mContentSeekOffset > 0)
- {
- mBasePeriodOffset = mCdaiObject->mContentSeekOffset;
- }
- }
- if(basePeriodIdx != -1)
- {
- if(mMPDParseHelper->IsEmptyPeriod(basePeriodIdx, (rate != AAMP_NORMAL_PLAY_RATE)))
- {
- AAMPLOG_WARN("[CDAI] period [%s] is empty not processing adevents if any",mBasePeriodId.c_str());
- return adStateChanged;
- }
- }
- AAMPLOG_WARN("[CDAI]Current Period : %s has DAI ADS .. PlaceAds",mBasePeriodId.c_str());
- mCdaiObject->PlaceAds(mpd);// to ensure the second ad break is placed to the ad object
- adStateChanged = onAdEvent(AdEvent::DEFAULT);//to play Second immediate ad break
- }
- AAMPLOG_WARN("[CDAI] total number of ads in AdBreakList:%zu",mCdaiObject->mAdtoInsertInNextBreakVec.size());
- return adStateChanged;
-}
-
-
-/* one or more empty period(s) can appear at live edge. player must not play into those periods until/unless those empty periods are instantiated.
- any empty period followed by non-empty period will never be instantiated, will remain empty, and will eventually slide out of the live window. These forever-empty periods must never be presented using alternate content, but should be skipped.
+ * @brief Retrieves the index of a valid period based on the given period index.
+ *
+ * This function checks if the period at the given index is empty or has a duration below a threshold.
+ * If the period is valid, the function returns the given period index.
+ * If the period is empty or has a tiny duration, the function searches for the next or previous non-empty period
+ * or a period with a duration greater than a threshold. If a valid period is found, its index is returned.
+ * If no valid period is found, the function returns the given period index.
+ * Any empty period followed by non-empty period will never be instantiated, will remain empty, and will eventually slide out of the live window.
+ * These forever-empty periods must never be presented using alternate content, but should be skipped.
+ *
+ * @param periodIdx The index of the period to check.
+ * @return The index of a valid period.
*/
-int StreamAbstractionAAMP_MPD::getValidperiodIdx(int periodIdx)
+int StreamAbstractionAAMP_MPD::GetValidPeriodIdx(int periodIdx)
{
int periodIter = periodIdx;
- if ((!mMPDParseHelper->IsEmptyPeriod(periodIter, (rate != AAMP_NORMAL_PLAY_RATE))) &&
- (mMPDParseHelper->GetPeriodDuration(periodIter,mLastPlaylistDownloadTimeMs,(rate != AAMP_NORMAL_PLAY_RATE),aamp->IsUninterruptedTSB()) >= THRESHOLD_TOIGNORE_TINYPERIOD))
+ bool isPeriodEmpty = mMPDParseHelper->IsEmptyPeriod(periodIter, (rate != AAMP_NORMAL_PLAY_RATE));
+ double periodDuration = mMPDParseHelper->GetPeriodDuration(periodIter, mLastPlaylistDownloadTimeMs, (rate != AAMP_NORMAL_PLAY_RATE), aamp->IsUninterruptedTSB());
+ if (!isPeriodEmpty && periodDuration >= THRESHOLD_TOIGNORE_TINYPERIOD)
{
- AAMPLOG_WARN("[CDAI] Landed at period (%s) periodIdx: %d duration(ms):%f",mpd->GetPeriods().at(periodIter)->GetId().c_str(),periodIter,mMPDParseHelper->GetPeriodDuration(periodIter,mLastPlaylistDownloadTimeMs,(rate != AAMP_NORMAL_PLAY_RATE),aamp->IsUninterruptedTSB()));
+ AAMPLOG_WARN("[CDAI] Landed at period (%s) periodIdx: %d duration(ms):%f",mpd->GetPeriods().at(periodIter)->GetId().c_str(), periodIter, periodDuration);
return periodIter;
}
if(periodIdx >= 0 && (periodIdx < mNumberOfPeriods))
{
- AAMPLOG_WARN("[CDAI] current period [id: %s d:%f] is empty or tiny,check if the immediate next period is non-empty",mpd->GetPeriods().at(periodIter)->GetId().c_str(),mMPDParseHelper->GetPeriodDuration(periodIter,mLastPlaylistDownloadTimeMs,(rate != AAMP_NORMAL_PLAY_RATE),aamp->IsUninterruptedTSB()));
+ AAMPLOG_WARN("[CDAI] current period [id:%s d:%f] is empty or tiny, check if the immediate next period is non-empty",
+ mpd->GetPeriods().at(periodIter)->GetId().c_str(), periodDuration);
+ // Find the next or prev non-empty period or period with duration greater than THRESHOLD_TOIGNORE_TINYPERIOD
bool bvalidperiodfound = false;
- int direction = 1;
- if(rate < 0)
- direction = -1;
+ int direction = (rate < 0) ? -1 : 1;
periodIter += direction; //point periodIter to next period
while((periodIter < mNumberOfPeriods) && (periodIter >= 0))
{
@@ -13771,7 +13694,8 @@ int StreamAbstractionAAMP_MPD::getValidperiodIdx(int periodIdx)
if ((!mMPDParseHelper->IsEmptyPeriod(periodIter, (rate != AAMP_NORMAL_PLAY_RATE))) &&
(mMPDParseHelper->GetPeriodDuration(periodIter,mLastPlaylistDownloadTimeMs,(rate != AAMP_NORMAL_PLAY_RATE),aamp->IsUninterruptedTSB()) >= THRESHOLD_TOIGNORE_TINYPERIOD))
{
- AAMPLOG_WARN("[CDAI] valid period(%s) after non-empty period(%s) found at index (%d)", mpd->GetPeriods().at(periodIter)->GetId().c_str(),mpd->GetPeriods().at(periodIdx)->GetId().c_str(),periodIter);
+ AAMPLOG_WARN("[CDAI] valid period(%s) after non-empty period(%s) found at index (%d)",
+ mpd->GetPeriods().at(periodIter)->GetId().c_str(), mpd->GetPeriods().at(periodIdx)->GetId().c_str(), periodIter);
bvalidperiodfound = true;
break;
}
@@ -13803,7 +13727,7 @@ void StreamAbstractionAAMP_MPD::SeekPosUpdate(double secondsRelativeToTuneTime)
}
/**
- * @brief Function to notify first video pts value from tsprocessor/demux
+ * @brief Function to notify first video pts value
*
* @param[in] pts
* @param[in] timescale
diff --git a/fragmentcollector_mpd.h b/fragmentcollector_mpd.h
index 48bd07d..cb2f859 100644
--- a/fragmentcollector_mpd.h
+++ b/fragmentcollector_mpd.h
@@ -142,7 +142,7 @@ public :
{
matchingBaseURL = aamp_getHostFromURL(matchingBaseURL);
matchingBaseURL += url;
- AAMPLOG_WARN( "baseURL with leading /" );
+ AAMPLOG_WARN( "baseURL with leading /" );
}
else
{
@@ -176,22 +176,28 @@ class StreamAbstractionAAMP_MPD : public StreamAbstractionAAMP
*/
~StreamAbstractionAAMP_MPD();
/**
- * @fn StreamAbstractionAAMP_MPD Copy constructor disabled
- *
- */
- StreamAbstractionAAMP_MPD(const StreamAbstractionAAMP_MPD&) = delete;
+ * @fn StreamAbstractionAAMP_MPD Copy constructor disabled
+ *
+ */
+ StreamAbstractionAAMP_MPD(const StreamAbstractionAAMP_MPD&) = delete;
/**
- * @fn StreamAbstractionAAMP_MPD assignment operator disabled
- *
- */
+ * @fn StreamAbstractionAAMP_MPD assignment operator disabled
+ *
+ */
StreamAbstractionAAMP_MPD& operator=(const StreamAbstractionAAMP_MPD&) = delete;
+ /**
+ * @fn Start
+ * @brief Start streaming
+ */
void Start() override;
+
/**
* @fn Stop
* @param clearChannelData - ignored.
*/
void Stop(bool clearChannelData) override;
+
/**
* @fn Init
* @param tuneType to set type of object.
@@ -546,6 +552,20 @@ class StreamAbstractionAAMP_MPD : public StreamAbstractionAAMP
bool UseIframeTrack(void) override;
protected:
+ /**
+ * @fn StartFromAampLocalTsb
+ *
+ * @brief Start streaming from AAMP Local TSB
+ */
+ void StartFromAampLocalTsb();
+
+ /**
+ * @fn StartFromOtherThanAampLocalTsb
+ *
+ * @brief Start streaming content from a source other than AAMP Local TSB (live, CloudTSB, FOG...)
+ */
+ void StartFromOtherThanAampLocalTsb();
+
/**
* @fn GetStartAndDurationForPtsRestamping
*
@@ -1007,9 +1027,13 @@ class StreamAbstractionAAMP_MPD : public StreamAbstractionAAMP
*/
void ProcessAllContentProtectionForMediaType(AampMediaType type, uint32_t priorityAdaptationIdx, std::set &chosenAdaptationIdxs);
- bool PlacenextAdBrkifAvail(dash::mpd::IMPD *mpd);
-
- int getValidperiodIdx(int periodIdx);
+ /**
+ * @brief Retrieves the index of a valid period based on the given period index.
+ *
+ * @param periodIdx The index of the period to check.
+ * @return The index of a valid period.
+ */
+ int GetValidPeriodIdx(int periodIdx);
void UpdateMPDPeriodDetails(std::vector& currMPDPeriodDetails,uint64_t &durMs);
@@ -1130,12 +1154,6 @@ class StreamAbstractionAAMP_MPD : public StreamAbstractionAAMP
* @param[in] trackIndex - index of current audio track
*/
- /**
- * @fn checkSrcAdisGreaterThanAdbreak
- * @param
- * @param
- */
- void checkSrcAdisGreaterThanAdbreak();
void SetAudioTrackInfo(const std::vector &tracks, const std::string &trackIndex);
void SetTextTrackInfo(const std::vector &tracks, const std::string &trackIndex);
/**
diff --git a/isobmff/isobmffbox.h b/isobmff/isobmffbox.h
index d3d7879..4706c5e 100644
--- a/isobmff/isobmffbox.h
+++ b/isobmff/isobmffbox.h
@@ -983,7 +983,7 @@ class PrftBox : public FullBox
/**
* @fn setMediaTime
*
- * @param[in] mediaTime - metia time value
+ * @param[in] mediaTime - media time value
* @return void
*/
void setMediaTime(uint64_t mediaTime);
diff --git a/jsbindings/jsbindings.cpp b/jsbindings/jsbindings.cpp
index 9e13eaf..2801a0c 100644
--- a/jsbindings/jsbindings.cpp
+++ b/jsbindings/jsbindings.cpp
@@ -2478,7 +2478,7 @@ static JSValueRef AAMP_setRate(JSContextRef context, JSObjectRef function, JSObj
{
int overshoot = 0;
float rate = (float)JSValueToNumber(context, arguments[0], exception);
- // present JS doesnt support overshoot , check for argument count and store.
+ // present JS doesn't support overshoot , check for argument count and store.
if(argumentCount > 1)
{
overshoot = (int)JSValueToNumber(context, arguments[1], exception);
diff --git a/jsbindings/jsmediaplayer.cpp b/jsbindings/jsmediaplayer.cpp
index c589d28..62ebca7 100644
--- a/jsbindings/jsmediaplayer.cpp
+++ b/jsbindings/jsmediaplayer.cpp
@@ -3418,7 +3418,7 @@ JSValueRef AAMPMediaPlayerJS_getVideoPlaybackQuality (JSContextRef ctx, JSObject
}
/**
- * @brief CFunction to set pre-proceed DASH manifest data.
+ * @brief C Function to set pre-proceed DASH manifest data.
*
* @param[in] ctx JS execution context
* @param[in] function JSObject that is the function being called
diff --git a/jsbindings/jsutils.cpp b/jsbindings/jsutils.cpp
index 32b6a68..7cec8c6 100644
--- a/jsbindings/jsutils.cpp
+++ b/jsbindings/jsutils.cpp
@@ -140,7 +140,7 @@ static EventTypeMap aamp_eventTypes[] =
*/
static EventTypeMap aampPlayer_eventTypes[] =
{
-//TODO: Need separate event list to avoid breaking existing viper impl. Unify later.
+//TODO: Need separate event list to avoid breaking existing legacy impl. Unify later.
{ (AAMPEventType)0, "onEvent"},
{ AAMP_EVENT_TUNED, "playbackStarted"},
{ AAMP_EVENT_TUNE_FAILED, "playbackFailed"},
diff --git a/main_aamp.cpp b/main_aamp.cpp
index 3bf7ed9..1b4a2ca 100755
--- a/main_aamp.cpp
+++ b/main_aamp.cpp
@@ -60,26 +60,30 @@ PlayerInstanceAAMP::PlayerInstanceAAMP(StreamSink* streamSink
//Need to do iarm initialization process before reading the tr181 aamp parameters.
//Using printf here since AAMP logs can only use after creating the global object
#ifdef IARM_MGR
- static bool iarmInitialized = false;
- if(!iarmInitialized)
+ // IARM doesn't work in container environment hence dont init IARM in container
+ if(!IsContainerEnvironment() )
{
- char processName[20] = {0};
- IARM_Result_t result;
- snprintf(processName, sizeof(processName), "AAMP-PLAYER-%u", getpid());
- if (IARM_RESULT_SUCCESS == (result = IARM_Bus_Init((const char*) &processName))) {
- printf("IARM Interface Inited in AAMP");
- }
- else {
- printf("IARM Interface Inited Externally : %d", result);
- }
+ static bool iarmInitialized = false;
+ if(!iarmInitialized)
+ {
+ char processName[20] = {0};
+ IARM_Result_t result;
+ snprintf(processName, sizeof(processName), "AAMP-PLAYER-%u", getpid());
+ if (IARM_RESULT_SUCCESS == (result = IARM_Bus_Init((const char*) &processName))) {
+ printf("IARM Interface Inited in AAMP");
+ }
+ else {
+ printf("IARM Interface Inited Externally : %d", result);
+ }
- if (IARM_RESULT_SUCCESS == (result = IARM_Bus_Connect())) {
- printf("IARM Interface Connected in AAMP");
- }
- else {
- printf("IARM Interface Connected Externally :%d", result);
+ if (IARM_RESULT_SUCCESS == (result = IARM_Bus_Connect())) {
+ printf("IARM Interface Connected in AAMP");
+ }
+ else {
+ printf("IARM Interface Connected Externally :%d", result);
+ }
+ iarmInitialized = true;
}
- iarmInitialized = true;
}
#endif // IARM_MGR
// Create very first instance of Aamp Config to read the cfg & Operator file .This is needed for very first
@@ -833,19 +837,36 @@ void PlayerInstanceAAMP::SetRateInternal(float rate,int overshootcorrection)
{ // no change in desired play rate
// no deferring for playback resume
if (aamp->pipeline_paused && rate != 0)
- { // but need to unpause pipeline
+ {
AAMPLOG_INFO("Resuming Playback at Position '%lld'.", aamp->GetPositionMilliseconds());
- // check if unpausing in the middle of fragments caching
- if(!aamp->SetStateBufferingIfRequired())
+ // Resuming payback from pause
+ // If have local TSB, but playing from Live then seek into the TSB
+ // Otherwise unpause the pipeline
+ if(aamp->IsLocalAAMPTsb() && !aamp->IsLocalAAMPTsbInjection())
+ {
+ retValue = false;
+ aamp->SetState(eSTATE_SEEKING);
+ aamp->seek_pos_seconds = aamp->GetPositionSeconds();
+ aamp->rate = AAMP_NORMAL_PLAY_RATE;
+ aamp->pipeline_paused = false;
+ aamp->AcquireStreamLock();
+ aamp->TuneHelper(eTUNETYPE_SEEK, false);
+ aamp->ReleaseStreamLock();
+ }
+ else
{
- aamp->mpStreamAbstractionAAMP->NotifyPlaybackPaused(false);
- StreamSink *sink = AampStreamSinkManager::GetInstance().GetStreamSink(aamp);
- if (sink)
+ // check if unpausing in the middle of fragments caching
+ if(!aamp->SetStateBufferingIfRequired())
{
- retValue = sink->Pause(false, false);
+ aamp->mpStreamAbstractionAAMP->NotifyPlaybackPaused(false);
+ StreamSink *sink = AampStreamSinkManager::GetInstance().GetStreamSink(aamp);
+ if (sink)
+ {
+ retValue = sink->Pause(false, false);
+ }
+ // required since buffers are already cached in paused state
+ aamp->NotifyFirstBufferProcessed(sink ? sink->GetVideoRectangle() : std::string());
}
- // required since buffers are already cached in paused state
- aamp->NotifyFirstBufferProcessed(sink ? sink->GetVideoRectangle() : std::string());
}
aamp->pipeline_paused = false;
aamp->ResumeDownloads();
@@ -856,27 +877,18 @@ void PlayerInstanceAAMP::SetRateInternal(float rate,int overshootcorrection)
if (!aamp->pipeline_paused)
{
aamp->mpStreamAbstractionAAMP->NotifyPlaybackPaused(true);
- aamp->StopDownloads();
- if(aamp->IsLocalAAMPTsb() && aamp->rate == AAMP_NORMAL_PLAY_RATE) //avoid new pause logic for pause as part of lightning seek
+ if (!aamp->IsLocalAAMPTsb())
{
- retValue = false;
- aamp->SetState(eSTATE_SEEKING);
- aamp->seek_pos_seconds = aamp->GetPositionSeconds();
- aamp->rate = AAMP_NORMAL_PLAY_RATE;
- aamp->AcquireStreamLock();
- aamp->TuneHelper(eTUNETYPE_SEEK, true);
- aamp->ReleaseStreamLock();
- aamp->ResumeDownloads();
+ aamp->StopDownloads();
}
- else
+
+ StreamSink *sink = AampStreamSinkManager::GetInstance().GetStreamSink(aamp);
+ if (sink)
{
- StreamSink *sink = AampStreamSinkManager::GetInstance().GetStreamSink(aamp);
- if (sink)
- {
- retValue = sink->Pause(true, false);
- }
- aamp->pipeline_paused = true;
+ retValue = sink->Pause(true, false);
}
+ aamp->pipeline_paused = true;
+
if(aamp->GetLLDashServiceData()->lowLatencyMode)
{
// PAUSED to PLAY without tune, LLD rate correction is disabled to keep position
@@ -2489,7 +2501,6 @@ void PlayerInstanceAAMP::SetMatchingBaseUrlConfig(bool bValue)
void PlayerInstanceAAMP::SetNewABRConfig(bool bValue)
{
SETCONFIGVALUE(AAMP_APPLICATION_SETTING,eAAMPConfig_ABRBufferCheckEnabled,bValue);
- // Piggybacked following setting along with NewABR
SETCONFIGVALUE(AAMP_APPLICATION_SETTING,eAAMPConfig_NewDiscontinuity,bValue);
SETCONFIGVALUE(AAMP_APPLICATION_SETTING,eAAMPConfig_HLSAVTrackSyncUsingStartTime,bValue);
}
@@ -3099,7 +3110,7 @@ void PlayerInstanceAAMP::SetAsyncTuneConfig(bool bValue)
{
SETCONFIGVALUE(AAMP_APPLICATION_SETTING,eAAMPConfig_AsyncTune,bValue);
// Start it for the playerinstance if default not started and App wants
- // Stop Async operation for the playerinstance if default started and App doesnt want
+ // Stop Async operation for the playerinstance if default started and App doesn't want
AsyncStartStop();
}
diff --git a/middleware/InterfacePlayerRDK.cpp b/middleware/InterfacePlayerRDK.cpp
index b05ccc3..269fcbc 100644
--- a/middleware/InterfacePlayerRDK.cpp
+++ b/middleware/InterfacePlayerRDK.cpp
@@ -461,8 +461,8 @@ void InterfacePlayerRDK::ConfigurePipeline(int format, int audioFormat, int auxF
if( !gstPrivateContext->subtitle_sink ) MW_LOG_WARN( "subtitle_sink==NULL" );
gst_structure_set(
contextStructure,
- "video-streams", G_TYPE_UINT, 0x1u,
- "audio-streams", G_TYPE_UINT, 0x1u,
+ "video-streams", G_TYPE_UINT, (gstPrivateContext->video_sink)?0x1u:0x0u,
+ "audio-streams", G_TYPE_UINT, (gstPrivateContext->audio_sink)?0x1u:0x0u,
"text-streams", G_TYPE_UINT, (gstPrivateContext->subtitle_sink)?0x1u:0x0u,
nullptr );
gst_element_set_context(GST_ELEMENT(gstPrivateContext->pipeline), context);
@@ -948,13 +948,24 @@ void InterfacePlayerRDK::RemoveProbes()
{
for (int i = 0; i < GST_TRACK_COUNT; i++)
{
- gst_media_stream *stream = &gstPrivateContext->stream[(GstMediaType)i];
- if (stream->demuxProbeId && stream->demuxPad)
- {
- gst_pad_remove_probe(stream->demuxPad, stream->demuxProbeId);
- stream->demuxProbeId = 0;
- stream->demuxPad = NULL;
- }
+ RemoveProbe((GstMediaType)i);
+ }
+}
+
+/**
+ * @fn RemoveProbe
+ * @brief Remove probe for a particular media type
+ * @param[in] mediaType The media type for which the probe should be removed
+ */
+void InterfacePlayerRDK::RemoveProbe(GstMediaType mediaType)
+{
+ gst_media_stream *stream = &gstPrivateContext->stream[mediaType];
+ if (stream->demuxProbeId && stream->demuxPad)
+ {
+ MW_LOG_WARN("InterfacePlayerRDK: Removing probe for media type %d, probe id %lu", mediaType, stream->demuxProbeId);
+ gst_pad_remove_probe(stream->demuxPad, stream->demuxProbeId);
+ stream->demuxProbeId = 0;
+ stream->demuxPad = NULL;
}
}
@@ -1221,6 +1232,7 @@ static GstStateChangeReturn SetStateWithWarnings(GstElement *element, GstState t
void InterfacePlayerRDK::TearDownStream(GstMediaType mediaType)
{
tearDownCb(true, mediaType);
+ RemoveProbe(mediaType);
gst_media_stream* stream = &gstPrivateContext->stream[mediaType];
stream->bufferUnderrun = false;
stream->eosReached = false;
@@ -1690,7 +1702,7 @@ static void gst_enough_data(GstElement *source, void *_this)
MW_LOG_ERR( "Null check failed." );
}
}
-void InterfacePlayerRDK::InitializeSourceForPlayer(void *PlayerInstance, void * source, GstMediaType mediaType, bool isFogEnabled)
+void InterfacePlayerRDK::InitializeSourceForPlayer(void *PlayerInstance, void * source, GstMediaType mediaType)
{
InterfacePlayerRDK* _this = (InterfacePlayerRDK*)PlayerInstance;
GstCaps * caps = NULL;
@@ -1701,15 +1713,15 @@ void InterfacePlayerRDK::InitializeSourceForPlayer(void *PlayerInstance, void *
gst_app_src_set_stream_type(GST_APP_SRC(source), GST_APP_STREAM_TYPE_SEEKABLE);
if (eGST_MEDIATYPE_VIDEO == mediaType )
{
- int MaxGstVideoBufBytes = isFogEnabled ? m_gstConfigParam->videoBufBytesForFog : m_gstConfigParam->videoBufBytes;
- MW_LOG_INFO("Setting gst Video buffer max bytes to %d FogLive :%d ", MaxGstVideoBufBytes,isFogEnabled);
+ int MaxGstVideoBufBytes = m_gstConfigParam->videoBufBytes;
+ MW_LOG_INFO("Setting gst Video buffer max bytes to %d", MaxGstVideoBufBytes);
g_object_set(source, "max-bytes", (guint64)MaxGstVideoBufBytes, NULL); /* Sets the maximum video buffer bytes as per configuration*/
}
else if (eGST_MEDIATYPE_AUDIO == mediaType || eGST_MEDIATYPE_AUX_AUDIO == mediaType)
{
- int MaxGstAudioBufBytes = isFogEnabled ? m_gstConfigParam->audioBufBytesForFog : m_gstConfigParam->audioBufBytes;
- MW_LOG_INFO("Setting gst Audio buffer max bytes to %d FogLive :%d ", MaxGstAudioBufBytes,isFogEnabled);
+ int MaxGstAudioBufBytes = m_gstConfigParam->audioBufBytes;
+ MW_LOG_INFO("Setting gst Audio buffer max bytes to %d", MaxGstAudioBufBytes);
g_object_set(source, "max-bytes", (guint64)MaxGstAudioBufBytes, NULL); /* Sets the maximum audio buffer bytes as per configuration*/
}
g_object_set(source, "min-percent", 50, NULL); /* Trigger the need data event when the queued bytes fall below 50% */
@@ -1891,10 +1903,9 @@ static void gstInitializeSource(void *_this, GObject *source, int iMediaType = e
InterfacePlayerRDK* pInterfacePlayerRDK = (InterfacePlayerRDK*)_this;
GstMediaType mediaType = (GstMediaType)iMediaType;
- bool isFogEnabled = pInterfacePlayerRDK->m_gstConfigParam->tsbEnabled;
gst_media_stream *stream = &pInterfacePlayerRDK->gstPrivateContext->stream[mediaType];
- pInterfacePlayerRDK->InitializeSourceForPlayer(pInterfacePlayerRDK,source, mediaType, isFogEnabled);
+ pInterfacePlayerRDK->InitializeSourceForPlayer(pInterfacePlayerRDK,source, mediaType);
stream->sourceConfigured = true;
}
/**
@@ -2087,6 +2098,7 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st
pInterfacePlayerRDK->gstPrivateContext->subtitle_sink = textsink;
MW_LOG_MIL("using rialtomsesubtitlesink muted=%d sink=%p", pInterfacePlayerRDK->gstPrivateContext->subtitleMuted, pInterfacePlayerRDK->gstPrivateContext->subtitle_sink);
g_object_set(textsink, "mute", pInterfacePlayerRDK->gstPrivateContext->subtitleMuted ? TRUE : FALSE, NULL);
+ g_object_set(textsink, "pts-offset", static_cast(0), NULL);
}
else
{
@@ -2114,7 +2126,7 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st
gst_element_sync_state_with_parent(stream->sinkbin);
pInterfacePlayerRDK->gstPrivateContext->subtitle_sink = GST_ELEMENT(gst_object_ref(stream->sinkbin));
g_object_set(stream->sinkbin, "mute", pInterfacePlayerRDK->gstPrivateContext->subtitleMuted ? TRUE : FALSE, NULL);
-
+ g_object_set(pInterfacePlayerRDK->gstPrivateContext->subtitle_sink, "pts-offset", static_cast(0), NULL);
return 0;
#else
MW_LOG_INFO("subs using playbin");
@@ -2159,6 +2171,7 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st
GstElement* vidsink = gst_element_factory_make("rialtomsevideosink", NULL);
if (vidsink)
{
+ MW_LOG_INFO("Created rialtomsevideosink: %s", GST_ELEMENT_NAME(vidsink));
g_object_set(stream->sinkbin, "video-sink", vidsink, NULL); /* In the stream->sinkbin, set the video-sink property to vidsink */
GstMediaFormat mediaFormat = (GstMediaFormat)m_gstConfigParam->media;
if(eGST_MEDIAFORMAT_HLS == mediaFormat)
@@ -2166,12 +2179,28 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st
MW_LOG_INFO("setting has-drm=false for clear HLS/TS playback");
g_object_set(vidsink, "has-drm", FALSE, NULL);
}
+ pInterfacePlayerRDK->gstPrivateContext->video_sink = vidsink;
}
else
{
MW_LOG_WARN("Failed to create rialtomsevideosink");
}
}
+ else if (pInterfacePlayerRDK->gstPrivateContext->usingRialtoSink && eGST_MEDIATYPE_AUDIO == streamId)
+ {
+ MW_LOG_INFO("using rialtomseaudiosink");
+ GstElement* audSink = gst_element_factory_make("rialtomseaudiosink",NULL);
+ if(audSink)
+ {
+ MW_LOG_INFO("Created rialtomseaudiosink : %s",GST_ELEMENT_NAME(audSink));
+ g_object_set(stream->sinkbin, "audio-sink", audSink, NULL);
+ pInterfacePlayerRDK->gstPrivateContext->audio_sink = audSink;
+ }
+ else
+ {
+ AAMPLOG_WARN("Failed to create rialtomseaudiosink");
+ }
+ }
else if (pInterfacePlayerRDK->gstPrivateContext->using_westerossink && eGST_MEDIATYPE_VIDEO == streamId)
{
MW_LOG_INFO("using westerossink");
@@ -2285,9 +2314,8 @@ int InterfacePlayerRDK::SetupStream(int streamId, void *playerInstance, std::st
{
if (eGST_MEDIATYPE_VIDEO == streamId && (mediaFormat==eGST_MEDIAFORMAT_DASH || mediaFormat==eGST_MEDIAFORMAT_HLS_MP4) )
{ // enable multiqueue
- bool isFogEnabled = m_gstConfigParam->tsbEnabled;
- int MaxGstVideoBufBytes = isFogEnabled ? m_gstConfigParam->videoBufBytesForFog : m_gstConfigParam->videoBufBytes;
- MW_LOG_INFO("Setting gst Video buffer size bytes to %d FogLive : %d", MaxGstVideoBufBytes,isFogEnabled);
+ int MaxGstVideoBufBytes = m_gstConfigParam->videoBufBytes;
+ MW_LOG_INFO("Setting gst Video buffer size bytes to %d", MaxGstVideoBufBytes);
g_object_set(stream->sinkbin, "buffer-size", (guint64)MaxGstVideoBufBytes, NULL);
g_object_set(stream->sinkbin, "buffer-duration", 3000000000, NULL); //3000000000(ns), 3s
}
@@ -3655,7 +3683,7 @@ bool GstPlayer_isVideoOrAudioDecoder(const char* name, InterfacePlayerRDK * pInt
{
// The idea is to identify video or audio decoder plugin created at runtime by playbin and register to its first-frame/pts-error callbacks
// This support is available in specific platform plugins in RDK builds and hence checking only for such plugin instances here
- // For platforms that doesnt support callback, we use GST_STATE_PLAYING state change of playbin to notify first frame to app
+ // For platforms that don't support callback, we use GST_STATE_PLAYING state change of playbin to notify first frame to app
bool isAudioOrVideoDecoder = false;
const auto platformType = pInterfacePlayerRDK->m_gstConfigParam->platformType;
if (!pInterfacePlayerRDK->gstPrivateContext->using_westerossink && gst_StartsWith(name, "brcmvideodecoder"))
diff --git a/middleware/InterfacePlayerRDK.h b/middleware/InterfacePlayerRDK.h
index 773d809..82716ed 100644
--- a/middleware/InterfacePlayerRDK.h
+++ b/middleware/InterfacePlayerRDK.h
@@ -95,9 +95,7 @@ struct Configs
bool enablePTSReStamp;
std::string manifestUrl;
int media;
- bool tsbEnabled;
int videoBufBytes;
- int videoBufBytesForFog;
int platformType;
bool noNativeAV;
bool enableDisconnectSignals;
@@ -107,7 +105,6 @@ struct Configs
int vodTrickModeFPS;
int enableGstPosQuery;
int audioBufBytes;
- int audioBufBytesForFog;
std::string networkProxy;
float progressTimer;
bool audioOnlyMode;
@@ -792,9 +789,8 @@ class InterfacePlayerRDK
* @param[in] PlayerInstance The player instance.
* @param[in] source The source to initialize.
* @param[in] eMEDIATYPE_VIDEO The media type for video.
- * @param[in] isFogEnabled Indicates whether Fog is enabled.
*/
- void InitializeSourceForPlayer(void *PlayerInstance, void *source, GstMediaType eMEDIATYPE_VIDEO, bool isFogEnabled);
+ void InitializeSourceForPlayer(void *PlayerInstance, void *source, GstMediaType eMEDIATYPE_VIDEO);
/**
* @brief Gets the app source element for a given media type.
@@ -867,7 +863,7 @@ class InterfacePlayerRDK
/**
* @brief Pauses GStreamer.
* @param[in] pause Indicates whether to pause or resume.
- * @param[in] forceStopGstreamerPreBuffering Indicates whether to force stop GStreamer pre-buffering.
+ * @param[in] forceStopGstreamerPreBuffering Indicates whether to force stop GStreamer prebuffering.
* @return True if the operation was successful, false otherwise.
*/
bool Pause(bool pause, bool forceStopGstreamerPreBuffering);
@@ -1009,6 +1005,13 @@ class InterfacePlayerRDK
*/
void RemoveProbes();
+ /**
+ * @fn RemoveProbe
+ * @brief Remove probe for a particular media type
+ * @param[in] mediaType The media type for which the probe should be removed
+ */
+ void RemoveProbe(GstMediaType mediaType);
+
/**
* @brief Destroys the GStreamer pipeline.
*/
diff --git a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampcdmidecryptor.cpp b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampcdmidecryptor.cpp
index e65250a..a50cad9 100755
--- a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampcdmidecryptor.cpp
+++ b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampcdmidecryptor.cpp
@@ -137,7 +137,7 @@ static void gst_aampcdmidecryptor_class_init(
"Decrypt encrypted content with CDMi",
GST_ELEMENT_FACTORY_KLASS_DECRYPTOR,
"Decrypts streams encrypted using Encryption.",
- "comcast");
+ "Comcast");
//GST_DEBUG_OBJECT(aampcdmidecryptor, "Inside custom plugin init\n");
}
diff --git a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampclearkeydecryptor.cpp b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampclearkeydecryptor.cpp
index f75d1f6..12a51c7 100644
--- a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampclearkeydecryptor.cpp
+++ b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampclearkeydecryptor.cpp
@@ -91,7 +91,7 @@ static void gst_aampclearkeydecryptor_class_init(
"Decrypt ClearKey encrypted contents",
GST_ELEMENT_FACTORY_KLASS_DECRYPTOR,
"Decrypts streams encrypted using ClearKey Encryption.",
- "comcast");
+ "Comcast");
}
/**
diff --git a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampplayreadydecryptor.cpp b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampplayreadydecryptor.cpp
index fcb9101..7eafdbe 100644
--- a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampplayreadydecryptor.cpp
+++ b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampplayreadydecryptor.cpp
@@ -91,7 +91,7 @@ static void gst_aampplayreadydecryptor_class_init(
"Decrypt PlayReady encrypted contents",
GST_ELEMENT_FACTORY_KLASS_DECRYPTOR,
"Decrypts streams encrypted using PlayReady Encryption.",
- "comcast");
+ "Comcast");
}
/**
diff --git a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampverimatrixdecryptor.cpp b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampverimatrixdecryptor.cpp
index 3fb2745..eef78b5 100755
--- a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampverimatrixdecryptor.cpp
+++ b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampverimatrixdecryptor.cpp
@@ -81,7 +81,7 @@ static void gst_aampverimatrixdecryptor_class_init(GstAampverimatrixdecryptorCla
"Decrypt Verimatrix encrypted contents",
GST_ELEMENT_FACTORY_KLASS_DECRYPTOR,
"Decrypts streams encrypted using Verimatrix Encryption.",
- "comcast");
+ "Comcast");
}
static void gst_aampverimatrixdecryptor_init(GstAampverimatrixdecryptor *aampverimatrixdecryptor)
diff --git a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampwidevinedecryptor.cpp b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampwidevinedecryptor.cpp
index e6300f3..72fecd9 100644
--- a/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampwidevinedecryptor.cpp
+++ b/plugins/gst-plugins-rdk-aamp/drm/gst/gstaampwidevinedecryptor.cpp
@@ -84,7 +84,7 @@ static void gst_aampwidevinedecryptor_class_init(GstAampwidevinedecryptorClass *
"Decrypt Widevine encrypted contents",
GST_ELEMENT_FACTORY_KLASS_DECRYPTOR,
"Decrypts streams encrypted using Widevine Encryption.",
- "comcast");
+ "Comcast");
}
static void gst_aampwidevinedecryptor_init(GstAampwidevinedecryptor *aampwidevinedecryptor)
diff --git a/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecbin.cpp b/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecbin.cpp
index a070cf7..67958d6 100644
--- a/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecbin.cpp
+++ b/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecbin.cpp
@@ -78,8 +78,7 @@ gst_subtecbin_class_init (GstSubtecBinClass * klass)
&gst_subtecbin_sink_template);
gst_element_class_set_static_metadata (GST_ELEMENT_CLASS(klass),
- "OOB Subtec data sink", "Sink/Parser/Subtitle", "Packs TTML or WebVTT data into SubTtxRend APP suitable packets",
- "Stephen Waddell ");
+ "OOB Subtec data sink", "Sink/Parser/Subtitle", "Packs TTML or WebVTT data into SubTtxRend APP suitable packets", "Comcast");
gobject_class->set_property = gst_subtecbin_set_property;
gobject_class->get_property = gst_subtecbin_get_property;
diff --git a/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecmp4transform.cpp b/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecmp4transform.cpp
index 9fe1257..2e6c32e 100644
--- a/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecmp4transform.cpp
+++ b/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecmp4transform.cpp
@@ -120,8 +120,7 @@ gst_subtecmp4transform_class_init (GstSubtecMp4TransformClass * klass)
&gst_subtecmp4transform_sink_template);
gst_element_class_set_static_metadata (GST_ELEMENT_CLASS(klass),
- "Subtec ISO MP4 demuxer", "Demuxer/Subtitle", "Pulls subtitle data from stpp box",
- "Stephen Waddell ");
+ "Subtec ISO MP4 demuxer", "Demuxer/Subtitle", "Pulls subtitle data from stpp box", "Comcast");
base_transform_class->transform_caps = GST_DEBUG_FUNCPTR (gst_subtecmp4transform_transform_caps);
base_transform_class->transform_ip = GST_DEBUG_FUNCPTR (gst_subtecmp4transform_transform_ip);
diff --git a/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecsink.cpp b/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecsink.cpp
index 1f85fec..1ac59e6 100644
--- a/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecsink.cpp
+++ b/plugins/gst-plugins-rdk-aamp/gst_subtec/gstsubtecsink.cpp
@@ -111,8 +111,7 @@ gst_subtecsink_class_init (GstSubtecSinkClass * klass)
&gst_subtecsink_sink_template);
gst_element_class_set_static_metadata (GST_ELEMENT_CLASS(klass),
- "OOB Subtec data sink", "Sink/Parser/Subtitle", "Packs TTML or WebVTT data into SubTtxRend APP suitable packets",
- "Stephen Waddell ");
+ "OOB Subtec data sink", "Sink/Parser/Subtitle", "Packs TTML or WebVTT data into SubTtxRend APP suitable packets", "Comcast");
gobject_class->set_property = gst_subtecsink_set_property;
diff --git a/plugins/gst-plugins-rdk-aamp/gst_subtec/gstvipertransform.cpp b/plugins/gst-plugins-rdk-aamp/gst_subtec/gstvipertransform.cpp
index a0fe49d..7b355f7 100644
--- a/plugins/gst-plugins-rdk-aamp/gst_subtec/gstvipertransform.cpp
+++ b/plugins/gst-plugins-rdk-aamp/gst_subtec/gstvipertransform.cpp
@@ -19,7 +19,7 @@
/**
* SECTION:element-gstvipertransform
*
- * The vipertransform element performs the necessary transforms for Comcast Viper linear content.
+ * The vipertransform element performs the necessary transforms for legacy linear content.
* These are needed to overcome limitations in the TTML delivery
*
*/
@@ -91,8 +91,7 @@ gst_vipertransform_class_init (GstViperTransformClass * klass)
&gst_vipertransform_sink_template);
gst_element_class_set_static_metadata (GST_ELEMENT_CLASS(klass),
- "vipertransform", "Formatter/Subtitle", "Transforms TTML buffers for Viper broadcast",
- "Stephen Waddell ");
+ "vipertransform", "Formatter/Subtitle", "Transforms TTML buffers for broadcast", "Comcast");
gobject_class->dispose = gst_vipertransform_dispose;
gobject_class->finalize = gst_vipertransform_finalize;
@@ -573,6 +572,6 @@ plugin_init (GstPlugin * plugin)
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
vipertransform,
- "Applies any necessary transforms for Viper TTML content",
+ "Applies any necessary transforms for TTML content",
plugin_init, VERSION, "LGPL", PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/priv_aamp.cpp b/priv_aamp.cpp
index faa0602..a9202bb 100644
--- a/priv_aamp.cpp
+++ b/priv_aamp.cpp
@@ -144,7 +144,6 @@ struct gActivePrivAAMP_t
};
static std::list gActivePrivAAMPs = std::list();
-
static std::mutex gMutex;
static std::condition_variable gCond;
@@ -567,6 +566,8 @@ static bool IsActiveStreamingInterfaceWifi (void)
{
bool wifiStatus = false;
#ifdef IARM_MGR
+if(!IsContainerEnvironment()) // IARM doesn't work in container
+{
IARM_Result_t ret = IARM_RESULT_SUCCESS;
IARM_BUS_NetSrvMgr_Iface_EventData_t param;
@@ -582,6 +583,7 @@ static bool IsActiveStreamingInterfaceWifi (void)
}
}
IARM_Bus_RegisterEventHandler("NET_SRV_MGR", IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_IPADDRESS, getActiveInterfaceEventHandler);
+}
#endif
return wifiStatus;
}
@@ -1095,7 +1097,7 @@ int PrivateInstanceAAMP::HandleSSLProgressCallback ( void *clientp, double dltot
PrivateInstanceAAMP::PrivateInstanceAAMP(AampConfig *config) : mReportProgressPosn(0.0), mLastTelemetryTimeMS(0), mDiscontinuityFound(false), mTelemetryInterval(0), mAbrBitrateData(), mLock(),
mpStreamAbstractionAAMP(NULL), mInitSuccess(false), mVideoFormat(FORMAT_INVALID), mAudioFormat(FORMAT_INVALID), mDownloadsDisabled(),
mDownloadsEnabled(true), profiler(), licenceFromManifest(false), previousAudioType(eAUDIO_UNKNOWN),isPreferredDRMConfigured(false),
- mbDownloadsBlocked(false), streamerIsActive(false), mTSBEnabled(false), mIscDVR(false), mLiveOffset(AAMP_LIVE_OFFSET),
+ mbDownloadsBlocked(false), streamerIsActive(false), mFogTSBEnabled(false), mIscDVR(false), mLiveOffset(AAMP_LIVE_OFFSET),
seek_pos_seconds(-1), rate(0), pipeline_paused(false), mMaxLanguageCount(0), zoom_mode(VIDEO_ZOOM_NONE),
video_muted(false), subtitles_muted(true), audio_volume(100), subscribedTags(), manifestHeadersNeeded(), httpHeaderResponses(), timedMetadata(), timedMetadataNew(), IsTuneTypeNew(false), trickStartUTCMS(-1), durationSeconds(0.0), culledSeconds(0.0), culledOffset(0.0), maxRefreshPlaylistIntervalSecs(DEFAULT_INTERVAL_BETWEEN_PLAYLIST_UPDATES_MS/1000),
mEventListener(NULL), mNewSeekInfo(), discardEnteringLiveEvt(false),
@@ -1337,7 +1339,6 @@ PrivateInstanceAAMP::PrivateInstanceAAMP(AampConfig *config) : mReportProgressPo
mProcessingDiscontinuity[i] = false;
mIsDiscontinuityIgnored[i] = false;
}
-
{
std::lock_guard guard(gMutex);
gActivePrivAAMP_t gAAMPInstance = { this, false, 0 };
@@ -1391,14 +1392,11 @@ PrivateInstanceAAMP::~PrivateInstanceAAMP()
gActivePrivAAMPs.erase(iter);
}
}
-
mMediaDownloadsEnabled.clear();
-
{
std::lock_guard guard(mLock);
SAFE_DELETE(mVideoEnd);
}
-
#ifdef AAMP_HLS_DRM
aesCtrAttrDataList.clear();
#endif
@@ -1407,7 +1405,6 @@ PrivateInstanceAAMP::~PrivateInstanceAAMP()
#if defined(AAMP_MPD_DRM) || defined(AAMP_HLS_DRM)
SAFE_DELETE(mDRMSessionManager);
#endif
-
if( ISCONFIGSET_PRIV(eAAMPConfig_EnableCurlStore) )
{
for (int i = 0; i < eCURLINSTANCE_MAX; i++)
@@ -1425,7 +1422,10 @@ PrivateInstanceAAMP::~PrivateInstanceAAMP()
}
}
#ifdef IARM_MGR
+if(!IsContainerEnvironment())
+{
IARM_Bus_RemoveEventHandler("NET_SRV_MGR", IARM_BUS_NETWORK_MANAGER_EVENT_INTERFACE_IPADDRESS, getActiveInterfaceEventHandler);
+}
#endif //IARM_MGR
SAFE_DELETE(mEventManager);
SAFE_DELETE(mCMCDCollector);
@@ -2137,7 +2137,6 @@ void PrivateInstanceAAMP::ReportProgress(bool sync, bool beginningOfStream)
videoPTS = sink->GetVideoPTS() + mVideoBasePTS;
}
}
-
{
std::lock_guard guard(mStreamLock);
if (mpStreamAbstractionAAMP)
@@ -2145,7 +2144,6 @@ void PrivateInstanceAAMP::ReportProgress(bool sync, bool beginningOfStream)
bufferedDuration = mpStreamAbstractionAAMP->GetBufferedVideoDurationSec() * 1000.0;
}
}
-
if ((mReportProgressPosn == position) && !pipeline_paused && beginningOfStream != true)
{
// Avoid sending the progress event, if the previous position and the current position is same when pipeline is in playing state.
@@ -2180,7 +2178,7 @@ void PrivateInstanceAAMP::ReportProgress(bool sync, bool beginningOfStream)
// If tsb is not available for linear send -1 for start and end
// so that xre detect this as tsbless playback
// Override above logic if mEnableSeekableRange is set, used by third-party apps
- if (!ISCONFIGSET_PRIV(eAAMPConfig_EnableSeekRange) && (mContentType == ContentType_LINEAR && !mTSBEnabled && !IsLocalAAMPTsb()))
+ if (!ISCONFIGSET_PRIV(eAAMPConfig_EnableSeekRange) && (mContentType == ContentType_LINEAR && !mFogTSBEnabled && !IsLocalAAMPTsb()))
{
start = -1;
end = -1;
@@ -2651,7 +2649,7 @@ void PrivateInstanceAAMP::SendDownloadErrorEvent(AAMPTuneFailure tuneFailure, in
retryStatus = false;
}
}
- if( IsTSBSupported() )
+ if( IsFogTSBSupported() )
{
strcat(description, "(FOG)");
}
@@ -2763,7 +2761,7 @@ void PrivateInstanceAAMP::SendErrorEvent(AAMPTuneFailure tuneFailure, const char
std::unique_lock lock(mLock);
if(mState != eSTATE_ERROR)
{
- if(IsTSBSupported() && mState <= eSTATE_PREPARED)
+ if(IsFogTSBSupported() && mState <= eSTATE_PREPARED)
{
// Send a TSB delete request when player is not tuned successfully.
// If player is once tuned, retune happens with same content and player can reuse same TSB.
@@ -2926,12 +2924,12 @@ void PrivateInstanceAAMP::NotifyBitRateChangeEvent(BitsPerSecond bitrate, Bitrat
if(GetBWIndex)
{
AAMPLOG_WARN("NotifyBitRateChangeEvent :: bitrate:%" BITSPERSECOND_FORMAT " desc:%s width:%d height:%d fps:%f position:%f IndexFromTopProfile: %d%s profileCap:%d tvWidth:%d tvHeight:%d, scantype:%d, aspectRatioW:%d, aspectRatioH:%d",
- bitrate, BITRATEREASON2STRING(reason), width, height, frameRate, position, mpStreamAbstractionAAMP->GetBWIndex(bitrate), (IsTSBSupported()? ", fog": " "), mProfileCappedStatus, mDisplayWidth, mDisplayHeight, scantype, aspectRatioWidth, aspectRatioHeight);
+ bitrate, BITRATEREASON2STRING(reason), width, height, frameRate, position, mpStreamAbstractionAAMP->GetBWIndex(bitrate), (IsFogTSBSupported()? ", fog": " "), mProfileCappedStatus, mDisplayWidth, mDisplayHeight, scantype, aspectRatioWidth, aspectRatioHeight);
}
else
{
AAMPLOG_WARN("NotifyBitRateChangeEvent :: bitrate:%" BITSPERSECOND_FORMAT " desc:%s width:%d height:%d fps:%f position:%f %s profileCap:%d tvWidth:%d tvHeight:%d, scantype:%d, aspectRatioW:%d, aspectRatioH:%d",
- bitrate, BITRATEREASON2STRING(reason), width, height, frameRate, position, (IsTSBSupported()? ", fog": " "), mProfileCappedStatus, mDisplayWidth, mDisplayHeight, scantype, aspectRatioWidth, aspectRatioHeight);
+ bitrate, BITRATEREASON2STRING(reason), width, height, frameRate, position, (IsFogTSBSupported()? ", fog": " "), mProfileCappedStatus, mDisplayWidth, mDisplayHeight, scantype, aspectRatioWidth, aspectRatioHeight);
}
SendEvent(event,AAMP_EVENT_ASYNC_MODE);
@@ -2941,12 +2939,12 @@ void PrivateInstanceAAMP::NotifyBitRateChangeEvent(BitsPerSecond bitrate, Bitrat
if(GetBWIndex)
{
AAMPLOG_WARN("NotifyBitRateChangeEvent ::NO LISTENERS bitrate:%" BITSPERSECOND_FORMAT " desc:%s width:%d height:%d, fps:%f position:%f IndexFromTopProfile: %d%s profileCap:%d tvWidth:%d tvHeight:%d, scantype:%d, aspectRatioW:%d, aspectRatioH:%d",
- bitrate, BITRATEREASON2STRING(reason), width, height, frameRate, position, mpStreamAbstractionAAMP->GetBWIndex(bitrate), (IsTSBSupported()? ", fog": " "), mProfileCappedStatus, mDisplayWidth, mDisplayHeight, scantype, aspectRatioWidth, aspectRatioHeight);
+ bitrate, BITRATEREASON2STRING(reason), width, height, frameRate, position, mpStreamAbstractionAAMP->GetBWIndex(bitrate), (IsFogTSBSupported()? ", fog": " "), mProfileCappedStatus, mDisplayWidth, mDisplayHeight, scantype, aspectRatioWidth, aspectRatioHeight);
}
else
{
AAMPLOG_WARN("NotifyBitRateChangeEvent ::NO LISTENERS bitrate:%" BITSPERSECOND_FORMAT " desc:%s width:%d height:%d fps:%f position:%f %s profileCap:%d tvWidth:%d tvHeight:%d, scantype:%d, aspectRatioW:%d, aspectRatioH:%d",
- bitrate, BITRATEREASON2STRING(reason), width, height, frameRate, position, (IsTSBSupported()? ", fog": " "), mProfileCappedStatus, mDisplayWidth, mDisplayHeight, scantype, aspectRatioWidth, aspectRatioHeight);
+ bitrate, BITRATEREASON2STRING(reason), width, height, frameRate, position, (IsFogTSBSupported()? ", fog": " "), mProfileCappedStatus, mDisplayWidth, mDisplayHeight, scantype, aspectRatioWidth, aspectRatioHeight);
}
}
@@ -3328,9 +3326,9 @@ void PrivateInstanceAAMP::NotifyEOSReached()
{
rate = AAMP_NORMAL_PLAY_RATE;
AcquireStreamLock();
- if (IsLocalAAMPTsb() && !GetLLDashChunkMode())
+ if (IsLocalAAMPTsb() && !GetLLDashChunkMode())
{
- seek_pos_seconds = (aamp_GetCurrentTimeMS()/1000) - mLiveOffset;
+ seek_pos_seconds = (aamp_GetCurrentTimeMS()/1000) - mLiveOffset;
AAMPLOG_INFO("Reached EOS during FF (aamp_GetCurrentTimeMS: %lld), so seeking to %fs",aamp_GetCurrentTimeMS(), seek_pos_seconds );
TuneHelper(eTUNETYPE_SEEK);
}
@@ -3465,10 +3463,10 @@ void PrivateInstanceAAMP::TuneFail(bool fail)
mTuneMetrics.mTuneAttempts = mTuneAttempts;
mTuneMetrics.contentType = mContentType;
mTuneMetrics.streamType = streamType;
- mTuneMetrics.mTSBEnabled = mTSBEnabled;
+ mTuneMetrics.mFogTSBEnabled = mFogTSBEnabled;
if(mTuneMetrics.success == -1 && mPlayerPreBuffered)
{
- LogPlayerPreBuffered(); //Need to calculate prebufferedtime when tune interruption happens with playerprebuffer
+ LogPlayerPreBuffered(); //Need to calculate prebuffered time when tune interruption happens with player prebuffer
}
bool eventAvailStatus = IsEventListenerAvailable(AAMP_EVENT_TUNE_TIME_METRICS);
std::string tuneData("");
@@ -3495,7 +3493,7 @@ void PrivateInstanceAAMP::LogTuneComplete(void)
mTuneMetrics.mTimedMetadataDuration = (int)mTimedMetadataDuration;
mTuneMetrics.mTuneAttempts = mTuneAttempts;
mTuneMetrics.streamType = streamType;
- mTuneMetrics.mTSBEnabled = mTSBEnabled;
+ mTuneMetrics.mFogTSBEnabled = mFogTSBEnabled;
bool eventAvailStatus = IsEventListenerAvailable(AAMP_EVENT_TUNE_TIME_METRICS);
std::string tuneData("");
profiler.TuneEnd(mTuneMetrics,mAppName,(mbPlayEnabled?STRFGPLAYER:STRBGPLAYER), mPlayerId, mPlayerPreBuffered, durationSeconds, activeInterfaceWifi, mFailureReason, eventAvailStatus ? &tuneData : NULL);
@@ -3504,7 +3502,7 @@ void PrivateInstanceAAMP::LogTuneComplete(void)
SendTuneMetricsEvent(tuneData);
}
//update tunedManifestUrl if FOG was NOT used as manifestUrl might be updated with redirected url.
- if(!IsTSBSupported())
+ if(!IsFogTSBSupported())
{
SetTunedManifestUrl(); /* Redirect URL in case on VOD */
}
@@ -3530,7 +3528,7 @@ void PrivateInstanceAAMP::LogTuneComplete(void)
if(mContentType == ContentType_LINEAR)
{
- if(mTSBEnabled)
+ if(mFogTSBEnabled)
{
playbackType.append(":TSB=true");
}
@@ -3554,7 +3552,7 @@ void PrivateInstanceAAMP::LogFirstFrame(void)
}
/**
- * @brief Profile Player changed from background to foreground i.e prebuffred
+ * @brief Profile Player changed from background to foreground i.e prebuffered
*/
void PrivateInstanceAAMP::ResetProfileCache(void)
{
@@ -3572,7 +3570,7 @@ void PrivateInstanceAAMP::ActivatePlayer(void)
AampStreamSinkManager::GetInstance().ActivatePlayer(this);
}
/**
- * @brief Profile Player changed from background to foreground i.e prebuffred
+ * @brief Profile Player changed from background to foreground i.e prebuffered
*/
void PrivateInstanceAAMP::LogPlayerPreBuffered(void)
{
@@ -3866,7 +3864,6 @@ BitsPerSecond PrivateInstanceAAMP::GetCurrentlyAvailableBandwidth(void)
std::lock_guard guard(mLock);
mhAbrManager.UpdateABRBitrateDataBasedOnCacheLife(mAbrBitrateData,tmpData);
}
-
if (tmpData.size())
{
//AAMPLOG_WARN("NwBW with newlogic size[%d] avg[%ld] ",tmpData.size(), avg/tmpData.size());
@@ -3888,7 +3885,6 @@ BitsPerSecond PrivateInstanceAAMP::GetCurrentlyAvailableBandwidth(void)
//AAMPLOG_WARN("No prior data available for abr , return -1 ");
ret = -1;
}
-
return ret;
}
@@ -3903,7 +3899,7 @@ bool PrivateInstanceAAMP::GetFile( std::string remoteUrl, AampMediaType mediaTyp
}
MediaTypeTelemetry mediaTypeTelemetry = aamp_GetMediaTypeForTelemetry(mediaType);
replace( remoteUrl, " ", "%20" ); // CURL gives error if passed URL containing whitespace
-
+
int http_code = -1;
double total = 0;
bool ret = false;
@@ -3924,7 +3920,7 @@ bool PrivateInstanceAAMP::GetFile( std::string remoteUrl, AampMediaType mediaTyp
maxDownloadAttempt += DEFAULT_DOWNLOAD_RETRY_COUNT;
break;
}
-
+
if( mediaType == eMEDIATYPE_MANIFEST && ISCONFIGSET_PRIV(eAAMPConfig_CurlHeader) )
{ // append custom uri parameter with remoteUrl at the end before curl request if curlHeader logging enabled.
std::string uriParameter = GETCONFIGVALUE_PRIV(eAAMPConfig_URIParameter);
@@ -3942,7 +3938,7 @@ bool PrivateInstanceAAMP::GetFile( std::string remoteUrl, AampMediaType mediaTyp
{
buffer->Clear();
}
-
+
if (mDownloadsEnabled)
{
int downloadTimeMS = 0;
@@ -4041,7 +4037,15 @@ bool PrivateInstanceAAMP::GetFile( std::string remoteUrl, AampMediaType mediaTyp
lowBWTimeout = GETCONFIGVALUE_PRIV(eAAMPConfig_NetworkTimeout) * LOW_BW_TIMEOUT_FACTOR;
lowBWTimeout = std::max(DEFAULT_LOW_BW_TIMEOUT, lowBWTimeout);
}
- progressCtx.lowBWTimeout = lowBWTimeout;
+ if (mFogTSBEnabled)
+ {
+ AAMPLOG_DEBUG("Disable low bandwidth timeout in aamp, it will be done in fog");
+ progressCtx.lowBWTimeout = 0;
+ }
+ else
+ {
+ progressCtx.lowBWTimeout = lowBWTimeout;
+ }
}
progressCtx.stallTimeout = GETCONFIGVALUE_PRIV(eAAMPConfig_CurlStallTimeout);
@@ -4145,9 +4149,9 @@ bool PrivateInstanceAAMP::GetFile( std::string remoteUrl, AampMediaType mediaTyp
else
{
//When Fog is having tsb write error , then it will respond back with 302 with direct CDN url,In this case alone TSB should be disabled
- if(mTSBEnabled && http_code == 302)
+ if(mFogTSBEnabled && http_code == 302)
{
- mTSBEnabled = false;
+ mFogTSBEnabled = false;
}
effectiveUrlPtr = aamp_CurlEasyGetinfoString(curl, CURLINFO_EFFECTIVE_URL);
if((mediaType == eMEDIATYPE_INIT_VIDEO || mediaType == eMEDIATYPE_INIT_AUDIO))
@@ -4218,7 +4222,7 @@ bool PrivateInstanceAAMP::GetFile( std::string remoteUrl, AampMediaType mediaTyp
{
AAMPLOG_INFO("TSB not available from fog, playing from:%s ", effectiveUrl.c_str());
}
- this->UpdateVideoEndTsbStatus(mTSBEnabled);
+ this->UpdateVideoEndTsbStatus(mFogTSBEnabled);
}
/*
@@ -4434,7 +4438,6 @@ bool PrivateInstanceAAMP::GetFile( std::string remoteUrl, AampMediaType mediaTyp
std::lock_guard guard(mLock);
mhAbrManager.UpdateABRBitrateDataBasedOnCacheLength(mAbrBitrateData,downloadbps,false);
}
-
}
}
}
@@ -4512,14 +4515,14 @@ bool PrivateInstanceAAMP::GetFile( std::string remoteUrl, AampMediaType mediaTyp
// these are generated after trick play options,
if( !(http_code == CURLE_ABORTED_BY_CALLBACK || http_code == CURLE_WRITE_ERROR || http_code == 204))
{
- SendAnomalyEvent(ANOMALY_WARNING, "%s:%s,%s-%d url:%s", (mTSBEnabled ? "FOG" : "CDN"),
+ SendAnomalyEvent(ANOMALY_WARNING, "%s:%s,%s-%d url:%s", (mFogTSBEnabled ? "FOG" : "CDN"),
GetMediaTypeName(mediaType), (http_code < 100) ? "Curl" : "HTTP", http_code, remoteUrl.c_str());
}
if ( (httpRespHeaders[curlInstance].type == eHTTPHEADERTYPE_XREASON) && (httpRespHeaders[curlInstance].data.length() > 0) )
{
- AAMPLOG_WARN("Received X-Reason header from %s: '%s'", mTSBEnabled?"Fog":"CDN Server", httpRespHeaders[curlInstance].data.c_str());
- SendAnomalyEvent(ANOMALY_WARNING, "%s X-Reason:%s", mTSBEnabled ? "Fog" : "CDN", httpRespHeaders[curlInstance].data.c_str());
+ AAMPLOG_WARN("Received X-Reason header from %s: '%s'", mFogTSBEnabled?"Fog":"CDN Server", httpRespHeaders[curlInstance].data.c_str());
+ SendAnomalyEvent(ANOMALY_WARNING, "%s X-Reason:%s", mFogTSBEnabled ? "Fog" : "CDN", httpRespHeaders[curlInstance].data.c_str());
}
else if ( (httpRespHeaders[curlInstance].type == eHTTPHEADERTYPE_FOG_REASON) && (httpRespHeaders[curlInstance].data.length() > 0) )
{
@@ -5081,7 +5084,6 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused)
mFirstVideoFrameDisplayedEnabled = false;
prevFirstPeriodStartTime = 0;
}
-
if( seekWhilePaused )
{ // Player state not updated correctly after seek
// Prevent gstreamer callbacks from placing us back into playing state by setting these gate flags before CBs are triggered
@@ -5242,6 +5244,7 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused)
else
{
mpStreamAbstractionAAMP->SetTrickplayMode(rate);
+ mpStreamAbstractionAAMP->ResetTrickModePtsRestamping();
if (!GetLLDashChunkMode())
{
mpStreamAbstractionAAMP->SetVideoPlaybackRate(rate);
@@ -5318,22 +5321,29 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused)
if(newTune && !IsLocalAAMPTsb() && GetTSBSessionManager())
{
// Set Local TSB flag after starting the streamabstraction
- AAMPLOG_WARN("Enabling local TSB handling for the new tune");
+ AAMPLOG_MIL("Enabling local TSB handling for the new tune");
SetLocalAAMPTsb(true);
}
+ // Local AAMP TSB injection is true if Local AAMP TSB is enabled and TuneHelper() is called for
+ // any reason other than a new tune (set rate, seek...)
+ if (!newTune && IsLocalAAMPTsb())
+ {
+ SetLocalAAMPTsbInjection(true);
+ }
+
if (mpStreamAbstractionAAMP)
{
- if(!IsLocalAAMPTsb() || !IsLocalAAMPTsbInjection())
- {
- mpStreamAbstractionAAMP->SetCDAIObject(mCdaiObject);
- retVal = mpStreamAbstractionAAMP->Init(tuneType);
- }
- else
+ if (IsLocalAAMPTsbInjection())
{
// Update StreamAbstraction object seek position to the absolute position (seconds since 1970)
mpStreamAbstractionAAMP->SeekPosUpdate(seek_pos_seconds);
retVal = mpStreamAbstractionAAMP->InitTsbReader(tuneType);
}
+ else
+ {
+ mpStreamAbstractionAAMP->SetCDAIObject(mCdaiObject);
+ retVal = mpStreamAbstractionAAMP->Init(tuneType);
+ }
}
else
{
@@ -5520,7 +5530,7 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused)
Trick play freeze issues observed for partner cDVR content
@TODO Need to investigate and identify proper way to send Flush and segment
events to avoid the freeze
- if (!(newTune || (eTUNETYPE_RETUNE == tuneType)) && !IsTSBSupported())
+ if (!(newTune || (eTUNETYPE_RETUNE == tuneType)) && !IsFogTSBSupported())
{
StreamSink *sink = AampStreamSinkManager::GetInstance().GetStreamSink(this);
if (sink)
@@ -5633,11 +5643,9 @@ void PrivateInstanceAAMP::TuneHelper(TuneType tuneType, bool seekWhilePaused)
}
}
- // IsLocalAAMPTsb() being true already confirms TSBSessionManager and LLD cases are true.
- if(IsLocalAAMPTsb() && !IsLocalAAMPTsbInjection())
+ if (IsLocalAAMPTsb() && !IsLocalAAMPTsbInjection())
{
- // Update culled seconds and duration based on TSB
- SetLocalAAMPTsbInjection(true);
+ // Update culled seconds and duration based on TSB when watching live with AAMP Local TSB enabled
culledSeconds = seek_pos_seconds;
durationSeconds -= culledSeconds;
}
@@ -5693,7 +5701,7 @@ void PrivateInstanceAAMP::ReloadTSB()
mManifestUrl = mTsbSessionRequestUrl + "&reloadTSB=true";
// To post player configurations to fog on 1st time tune
long configPassCode = -1;
- if(mTSBEnabled && ISCONFIGSET_PRIV(eAAMPConfig_EnableAampConfigToFog))
+ if(mFogTSBEnabled && ISCONFIGSET_PRIV(eAAMPConfig_EnableAampConfigToFog))
{
configPassCode = LoadFogConfig();
}
@@ -5709,7 +5717,7 @@ void PrivateInstanceAAMP::ReloadTSB()
mMediaFormat = GetMediaFormatType(mManifestUrl.c_str());
ResumeDownloads();
- mIsFirstRequestToFOG = (mTSBEnabled == true);
+ mIsFirstRequestToFOG = (mFogTSBEnabled == true);
{
AAMPLOG_WARN("Reloading TSB, URL: %s", mManifestUrl.c_str());
@@ -5838,21 +5846,19 @@ void PrivateInstanceAAMP::Tune(const char *mainManifestUrl,
// store the url 2 from the application for mpd stitching
mMPDStichRefreshUrl = refreshManifestUrl ? refreshManifestUrl : "";
mMPDStichOption = (MPDStichOptions) (mpdStitchingMode % 2);
+ mMediaFormat = GetMediaFormatType(mainManifestUrl);
+ // Calling SetContentType without checking contentType != NULL, so that
+ // mContentType will be reset to ContentType_UNKNOWN at the start of tune by default
+ SetContentType(contentType);
+ AAMPLOG_INFO("Content type (%d): %s", mContentType, contentType == nullptr ? "null" : contentType);
- if( (mManifestUrl.find(AAMP_FOG_TSB_URL_KEYWORD) != std::string::npos) &&
- (mManifestUrl.find(AAMP_LOW_LATENCY_URL_KEYWORD_ENCODED) != std::string::npos))
+ if (ContentType_CDVR == mContentType)
{
-
- DeFog(mManifestUrl);
- mainManifestUrl = mManifestUrl.c_str();
- AAMPLOG_INFO("LLD trials Url Remapping done");
-
+ mIscDVR = true;
}
- mMediaFormat = GetMediaFormatType(mainManifestUrl);
-
- if (eMEDIAFORMAT_DASH == mMediaFormat)
+ if ((ContentType_LINEAR == mContentType) && (eMEDIAFORMAT_DASH == mMediaFormat))
{
if(mTSBSessionManager)
{
@@ -5860,41 +5866,40 @@ void PrivateInstanceAAMP::Tune(const char *mainManifestUrl,
}
if(ISCONFIGSET_PRIV(eAAMPConfig_LocalTSBEnabled))
{
- mTSBSessionManager = new AampTSBSessionManager(this);
- //TODO unique session id for each
- if(mTSBSessionManager)
+ if (ISCONFIGSET_PRIV(eAAMPConfig_EnablePTSReStamp))
{
- LoadLocalTSBConfig();
- if (mTSBSessionManager->IsActive())
+ mTSBSessionManager = new AampTSBSessionManager(this);
+ //TODO unique session id for each
+ if(mTSBSessionManager)
{
- SetIsIframeExtractionEnabled(true);
- AAMPLOG_INFO("TSB Session Manager created and Active!!");
- }
- if(mTSBStore)
- {
- AAMPLOG_INFO("Refreshing the TSB Store session!!");
- mTSBStore->Flush();
+ LoadLocalTSBConfig();
+ if (mTSBSessionManager->IsActive())
+ {
+ SetIsIframeExtractionEnabled(true);
+ AAMPLOG_INFO("TSB Session Manager created and Active!!");
+ }
+ if(mTSBStore)
+ {
+ AAMPLOG_INFO("Refreshing the TSB Store session!!");
+ mTSBStore->Flush();
+ }
}
}
- }
-
- const std::string &lldUrlKeyword = GETCONFIGVALUE_PRIV(eAAMPConfig_LLDUrlKeyword);
- AAMPLOG_INFO("LLD Url Keyword: %s", lldUrlKeyword.c_str());
- // For the LLD case, we need to update the manifest timeout before starting the MPDDownloader. So, we are updating the value here
- if (!lldUrlKeyword.empty() && mManifestUrl.find(lldUrlKeyword) != std::string::npos)
- {
- SETCONFIGVALUE_PRIV(AAMP_TUNE_SETTING,eAAMPConfig_ManifestTimeout,MANIFEST_TIMEOUT_FOR_LLD);
+ else
+ {
+ AAMPLOG_WARN("Local TSB is not enabled due to PTS Restamp is disabled");
+ }
}
}
- mTSBEnabled = strcasestr(mainManifestUrl, AAMP_FOG_TSB_URL_KEYWORD) && ISCONFIGSET_PRIV(eAAMPConfig_Fog);
+ mFogTSBEnabled = strcasestr(mainManifestUrl, AAMP_FOG_TSB_URL_KEYWORD) && ISCONFIGSET_PRIV(eAAMPConfig_Fog);
std::string sTraceId = (pTraceID?pTraceID:"unknown");
//CMCD to be enabled for player direct downloads, not for Fog . All downloads in Fog , CMCD response to be done in Fog.
- mCMCDCollector->Initialize((ISCONFIGSET_PRIV(eAAMPConfig_EnableCMCD) && !mTSBEnabled),sTraceId);
+ mCMCDCollector->Initialize((ISCONFIGSET_PRIV(eAAMPConfig_EnableCMCD) && !mFogTSBEnabled),sTraceId);
// This feature is causing trickplay issues for client dai
// hence removing code which reads this config from tune url , Ideally it should be fixed by app and not to enable this feature
-// SETCONFIGVALUE_PRIV(AAMP_STREAM_SETTING, eAAMPConfig_InterruptHandling, (mTSBEnabled && strcasestr(mainManifestUrl, "networkInterruption=true")));
+// SETCONFIGVALUE_PRIV(AAMP_STREAM_SETTING, eAAMPConfig_InterruptHandling, (mFogTSBEnabled && strcasestr(mainManifestUrl, "networkInterruption=true")));
if(!ISCONFIGSET_PRIV(eAAMPConfig_UseAbsoluteTimeline) && ISCONFIGSET_PRIV(eAAMPConfig_InterruptHandling))
{
AAMPLOG_INFO("Absolute timeline reporting enabled for interrupt enabled TSB stream");
@@ -5903,7 +5908,7 @@ void PrivateInstanceAAMP::Tune(const char *mainManifestUrl,
if (bFirstAttempt)
{
// To post player configurations to fog on 1st time tune
- if(mTSBEnabled && ISCONFIGSET_PRIV(eAAMPConfig_EnableAampConfigToFog))
+ if(mFogTSBEnabled && ISCONFIGSET_PRIV(eAAMPConfig_EnableAampConfigToFog))
{
LoadFogConfig();
}
@@ -5993,6 +5998,7 @@ void PrivateInstanceAAMP::Tune(const char *mainManifestUrl,
mbPlayEnabled = autoPlay;
mPlayerPreBuffered = !autoPlay ;
+ mVideoBasePTS = 0;
ResumeDownloads();
if (!autoPlay)
@@ -6089,14 +6095,6 @@ void PrivateInstanceAAMP::Tune(const char *mainManifestUrl,
mCurrentVideoTrackId = -1;
mCurrentDrm = nullptr;
- // Calling SetContentType without checking contentType != NULL, so that
- // mContentType will be reset to ContentType_UNKNOWN at the start of tune by default
- SetContentType(contentType);
- if (ContentType_CDVR == mContentType)
- {
- mIscDVR = true;
- }
-
#ifdef ENABLE_PTS_RESTAMP
if (ContentType_LINEAR == mContentType)
{
@@ -6150,7 +6148,7 @@ void PrivateInstanceAAMP::Tune(const char *mainManifestUrl,
if(ISCONFIGSET_PRIV(eAAMPConfig_ForceHttp))
{
replace(mManifestUrl, "https://", "http://");
- if(mTSBEnabled)
+ if(mFogTSBEnabled)
{
ForceHttpConversionForFog(mManifestUrl,"https","http");
}
@@ -6162,7 +6160,7 @@ void PrivateInstanceAAMP::Tune(const char *mainManifestUrl,
} // mpd
} // !remap_url
- mIsFirstRequestToFOG = (mTSBEnabled == true);
+ mIsFirstRequestToFOG = (mFogTSBEnabled == true);
{
char tuneStrPrefix[64];
@@ -6181,15 +6179,15 @@ void PrivateInstanceAAMP::Tune(const char *mainManifestUrl,
{
AAMPLOG_WARN("%s aamp_stich: Option[%d] URL: %s", tuneStrPrefix, mMPDStichOption, mMPDStichRefreshUrl.c_str());
}
- if(IsTSBSupported())
+ if(IsFogTSBSupported())
{
mTsbSessionRequestUrl = mManifestUrl;
}
}
- // this function uses mIsVSS and mTSBEnabled, hence it should be called after these variables are updated.
+ // this function uses mIsVSS and mFogTSBEnabled, hence it should be called after these variables are updated.
ExtractServiceZone(mManifestUrl);
- SetTunedManifestUrl(mTSBEnabled);
+ SetTunedManifestUrl(mFogTSBEnabled);
if(bFirstAttempt)
{ // TODO: make mFirstTuneFormat of type MediaFormat
@@ -6434,15 +6432,13 @@ void PrivateInstanceAAMP::CheckForDiscontinuityStall(AampMediaType mediaType)
{
{
std::lock_guard guard(mLock);
-
if (mDiscontinuityTuneOperationId != 0 || mDiscontinuityTuneOperationInProgress)
{
AAMPLOG_WARN("PrivateInstanceAAMP: Ignored retune!! Discontinuity handler already spawned(%d) or in progress(%d)",
- mDiscontinuityTuneOperationId, mDiscontinuityTuneOperationInProgress);
+ mDiscontinuityTuneOperationId, mDiscontinuityTuneOperationInProgress);
return;
}
}
-
AAMPLOG_INFO("No change in PTS for more than %d ms, schedule retune!", discontinuityTimeoutValue);
ResetDiscontinuityInTracks();
@@ -6460,7 +6456,7 @@ void PrivateInstanceAAMP::ExtractServiceZone(std::string url)
{
if(mIsVSS && !url.empty())
{
- if(mTSBEnabled)
+ if(mFogTSBEnabled)
{ // extract original locator from FOG recordedUrl URI parameter
DeFog(url);
}
@@ -7238,7 +7234,6 @@ void PrivateInstanceAAMP::EnableDownloads()
std::lock_guard guard(mLock);
mDownloadsEnabled = true;
}
-
StreamSink *sink = AampStreamSinkManager::GetInstance().GetStreamSink(this);
if (sink)
{
@@ -7561,7 +7556,6 @@ void PrivateInstanceAAMP::Stop()
{
return el.pAAMP == this;
});
-
if(iter != gActivePrivAAMPs.end())
{
if (iter->reTune && mIsRetuneInProgress)
@@ -7581,7 +7575,7 @@ void PrivateInstanceAAMP::Stop()
DisableDownloads();
//Moved the tsb delete request from XRE to AAMP to avoid the HTTP-404 erros
- if(IsTSBSupported())
+ if(IsFogTSBSupported())
{
std::string remoteUrl = "127.0.0.1:9080/tsb";
AampCurlDownloader T1;
@@ -7660,7 +7654,6 @@ void PrivateInstanceAAMP::Stop()
}
mId3MetadataCache.Reset();
-
{
std::lock_guard guard(mEventLock);
if (mPendingAsyncEvents.size() > 0)
@@ -7684,7 +7677,6 @@ void PrivateInstanceAAMP::Stop()
mPendingAsyncEvents.clear();
}
}
-
// Streamer threads are stopped when we reach here, thread synchronization not required
if (timedMetadata.size() > 0)
{
@@ -8066,12 +8058,10 @@ void PrivateInstanceAAMP::NotifyFirstFrameReceived(unsigned long ccDecoderHandle
{
SetState(eSTATE_PLAYING);
}
-
{
std::lock_guard guard(mMutexPlaystart);
waitforplaystart.notify_all();
}
-
if (eTUNED_EVENT_ON_GST_PLAYING == GetTuneEventConfig(IsLive()))
{
// This is an idle callback, so we can sent event synchronously
@@ -8144,7 +8134,7 @@ void PrivateInstanceAAMP::ScheduleRetune(PlaybackErrorType errorType, AampMediaT
gLock.lock();
if (this->mIsRetuneInProgress)
{
- AAMPLOG_WARN("PrivateInstanceAAMP:: Already Retune inprogress");
+ AAMPLOG_WARN("PrivateInstanceAAMP:: Already Retune in progress");
return;
}
gLock.unlock();
@@ -8293,7 +8283,6 @@ void PrivateInstanceAAMP::ScheduleRetune(PlaybackErrorType errorType, AampMediaT
{
AAMPLOG_WARN("Processing retune for GstPipeline Internal Error and rate %f", rate);
SendAnomalyEvent(ANOMALY_WARNING, "%s GstPipeline Internal Error", GetMediaTypeName(trackType));
-
gLock.lock();
for (std::list::iterator iter = gActivePrivAAMPs.begin(); iter != gActivePrivAAMPs.end(); iter++)
{
@@ -8331,9 +8320,7 @@ void PrivateInstanceAAMP::SetState(AAMPPlayerState state)
{
SeekedEventPtr event = std::make_shared(GetPositionMilliseconds(), GetSessionId());
mEventManager->SendEvent(event,AAMP_EVENT_SYNC_MODE);
-
}
-
{
std::lock_guard guard(mLock);
mState = state;
@@ -8433,7 +8420,6 @@ bool PrivateInstanceAAMP::SendTunedEvent(bool isSynchronous)
ret = mTunedEventPending;
mTunedEventPending = false;
}
-
if(ret)
{
AAMPEventPtr ev = std::make_shared(AAMP_EVENT_TUNED, GetSessionId());
@@ -8471,7 +8457,7 @@ bool PrivateInstanceAAMP::SendVideoEndEvent()
//Memory of this string will be deleted after sending event by destructor of AsyncMetricsEventDescriptor
if(ISCONFIGSET_PRIV(eAAMPConfig_EnableVideoEndEvent) && mEventManager->IsEventListenerAvailable(AAMP_EVENT_REPORT_METRICS_DATA))
{
- if(mTSBEnabled)
+ if(mFogTSBEnabled)
{
std::string videoEndData;
GetOnVideoEndSessionStatData(videoEndData);
@@ -8539,7 +8525,6 @@ void PrivateInstanceAAMP::UpdateVideoEndTsbStatus(bool btsbAvailable)
std::lock_guard guard(mLock);
if(mVideoEnd)
{
-
mVideoEnd->SetTsbStatus(btsbAvailable);
}
}
@@ -8780,7 +8765,6 @@ void PrivateInstanceAAMP::UpdateVideoEndMetrics(double adjustedRate)
*/
void PrivateInstanceAAMP::UpdateVideoEndMetrics(AampMediaType mediaType, BitsPerSecond bitrate, int curlOrHTTPCode, std::string& strUrl, double curlDownloadTime, ManifestData * manifestData)
{
-
UpdateVideoEndMetrics(mediaType, bitrate, curlOrHTTPCode, strUrl,0,curlDownloadTime, false, false, manifestData);
}
@@ -9358,9 +9342,9 @@ void PrivateInstanceAAMP::FoundEventBreak(const std::string &adBreakId, uint64_t
mCdaiObject->SetAlternateContents(adBreakId, adId, url, startMS, brInfo.duration); //A placeholder to avoid multiple scte35 event firing for the same adbreak
}
//Ignoring past SCTE events.
- //mTSBEnabled check is added to ensure the change won't effect IPVOD
- AAMPLOG_INFO("[CDAI] mTuneCompleted:%d mTSBEnabled:%d", mTuneCompleted, mTSBEnabled);
- if (mTuneCompleted || !mTSBEnabled)
+ //mFogTSBEnabled check is added to ensure the change won't effect IPVOD
+ AAMPLOG_INFO("[CDAI] mTuneCompleted:%d mFogTSBEnabled:%d", mTuneCompleted, mFogTSBEnabled);
+ if (mTuneCompleted || !mFogTSBEnabled)
{
SaveNewTimedMetadata((long long) startMS, brInfo.name.c_str(), brInfo.payload.c_str(), (int)brInfo.payload.size(), adBreakId.c_str(), brInfo.duration);
}
@@ -9713,7 +9697,7 @@ void PrivateInstanceAAMP::NotifyVideoBasePTS(unsigned long long basepts, unsigne
{
mVideoBasePTS = basepts;
}
- AAMPLOG_INFO("mVideoBasePTS::%llus", mVideoBasePTS);
+ AAMPLOG_INFO("mVideoBasePTS::%llu", mVideoBasePTS);
}
/**
@@ -10100,7 +10084,6 @@ std::string PrivateInstanceAAMP::GetAvailableVideoTracks()
{
std::string tracks;
std::lock_guard guard(mStreamLock);
-
if (mpStreamAbstractionAAMP)
{
std::vector trackInfo = mpStreamAbstractionAAMP->GetAvailableVideoTracks();
@@ -10188,7 +10171,6 @@ std::string PrivateInstanceAAMP::GetAvailableAudioTracks(bool allTrack)
{
std::string tracks;
std::lock_guard guard(mStreamLock);
-
if (mpStreamAbstractionAAMP)
{
std::vector trackInfo = mpStreamAbstractionAAMP->GetAvailableAudioTracks(allTrack);
@@ -10284,8 +10266,8 @@ std::string PrivateInstanceAAMP::GetAvailableAudioTracks(bool allTrack)
std::string PrivateInstanceAAMP::GetAvailableTextTracks(bool allTrack)
{
std::string tracks;
- std::lock_guard guard(mStreamLock);
+ std::lock_guard guard(mStreamLock);
if (mpStreamAbstractionAAMP)
{
std::vector trackInfo = mpStreamAbstractionAAMP->GetAvailableTextTracks(allTrack);
@@ -10489,7 +10471,6 @@ bool PrivateInstanceAAMP::SetStateBufferingIfRequired()
{
bool bufferingSet = false;
std::lock_guard guard(mFragmentCachingLock);
-
if(IsFragmentCachingRequired())
{
bufferingSet = true;
@@ -10591,7 +10572,6 @@ std::string PrivateInstanceAAMP::GetAudioTrackInfo()
{
std::string track;
std::lock_guard guard(mStreamLock);
-
if (mpStreamAbstractionAAMP)
{
AudioTrackInfo trackInfo;
@@ -10686,7 +10666,6 @@ std::string PrivateInstanceAAMP::GetTextTrackInfo()
std::string track;
bool trackInfoAvailable = false;
std::lock_guard guard(mStreamLock);
-
if (mpStreamAbstractionAAMP)
{
TextTrackInfo trackInfo;
@@ -10916,14 +10895,9 @@ void PrivateInstanceAAMP::SetTextTrack(int trackId, char *data)
else
{
SetPreferredTextTrack(track);
- if(ISCONFIGSET_PRIV(eAAMPConfig_useRialtoSink))
+ if((ISCONFIGSET_PRIV(eAAMPConfig_useRialtoSink)) && ((mCurrentTextTrackIndex == -1) || (mCurrentTextTrackIndex == trackId)))
{ // by default text track is enabled and muted for Rialto; notify only if there is change in the subtitles
AAMPLOG_INFO("useRialtoSink mCurrentTextTrackIndex = %d trackId = %d",mCurrentTextTrackIndex,trackId);
- if (-1 != mCurrentTextTrackIndex && mCurrentTextTrackIndex != trackId)
- {
- AAMPLOG_INFO("useRialtoSink TextTrackChanges");
- NotifyTextTracksChanged();
- }
mpStreamAbstractionAAMP->currentTextTrackProfileIndex = mCurrentTextTrackIndex = trackId;
}
else
@@ -11966,7 +11940,7 @@ void PrivateInstanceAAMP::SetPreferredLanguages(const char *languageList, const
{
seek_pos_seconds = GetPositionSeconds();
TeardownStream(false);
- if(IsTSBSupported() &&
+ if(IsFogTSBSupported() &&
((languagePresent && !languageAvailabilityInManifest) ||
(renditionPresent && !renditionAvailabilityInManifest) ||
(accessibilityTypePresent && !accessibilityAvailabilityInManifest) ||
@@ -12343,7 +12317,7 @@ void PrivateInstanceAAMP::SetPreferredTextLanguages(const char *param )
{
seek_pos_seconds = GetPositionSeconds();
TeardownStream(false);
- if(IsTSBSupported() &&
+ if(IsFogTSBSupported() &&
((languagePresent && !languageAvailabilityInManifest) ||
(renditionPresent && !renditionAvailabilityInManifest) ||
(accessibilityTypePresent && !accessibilityAvailabilityInManifest) ||
@@ -12591,7 +12565,7 @@ struct curl_slist* PrivateInstanceAAMP::GetCustomHeaders(AampMediaType mediaType
headerValue = it->second.at(0);
if (it->first.compare("X-MoneyTrace:") == 0)
{
- if (mTSBEnabled && !mIsFirstRequestToFOG)
+ if (mFogTSBEnabled && !mIsFirstRequestToFOG)
{
continue;
}
@@ -12627,7 +12601,7 @@ struct curl_slist* PrivateInstanceAAMP::GetCustomHeaders(AampMediaType mediaType
customHeader.append(headerValue);
httpHeaders = curl_slist_append(httpHeaders, customHeader.c_str());
}
- if (ISCONFIGSET_PRIV(eAAMPConfig_LimitResolution) && mIsFirstRequestToFOG && mTSBEnabled && eMEDIATYPE_MANIFEST == mediaType)
+ if (ISCONFIGSET_PRIV(eAAMPConfig_LimitResolution) && mIsFirstRequestToFOG && mFogTSBEnabled && eMEDIATYPE_MANIFEST == mediaType)
{
std::string customHeader;
customHeader.clear();
@@ -12638,7 +12612,7 @@ struct curl_slist* PrivateInstanceAAMP::GetCustomHeaders(AampMediaType mediaType
httpHeaders = curl_slist_append(httpHeaders, customHeader.c_str());
}
- if(mTSBEnabled && eMEDIATYPE_VIDEO == mediaType)
+ if(mFogTSBEnabled && eMEDIATYPE_VIDEO == mediaType)
{
double bufferedDuration = mpStreamAbstractionAAMP->GetBufferedVideoDurationSec() * 1000.0;
std::string customHeader;
@@ -12646,7 +12620,7 @@ struct curl_slist* PrivateInstanceAAMP::GetCustomHeaders(AampMediaType mediaType
customHeader = "Buffer: " +std::to_string(bufferedDuration);
httpHeaders = curl_slist_append(httpHeaders, customHeader.c_str());
}
- if(mTSBEnabled && eMEDIATYPE_AUDIO == mediaType)
+ if(mFogTSBEnabled && eMEDIATYPE_AUDIO == mediaType)
{
double bufferedAudioDuration = mpStreamAbstractionAAMP->GetBufferedDuration() * 1000.0;
std::string customHeader;
@@ -12654,7 +12628,7 @@ struct curl_slist* PrivateInstanceAAMP::GetCustomHeaders(AampMediaType mediaType
customHeader = "AudioBuffer: " +std::to_string(bufferedAudioDuration);
httpHeaders = curl_slist_append(httpHeaders, customHeader.c_str());
}
- if(mTSBEnabled && (eMEDIATYPE_VIDEO == mediaType || eMEDIATYPE_AUDIO == mediaType))
+ if(mFogTSBEnabled && (eMEDIATYPE_VIDEO == mediaType || eMEDIATYPE_AUDIO == mediaType))
{
MediaTrack* mediaTrack = (eMEDIATYPE_VIDEO == mediaType)?(mpStreamAbstractionAAMP->GetMediaTrack(eTRACK_VIDEO)):(mpStreamAbstractionAAMP->GetMediaTrack(eTRACK_AUDIO));
if((mediaTrack) && (mediaTrack->GetBufferStatus() == BUFFER_STATUS_RED))
@@ -12676,7 +12650,7 @@ struct curl_slist* PrivateInstanceAAMP::GetCustomHeaders(AampMediaType mediaType
}
}
- if (mIsFirstRequestToFOG && mTSBEnabled && eMEDIATYPE_MANIFEST == mediaType)
+ if (mIsFirstRequestToFOG && mFogTSBEnabled && eMEDIATYPE_MANIFEST == mediaType)
{
std::string customHeader = "4k: 1";
if (ISCONFIGSET_PRIV(eAAMPConfig_Disable4K))
@@ -13339,7 +13313,7 @@ void PrivateInstanceAAMP::UpdateMaxDRMSessions()
std::shared_ptr PrivateInstanceAAMP::prepareManifestDownloadConfig()
{
// initialize the MPD Downloader instance
- std::shared_ptr inpData = std::make_shared ();
+ std::shared_ptr inpData = std::make_shared (mPlayerId);
inpData->mTuneUrl = GetManifestUrl();
if(!mMPDStichRefreshUrl.empty() && ISCONFIGSET_PRIV(eAAMPConfig_MPDStitchingSupport))
{
@@ -13554,9 +13528,7 @@ void PrivateInstanceAAMP::ReleaseDynamicDRMToUpdateWait()
AAMPLOG_INFO("Signal sent for mWaitForDynamicDRMToUpdate");
}
-/*
- * @brief Set local TSB injection flag
- */
+
void PrivateInstanceAAMP::SetLocalAAMPTsbInjection(bool value)
{
std::lock_guard guard(mLock);
@@ -13564,9 +13536,6 @@ void PrivateInstanceAAMP::SetLocalAAMPTsbInjection(bool value)
AAMPLOG_INFO("Local AAMP TSB injection %d", mLocalAAMPInjectionEnabled);
}
-/**
- * @brief Is mLocalAAMPTsb enabled/disabled
- */
bool PrivateInstanceAAMP::IsLocalAAMPTsbInjection()
{
return mLocalAAMPInjectionEnabled;
@@ -13662,6 +13631,8 @@ void PrivateInstanceAAMP::SetLLDashChunkMode(bool enable)
AampLLDashServiceData* stLLServiceData = GetLLDashServiceData();
if(mIsChunkMode)
{
+ mMPDDownloaderInstance->SetNetworkTimeout(MANIFEST_TIMEOUT_FOR_LLD);
+ SETCONFIGVALUE_PRIV(AAMP_TUNE_SETTING,eAAMPConfig_ManifestTimeout,MANIFEST_TIMEOUT_FOR_LLD);
SETCONFIGVALUE_PRIV(AAMP_TUNE_SETTING,eAAMPConfig_MinABRNWBufferRampDown,AAMP_LOW_BUFFER_BEFORE_RAMPDOWN_FOR_LLD);
SETCONFIGVALUE_PRIV(AAMP_TUNE_SETTING,eAAMPConfig_MaxABRNWBufferRampUp,AAMP_HIGH_BUFFER_BEFORE_RAMPUP_FOR_LLD);
diff --git a/priv_aamp.h b/priv_aamp.h
index e50809c..854cc32 100644
--- a/priv_aamp.h
+++ b/priv_aamp.h
@@ -867,7 +867,7 @@ class PrivateInstanceAAMP : public AampDrmCallbacks, public std::enable_shared_f
int mPreCacheDnldTimeWindow; /**< Stores PreCaching timewindow */
bool mbDownloadsBlocked;
bool streamerIsActive;
- bool mTSBEnabled;
+ bool mFogTSBEnabled;
bool mIscDVR;
double mLiveOffset;
double mLiveOffsetDrift; /**< allowed drift value from live offset configured **/
@@ -1159,7 +1159,7 @@ class PrivateInstanceAAMP : public AampDrmCallbacks, public std::enable_shared_f
aamp::id3_metadata::MetadataCache mId3MetadataCache; /**< Metadata cache object for the JS event */
bool mIsFlushFdsInCurlStore; /**< Mark to clear curl store instance in case of playback stopped due to download Error */
- bool mIsFlushOperationInProgress; /**< Flag to indicate pipeline flush Opeartion is going on */
+ bool mIsFlushOperationInProgress; /**< Flag to indicate pipeline flush operation is going on */
/**
* @fn ProcessID3Metadata
@@ -1758,7 +1758,7 @@ class PrivateInstanceAAMP : public AampDrmCallbacks, public std::enable_shared_f
*
* @return True or False
*/
- bool IsTSBSupported() { return mTSBEnabled;}
+ bool IsFogTSBSupported() { return mFogTSBEnabled;}
/**
* @brief Checking whether CDVR in progress
@@ -1772,7 +1772,7 @@ class PrivateInstanceAAMP : public AampDrmCallbacks, public std::enable_shared_f
*
* @return True or False
*/
- bool IsUninterruptedTSB() {return (IsTSBSupported() && !IsLive());}
+ bool IsUninterruptedTSB() {return (IsFogTSBSupported() && !IsLive());}
/**
* @brief Checking whether CDVR Stream or not
@@ -4172,7 +4172,7 @@ class PrivateInstanceAAMP : public AampDrmCallbacks, public std::enable_shared_f
AampTSBSessionManager *GetTSBSessionManager();
/**
- * @brief Set local TSB flag
+ * @brief Set AAMP local TSB flag
*/
void SetLocalAAMPTsb(bool value)
{
@@ -4181,7 +4181,7 @@ class PrivateInstanceAAMP : public AampDrmCallbacks, public std::enable_shared_f
}
/**
- * @brief Is mLocalAAMPTsb enabled/disabled
+ * @brief Is AAMP local TSB enabled/disabled
*/
bool IsLocalAAMPTsb()
{
@@ -4189,12 +4189,12 @@ class PrivateInstanceAAMP : public AampDrmCallbacks, public std::enable_shared_f
}
/**
- * @brief Set local TSB injection flag
+ * @brief Set AAMP local TSB injection flag
*/
void SetLocalAAMPTsbInjection(bool value);
/**
- * @brief Is mLocalAAMPTsb enabled/disabled
+ * @brief Is AAMP local TSB injection enabled/disabled
*/
bool IsLocalAAMPTsbInjection();
/**
@@ -4443,8 +4443,9 @@ class PrivateInstanceAAMP : public AampDrmCallbacks, public std::enable_shared_f
std::string mSessionId; /**< ID of the current session as set by the player */
AampTSBSessionManager *mTSBSessionManager;
- bool mLocalAAMPInjectionEnabled;
- bool mLocalAAMPTsb;
+ bool mLocalAAMPInjectionEnabled; /**< Injecting segments from AAMP Local TSB */
+ bool mLocalAAMPTsb; /**< AAMP Local TSB enabled for the current channel
+ (localTSBEnabled and enablePTSReStamp enabled, and playing DASH content) */
bool mbPauseOnStartPlayback; /**< Start playback in paused state */
std::mutex mPreProcessLock;
diff --git a/rmf_shim.h b/rmf_shim.h
index bb11faf..9934e7a 100644
--- a/rmf_shim.h
+++ b/rmf_shim.h
@@ -96,7 +96,7 @@ class StreamAbstractionAAMP_RMF : public StreamAbstractionAAMP
* @param[out] primaryOutputFormat - format of primary track
* @param[out] audioOutputFormat - format of audio track
* @param[out] auxOutputFormat - format of aux audio track
- * @param[out] subtitleOutputFormat - format of sutbtile track
+ * @param[out] subtitleOutputFormat - format of subtitle track
*/
void GetStreamFormat(StreamOutputFormat &primaryOutputFormat, StreamOutputFormat &audioOutputFormat, StreamOutputFormat &auxOutputFormat, StreamOutputFormat &subtitleOutputFormat) override;
/**
diff --git a/scripts/install_aampcli.sh b/scripts/install_aampcli.sh
index 4b94db1..dfa35d8 100644
--- a/scripts/install_aampcli.sh
+++ b/scripts/install_aampcli.sh
@@ -26,10 +26,6 @@ function aampcli_install_postbuild_fn()
if [ $OPTION_DONT_RUN_AAMPCLI = false ];then
# Launch Xcode
(open AAMP.xcodeproj) &
-
- #Launching aamp-cli
- otool -L ./Debug/aamp-cli
- ./Debug/aamp-cli https://example.com/VideoTestStream/main.mpd
else
echo "To use Xcode, open aamp/build/AAMP.xcodeproj project file"
fi
diff --git a/streamabstraction.cpp b/streamabstraction.cpp
index 8edd748..a4427d3 100644
--- a/streamabstraction.cpp
+++ b/streamabstraction.cpp
@@ -939,7 +939,7 @@ bool MediaTrack::ProcessFragmentChunk()
{
AAMPLOG_INFO("Injecting init chunk for %s",name);
InjectFragmentChunkInternal((AampMediaType)type, &cachedFragment->fragment, cachedFragment->position, cachedFragment->position, cachedFragment->duration, cachedFragment->initFragment, cachedFragment->discontinuity);
- if (eTRACK_VIDEO == type && aamp->IsLocalAAMPTsb() && pContext && pContext->GetProfileCount())
+ if (eTRACK_VIDEO == type && pContext && pContext->GetProfileCount())
{
pContext->NotifyBitRateUpdate(cachedFragment->profileIndex, cachedFragment->cacheFragStreamInfo, cachedFragment->position);
}
@@ -1089,6 +1089,24 @@ bool MediaTrack::ProcessFragmentChunk()
return true;
}
+void StreamAbstractionAAMP::ResetTrickModePtsRestamping(void)
+{
+ for (int i = 0; i < AAMP_TRACK_COUNT; i++)
+ {
+ auto track = GetMediaTrack(static_cast(i));
+ if(nullptr != track)
+ {
+ track->ResetTrickModePtsRestamping();
+ }
+ }
+}
+
+void MediaTrack::ResetTrickModePtsRestamping(void)
+{
+ mTrickmodeState = TrickmodeState::UNDEF;
+ mRestampedPts = 0.0;
+}
+
void MediaTrack::TrickModePtsRestamp(AampGrowableBuffer &fragment, double &position, double &duration,
bool initFragment, bool discontinuity)
{
@@ -1122,9 +1140,10 @@ void MediaTrack::TrickModePtsRestamp(AampGrowableBuffer &fragment, double &posit
}
else
{
- // Initialize the restamped pts timeline when handling the first media fragment
- mTrickmodeState = TrickmodeState::FIRST_FRAGMENT;
- mRestampedPts = 0.0;
+ if (TrickmodeState::UNDEF == mTrickmodeState)
+ {
+ mTrickmodeState = TrickmodeState::FIRST_FRAGMENT;
+ }
}
}
else // Media segment
@@ -1173,9 +1192,10 @@ void MediaTrack::TrickModePtsRestamp(AampGrowableBuffer &fragment, double &posit
// Update cached values for GStreamer
position = mRestampedPts.inSeconds();
- AAMPLOG_INFO("rate %f, initFragment %d, discontinuity %d, "
- "position %lfs, duration %lfs, restamped position %lfs, duration %lfs",
- aamp->rate, initFragment, discontinuity,
+ AAMPLOG_INFO("state %d rate %f trickPlayFPS %d initFragment %d discontinuity %d "
+ "position %lfs duration %lfs restamped position %lfs duration %lfs",
+ static_cast(mTrickmodeState),
+ aamp->rate, trickPlayFPS, initFragment, discontinuity,
inFragmentPosition.inSeconds(), inFragmentDuration.inSeconds(),
position, duration);
}
@@ -1245,7 +1265,7 @@ void MediaTrack::ProcessAndInjectFragment(CachedFragment *cachedFragment, bool f
}
}
class StreamAbstractionAAMP* pContext = GetContext();
- if (eTRACK_VIDEO == type && !aamp->IsLocalAAMPTsb() && pContext && pContext->GetProfileCount())
+ if (eTRACK_VIDEO == type && pContext && pContext->GetProfileCount())
{
pContext->NotifyBitRateUpdate(cachedFragment->profileIndex, cachedFragment->cacheFragStreamInfo, cachedFragment->position);
}
@@ -1537,7 +1557,7 @@ void MediaTrack::RunInjectLoop()
}
}
// Disable audio video balancing for CDVR content ..
- // CDVR Content includes eac3 audio, the duration of audio doesnt match with video
+ // CDVR Content includes eac3 audio, the duration of audio doesn't match with video
// and hence balancing fetch/inject not needed for CDVR //TBD Not needed for LLD
if(!ISCONFIGSET(eAAMPConfig_AudioOnlyPlayback) && !aamp->IsCDVRContent() && (!aamp->mAudioOnlyPb && !aamp->mVideoOnlyPb) && !lowLatency)
{
@@ -1676,6 +1696,29 @@ int MediaTrack::GetCurrentBandWidth()
return this->bandwidthBitsPerSecond;
}
+/**
+ * @brief Flushes all fetched cached fragments
+ * Flushes all fetched media fragments
+ */
+void MediaTrack::FlushFetchedFragments()
+{
+ std::lock_guard guard(mutex);
+ while(numberOfFragmentsCached)
+ {
+ AAMPLOG_DEBUG("[%s] Free cachedFragment[%d] numberOfFragmentsCached %d", name, fragmentIdxToInject, numberOfFragmentsCached);
+ mCachedFragment[fragmentIdxToInject].fragment.Free();
+ memset(&mCachedFragment[fragmentIdxToInject], 0, sizeof(CachedFragment));
+
+ fragmentIdxToInject++;
+ if (fragmentIdxToInject == maxCachedFragmentsPerTrack)
+ {
+ fragmentIdxToInject = 0;
+ }
+ numberOfFragmentsCached--;
+ }
+ fragmentInjected.notify_one();
+}
+
/**
* @brief Flushes all cached fragments
* Flushes all media fragments and resets all relevant counters
@@ -1900,7 +1943,7 @@ StreamAbstractionAAMP::StreamAbstractionAAMP(PrivateInstanceAAMP* aamp, id3_call
mNetworkDownDetected(false), mTotalPausedDurationMS(0), mIsPaused(false), mProgramStartTime(-1),
mStartTimeStamp(-1),mLastPausedTimeStamp(-1), aamp(aamp),
mIsPlaybackStalled(false), mTuneType(), mLock(),
- mCond(), mLastVideoFragCheckedforABR(0), mLastVideoFragParsedTimeMS(0),
+ mCond(), mLastVideoFragCheckedForABR(0), mLastVideoFragParsedTimeMS(0),
mSubCond(), mAudioTracks(), mTextTracks(),mABRHighBufferCounter(0),mABRLowBufferCounter(0),mMaxBufferCountCheck(0),
mStateLock(), mStateCond(), mTrackState(eDISCONTINUITY_FREE),
mRampDownLimit(-1), mRampDownCount(0),mABRMaxBuffer(0), mABRCacheLength(0), mABRMinBuffer(0), mABRNwConsistency(0),
@@ -1998,7 +2041,7 @@ int StreamAbstractionAAMP::GetDesiredProfile(bool getMidProfile)
int StreamAbstractionAAMP::GetMaxBWProfile()
{
int ret = 0;
- if(aamp->IsTSBSupported() && mTsbMaxBitrateProfileIndex >= 0)
+ if(aamp->IsFogTSBSupported() && mTsbMaxBitrateProfileIndex >= 0)
{
ret = mTsbMaxBitrateProfileIndex;
}
@@ -2110,7 +2153,7 @@ void StreamAbstractionAAMP::UpdateProfileBasedOnFragmentDownloaded(void)
void StreamAbstractionAAMP::UpdateRampUpOrDownProfileReason(void)
{
mBitrateReason = eAAMP_BITRATE_CHANGE_BY_RAMPDOWN;
- if(mUpdateReason && aamp->IsTSBSupported())
+ if(mUpdateReason && aamp->IsFogTSBSupported())
{
mBitrateReason = eAAMP_BITRATE_CHANGE_BY_FOG_ABR;
mUpdateReason = false;
@@ -4173,7 +4216,7 @@ double MediaTrack::GetTotalInjectedDuration()
{
std::lock_guard lock(mTrackParamsMutex);
double ret = totalInjectedDuration;
- if(aamp->GetLLDashServiceData()->lowLatencyMode)
+ if (IsInjectionFromCachedFragmentChunks())
{
ret = totalInjectedChunksDuration;
}
diff --git a/support/aampabr/ABRManager.cpp b/support/aampabr/ABRManager.cpp
index 6ec35a7..7e218eb 100644
--- a/support/aampabr/ABRManager.cpp
+++ b/support/aampabr/ABRManager.cpp
@@ -25,7 +25,7 @@
#include
#include
-#if !(defined(WIN32) || defined(__APPLE__))
+#if !defined(__APPLE__)
#if defined(USE_SYSTEMD_JOURNAL_PRINT)
#define ENABLE_RDK_LOGGER true
#include
@@ -313,7 +313,7 @@ int ABRManager::getBestMatchedProfileIndexByBandWidth(int bandwidth) {
desiredProfileIndex = i;
break;
} else if (profile.bandwidthBitsPerSecond < bandwidth) {
- // fragment file name bandwidth doesnt match the profile bandwidth, will be always less
+ // fragment file name bandwidth doesn't match the profile bandwidth, will be always less
if((i+1) == profileCount) {
desiredProfileIndex = i;
break;
diff --git a/support/aampabr/HybridABRManager.cpp b/support/aampabr/HybridABRManager.cpp
index 302a5cc..2c1e5b2 100644
--- a/support/aampabr/HybridABRManager.cpp
+++ b/support/aampabr/HybridABRManager.cpp
@@ -28,7 +28,7 @@
#include
#include
#include
-#if !(defined(WIN32) || defined(__APPLE__))
+#if !defined(__APPLE__)
#if defined(USE_SYSTEMD_JOURNAL_PRINT)
#define ENABLE_RDK_LOGGER true
#include
diff --git a/test/aampcli/Aampcli.cpp b/test/aampcli/Aampcli.cpp
index 32bd515..15bac44 100644
--- a/test/aampcli/Aampcli.cpp
+++ b/test/aampcli/Aampcli.cpp
@@ -31,8 +31,8 @@ Aampcli mAampcli;
const char *gApplicationPath = NULL;
extern VirtualChannelMap mVirtualChannelMap;
extern void tsdemuxer_InduceRollover( bool enable );
-extern std::vector> mAdvertList;
-static int mAdvertIndex = 0;
+
+extern std::vector mAdvertList;
static int mAdReservationIndex = 0;
Aampcli :: Aampcli():
@@ -403,100 +403,6 @@ int main(int argc, char **argv)
printf( "[AAMPCLI] done\n" );
}
-void Aampcli::getAdvertUrl( uint32_t reqDuration, uint32_t &adDuration, std::vector& adList)
-{
- bool loop = false;
- std::string defUrl = "";
- advertInfo ad;
- mAdvertIndex = (mAdvertIndex < mAdvertList.size()) ? mAdvertIndex : 0;
- while (mAdvertIndex < mAdvertList.size())
- {
- if(mAdvertList[mAdvertIndex].size() == 0)
- {
- ++mAdvertIndex;
- continue;
- }
- //If required duration Ad present in advert list will select it
- if(reqDuration == mAdvertList[mAdvertIndex][0].duration)
- {
- ad.url = mAdvertList[mAdvertIndex][0].url;
- ad.duration = mAdvertList[mAdvertIndex][0].duration;
- adList.push_back(ad);
- mAdvertIndex = mAdvertIndex + 1;
- break;
- }
- if((defUrl.empty()) && (mAdvertList[mAdvertIndex][0].duration == 0))
- {
- defUrl = mAdvertList[mAdvertIndex][0].url;
- }
-
- if(( loop == false) && ( mAdvertIndex + 1 == mAdvertList.size()))
- {
- mAdvertIndex = 0;
- loop = true;
- }
- else
- {
- mAdvertIndex++;
- }
- }
-
- //Required duration is not found in advert list then will add the present ads in list
- if(!adList.size())
- {
- mAdvertIndex = 0;
- int curDuration = 0;
- while((mAdvertIndex < mAdvertList.size()) && (curDuration < reqDuration))
- {
- if(mAdvertList[mAdvertIndex].size() == 0)
- {
- ++mAdvertIndex;
- continue;
- }
- if((reqDuration - curDuration) >= mAdvertList[mAdvertIndex][0].duration)
- {
- ad.url = mAdvertList[mAdvertIndex][0].url;
- ad.duration = mAdvertList[mAdvertIndex][0].duration;
- adList.push_back(ad);
- mAdvertIndex = mAdvertIndex + 1;
- curDuration += ad.duration;
- }
- else
- {
- mAdvertIndex = mAdvertIndex + 1;
- }
- }
- }
-
- if((!adList.size()) && (!defUrl.empty()))
- {
- ad.url = defUrl;
- ad.duration = 0;
- adList.push_back(ad);
- }
-}
-
-void Aampcli::getAdvertUrlIndexed( std::vector& adList, int idx)
-{
- if(idx < 0)
- {
- printf("[AAMPCLI] Invalid index\n");
- return;
- }
- if(mAdvertList.size()==0)
- {
- printf("[AAMPCLI] Advert list is empty\n");
- return;
- }
- advertInfo ad;
- for (AdvertInfo& advert : mAdvertList[idx])
- {
- ad.url = advert.url;
- ad.duration =advert.duration;
- adList.push_back(ad);
- }
-}
-
const char *MyAAMPEventListener::stringifyPlayerState(AAMPPlayerState state)
{
static const char *stateName[] =
@@ -678,9 +584,9 @@ void MyAAMPEventListener::Event(const AAMPEventPtr& e)
case AAMP_EVENT_CONTENT_PROTECTION_DATA_UPDATE:
{
ContentProtectionDataEventPtr ev = std::dynamic_pointer_cast(e);
- printf("[AMPCLI] AAMP_EVENT_CONTENT_PROTECTION_UPDATE received stream type %s\n",ev->getStreamType().c_str());
+ printf("[AAMPCLI] AAMP_EVENT_CONTENT_PROTECTION_UPDATE received stream type %s\n",ev->getStreamType().c_str());
std::vector key = ev->getKeyID();
- printf("[AMPCLI] AAMP_EVENT_CONTENT_PROTECTION_UPDATE received key is ");
+ printf("[AAMPCLI] AAMP_EVENT_CONTENT_PROTECTION_UPDATE received key is ");
for(int i=0;i(e);
- if ( ev->getName() == "SCTE35" )
+ if( ev->getName() == "SCTE35" )
{
- printf("\n[AAMPCLI] AAMP_EVENT_TIMED_METADATA received\n");
+ printf("[AAMPCLI] AAMP_EVENT_TIMED_METADATA received\n");
/* Decode any SCTE35 splice info event. */
std::vector spliceInfoSummary;
SCTE35SpliceInfo spliceInfo(ev->getContent());
-
spliceInfo.getSummary(spliceInfoSummary);
- for (auto &splice : spliceInfoSummary)
+ bool mapped = false;
+ for( auto &splice : spliceInfoSummary)
{
- AAMPLOG_WARN("[CDAI] splice info type %d, time %f, duration %f, id 0x%" PRIx32,
- (int)splice.type, splice.time, splice.duration, splice.event_id);
-
- if ((splice.type == SCTE35SpliceInfo::SEGMENTATION_TYPE::PROVIDER_ADVERTISEMENT_START) ||
- (splice.type == SCTE35SpliceInfo::SEGMENTATION_TYPE::PROVIDER_PLACEMENT_OPPORTUNITY_START))
+ printf("[AAMPCLI] SCTE35SpliceInfo type=%d time=%fs duration=%fs id=0x%" PRIx32 "\n",
+ static_cast(splice.type), splice.time, splice.duration, splice.event_id );
+ switch( splice.type )
{
- /* A set of ads should be selected for insertion based
- * on the splice info event type, id and duration.
- */
- AAMPLOG_WARN("[CDAI] Dynamic ad start signalled mAdBrkIndex(%d)", mAampcli.mAdBrkIndex);
-
- uint32_t adDuration = 0;
- std::vector adList;
- std::string adId = "adId";
- if(!mAampcli.mIndexedAds)
- {
- //If we have an advert list, use that
- if (mAdvertList.size())
- {
- mAampcli.getAdvertUrl(splice.duration, adDuration, adList);
- }
- else
- {
- // set default url
- advertInfo ad;
- ad.url = "https://example.com/AD/HD/manifest.mpd";
- ad.duration = 0;
- adList.push_back(ad);
-
- }
- }
- else
+ case SCTE35SpliceInfo::SEGMENTATION_TYPE::PROVIDER_ADVERTISEMENT_START:
+ case SCTE35SpliceInfo::SEGMENTATION_TYPE::PROVIDER_PLACEMENT_OPPORTUNITY_START:
+ printf("[AAMPCLI] [CDAI] Dynamic ad start signalled for breakId='%s'\n)", ev->getId().c_str() );
+ for( const AdvertInfo &advertInfo : mAdvertList )
{
- //If we have an advert list, use that
- if (mAdvertList.size())
+ if( advertInfo.adBreakId == ev->getId() )
{
- mAampcli.getAdvertUrlIndexed(adList,mAampcli.mAdBrkIndex);
+ std::string adId = "adId" + std::to_string(++mAdReservationIndex);
+ printf("[AAMPCLI] AAMP_EVENT_TIMED_METADATA place advert breakId=%s adId=%s url=%s\n", ev->getId().c_str(), adId.c_str(), advertInfo.url.c_str());
+ mAampcli.mSingleton->SetAlternateContents(ev->getId(), adId, advertInfo.url);
+ mapped = true;
}
}
- for(int i=0; igetId().c_str(), adId.c_str());
- }
- else
- {
- printf("[AMPCLI] AAMP_EVENT_TIMED_METADATA place advert breakId=%s adId=%s duration=%d url=%s\n", ev->getId().c_str(), adId.c_str(), adList[i].duration, adList[i].url.c_str());
- mAampcli.mSingleton->SetAlternateContents(ev->getId(), adId, adList[i].url);
- }
- }
-
- mAampcli.mAdBrkIndex++;
- if(mAampcli.mAdBrkIndex >= mAdvertList.size()) // shouldn't go hear ideally , just safety measure
+ if( !mapped )
{
- mAampcli.mAdBrkIndex = 0;
+ printf( "[AAMPCLI] unmapped breakId=%s\n", ev->getId().c_str() );
}
- }
- else
- {
- AAMPLOG_INFO("[CDAI] No dynamic ad start signalled");
- }
- }
- }
+ break;
+ default:
+ break;
+ } // splice.type
+ } // spliceInfoSummary
+ } // SCTE35
break;
}
-
+
case AAMP_EVENT_MANIFEST_REFRESH_NOTIFY:
{
std::string manifest;
diff --git a/test/aampcli/Aampcli.h b/test/aampcli/Aampcli.h
index c301ca7..d3d70b8 100644
--- a/test/aampcli/Aampcli.h
+++ b/test/aampcli/Aampcli.h
@@ -62,7 +62,7 @@ class Aampcli
bool mEnableProgressLog;
bool mbAutoPlay;
bool mIndexedAds = false;
- int mAdBrkIndex=0;
+ std::string mContentType;
std::string mTuneFailureDescription;
PlayerInstanceAAMP *mSingleton;
MyAAMPEventListener *mEventListener;
@@ -79,8 +79,7 @@ class Aampcli
void newPlayerInstance( std::string appName = "");
int getApplicationDir( char *buffer, uint32_t size );
void getAdvertUrl( uint32_t reqDuration, uint32_t &adDuration, std::vector& adList);
- void getAdvertUrlIndexed( std::vector& adList, int idx);
-
+
bool SetSessionId(std::string sid);
std::string GetSessionId() const;
std::string GetSessionId(size_t index) const;
diff --git a/test/aampcli/AampcliPlaybackCommand.cpp b/test/aampcli/AampcliPlaybackCommand.cpp
index 7331ea1..929517b 100644
--- a/test/aampcli/AampcliPlaybackCommand.cpp
+++ b/test/aampcli/AampcliPlaybackCommand.cpp
@@ -37,7 +37,7 @@ extern void tsdemuxer_InduceRollover( bool enable );
std::map PlaybackCommand::playbackCommands = std::map();
std::vector PlaybackCommand::commands(0);
static std::string mFogHostPrefix="127.0.0.1:9080"; //Default host string for "fog" command
-std::vector> mAdvertList = std::vector>();
+std::vector mAdvertList;
void PlaybackCommand::getRange(const char* cmd, unsigned long& start, unsigned long& end, unsigned long& tail)
{
@@ -132,6 +132,20 @@ void PlaybackCommand::HandleCommandList( const char *cmd )
mVirtualChannelMap.showList(start, end, tail);
}
+void PlaybackCommand::HandleCommandContentType( const char *cmd )
+{
+ if (strlen(cmd) > strlen("contentType "))
+ {
+ mAampcli.mContentType = std::string(&cmd[strlen("contentType ")]);
+ printf("[AAMPCLI] contentType set to %s\n", mAampcli.mContentType.c_str());
+ }
+ else
+ {
+ mAampcli.mContentType.clear();
+ printf("[AAMPCLI] contentType not set\n");
+ }
+}
+
void PlaybackCommand::HandleCommandNew( const char *cmd )
{
char playerName[50] = {'\0'};
@@ -159,7 +173,7 @@ void PlaybackCommand::HandleCommandSelect( const char *cmd, PlayerInstanceAAMP *
found->GetId(),
found,
found->GetAppName().c_str() );
-
+
mAampcli.mSingleton = found;
}
//else
@@ -182,10 +196,6 @@ void PlaybackCommand::HandleCommandSelect( const char *cmd, PlayerInstanceAAMP *
{
printf( " (selected)");
}
- //if( !player->aamp )
- //{
- // printf( " (!)" );
- //}
printf( "\n");
}
}
@@ -232,14 +242,15 @@ void PlaybackCommand::HandleCommandSleep( const char *cmd )
void PlaybackCommand::HandleCommandTuneLocator( const char *cmd, PlayerInstanceAAMP *playerInstanceAamp )
{
const auto sid = mAampcli.GetSessionId();
+ const char *contentType = (mAampcli.mContentType.empty()) ? nullptr : mAampcli.mContentType.c_str();
if (sid.empty())
{
- playerInstanceAamp->Tune(cmd, mAampcli.mbAutoPlay);
+ playerInstanceAamp->Tune(cmd, mAampcli.mbAutoPlay, contentType);
}
else
{
playerInstanceAamp->Tune(cmd, mAampcli.mbAutoPlay,
- nullptr, true, false, nullptr, true, nullptr, 0,
+ contentType, true, false, nullptr, true, nullptr, 0,
std::move(sid),nullptr);
}
}
@@ -275,7 +286,7 @@ void PlaybackCommand::HandleCommandPrev( const char *cmd, PlayerInstanceAAMP *pl
void PlaybackCommand::HandleCommandTuneIndex( const char *cmd, PlayerInstanceAAMP *playerInstanceAamp )
{
int channelNumber = atoi(cmd); // invalid input results in 0 -- will not be found
-
+
VirtualChannelInfo *pChannelInfo = mVirtualChannelMap.find(channelNumber);
if (pChannelInfo != NULL)
{
@@ -332,11 +343,11 @@ void PlaybackCommand::HandleCommandCustomHeader( const char *cmd, PlayerInstance
int parameter=0;
bool isLicenceHeader=false;
cmdptr = strtok (const_cast(cmd)," ,");
-
+
printf("[AAMPCLI] customheader Command is %s\n" , cmd);
-
+
std::string subString;
-
+
// accepts just one headervalue for now, not an array.
// header value of '.' -> remove the header, else it adds it
while (cmdptr)
@@ -387,9 +398,9 @@ void PlaybackCommand::HandleCommandSubtec( void )
#define MAX_SUBTEC_PATH_LEN 560
char scriptPath[MAX_SCRIPT_PATH_LEN] = "";
char subtecCommand[MAX_SUBTEC_PATH_LEN] = "";
-
+
mAampcli.mSingleton->SetCCStatus(true);
-
+
if (mAampcli.getApplicationDir(scriptPath, MAX_SCRIPT_PATH_LEN) > 0)
{
#ifdef __APPLE__
@@ -493,194 +504,26 @@ void PlaybackCommand::HandleCommandAdvert( const char *cmd, PlayerInstanceAAMP *
if (std::getline(input, token, ' '))
{
- if (token == "list")
+ if( token == "list" )
{
- printf("[AAMP-CLI] Ad Map -------->\n");
- for (size_t i = 0; i < mAdvertList.size(); i++)
+ printf("[AAMP-CLI] Ad Map:\n");
+ for( const AdvertInfo &advertInfo : mAdvertList )
{
- if(mAdvertList[i].size()>0)
- {
- for (size_t j = 0; j < mAdvertList[i].size(); j++)
- {
- const AdvertInfo& advert = mAdvertList[i][j];
- printf("[AAMP-CLI] Index %zu --> advert %zu: url %s duration %d\n", i, j, advert.url.c_str(), advert.duration);
- }
- }
+ printf("[AAMP-CLI] advert %s -> %s\n", advertInfo.adBreakId.c_str(), advertInfo.url.c_str() );
}
}
- else if(token == "clear")
+ else if( token == "clear" )
{
mAdvertList.clear();
printf("[AAMP-CLI] Cleared Ad List\n");
}
- else
+ else if( token == "map" )
{
- std::string url;
- std::string identifier;
-
- // The next para should be a url or an index to a url
- if (!std::getline(input, identifier, ' '))
- {
- printf("[AAMP-CLI] ERROR - unable to parse url identifier\n");
- }
- else if (playerInstanceAamp->isTuneScheme(identifier.c_str()))
- {
- // If we have a URL, add or remove it from the list
- if (token == "add")
- {
- std::string duration;
- AdvertInfo lAdvertInfo;
- lAdvertInfo.url = identifier;
-
- if (std::getline(input, duration, ' '))
- lAdvertInfo.duration = std::stoi(duration);
- else
- lAdvertInfo.duration = 0;
-
- int idx = 0;
- if(std::getline(input, token, ' '))
- {
- try
- {
- idx = std::stoi(token);
- }
- catch(...)
- {
- printf("[AAMP-CLI] ERROR - invalid index '%s'\n", token.c_str());
- idx = 0;
- }
-
- if (idx >= mAdvertList.size())
- {
- mAdvertList.resize(idx + 1);
- }
- mAdvertList[idx].push_back(lAdvertInfo);
- printf("[AAMP-CLI] Added to advert list url: %s duration: %d at index : %d mIndexedAds : %d\n", (lAdvertInfo.url).c_str(), lAdvertInfo.duration , idx , mAampcli.mIndexedAds);
-
- }
- else
- {
- std::vector newAdvertList;
- newAdvertList.push_back(lAdvertInfo);
- mAdvertList.push_back(newAdvertList);
- printf("[AAMP-CLI] Added to advert list url: %s duration: %d at new index : %zu mIndexedAds : %d\n", (lAdvertInfo.url).c_str(), lAdvertInfo.duration, mAdvertList.size() - 1, mAampcli.mIndexedAds);
- }
- }
- else if (token == "rm")
- {
- bool urlFlag = false;
- for (size_t i = 0; i < mAdvertList.size(); ++i)
- {
- for (auto itr = mAdvertList[i].begin(); itr != mAdvertList[i].end(); ++itr)
- {
- if (identifier == itr->url)
- {
- mAdvertList[i].erase(itr);
- urlFlag = true;
- printf("[AAMP-CLI] Removed from advert list url: %s \n", identifier.c_str());
- break;
- }
- }
-
- if (urlFlag)
- {
- break;
- }
- }
-
- if(!urlFlag)
- {
- printf("[AAMP-CLI] ERROR - no url '%s' in list\n", identifier.c_str());
- }
-
- }
- else
- {
- printf("[AAMP-CLI] ERROR - unrecognised command 'advert %s'\n", token.c_str());
- }
- }
- else if (isNumber(identifier.c_str()))
- {
- uint32_t urlIndex = -1;
- try
- {
- urlIndex = (uint32_t)std::stoi(identifier);
-
- // If adding a url by index, get the url from the virtual channel map
- if (token == "add")
- {
- // Add a url from the virtual channel map
- VirtualChannelInfo *info = mVirtualChannelMap.find(urlIndex);
- if (info)
- {
- std::string duration;
- AdvertInfo lAdvertInfo;
- lAdvertInfo.url = info->uri;
-
- if (std::getline(input, duration, ' '))
- lAdvertInfo.duration = stoi(duration);
- else
- lAdvertInfo.duration = 0;
- if(std::getline(input, token, ' '))
- {
- int idx;
- try
- {
- idx = std::stoi(token);
- }
- catch(...)
- {
- printf("[AAMP-CLI] ERROR - invalid index '%s'\n", token.c_str());
- idx = 0;
- }
-
- if (idx >= mAdvertList.size())
- {
- mAdvertList.resize(idx + 1);
- }
- mAdvertList[idx].push_back(lAdvertInfo);
- printf("[AAMP-CLI] Added to advert list url: %s duration: %d at index : %d mIndexedAds : %d\n", (lAdvertInfo.url).c_str(), lAdvertInfo.duration , idx , mAampcli.mIndexedAds);
-
- }
- else
- {
- std::vector newAdvertList;
- newAdvertList.push_back(lAdvertInfo);
- mAdvertList.push_back(newAdvertList);
- printf("[AAMP-CLI] Added to advert list url: %s duration: %d at new index : %zu mIndexedAds : %d\n", (lAdvertInfo.url).c_str(), lAdvertInfo.duration, mAdvertList.size() - 1, mAampcli.mIndexedAds);
- }
- }
- else
- {
- printf("[AAMP-CLI] ERROR - invalid index into virtual channel map %d\n", urlIndex);
- }
- }
-
- // If deleting a url by index, get the url at that index
- else if (token == "rm")
- {
- // Remove a url by index
-
- if (urlIndex < mAdvertList.size())
- {
- mAdvertList[urlIndex].clear();
- printf("[AAMP-CLI] Cleared all elements at index %d\n", urlIndex);
- }
- else
- {
- printf("[AAMP-CLI] ERROR - invalid index %d\n", urlIndex);
- }
- }
- }
- catch (...)
- {
- printf("[AAMP-CLI] ERROR - invalid index '%s'\n", identifier.c_str());
- }
- }
- else
- {
- printf("[AAMP-CLI] ERROR - param '%s'\n", identifier.c_str());
- }
+ AdvertInfo advertInfo;
+ std::getline( input, advertInfo.adBreakId, ' ' );
+ std::getline( input, advertInfo.url, ' ' );
+ mAdvertList.push_back(advertInfo);
+ printf("[AAMP-CLI] mapped adBreakId %s\n", advertInfo.adBreakId.c_str() );
}
}
else
@@ -693,11 +536,11 @@ void PlaybackCommand::HandleCommandScte35( const char *cmd )
{
std::istringstream input;
input.str(cmd);
-
+
std::string token;
std::getline(input, token, ' ');
assert(token == "scte35");
-
+
if (std::getline(input, token, ' '))
{
SCTE35SpliceInfo spliceInfo(token);
@@ -712,10 +555,10 @@ void PlaybackCommand::HandleCommandScte35( const char *cmd )
void PlaybackCommand::HandleCommandSessionId( const char *cmd )
{
char sid[128] = {'\0'};
-
+
printf("[AAMPCLI] Matched Command SessionID - %s\n", cmd);
const auto res = sscanf(cmd, "sessionid %127s", sid);
-
+
if (res == 1)
{
mAampcli.SetSessionId({sid});
@@ -868,6 +711,10 @@ bool PlaybackCommand::execute( const char *cmd, PlayerInstanceAAMP *playerInstan
mAampcli.mbAutoPlay = !mAampcli.mbAutoPlay;
printf( "autoplay = %s\n", mAampcli.mbAutoPlay?"true":"false" );
}
+ else if( isCommandMatch(cmd,"contentType") )
+ {
+ HandleCommandContentType(cmd);
+ }
else if( isCommandMatch(cmd,"new") )
{
HandleCommandNew(cmd);
@@ -1125,6 +972,7 @@ void PlaybackCommand::registerPlaybackCommands()
// tuning
addCommand("autoplay","Toggle whether to autoplay (default=true)");
+ addCommand("contentType ","Specify contentType to use when tuning e.g contentType LINEAR_TV");
addCommand("list","Show virtual channel map; optionally pass a range e.g. 1-10, a start channel or -n to show the last n channels");
addCommand("","Tune specified virtual channel");
addCommand("next","Tune next virtual channel");
@@ -1173,7 +1021,7 @@ void PlaybackCommand::registerPlaybackCommands()
addCommand("exit","Exit aampcli");
addCommand("advert ", "manage injected advert list - 'list', 'add ', 'rm '");
addCommand("scte35 ", "decode SCTE-35 signal base64 string");
- addCommand("release ", "to remove the player");
+ addCommand("release ", "to remove the player");
addCommand("tunedata ","Tune passing a manifest buffer as a string");
addCommand("adtesting", "toggle index based adtesting logic for testing");
}
diff --git a/test/aampcli/AampcliPlaybackCommand.h b/test/aampcli/AampcliPlaybackCommand.h
index 1e3d7a6..bd9624a 100644
--- a/test/aampcli/AampcliPlaybackCommand.h
+++ b/test/aampcli/AampcliPlaybackCommand.h
@@ -27,13 +27,12 @@
#include "AampcliCommand.h"
-typedef struct advertInfo
+typedef struct AdvertInfo
{
std::string url;
- uint32_t duration;
-
- advertInfo():url(),duration(0){};
-}AdvertInfo;
+ std::string adBreakId;
+ AdvertInfo():url(),adBreakId(){};
+} AdvertInfo;
class PlaybackCommand : public Command
{
@@ -57,6 +56,7 @@ class PlaybackCommand : public Command
static std::map playbackCommands;
void HandleCommandList( const char *cmd );
+ void HandleCommandContentType( const char *cmd );
void HandleCommandNew( const char *cmd );
void HandleCommandSelect( const char *cmd, PlayerInstanceAAMP *playerInstanceAamp );
void HandleCommandRelease( const char *cmd, PlayerInstanceAAMP *playerInstanceAamp );
diff --git a/test/gstTestHarness/gst-port.h b/test/gstTestHarness/gst-port.h
index 5cea3d1..c9a1b7d 100644
--- a/test/gstTestHarness/gst-port.h
+++ b/test/gstTestHarness/gst-port.h
@@ -41,10 +41,10 @@ typedef enum
typedef enum
{ // 1-to-1 map to GstState
- ePIPELINeSTATE_NULL = 1, // GST_STATE_NULL
- ePIPELINeSTATE_READY = 2, // GST_STATE_READY
- ePIPELINeSTATE_PAUSED = 3, // GST_STATE_PAUSED
- ePIPELINeSTATE_PLAYING = 4, // GST_STATE_PLAYING
+ ePIPELINE_STATE_NULL = 1, // GST_STATE_NULL
+ ePIPELINE_STATE_READY = 2, // GST_STATE_READY
+ ePIPELINE_STATE_PAUSED = 3, // GST_STATE_PAUSED
+ ePIPELINE_STATE_PLAYING = 4, // GST_STATE_PLAYING
} PipelineState;
struct _GstElement;
diff --git a/test/gstTestHarness/gst-test.cpp b/test/gstTestHarness/gst-test.cpp
index ab8845d..ea55ae9 100644
--- a/test/gstTestHarness/gst-test.cpp
+++ b/test/gstTestHarness/gst-test.cpp
@@ -14,6 +14,7 @@
* 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
+ * See the License for the specfaific language governing permissions and
* limitations under the License.
*/
#include "gst-test.h"
@@ -197,6 +198,7 @@ class TrackFragment: public TrackEvent
gpointer ptr;
double duration;
double pts_offset;
+ MediaType mediaType;
// for demuxed ts segment
TsDemux *tsDemux;
@@ -218,17 +220,15 @@ class TrackFragment: public TrackEvent
break;
case eCONTENTFORMAT_TS_ES:
- tsDemux = new TsDemux( ptr, len );
+ tsDemux = new TsDemux( mediaType, ptr, len );
assert( tsDemux );
break;
}
}
public:
- TrackFragment( uint32_t timeScale, const char *path, double duration, int64_t pts_offset=0 ):len(), ptr(), tsDemux(), mp4Demux(), pts_offset(pts_offset), duration(duration)
- { // new variation - caller passes timeScale
- this->timeScale = timeScale;
- url = path;
+ TrackFragment( MediaType mediaType, uint32_t timeScale, const char *path, double duration, double pts_offset=0 ):len(), ptr(), tsDemux(), mp4Demux(), pts_offset(pts_offset), duration(duration), timeScale(timeScale), url(path), mediaType(mediaType)
+ {
}
~TrackFragment()
@@ -244,6 +244,8 @@ class TrackFragment: public TrackEvent
if( tsDemux )
{
int count = tsDemux->count();
+ // assert( count>0 );
+ // printf( "***mediaType=%d pts=%f\n", mediaType, tsDemux->getPts(0) );
for( int i=0; igetLen(i);
@@ -470,7 +472,7 @@ class TrackWaitState: public TrackEvent
PipelineState prevState;
PipelineState desiredState;
public:
- TrackWaitState( PipelineState desiredState ) : prevState(ePIPELINeSTATE_NULL),desiredState(desiredState)
+ TrackWaitState( PipelineState desiredState ) : prevState(ePIPELINE_STATE_NULL),desiredState(desiredState)
{
}
@@ -485,16 +487,16 @@ class TrackWaitState: public TrackEvent
{
switch( state )
{
- case ePIPELINeSTATE_NULL:
+ case ePIPELINE_STATE_NULL:
printf( "TrackWaitState(PIPELINeSTATE_NULL)\n" );
break;
- case ePIPELINeSTATE_READY:
+ case ePIPELINE_STATE_READY:
printf( "TrackWaitState(PIPELINeSTATE_READY)\n" );
break;
- case ePIPELINeSTATE_PAUSED:
+ case ePIPELINE_STATE_PAUSED:
printf( "TrackWaitState(PIPELINeSTATE_PAUSED)\n" );
break;
- case ePIPELINeSTATE_PLAYING:
+ case ePIPELINE_STATE_PLAYING:
printf( "TrackWaitState(PIPELINeSTATE_PLAYING)\n" );
break;
default:
@@ -601,7 +603,7 @@ class TrackPlay: public TrackEvent
bool Inject( MyPipelineContext *context, MediaType mediaType)
{
- context->pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ context->pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
return true;
}
};
@@ -642,7 +644,7 @@ void Track::QueueVideoHeader( VideoResolution resolution )
{
char path[MAX_PATH_SIZE];
GetVideoIHeaderPath(path, resolution );
- EnqueueSegment( new TrackFragment( 0, path, 0 ) );
+ EnqueueSegment( new TrackFragment( eMEDIATYPE_VIDEO, 0, path, 0 ) );
}
}
@@ -655,7 +657,7 @@ void Track::QueueVideoSegment( VideoResolution resolution, int startIndex, int c
while( count>0 )
{
GetVideoSegmentPath(path, startIndex, resolution );
- EnqueueSegment( new TrackFragment( timescale, path, SEGMENT_DURATION_SECONDS, pts_offset ) );
+ EnqueueSegment( new TrackFragment( eMEDIATYPE_VIDEO, timescale, path, SEGMENT_DURATION_SECONDS, pts_offset ) );
startIndex++;
count--;
}
@@ -665,7 +667,7 @@ void Track::QueueVideoSegment( VideoResolution resolution, int startIndex, int c
while( count<0 )
{
GetVideoSegmentPath(path, startIndex, resolution );
- EnqueueSegment( new TrackFragment( timescale, path, SEGMENT_DURATION_SECONDS, pts_offset ) );
+ EnqueueSegment( new TrackFragment( eMEDIATYPE_VIDEO, timescale, path, SEGMENT_DURATION_SECONDS, pts_offset ) );
startIndex--;
count++;
}
@@ -681,7 +683,7 @@ void Track::QueueAudioHeader( const char *language )
{
char path[MAX_PATH_SIZE];
GetAudioHeaderPath( path, language );
- EnqueueSegment( new TrackFragment( 0, path, 0 ) );
+ EnqueueSegment( new TrackFragment( eMEDIATYPE_AUDIO, 0, path, 0 ) );
}
}
@@ -693,7 +695,7 @@ void Track::QueueAudioSegment( const char *language, int startIndex, int count,
{
int segmentNumber = startIndex + i;
GetAudioSegmentPath( path, segmentNumber, language );
- EnqueueSegment( new TrackFragment( timescale, path, SEGMENT_DURATION_SECONDS, pts_offset ) );
+ EnqueueSegment( new TrackFragment( eMEDIATYPE_AUDIO, timescale, path, SEGMENT_DURATION_SECONDS, pts_offset ) );
}
}
@@ -802,7 +804,7 @@ class AppContext
pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
pipelineContext.pipeline->Configure( eMEDIATYPE_AUDIO );
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
}
void TestDAI( void )
@@ -849,7 +851,7 @@ class AppContext
// configure pipelines and begin streaming
pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
pipelineContext.pipeline->Configure( eMEDIATYPE_AUDIO );
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
}
void TestDAI2( void )
@@ -890,7 +892,7 @@ class AppContext
// configure pipelines and begin streaming
pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
pipelineContext.pipeline->Configure( eMEDIATYPE_AUDIO );
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
}
void TestStream( double start, double stop, const char *language )
@@ -914,7 +916,7 @@ class AppContext
pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
pipelineContext.pipeline->Configure( eMEDIATYPE_AUDIO );
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
}
void Test_Seek( double seek_pos )
@@ -945,12 +947,12 @@ class AppContext
Flush();
video.QueueVideoHeader( eVIDEORESOLUTION_IFRAME );
pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PAUSED);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PAUSED);
for( int frame=0; frameConfigure( eMEDIATYPE_VIDEO );
- pipelineContext.pipeline->SetPipelineState( ePIPELINeSTATE_PLAYING );
+ pipelineContext.pipeline->SetPipelineState( ePIPELINE_STATE_PLAYING );
}
/**
@@ -988,7 +990,7 @@ class AppContext
Flush( rate, pts, -1, pts );
video.QueueVideoHeader(eVIDEORESOLUTION_IFRAME );
pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PAUSED);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PAUSED);
first = false;
}
else
@@ -997,7 +999,7 @@ class AppContext
}
video.QueueVideoSegment(eVIDEORESOLUTION_IFRAME, frame, 1 );
video.EnqueueControl( new TrackEOS() ); // needed for small segment to render
- video.EnqueueControl( new TrackWaitState(ePIPELINeSTATE_PAUSED) );
+ video.EnqueueControl( new TrackWaitState(ePIPELINE_STATE_PAUSED) );
video.EnqueueControl( new TrackSleep(IFRAME_TRACK_CADENCE_MS) );
}
}
@@ -1018,7 +1020,7 @@ class AppContext
video.QueueVideoSegment(eVIDEORESOLUTION_IFRAME, frame, -SEGMENT_COUNT );
video.EnqueueControl( new TrackEOS() );
pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
} // TestREW
/**
@@ -1036,7 +1038,7 @@ class AppContext
video.QueueVideoSegment( eVIDEORESOLUTION_IFRAME, frame, -SEGMENT_COUNT );
video.EnqueueControl( new TrackEOS() );
pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
- pipelineContext.pipeline->SetPipelineState( ePIPELINeSTATE_PAUSED );
+ pipelineContext.pipeline->SetPipelineState( ePIPELINE_STATE_PAUSED );
// periodically step through playback, with autoStepDelayMs (250ms) delay
autoStepCount = SEGMENT_COUNT+1;
@@ -1044,12 +1046,12 @@ class AppContext
void TestSAP( void )
{
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PAUSED);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PAUSED);
auto position = pipelineContext.pipeline->GetPositionMilliseconds(eMEDIATYPE_VIDEO)/1000.0;
Flush( 1, position, -1, position );
LoadVideo( eVIDEORESOLUTION_360P );
LoadAudio("fr");
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
}
void TestGap( const char *videoGap, const char *audioGap )
@@ -1112,7 +1114,7 @@ class AppContext
videoTrack.EnqueueControl( new TrackEOS() );
audioTrack.EnqueueControl( new TrackEOS() );
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
}
void TestSeamlessAudioSwitch()
@@ -1233,7 +1235,7 @@ class AppContext
FeedPipelineIfNeeded( eMEDIATYPE_AUDIO );
if(( autoStepCount>0 ) &&
- ( ePIPELINeSTATE_PAUSED == pipelineContext.pipeline->GetPipelineState() ))
+ ( ePIPELINE_STATE_PAUSED == pipelineContext.pipeline->GetPipelineState() ))
{ // delay between iframe presentation
g_usleep(autoStepDelayMs*1000);
pipelineContext.pipeline->Step();
@@ -1439,7 +1441,7 @@ class AppContext
std::cout << initHeaderUrl << "\n";
if( !inventory )
{
- pipelineContext.track[mediaType].EnqueueSegment(new TrackFragment(representation.data.timescale, initHeaderUrl.c_str(), 0 ) );
+ pipelineContext.track[mediaType].EnqueueSegment(new TrackFragment( mediaType, representation.data.timescale, initHeaderUrl.c_str(), 0 ) );
}
double skip = secondsToSkip;
@@ -1526,6 +1528,7 @@ class AppContext
continue;
}
pipelineContext.track[mediaType].EnqueueSegment( new TrackFragment(
+ mediaType,
representation.data.timescale,
mediaUrl.c_str(), segmentDurationS, pts_offset ) );
}
@@ -1553,32 +1556,127 @@ class AppContext
pipelineContext.pipeline->Configure( eMEDIATYPE_AUDIO );
// begin playing immediately
- //pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ //pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
// useful for seek-while-paused
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PAUSED);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PAUSED);
}
}
+ /**
+ * @brief basic support for playing a muxed hls/ts playlist, with pts restamping for seamless playback across discontinuities
+ */
+ void LoadHLS( const char *ptr, size_t size, const std::string &url )
+ {
+ struct SegmentInfo
+ {
+ float duration;
+ std::string path;
+ bool discontinuity;
+ double firstPts;
+ };
+ std::vector segmentList;
+
+ std::string text = std::string(ptr,size);
+ std::istringstream iss(text);
+ std::string line;
+ SegmentInfo info;
+ memset( &info, 0, sizeof(info) );
+ while (std::getline(iss, line)) {
+ if( starts_with(line,"#EXT-X-DISCONTINUITY") )
+ {
+ info.discontinuity = true;
+ }
+ if( starts_with(line, "#EXTINF:") )
+ {
+ info.duration = std::stof(line.substr(8));
+ if( std::getline(iss, line) )
+ {
+ info.path = line;
+ info.firstPts = 0.0;
+ segmentList.push_back(info);
+ memset( &info, 0, sizeof(info) );
+ }
+ }
+ }
+
+ Track &video = pipelineContext.track[eMEDIATYPE_VIDEO];
+ Track &audio = pipelineContext.track[eMEDIATYPE_AUDIO];
+ double pts_offset = 0.0;
+ double total_duration = 0.0;
+ uint32_t timescale = 0; // n/a
+
+ mContentFormat = eCONTENTFORMAT_TS_ES; // use tsdemux.hpp
+
+ Flush( 1.0/*rate*/, 0/*start*/, -1/*stop*/, 0/*baseTime*/ );
+
+ for( auto segmentInfo : segmentList )
+ {
+ std::string fullpath = url;
+ auto delim = fullpath.find_last_of("/");
+ assert( delim!=std::string::npos );
+ fullpath = fullpath.substr(0,delim+1);
+ fullpath += segmentInfo.path;
+ if( segmentInfo.discontinuity )
+ { // below used to compute firstPts for future fragment
+ size_t segmentBytes = 0;
+ void *segmentPtr = LoadUrl(fullpath.c_str(),&segmentBytes);
+ assert( segmentPtr );
+ auto tsDemux = new TsDemux( eMEDIATYPE_VIDEO, segmentPtr, segmentBytes );
+ assert( tsDemux );
+ assert( tsDemux->count()>0 );
+ double firstPts = tsDemux->getPts(0);
+ pts_offset = total_duration - firstPts;
+ delete tsDemux;
+ g_free( segmentPtr);
+ }
+ total_duration += segmentInfo.duration;
+
+ video.EnqueueSegment( new TrackFragment( eMEDIATYPE_VIDEO, timescale, fullpath.c_str(), segmentInfo.duration, pts_offset ) );
+ audio.EnqueueSegment( new TrackFragment( eMEDIATYPE_AUDIO, timescale, fullpath.c_str(), segmentInfo.duration, pts_offset ) );
+ }
+
+ video.EnqueueControl( new TrackEOS() );
+ audio.EnqueueControl( new TrackEOS() );
+
+ // configure pipelines and begin streaming
+ pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
+ pipelineContext.pipeline->Configure( eMEDIATYPE_AUDIO );
+ //pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PAUSED);
+ }
+
+ void LoadDASH( const char *ptr, size_t size, const std::string &url, bool inventory )
+ {
+ XmlNode *xml = new XmlNode( "document", ptr, size );
+ auto numChildren = xml->children.size();
+ auto MPD = xml->children[numChildren-1];
+ DumpXml(MPD,0);
+ timeline = parseManifest( *MPD, url );
+ timeline.Debug();
+ ComputeTimestampOffsets( timeline );
+ InjectSegments( timeline, inventory );
+ delete xml;
+ }
+
void Load( const std::string &url, bool inventory )
{
size_t size = 0;
auto ptr = LoadUrl( url, &size );
if( ptr )
{
- XmlNode *xml = new XmlNode( "document", (char *)ptr, size );
- auto numChildren = xml->children.size();
- auto MPD = xml->children[numChildren-1];
- DumpXml(MPD,0);
- timeline = parseManifest( *MPD, url );
- timeline.Debug();
- ComputeTimestampOffsets( timeline );
- InjectSegments( timeline, inventory );
- delete xml;
+ if( size>=7 && memcmp(ptr,"#EXTM3U",7)==0 )
+ {
+ LoadHLS( (const char *)ptr, size, url );
+ }
+ else
+ {
+ LoadDASH( (const char *)ptr, size, url, inventory );
+ }
free( ptr );
}
}
-
+
void TestMultiPeriodFF( void )
{
Flush();
@@ -1657,14 +1755,14 @@ class AppContext
prefix,
periodInfo->baseUrl,
representationID );
- video.EnqueueSegment( new TrackFragment( 0, path, SEGMENT_DURATION_SECONDS ) );
+ video.EnqueueSegment( new TrackFragment( eMEDIATYPE_VIDEO, 0, path, SEGMENT_DURATION_SECONDS ) );
if( first )
{ // configure pipeline
pipelineContext.pipeline->Configure( eMEDIATYPE_VIDEO );
#ifdef REALTEK_HACK
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
#else
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PAUSED);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PAUSED);
#endif
first = false;
}
@@ -1677,15 +1775,15 @@ class AppContext
representationID,
fragmentNumber );
double pts = fragmentNumber*fragmentDuration;
- video.EnqueueSegment( new TrackFragment( 0, path, SEGMENT_DURATION_SECONDS ) ); // inject next iframe
+ video.EnqueueSegment( new TrackFragment( eMEDIATYPE_VIDEO, 0, path, SEGMENT_DURATION_SECONDS ) ); // inject next iframe
#ifdef REALTEK_HACK
- video.EnqueueSegment( new TrackFragment( path, 0 ) ); // inject next iframe
+ video.EnqueueSegment( new TrackFragment( eMEDIATYPE_VIDEO, path, 0 ) ); // inject next iframe
#endif
video.EnqueueControl( new TrackEOS() ); // inject EOS; needed for small segment to render
#ifdef REALTEK_HACK
- video.EnqueueControl( new TrackWaitState(ePIPELINeSTATE_PLAYING) ); // wait for segment to be visible
+ video.EnqueueControl( new TrackWaitState(ePIPELINE_STATE_PLAYING) ); // wait for segment to be visible
#else
- video.EnqueueControl( new TrackWaitState(ePIPELINeSTATE_PAUSED) ); // wait for segment to be visible
+ video.EnqueueControl( new TrackWaitState(ePIPELINE_STATE_PAUSED) ); // wait for segment to be visible
#endif
video.EnqueueControl( new TrackSleep( m_ff_delay ) );
video.EnqueueControl( new TrackFlush( 1, pts, -1, pts ) );
@@ -1847,23 +1945,23 @@ class AppContext
}
else if( strcmp(str,"ready")==0 )
{
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_READY);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_READY);
}
else if( strcmp(str,"pause")==0 )
{
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PAUSED);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PAUSED);
}
else if( strcmp(str,"play")==0 )
{
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_PLAYING);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_PLAYING);
}
else if( strcmp(str,"null")==0 )
{
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_NULL);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_NULL);
}
else if( strcmp(str,"stop")==0 )
{
- pipelineContext.pipeline->SetPipelineState(ePIPELINeSTATE_NULL);
+ pipelineContext.pipeline->SetPipelineState(ePIPELINE_STATE_NULL);
delete pipelineContext.pipeline;
pipelineContext.pipeline = new Pipeline( (class PipelineContext *)&pipelineContext );
}
@@ -2061,7 +2159,7 @@ int main(int argc, char **argv)
#if defined(__APPLE__) && defined (__GST_MACOS_H__)
// https://gstreamer.freedesktop.org/documentation/tutorials/basic/concepts.html?gi-language=c
return gst_macos_main((GstMainFunc)my_main, argc, argv, NULL);
-#else[
+#else
return my_main(argc,argv);
#endif
}
diff --git a/test/gstTestHarness/tsdemux.hpp b/test/gstTestHarness/tsdemux.hpp
index 3a83ce6..c9f6325 100644
--- a/test/gstTestHarness/tsdemux.hpp
+++ b/test/gstTestHarness/tsdemux.hpp
@@ -41,6 +41,7 @@ struct TsPart
class TsDemux
{
private:
+ MediaType mediaType;
unsigned char *ptr; // raw data (mpegts)
size_t len;
@@ -318,37 +319,68 @@ class TsDemux
void parsePMT()
{
parseSectionHeader( 0x02 );
- int reserved = readBits(3);
- assert( reserved == 0x07 );
+ int reserved = readBits(3); assert( reserved == 0x07 );
ts.pcr_pid = readBits( 13 );
- reserved = readBits( 4 );
- assert( reserved == 0xf );
- reserved = readBits( 2 ); // program_info_length_unused_bits
- assert( reserved == 0 );
+ reserved = readBits( 4 ); assert( reserved == 0xf );
+ reserved = readBits( 2 ); assert( reserved == 0 );
int program_info_length = readBits( 10 );
- for( int i=0; i(mLocation);
@@ -257,26 +291,16 @@ StoreImpl::StoreImpl(const Store::Config& config, LogFunction logger, LogLevel l
throw std::invalid_argument("Invalid minimum free space percentage");
}
- // Create the initial flush directory if it doesn't exist
- FS::path flushDir = mLocation / std::to_string(mFlushDirNum.load());
- if (!FS::create_directory(flushDir, ec) && ec.default_error_condition())
+ // Move any stale files / directories present in the storage due to a non clean shutdown.
+ for (const auto& dir_entry : FS::directory_iterator{mLocation})
{
- TSB_LOG_ERROR(mLogger, "Failed to create", "flushDir", flushDir, "errorCode", ec);
- throw std::invalid_argument("Failed to create flushDir");
- }
- else
- {
- // Move any stale files / directories present in the storage due to a non clean shutdown.
- for (const auto& dir_entry : FS::directory_iterator{mLocation})
+ if (dir_entry.path() != flushDir)
{
- if (dir_entry.path() != flushDir)
+ FS::rename(dir_entry.path(), flushDir / dir_entry.path().filename(), ec);
+ if (ec.default_error_condition())
{
- FS::rename(dir_entry.path(), flushDir / dir_entry.path().filename(), ec);
- if (ec.default_error_condition())
- {
- TSB_LOG_ERROR(mLogger, "Failed to move stale directory", "path",
- dir_entry.path(), "errorCode", ec);
- }
+ TSB_LOG_ERROR(mLogger, "Failed to move stale directory", "path",
+ dir_entry.path(), "errorCode", ec);
}
}
}
@@ -367,6 +391,7 @@ Status StoreImpl::WriteBuffer(const FS::path& path, const void* buffer, std::siz
do
{
FS::ofstream file;
+ std::error_code ec;
/* Set the buffer size to 0, so the data is not buffered.
* The client is writing one segment at a time. With that amount of data, using an
* intermediate buffer will only degrade performance and slow things down. */
@@ -379,56 +404,69 @@ Status StoreImpl::WriteBuffer(const FS::path& path, const void* buffer, std::siz
}
else
{
- file.write(static_cast(buffer), size);
- // The ofstream's bad bit is set on writing errors raised by the underlying
- // platform-specific implementation, such as ENOSPC. The ENOSPC checks below assume
- // that the implementation sets errno when such writing errors occur, which is
- // highly likely on Linux-based systems as they will be using the Linux C standard
- // library write() function. This behavior may not be portable to other systems.
- bool errnoSetFollowingWriteError = file.bad();
- if (file.fail() == false)
- {
- mAvailable -= size;
- TSB_LOG_TRACE(mLogger, "File written", "file", path,
- "fileSize", size, "availableSpace", mAvailable);
- retry = false;
- status = Status::OK;
- }
- else if ((timeWaited >= timeout) && errnoSetFollowingWriteError && (errno == ENOSPC))
+ // Set read and write permissions for all. This is necessary so other AAMP instances can
+ // delete the file, in case the first instance does not exit cleanly.
+ FS::perms permissions = FS::perms::owner_read | FS::perms::owner_write |
+ FS::perms::group_read | FS::perms::group_write |
+ FS::perms::others_read | FS::perms::others_write;
+ FS::permissions(path, permissions, ec);
+ if (ec)
{
- retry = false;
- TSB_LOG_ERROR(mLogger, "Not enough space to write - timed out", "file", path, "timeout", timeout.count());
- status = Status::NO_SPACE;
+ TSB_LOG_ERROR(mLogger, "Failed to set permissions", "file", path, "errorCode", ec);
}
- // Timeout, but the write failed for a reason other than ENOSPC
- else if (timeWaited >= timeout)
- {
- retry = false;
- TSB_LOG_ERROR(mLogger, "Failed to write - timed out", "file", path, "timeout", timeout.count(),
- "errno", std::strerror(errno));
- }
- else if (retry && errnoSetFollowingWriteError && (errno == ENOSPC))
- {
- TSB_LOG_TRACE(mLogger, "Not enough space to write - retrying...",
- "sleepTime", sleepTime.count(),
- "fileSize", size,
- "available", mAvailable,
- "errno", std::strerror(errno));
- FS::sleep_for(sleepTime);
- timeWaited += sleepTime;
- }
- else if (errnoSetFollowingWriteError && (errno == ENOSPC))
- {
- // This is a TRACE only, as the client can cull (delete files) and retry the Write
- TSB_LOG_TRACE(mLogger, "Not enough space to write", "file", path,
- "size", size);
- status = Status::NO_SPACE;
- }
- else // No timeout, but the write failed for a reason other than ENOSPC
+ else
{
- retry = false;
- TSB_LOG_ERROR(mLogger, "Failed to write to file", "file", path,
- "size", size, "errno", std::strerror(errno));
+ file.write(static_cast(buffer), size);
+ // The ofstream's bad bit is set on writing errors raised by the underlying
+ // platform-specific implementation, such as ENOSPC. The ENOSPC checks below assume
+ // that the implementation sets errno when such writing errors occur, which is
+ // highly likely on Linux-based systems as they will be using the Linux C standard
+ // library write() function. This behavior may not be portable to other systems.
+ bool errnoSetFollowingWriteError = file.bad();
+ if (file.fail() == false)
+ {
+ mAvailable -= size;
+ TSB_LOG_TRACE(mLogger, "File written", "file", path,
+ "fileSize", size, "availableSpace", mAvailable);
+ retry = false;
+ status = Status::OK;
+ }
+ else if ((timeWaited >= timeout) && errnoSetFollowingWriteError && (errno == ENOSPC))
+ {
+ retry = false;
+ TSB_LOG_ERROR(mLogger, "Not enough space to write - timed out", "file", path, "timeout", timeout.count());
+ status = Status::NO_SPACE;
+ }
+ // Timeout, but the write failed for a reason other than ENOSPC
+ else if (timeWaited >= timeout)
+ {
+ retry = false;
+ TSB_LOG_ERROR(mLogger, "Failed to write - timed out", "file", path, "timeout", timeout.count(),
+ "errno", std::strerror(errno));
+ }
+ else if (retry && errnoSetFollowingWriteError && (errno == ENOSPC))
+ {
+ TSB_LOG_TRACE(mLogger, "Not enough space to write - retrying...",
+ "sleepTime", sleepTime.count(),
+ "fileSize", size,
+ "available", mAvailable,
+ "errno", std::strerror(errno));
+ FS::sleep_for(sleepTime);
+ timeWaited += sleepTime;
+ }
+ else if (errnoSetFollowingWriteError && (errno == ENOSPC))
+ {
+ // This is a TRACE only, as the client can cull (delete files) and retry the Write
+ TSB_LOG_TRACE(mLogger, "Not enough space to write", "file", path,
+ "size", size);
+ status = Status::NO_SPACE;
+ }
+ else // No timeout, but the write failed for a reason other than ENOSPC
+ {
+ retry = false;
+ TSB_LOG_ERROR(mLogger, "Failed to write to file", "file", path,
+ "size", size, "errno", std::strerror(errno));
+ }
}
file.close();
@@ -479,11 +517,9 @@ Status StoreImpl::Write(const std::string& url, const void* buffer, std::size_t
"availableSpace", mAvailable);
returnStatus = Status::NO_SPACE;
}
- else if (!FS::create_directories(path.parent_path(), ec) &&
- ec.default_error_condition())
+ else if (!CreateDirectoriesWithPermissions(path.parent_path()))
{
- TSB_LOG_ERROR(mLogger, "Failed to create directory", "directory",
- path.parent_path(), "errorCode", ec);
+ TSB_LOG_ERROR(mLogger, "Failed to create directory", "directory", path.parent_path());
}
else
{
diff --git a/tsb/src/fs/TsbFs.h b/tsb/src/fs/TsbFs.h
index 2b4cb15..729a8ea 100644
--- a/tsb/src/fs/TsbFs.h
+++ b/tsb/src/fs/TsbFs.h
@@ -35,18 +35,19 @@ namespace FS
using std::ofstream;
using std::ifstream;
-using std::filesystem::exists;
-using std::filesystem::file_size;
-using std::filesystem::remove;
-using std::filesystem::space;
+using std::filesystem::create_directory;
using std::filesystem::directory_entry;
using std::filesystem::directory_iterator;
+using std::filesystem::exists;
+using std::filesystem::file_size;
using std::filesystem::path;
-using std::filesystem::space_info;
-using std::filesystem::create_directories;
-using std::filesystem::create_directory;
+using std::filesystem::permissions;
+using std::filesystem::perms;
+using std::filesystem::remove;
using std::filesystem::remove_all;
using std::filesystem::rename;
+using std::filesystem::space;
+using std::filesystem::space_info;
using std::this_thread::sleep_for;
diff --git a/tsprocessor.cpp b/tsprocessor.cpp
index f10ad77..2d07d9d 100644
--- a/tsprocessor.cpp
+++ b/tsprocessor.cpp
@@ -386,6 +386,7 @@ void TSProcessor::processPMTSection(unsigned char* section, int sectionLength)
char work[32];
StreamOutputFormat videoFormat = FORMAT_INVALID;
StreamOutputFormat audioFormat = FORMAT_INVALID;
+ bool cueiDescriptorFound = false;
int version = ((section[2] >> 1) & 0x1F);
int pcrPid = (((section[5] & 0x1F) << 8) + section[6]);
@@ -409,10 +410,30 @@ void TSProcessor::processPMTSection(unsigned char* section, int sectionLength)
videoComponentCount = audioComponentCount = 0;
m_dsmccComponentFound = false;
+ //program info descriptors
+ unsigned char *esInfo = section + 9;
+ unsigned char *esInfoEnd = esInfo + infoLength;
+ while (esInfo < esInfoEnd)
+ {
+ /*If the PMT program_info loop carries a registration descriptor (tag = 0x05)
+ and the registration descriptor carries a format_identifier attribute with value of "0x43554549" (as per ANSI/SCTE 35 2019a), then the corresponding ES with stream_type as "0x86" is an ES carrying SCTE-35 payload */
+ int descriptorTag = esInfo[0];
+ int descriptorLength = esInfo[1];
+ AAMPLOG_INFO("program info descriptors : descriptorTag 0x%x descriptorLength %d", descriptorTag ,descriptorLength);
+ if (descriptorTag == 0x05 && descriptorLength >= 4 &&
+ esInfo[2] == 'C' && esInfo[3] == 'U' && esInfo[4] == 'E' && esInfo[5] == 'I')
+ {
+ AAMPLOG_INFO("Found SCTE-35 descriptor (CUEI)");
+ cueiDescriptorFound = true;
+ }
+ // move to the next descriptor
+ esInfo += 2 + descriptorLength; // 2 - descriptor tag and descriptor length bytes
+ }
// Program loop starts after program info descriptor and continues
// to the CRC at the end of the section
programInfo = §ion[9 + infoLength];
programInfoEnd = section + sectionLength - 4;
+
while (programInfo < programInfoEnd)
{
streamType = programInfo[0];
@@ -498,6 +519,12 @@ void TSProcessor::processPMTSection(unsigned char* section, int sectionLength)
case eSTREAM_TYPE_LPCM_AUDIO:
case eSTREAM_TYPE_ATSC_AC3PLUS:
case eSTREAM_TYPE_DTSHD_AUDIO:
+ if (cueiDescriptorFound && streamType == eSTREAM_TYPE_DTSHD_AUDIO)
+ {
+ // Skip processing for DTSHD_AUDIO(0x86) if cueiDescriptorFound is true , since it is SCTE-35 data
+ AAMPLOG_INFO(" Stream Type : SCTE-35");
+ break;
+ }
case eSTREAM_TYPE_ATSC_EAC3:
case eSTREAM_TYPE_DTS_AUDIO:
case eSTREAM_TYPE_AC3_AUDIO: