--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/videofeeds/server/IptvScheduledDownload/src/iptvvodscheduleddownloadactivescheduler.cpp Mon Jan 18 20:21:12 2010 +0200
@@ -0,0 +1,574 @@
+/*
+* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Scheduled download scheduler active object.*
+*/
+
+
+
+
+#include <ipvideo/CCseScheduledProgram.h>
+#include <ipvideo/CCseSchedulerAPI.h>
+#include "IptvDebug.h"
+#include <e32math.h>
+#include <s32mem.h>
+#include "IptvEngineUids.h"
+
+#include "iptvvodscheduleddownloadactivescheduler.h"
+#include "iptvvodscheduleddownloadscheduler.h"
+
+// CONSTANTS
+const TInt KIptvNumberOfDaysToSchedule(7); // Days to schedule
+const TInt KIptvMorningStartHour = 6;
+const TInt KIptvNoonStartHour = 11;
+const TInt KIptvAfternoonStartHour = 13;
+const TInt KIptvEveningStartHour = 18;
+const TInt KIptvTenPercentDivider = 10;
+const TInt KIptvTwiceTenPercent = 2;
+
+//#define RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC
+
+#ifdef RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC
+#warning The scheduled download test flag has been defined! Do not release this build!
+const TInt KIptvDayMonthAdvance = 1;
+#endif // RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC
+
+#if defined(_DEBUG) && ! defined(RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC)
+const TInt KIptvDayMonthAdvanceDebug = 1;
+#endif // _DEBUG && ! RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC
+
+#ifdef RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC
+const TInt KIptv30SecondsStartDelay = 30;
+const TInt Kiptv60MinutesTestSlot = 60;
+#endif // RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC
+
+#if defined(RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC) || defined(_DEBUG)
+const TInt KIptvDebugStringLength = 80;
+#endif // RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC || _DEBUG
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::CIptvVODScheduledDownloadActiveScheduler
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CIptvVODScheduledDownloadActiveScheduler::CIptvVODScheduledDownloadActiveScheduler(
+ CIptvVODScheduledDownloadScheduler& aScheduler,
+ TIptvServiceId aServiceId,
+ TIptvVodScheduleConnectionCondition aNetworkCondition,
+ TIptvVodScheduleDownloadtimeCombination aDownloadTime,
+ TIptvVodScheduleDownloadTypeCombination aDownloadType )
+ : CTimer( EPriorityNormal ), iScheduler( aScheduler ),
+ iServiceId( aServiceId ), iNetworkCondition( aNetworkCondition ),
+ iDownloadTime( aDownloadTime ), iDownloadType( aDownloadType )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CIptvVODScheduledDownloadActiveScheduler::ConstructL()
+ {
+ IPTVLOGSTRING_HIGH_LEVEL(">>> CIptvVODScheduledDownloadActiveScheduler::ConstructL()");
+
+ CTimer::ConstructL();
+ CActiveScheduler::Add ( this );
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::ConstructL()");
+ }
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CIptvVODScheduledDownloadActiveScheduler* CIptvVODScheduledDownloadActiveScheduler::NewL(
+ CIptvVODScheduledDownloadScheduler& aScheduler,
+ TIptvServiceId aServiceId,
+ TIptvVodScheduleConnectionCondition aNetworkCondition,
+ TIptvVodScheduleDownloadtimeCombination aDownloadTime,
+ TIptvVodScheduleDownloadTypeCombination aDownloadType )
+ {
+ IPTVLOGSTRING_HIGH_LEVEL(">>> CIptvVODScheduledDownloadActiveScheduler::NewL()");
+ CIptvVODScheduledDownloadActiveScheduler* self =
+ new( ELeave ) CIptvVODScheduledDownloadActiveScheduler(
+ aScheduler,
+ aServiceId,
+ aNetworkCondition,
+ aDownloadTime,
+ aDownloadType );
+
+ CleanupStack::PushL( self );
+ self->ConstructL();
+ CleanupStack::Pop( self );
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::NewL()");
+
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// Destructor
+// -----------------------------------------------------------------------------
+//
+CIptvVODScheduledDownloadActiveScheduler::~CIptvVODScheduledDownloadActiveScheduler()
+ {
+ IPTVLOGSTRING_HIGH_LEVEL(">>> CIptvVODScheduledDownloadActiveScheduler::~CIptvVODScheduledDownloadActiveScheduler()");
+
+ // Remove us from the list
+ iScheduler.RemoveActive( this );
+
+ delete iCse;
+ iScheduledDownloads.ResetAndDestroy();
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::~CIptvVODScheduledDownloadActiveScheduler()");
+ }
+
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::RunL
+// -----------------------------------------------------------------------------
+//
+void CIptvVODScheduledDownloadActiveScheduler::RunL()
+ {
+ IPTVLOGSTRING_HIGH_LEVEL(">>> CIptvVODScheduledDownloadActiveScheduler::RunL()");
+
+ CleanupStack::PushL( this );
+
+ // This must be done here and not in the constructor, because the plugin
+ // will cause the creation of this instance and the next call will cause
+ // deadlock if this is in the constructor
+ if (!iCse)
+ {
+ iCse = CCseSchedulerApi::NewL();
+ }
+
+ TRAP_IGNORE( UpdateScheduleL() );
+
+ // This will DESTROY us, don't do anything after this
+ CleanupStack::PopAndDestroy( this );
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::RunL()");
+ }
+
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::UpdateScheduleL
+// -----------------------------------------------------------------------------
+//
+void CIptvVODScheduledDownloadActiveScheduler::UpdateScheduleL()
+ {
+ IPTVLOGSTRING2_HIGH_LEVEL("CIptvVODScheduledDownloadActiveScheduler::UpdateScheduleL(), service %d", iServiceId);
+
+ // Just in case, reset the schedules
+ iScheduledDownloads.ResetAndDestroy();
+
+ // Get current schedules
+ User::LeaveIfError(
+ iCse->GetSchedulesByPluginUid(
+ KIptvScheduledDownloadPluginImplementationUid,
+ iScheduledDownloads ) );
+
+ // Remove from array schedules which are not for this service or app uid
+ for (TInt i = iScheduledDownloads.Count() - 1; i >= 0; i--)
+ {
+ if (GetServiceIdFromScheduledProgramL( *(iScheduledDownloads[i] ) ) !=
+ iServiceId || iScheduledDownloads[i]->AppUid() != IPTV_SERVER_UID)
+ {
+ delete iScheduledDownloads[i];
+ iScheduledDownloads.Remove( i );
+ }
+ }
+
+ // If manual update, no schedule or no download,
+ // remove all schedules from CSE
+ if (iNetworkCondition == EManual ||
+ iDownloadTime == ENoSchedule ||
+ iDownloadType == ENoDownload)
+ {
+ IPTVLOGSTRING_HIGH_LEVEL("CIptvVODScheduledDownloadActiveScheduler::UpdateScheduleL() removing all schedules");
+
+ // Remove all schedules
+ for (TInt i = 0; i < iScheduledDownloads.Count(); i++)
+ {
+ User::LeaveIfError( iCse->RemoveSchedule(
+ iScheduledDownloads[i]->DbIdentifier() ) );
+ }
+ }
+ else
+ {
+ // Reschedule the schedules
+ ReScheduleL();
+ }
+
+ iScheduledDownloads.ResetAndDestroy();
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::UpdateScheduleL()");
+ }
+
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::ReScheduleL
+// -----------------------------------------------------------------------------
+//
+void CIptvVODScheduledDownloadActiveScheduler::ReScheduleL()
+ {
+ IPTVLOGSTRING_HIGH_LEVEL(">>> CIptvVODScheduledDownloadActiveScheduler::ReScheduleL()");
+
+ // Create all time slots
+ RArray<TScheduleSlot> scheduleSlots;
+ CleanupClosePushL(scheduleSlots);
+ BuildScheduleSlotsL( scheduleSlots );
+
+ // Go through the scheduled downloads, try to find a place for them
+ for (TInt i = 0; i < iScheduledDownloads.Count(); i++)
+ {
+ CCseScheduledProgram* schedule = iScheduledDownloads[i];
+ TTime& scheduleTime = schedule->StartTime();
+
+ // Go through the schedule slots and
+ // try to find place for the schedule
+ for (TInt j = 0; j < scheduleSlots.Count(); j++)
+ {
+ TScheduleSlot& slot = scheduleSlots[j];
+ if (slot.iStartTime <= scheduleTime &&
+ slot.iEndTime > scheduleTime)
+ {
+ // Slot found, we can finish the loop after handling this
+ j = scheduleSlots.Count();
+
+ // Should there be a schedule and if so, is it empty
+ if (slot.iShouldHaveSchedule && !slot.iAlreadyHasSchedule)
+ {
+ // Suitable empty slot found
+ slot.iAlreadyHasSchedule = ETrue;
+ }
+ else
+ {
+ // Slot should not have schedule or it already has a
+ // schedule, cancel this
+ User::LeaveIfError(
+ iCse->RemoveSchedule( schedule->DbIdentifier() ) );
+ }
+ }
+ }
+ }
+
+#ifdef RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC // this is just for test
+
+ CCseScheduledProgram* newSchedule = CCseScheduledProgram::NewL();
+ CleanupStack::PushL( newSchedule );
+
+ TTime start;
+ start.UniversalTime();
+ start += TTimeIntervalSeconds( KIptv30SecondsStartDelay );
+
+ newSchedule->SetStartTime( start );
+ start += TTimeIntervalMinutes( Kiptv60MinutesTestSlot );
+ newSchedule->SetEndTime( start );
+ newSchedule->SetAppUid( IPTV_SERVER_UID );
+ newSchedule->SetPluginUid(
+ KIptvScheduledDownloadPluginImplementationUid );
+ newSchedule->SetScheduleType(
+ CCseScheduledProgram::ECseScheduleDownload );
+ HBufC8* data = WriteApplicationDataL();
+ CleanupStack::PushL( data );
+ newSchedule->SetApplicationDataL( data->Des() );
+ CleanupStack::PopAndDestroy( data );
+
+ User::LeaveIfError( iCse->AddSchedule( *newSchedule ) );
+
+ TDateTime date( start.DateTime() );
+ _LIT( KTimeFormat, "Scheduled download for service %d at %d.%d.%d %d:%d, 30s test schedule" );
+ TBuf<KIptvDebugStringLength> buffer;
+ buffer.Format(
+ KTimeFormat,
+ iServiceId,
+ date.Day() + KIptvDayMonthAdvance,
+ date.Month() + KIptvDayMonthAdvance,
+ date.Year(),
+ date.Hour(),
+ date.Minute() );
+ IPTVLOGTEXT_HIGH_LEVEL( buffer );
+
+ CleanupStack::PopAndDestroy( newSchedule );
+
+#else // RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC, this is normal case
+
+ // All schedules in the CSE have been checked,
+ // now check if we need to add
+ for (TInt k = 0; k < scheduleSlots.Count(); k++)
+ {
+ TScheduleSlot& slot = scheduleSlots[k];
+
+ // Should we have schedule here and we don't have
+ if (slot.iShouldHaveSchedule && !slot.iAlreadyHasSchedule)
+ {
+ // We need to add new schedule here
+ CCseScheduledProgram* newSchedule =
+ CCseScheduledProgram::NewL();
+ CleanupStack::PushL( newSchedule );
+ // Randomize the run time
+ newSchedule->SetStartTime( RandomizeRunTime( slot ) );
+ newSchedule->SetEndTime( slot.iEndTime );
+ newSchedule->SetAppUid( IPTV_SERVER_UID );
+ newSchedule->SetPluginUid(
+ KIptvScheduledDownloadPluginImplementationUid );
+ newSchedule->SetScheduleType(
+ CCseScheduledProgram::ECseScheduleDownload );
+ HBufC8* data = WriteApplicationDataL();
+ CleanupStack::PushL( data );
+ newSchedule->SetApplicationDataL( data->Des() );
+ CleanupStack::PopAndDestroy( data );
+
+ User::LeaveIfError( iCse->AddSchedule( *newSchedule ) );
+
+#ifdef _DEBUG
+ // Print time for debugging purpose
+ TDateTime date( newSchedule->StartTime().DateTime() );
+ _LIT( KTimeFormat, "Scheduled download for service %d at %d.%d.%d %d:%d" );
+ TBuf<KIptvDebugStringLength> buffer;
+ buffer.Format(
+ KTimeFormat,
+ iServiceId,
+ date.Day() + KIptvDayMonthAdvanceDebug,
+ date.Month() + KIptvDayMonthAdvanceDebug,
+ date.Year(),
+ date.Hour(),
+ date.Minute() );
+ IPTVLOGTEXT_HIGH_LEVEL( buffer );
+#endif
+
+ CleanupStack::PopAndDestroy( newSchedule );
+ }
+ }
+
+#endif // RD_IPTV_FEA_SCHEDULE_DOWNLOAD_IN_30_SEC
+
+ CleanupStack::PopAndDestroy( &scheduleSlots );
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::ReScheduleL()");
+ }
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::BuildScheduleSlotsL
+// -----------------------------------------------------------------------------
+//
+void CIptvVODScheduledDownloadActiveScheduler::BuildScheduleSlotsL(
+ RArray<TScheduleSlot>& aScheduleSlots ) const
+ {
+ IPTVLOGSTRING_HIGH_LEVEL(">>> CIptvVODScheduledDownloadActiveScheduler::BuildScheduleSlotsL()");
+
+ TTime now;
+ now.UniversalTime();
+ TTime homeNow;
+ homeNow.HomeTime();
+ TTimeIntervalMicroSeconds homeUtcDiff = homeNow.MicroSecondsFrom( now );
+
+ aScheduleSlots.Reset();
+
+ // Set the seconds, minutes and micros to zero
+ TDateTime start = now.DateTime();
+ start.SetMinute( 0 );
+ start.SetSecond( 0 );
+ start.SetMicroSecond( 0 );
+
+ // Set slot start time for today in correct time
+ start.SetHour( 0 );
+ TTime night( start );
+ night -= homeUtcDiff; // change to UTC
+
+ start.SetHour( KIptvMorningStartHour );
+ TTime morning( start );
+ morning -= homeUtcDiff; // change to UTC
+
+ start.SetHour( KIptvNoonStartHour );
+ TTime noon( start );
+ noon -= homeUtcDiff; // change to UTC
+
+ start.SetHour( KIptvAfternoonStartHour );
+ TTime afternoon( start );
+ afternoon -= homeUtcDiff; // change to UTC
+
+ start.SetHour( KIptvEveningStartHour );
+ TTime evening( start );
+ evening -= homeUtcDiff; // change to UTC
+
+ // Create slots for KIptvNumberOfDaysToSchedule days
+ for (TInt i = 0; i < KIptvNumberOfDaysToSchedule; i++)
+ {
+ User::LeaveIfError( aScheduleSlots.Append(
+ TScheduleSlot( night, morning, iDownloadTime & ENight ) ) );
+ User::LeaveIfError( aScheduleSlots.Append(
+ TScheduleSlot( morning, noon, iDownloadTime & EMorning ) ) );
+ User::LeaveIfError( aScheduleSlots.Append(
+ TScheduleSlot( noon, afternoon, iDownloadTime & ENoon ) ) );
+ User::LeaveIfError( aScheduleSlots.Append(
+ TScheduleSlot(
+ afternoon,
+ evening,
+ iDownloadTime & EAfternoon ) ) );
+ User::LeaveIfError( aScheduleSlots.Append(
+ TScheduleSlot(
+ evening,
+ night + TTimeIntervalDays(1),
+ iDownloadTime & EEvening ) ) );
+
+ // Advance one day
+ night += TTimeIntervalDays(1);
+ morning += TTimeIntervalDays(1);
+ noon += TTimeIntervalDays(1);
+ afternoon += TTimeIntervalDays(1);
+ evening += TTimeIntervalDays(1);
+ }
+
+ // Some schedules may be in the past, remove them
+ for (TInt i = 0; i < aScheduleSlots.Count(); i++)
+ {
+ if (now > aScheduleSlots[i].iEndTime)
+ {
+ aScheduleSlots.Remove( i );
+ i--;
+ }
+ }
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::BuildScheduleSlotsL()");
+ }
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::GetServiceIdFromScheduledProgramL
+// -----------------------------------------------------------------------------
+//
+TIptvServiceId CIptvVODScheduledDownloadActiveScheduler::GetServiceIdFromScheduledProgramL(
+ CCseScheduledProgram& aProgram ) const
+ {
+ return ReadApplicationDataL( aProgram.ApplicationData() );
+ }
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::WriteApplicationDataL
+// -----------------------------------------------------------------------------
+//
+HBufC8* CIptvVODScheduledDownloadActiveScheduler::WriteApplicationDataL() const
+ {
+ IPTVLOGSTRING_HIGH_LEVEL(">>> CIptvVODScheduledDownloadActiveScheduler::WriteApplicationDataL()");
+
+ HBufC8* data = HBufC8::NewLC( sizeof(TIptvServiceId) );
+ TPtr8 dataPtr( data->Des() );
+
+ RDesWriteStream writeStream;
+ CleanupClosePushL( writeStream );
+ writeStream.Open( dataPtr );
+ writeStream.WriteUint32L( iServiceId );
+ CleanupStack::PopAndDestroy( &writeStream );
+
+ CleanupStack::Pop( data );
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::WriteApplicationDataL()");
+
+ return data;
+ }
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::ReadApplicationDataL
+// -----------------------------------------------------------------------------
+//
+TIptvServiceId CIptvVODScheduledDownloadActiveScheduler::ReadApplicationDataL(
+ TPtrC8 aDataPtr ) const
+ {
+ IPTVLOGSTRING_HIGH_LEVEL(">>> CIptvVODScheduledDownloadActiveScheduler::ReadApplicationDataL()");
+
+ RDesReadStream readStream;
+ CleanupClosePushL( readStream );
+ readStream.Open( aDataPtr );
+ TIptvServiceId serviceId = readStream.ReadUint32L();
+ CleanupStack::PopAndDestroy( &readStream );
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::ReadApplicationDataL()");
+
+ return serviceId;
+ }
+
+// -----------------------------------------------------------------------------
+// CIptvVODScheduledDownloadActiveScheduler::RandomizeRunTime
+// -----------------------------------------------------------------------------
+//
+TTime CIptvVODScheduledDownloadActiveScheduler::RandomizeRunTime(
+ const TScheduleSlot& aSlot ) const
+ {
+ IPTVLOGSTRING_HIGH_LEVEL(">>> CIptvVODScheduledDownloadActiveScheduler::RandomizeRunTime()");
+
+ TTime start;
+ start.UniversalTime();
+ TBool moveStart = EFalse;
+
+ // Earliest start is either slot start or current time
+ if (start < aSlot.iStartTime)
+ {
+ start = aSlot.iStartTime;
+ moveStart = ETrue;
+ }
+
+ // Get difference in minutes
+ TTimeIntervalMinutes diffMinutes;
+ aSlot.iEndTime.MinutesFrom( start, diffMinutes );
+
+ // If the end time is earlier than start time, just use the start time
+ if (diffMinutes.Int() < 0)
+ {
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::RandomizeRunTime()");
+ return start;
+ }
+
+ TInt diff = diffMinutes.Int();
+
+ TTime retVal( start.Int64() );
+ TInt32 tenPercent = diff / KIptvTenPercentDivider;
+ TTimeIntervalMinutes tenPercentMinutes( tenPercent );
+
+ // Start time is moved 10% forward if the start time is now
+ if (moveStart)
+ {
+ diff -= tenPercent;
+ retVal += tenPercentMinutes;
+ }
+
+ // Start it at least 20% before the end time
+ diff -= KIptvTwiceTenPercent * tenPercent;
+
+ // Randomize the differences
+ TUint32 random = Math::Random();
+ TUint64 resultRandom =
+ (TUint64(random) * TUint64(diff)) / TUint64(KMaxTUint32);
+
+ TTimeIntervalMinutes randomMinutes( resultRandom );
+
+ // Move random time to forward
+ retVal += randomMinutes;
+
+ // Note: We need to set microseconds to zero because for some reason schedule
+ // data reading from CSE database does not work correctly in E90 if microsecond
+ // component is set to non-zero value.
+ TDateTime fixedDate = retVal.DateTime();
+ fixedDate.SetMicroSecond( 0 );
+ TTime retValWithoutMicroSeconds( fixedDate );
+
+ IPTVLOGSTRING_HIGH_LEVEL("<<< CIptvVODScheduledDownloadActiveScheduler::RandomizeRunTime()");
+
+ return retValWithoutMicroSeconds;
+ }
+
+
+// End of File