nsresult WMFReader::SeekInternal(int64_t aTargetUs) { DECODER_LOG("WMFReader::Seek() %lld", aTargetUs); MOZ_ASSERT(OnTaskQueue()); #ifdef DEBUG bool canSeek = false; GetSourceReaderCanSeek(mSourceReader, canSeek); NS_ASSERTION(canSeek, "WMFReader::Seek() should only be called if we can seek!"); #endif nsresult rv = ResetDecode(); NS_ENSURE_SUCCESS(rv, rv); // Mark that we must recapture the audio frame count from the next sample. // WMF doesn't set a discontinuity marker when we seek to time 0, so we // must remember to recapture the audio frame offset and reset the frame // sum on the next audio packet we decode. mMustRecaptureAudioPosition = true; AutoPropVar var; HRESULT hr = InitPropVariantFromInt64(UsecsToHNs(aTargetUs), &var); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); hr = mSourceReader->SetCurrentPosition(GUID_NULL, var); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); return NS_OK; }
/* EW: This is part of the fix for seeking because calling SetCurrentPosition was failing. It is now split up to set a flag that seeking needs to be done, and we call this at a time that seems to work (in the read). */ static void Internal_DoSeek(Sound_Sample* sample) { Sound_SampleInternal *internal = (Sound_SampleInternal *) sample->opaque; MediaFoundationFileContainer* media_foundation_file_container = (MediaFoundationFileContainer*)internal->decoder_private; __int64 mf_seek_target = media_foundation_file_container->seekTargetPosition; PROPVARIANT prop_variant; HRESULT hr = S_OK; // this doesn't fail, see MS's implementation hr = InitPropVariantFromInt64(mf_seek_target, &prop_variant); // http://msdn.microsoft.com/en-us/library/dd374668(v=VS.85).aspx hr = media_foundation_file_container->sourceReader->SetCurrentPosition(GUID_NULL, prop_variant); if(FAILED(hr)) { // nothing we can do here as we can't fail (no facility to other than // crashing mixxx) // sample->flags |= SOUND_SAMPLEFLAG_ERROR; // more C++ BS sample->flags = (SoundDecoder_SampleFlags)(sample->flags | SOUND_SAMPLEFLAG_ERROR); if (hr == MF_E_INVALIDREQUEST) { SNDERR("WindowsMediaFoundation failed to seek: Sample requests still pending\n"); } else { SNDERR("WindowsMediaFoundation failed to seek\n"); } } PropVariantClear(&prop_variant); }
nsresult WMFReader::Seek(int64_t aTargetUs, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { LOG("WMFReader::Seek() %lld", aTargetUs); NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); if (!mCanSeek) { return NS_ERROR_FAILURE; } nsresult rv = ResetDecode(); NS_ENSURE_SUCCESS(rv, rv); AutoPropVar var; HRESULT hr = InitPropVariantFromInt64(UsecsToHNs(aTargetUs), &var); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); hr = mSourceReader->SetCurrentPosition(GUID_NULL, var); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); return DecodeToTarget(aTargetUs); }
/*virtual */bool MFMovieSource::Jump(long long frameNo) { PROPVARIANT prop; InitPropVariantFromInt64(frameNo, &prop); this->_reader->SetCurrentPosition(GUID_NULL, prop); PropVariantClear(&prop); long long time = 0; auto img = this->Read((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, &time); return !!img; }/*
SINT SoundSourceMediaFoundation::seekSampleFrame( SINT frameIndex) { DEBUG_ASSERT(isValidFrameIndex(frameIndex)); if (sDebug) { qDebug() << "seekSampleFrame()" << frameIndex; } qint64 mfSeekTarget(mfFromFrame(frameIndex, getSamplingRate()) - 1); // minus 1 here seems to make our seeking work properly, otherwise we will // (more often than not, maybe always) seek a bit too far (although not // enough for our calculatedFrameFromMF <= nextFrame assertion in ::read). // Has something to do with 100ns MF units being much smaller than most // frame offsets (in seconds) -bkgood SINT result = m_iCurrentPosition; if (m_dead) { return result; } PROPVARIANT prop; HRESULT hr; // this doesn't fail, see MS's implementation hr = InitPropVariantFromInt64(mfSeekTarget < 0 ? 0 : mfSeekTarget, &prop); hr = m_pReader->Flush(MF_SOURCE_READER_FIRST_AUDIO_STREAM); if (FAILED(hr)) { qWarning() << "SSMF: failed to flush before seek"; } // http://msdn.microsoft.com/en-us/library/dd374668(v=VS.85).aspx hr = m_pReader->SetCurrentPosition(GUID_NULL, prop); if (FAILED(hr)) { // nothing we can do here as we can't fail (no facility to other than // crashing mixxx) qWarning() << "SSMF: failed to seek" << (hr == MF_E_INVALIDREQUEST ? "Sample requests still pending" : ""); } else { result = frameIndex; } PropVariantClear(&prop); // record the next frame so that we can make sure we're there the next // time we get a buffer from MFSourceReader m_nextFrame = frameIndex; m_seeking = true; m_iCurrentPosition = result; return result; }
SINT SoundSourceMediaFoundation::seekSampleFrame( SINT frameIndex) { DEBUG_ASSERT(isValidFrameIndex(m_currentFrameIndex)); if (frameIndex >= getMaxFrameIndex()) { // EOF m_currentFrameIndex = getMaxFrameIndex(); return m_currentFrameIndex; } if (frameIndex > m_currentFrameIndex) { // seeking forward SINT skipFramesCount = frameIndex - m_currentFrameIndex; // When to prefer skipping over seeking: // 1) The sample buffer would be discarded before seeking anyway and // skipping those already decoded samples effectively costs nothing // 2) After seeking we need to decode at least kNumberOfPrefetchFrames // before reaching the actual target position -> Only seek if we // need to decode more than 2 * kNumberOfPrefetchFrames frames // while skipping SINT skipFramesCountMax = samples2frames(m_sampleBuffer.getSize()) + 2 * kNumberOfPrefetchFrames; if (skipFramesCount <= skipFramesCountMax) { skipSampleFrames(skipFramesCount); } } if (frameIndex == m_currentFrameIndex) { return m_currentFrameIndex; } // Discard decoded samples m_sampleBuffer.reset(); // Invalidate current position (end of stream) m_currentFrameIndex = getMaxFrameIndex(); if (m_pSourceReader == nullptr) { // reader is dead return m_currentFrameIndex; } // Jump to a position before the actual seeking position. // Prefetching a certain number of frames is necessary for // sample accurate decoding. The decoder needs to decode // some frames in advance to produce the same result at // each position in the stream. SINT seekIndex = std::max(SINT(frameIndex - kNumberOfPrefetchFrames), AudioSource::getMinFrameIndex()); LONGLONG seekPos = m_streamUnitConverter.fromFrameIndex(seekIndex); DEBUG_ASSERT(seekPos >= 0); PROPVARIANT prop; HRESULT hrInitPropVariantFromInt64 = InitPropVariantFromInt64(seekPos, &prop); DEBUG_ASSERT(SUCCEEDED(hrInitPropVariantFromInt64)); // never fails HRESULT hrSetCurrentPosition = m_pSourceReader->SetCurrentPosition(GUID_NULL, prop); PropVariantClear(&prop); if (SUCCEEDED(hrSetCurrentPosition)) { // NOTE(uklotzde): After SetCurrentPosition() the actual position // of the stream is unknown until reading the next samples from // the reader. Please note that the first sample decoded after // SetCurrentPosition() may start BEFORE the actual target position. // See also: https://msdn.microsoft.com/en-us/library/windows/desktop/dd374668(v=vs.85).aspx // "The SetCurrentPosition method does not guarantee exact seeking." ... // "After seeking, the application should call IMFSourceReader::ReadSample // and advance to the desired position. SINT skipFramesCount = frameIndex - seekIndex; if (skipFramesCount > 0) { // We need to fetch at least 1 sample from the reader to obtain the // current position! skipSampleFrames(skipFramesCount); // Now m_currentFrameIndex reflects the actual position of the reader if (m_currentFrameIndex < frameIndex) { // Skip more samples if frameIndex has not yet been reached skipSampleFrames(frameIndex - m_currentFrameIndex); } if (m_currentFrameIndex != frameIndex) { qWarning() << kLogPreamble << "Seek to frame" << frameIndex << "failed"; // Jump to end of stream (= invalidate current position) m_currentFrameIndex = getMaxFrameIndex(); } } else { // We are at the beginning of the stream and don't need // to skip any frames. Calling IMFSourceReader::ReadSample // is not necessary in this special case. DEBUG_ASSERT(frameIndex == AudioSource::getMinFrameIndex()); m_currentFrameIndex = frameIndex; } } else { qWarning() << kLogPreamble << "IMFSourceReader::SetCurrentPosition() failed" << hrSetCurrentPosition; safeRelease(&m_pSourceReader); // kill the reader } return m_currentFrameIndex; }
// This routine initializes the sensor to its default properties NTSTATUS PedometerDevice::Initialize( _In_ WDFDEVICE Device, // WDFDEVICE object _In_ SENSOROBJECT SensorInstance // SENSOROBJECT for each sensor instance ) { ULONG Size = 0; WDF_OBJECT_ATTRIBUTES MemoryAttributes; WDFMEMORY MemoryHandle = NULL; FILETIME Time = {}; WDF_OBJECT_ATTRIBUTES TimerAttributes; WDF_TIMER_CONFIG TimerConfig; NTSTATUS Status = STATUS_SUCCESS; PHardwareSimulator pSimulator = nullptr; ULONG HistorySizeInRecords = 0; SENSOR_FunctionEnter(); // Store device and instance m_FxDevice = Device; m_SensorInstance = SensorInstance; m_Started = FALSE; m_HistoryRetrievalStarted = FALSE; // Initialize the pedometer simulator Status = HardwareSimulator::Initialize(Device, &m_SimulatorInstance); if (!NT_SUCCESS(Status)) { TraceError("PED %!FUNC! HardwareSimulator::Initialize failed %!STATUS!", Status); goto Exit; } pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance); if (nullptr == pSimulator) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); goto Exit; } // Create Lock Status = WdfWaitLockCreate(WDF_NO_OBJECT_ATTRIBUTES, &m_Lock); if (!NT_SUCCESS(Status)) { TraceError("PED %!FUNC! WdfWaitLockCreate failed %!STATUS!", Status); goto Exit; } // Create timer object for polling sensor samples WDF_TIMER_CONFIG_INIT(&TimerConfig, PedometerDevice::OnTimerExpire); WDF_OBJECT_ATTRIBUTES_INIT(&TimerAttributes); TimerAttributes.ParentObject = SensorInstance; TimerAttributes.ExecutionLevel = WdfExecutionLevelPassive; Status = WdfTimerCreate(&TimerConfig, &TimerAttributes, &m_Timer); if (!NT_SUCCESS(Status)) { TraceError("PED %!FUNC! WdfTimerCreate failed %!STATUS!", Status); goto Exit; } // Supported Data-Fields Size = SENSOR_PROPERTY_LIST_SIZE(PEDOMETER_DATAFIELD_COUNT); MemoryHandle = NULL; WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); MemoryAttributes.ParentObject = SensorInstance; Status = WdfMemoryCreate(&MemoryAttributes, PagedPool, SENSOR_POOL_TAG_PEDOMETER, Size, &MemoryHandle, reinterpret_cast<PVOID*>(&m_pSupportedDataFields)); if (!NT_SUCCESS(Status) || nullptr == m_pSupportedDataFields) { TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); goto Exit; } SENSOR_PROPERTY_LIST_INIT(m_pSupportedDataFields, Size); m_pSupportedDataFields->Count = PEDOMETER_DATAFIELD_COUNT; m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_TIMESTAMP] = PKEY_SensorData_Timestamp; m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_FIRST_AFTER_RESET] = PKEY_SensorData_PedometerReset; m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_STEP_TYPE] = PKEY_SensorData_PedometerStepType; m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_STEP_COUNT] = PKEY_SensorData_PedometerStepCount; m_pSupportedDataFields->List[PEDOMETER_DATAFIELD_STEP_DURATION] = PKEY_SensorData_PedometerStepDuration_Ms; // Data Size = SENSOR_COLLECTION_LIST_SIZE(PEDOMETER_DATA_COUNT); MemoryHandle = NULL; WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); MemoryAttributes.ParentObject = SensorInstance; Status = WdfMemoryCreate(&MemoryAttributes, PagedPool, SENSOR_POOL_TAG_PEDOMETER, Size, &MemoryHandle, reinterpret_cast<PVOID*>(&m_pData)); if (!NT_SUCCESS(Status) || nullptr == m_pData) { TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); goto Exit; } SENSOR_COLLECTION_LIST_INIT(m_pData, Size); m_pData->Count = PEDOMETER_DATA_COUNT; m_pData->List[PEDOMETER_DATA_TIMESTAMP].Key = PKEY_SensorData_Timestamp; GetSystemTimePreciseAsFileTime(&Time); InitPropVariantFromFileTime(&Time, &(m_pData->List[PEDOMETER_DATA_TIMESTAMP].Value)); m_pData->List[PEDOMETER_DATA_FIRST_AFTER_RESET].Key = PKEY_SensorData_PedometerReset; InitPropVariantFromBoolean(FALSE, &(m_pData->List[PEDOMETER_DATA_FIRST_AFTER_RESET].Value)); m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_TYPE].Key = PKEY_SensorData_PedometerStepType; InitPropVariantFromUInt32(static_cast<ULONG>(PedometerStepType_Unknown), &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_TYPE].Value)); m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_COUNT].Key = PKEY_SensorData_PedometerStepCount; InitPropVariantFromUInt32(600, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_COUNT].Value)); m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_DURATION].Key = PKEY_SensorData_PedometerStepDuration_Ms; InitPropVariantFromInt64(123, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_DURATION].Value)); m_pData->List[PEDOMETER_DATA_WALKING_STEP_TYPE].Key = PKEY_SensorData_PedometerStepType; InitPropVariantFromUInt32(static_cast<ULONG>(PedometerStepType_Walking), &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_TYPE].Value)); m_pData->List[PEDOMETER_DATA_WALKING_STEP_COUNT].Key = PKEY_SensorData_PedometerStepCount; InitPropVariantFromUInt32(700, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_COUNT].Value)); m_pData->List[PEDOMETER_DATA_WALKING_STEP_DURATION].Key = PKEY_SensorData_PedometerStepDuration_Ms; InitPropVariantFromInt64(456, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_DURATION].Value)); m_pData->List[PEDOMETER_DATA_RUNNING_STEP_TYPE].Key = PKEY_SensorData_PedometerStepType; InitPropVariantFromUInt32(static_cast<ULONG>(PedometerStepType_Running), &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_TYPE].Value)); m_pData->List[PEDOMETER_DATA_RUNNING_STEP_COUNT].Key = PKEY_SensorData_PedometerStepCount; InitPropVariantFromUInt32(800, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_COUNT].Value)); m_pData->List[PEDOMETER_DATA_RUNNING_STEP_DURATION].Key = PKEY_SensorData_PedometerStepDuration_Ms; InitPropVariantFromInt64(789, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_DURATION].Value)); m_LastSample.Timestamp = Time; m_LastSample.UnknownStepCount = 0; m_LastSample.UnknownStepDurationMs = 0; m_LastSample.WalkingStepCount = 0; m_LastSample.WalkingStepDurationMs = 0; m_LastSample.RunningStepCount = 0; m_LastSample.RunningStepDurationMs = 0; m_LastSample.IsFirstAfterReset = FALSE; // Get the History Size to populate 'PKEY_SensorHistory_MaxSize_Bytes' // Typically the size needed to store a history record on the hardware is // smaller than the size needed to represent a history record as a // SENSOR_COLLECTION_LIST (collection of SENSOR_VALUE_PAIRs) // To be able to accurately represent the size of the history on the // hardware (simulator in this case), get the number of records that the HW // can store and multiply it with the marshalled size of // SENSOR_COLLECTION_LIST needed to represent a single record. HistorySizeInRecords = pSimulator->GetHistorySizeInRecords(); m_HistorySupported = (HistorySizeInRecords > 0) ? TRUE : FALSE; // Pedometer History format is exactly same as it's data sample. // so, we can simply reuse the 'm_pData' to compute the marshalled size // History Retrieval is not WOW64 compatible and hence will not involve // serializing the collections list. Should Use // CollectionsListGetMarshalledSizeWithoutSerialization instead of // CollectionsListGetMarshalledSize when dealing with History Collection list. m_HistoryMarshalledRecordSize = CollectionsListGetMarshalledSizeWithoutSerialization(m_pData); // Sensor Enumeration Properties Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_ENUMERATION_PROPERTIES_COUNT); MemoryHandle = NULL; WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); MemoryAttributes.ParentObject = SensorInstance; Status = WdfMemoryCreate(&MemoryAttributes, PagedPool, SENSOR_POOL_TAG_PEDOMETER, Size, &MemoryHandle, reinterpret_cast<PVOID*>(&m_pEnumerationProperties)); if (!NT_SUCCESS(Status) || nullptr == m_pEnumerationProperties) { TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); goto Exit; } SENSOR_COLLECTION_LIST_INIT(m_pEnumerationProperties, Size); m_pEnumerationProperties->Count = SENSOR_ENUMERATION_PROPERTIES_COUNT; m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Key = DEVPKEY_Sensor_Type; InitPropVariantFromCLSID(GUID_SensorType_Pedometer, &(m_pEnumerationProperties->List[SENSOR_TYPE_GUID].Value)); m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Key = DEVPKEY_Sensor_Manufacturer; InitPropVariantFromString(L"Microsoft", &(m_pEnumerationProperties->List[SENSOR_MANUFACTURER].Value)); m_pEnumerationProperties->List[SENSOR_MODEL].Key = DEVPKEY_Sensor_Model; InitPropVariantFromString(L"PEDOMETER", &(m_pEnumerationProperties->List[SENSOR_MODEL].Value)); m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Key = DEVPKEY_Sensor_PersistentUniqueId; InitPropVariantFromCLSID(GUID_PedometerDevice_UniqueID, &(m_pEnumerationProperties->List[SENSOR_PERSISTENT_UNIQUEID].Value)); m_pEnumerationProperties->List[SENSOR_CATEGORY].Key = DEVPKEY_Sensor_Category; InitPropVariantFromCLSID(GUID_SensorCategory_Motion, &(m_pEnumerationProperties->List[SENSOR_CATEGORY].Value)); m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Key = DEVPKEY_Sensor_IsPrimary; InitPropVariantFromBoolean(FALSE, &(m_pEnumerationProperties->List[SENSOR_ISPRIMARY].Value)); // This value should be set to TRUE if multiple pedometers // exist on the system and this sensor is the primary sensor m_pEnumerationProperties->List[SENSOR_POWER].Key = PKEY_Sensor_Power_Milliwatts; InitPropVariantFromFloat(Pedometer_Default_Power_Milliwatts, &(m_pEnumerationProperties->List[SENSOR_POWER].Value)); m_pEnumerationProperties->List[SENSOR_MAX_HISTORYSIZE].Key = PKEY_SensorHistory_MaxSize_Bytes; InitPropVariantFromUInt32(((FALSE != m_HistorySupported) ? (SENSOR_COLLECTION_LIST_HEADER_SIZE + ((m_HistoryMarshalledRecordSize - SENSOR_COLLECTION_LIST_HEADER_SIZE) * HistorySizeInRecords)) : 0), &(m_pEnumerationProperties->List[SENSOR_MAX_HISTORYSIZE].Value)); m_pEnumerationProperties->List[SENSOR_SUPPORTED_STEPTYPES].Key = PKEY_SensorData_SupportedStepTypes; InitPropVariantFromUInt32(PedometerStepType_Unknown | PedometerStepType_Walking | PedometerStepType_Running, &(m_pEnumerationProperties->List[SENSOR_SUPPORTED_STEPTYPES].Value)); // Sensor Properties m_Interval = Pedometer_Default_MinDataInterval_Ms; Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_COMMON_PROPERTIES_COUNT); MemoryHandle = NULL; WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); MemoryAttributes.ParentObject = SensorInstance; Status = WdfMemoryCreate(&MemoryAttributes, PagedPool, SENSOR_POOL_TAG_PEDOMETER, Size, &MemoryHandle, reinterpret_cast<PVOID*>(&m_pProperties)); if (!NT_SUCCESS(Status) || nullptr == m_pProperties) { TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); goto Exit; } SENSOR_COLLECTION_LIST_INIT(m_pProperties, Size); m_pProperties->Count = SENSOR_COMMON_PROPERTIES_COUNT; m_pProperties->List[SENSOR_PROPERTY_STATE].Key = PKEY_Sensor_State; InitPropVariantFromUInt32(SensorState_Initializing, &(m_pProperties->List[SENSOR_PROPERTY_STATE].Value)); m_pProperties->List[SENSOR_PROPERTY_MIN_INTERVAL].Key = PKEY_Sensor_MinimumDataInterval_Ms; InitPropVariantFromUInt32(Pedometer_Default_MinDataInterval_Ms, &(m_pProperties->List[SENSOR_PROPERTY_MIN_INTERVAL].Value)); m_pProperties->List[SENSOR_PROPERTY_MAX_DATAFIELDSIZE].Key = PKEY_Sensor_MaximumDataFieldSize_Bytes; InitPropVariantFromUInt32(CollectionsListGetMarshalledSize(m_pData), &(m_pProperties->List[SENSOR_PROPERTY_MAX_DATAFIELDSIZE].Value)); m_pProperties->List[SENSOR_PROPERTY_SENSOR_TYPE].Key = PKEY_Sensor_Type; InitPropVariantFromCLSID(GUID_SensorType_Pedometer, &(m_pProperties->List[SENSOR_PROPERTY_SENSOR_TYPE].Value)); m_pProperties->List[SENSOR_PROPERTY_SENSOR_POWER].Key = PKEY_Sensor_Power_Milliwatts; InitPropVariantFromFloat(Pedometer_Default_Power_Milliwatts, &(m_pProperties->List[SENSOR_PROPERTY_SENSOR_POWER].Value)); m_pProperties->List[SENSOR_PROPERTY_MAX_HISTORYSIZE].Key = PKEY_SensorHistory_MaxSize_Bytes; InitPropVariantFromUInt32(((FALSE != m_HistorySupported) ? (SENSOR_COLLECTION_LIST_HEADER_SIZE + ((m_HistoryMarshalledRecordSize - SENSOR_COLLECTION_LIST_HEADER_SIZE) * HistorySizeInRecords)) : 0), &(m_pProperties->List[SENSOR_PROPERTY_MAX_HISTORYSIZE].Value)); m_pProperties->List[SENSOR_PROPERTY_HISTORY_INTERVAL].Key = PKEY_SensorHistory_Interval_Ms; InitPropVariantFromUInt32(pSimulator->GetHistoryIntervalInMs(), &(m_pProperties->List[SENSOR_PROPERTY_HISTORY_INTERVAL].Value)); m_pProperties->List[SENSOR_PROPERTY_MAX_HISTROYRECORDSIZE].Key = PKEY_SensorHistory_MaximumRecordSize_Bytes; InitPropVariantFromUInt32(m_HistoryMarshalledRecordSize, &(m_pProperties->List[SENSOR_PROPERTY_MAX_HISTROYRECORDSIZE].Value)); m_pProperties->List[SENSOR_PROPERTY_SUPPORTED_STEPTYPES].Key = PKEY_SensorData_SupportedStepTypes; InitPropVariantFromUInt32(PedometerStepType_Unknown | PedometerStepType_Walking | PedometerStepType_Running, &(m_pProperties->List[SENSOR_PROPERTY_SUPPORTED_STEPTYPES].Value)); // Data field properties Size = SENSOR_COLLECTION_LIST_SIZE(SENSOR_DATA_FIELD_PROPERTY_COUNT); MemoryHandle = NULL; WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); MemoryAttributes.ParentObject = SensorInstance; Status = WdfMemoryCreate(&MemoryAttributes, PagedPool, SENSOR_POOL_TAG_PEDOMETER, Size, &MemoryHandle, reinterpret_cast<PVOID*>(&m_pDataFieldProperties)); if (!NT_SUCCESS(Status) || nullptr == m_pDataFieldProperties) { TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); goto Exit; } SENSOR_COLLECTION_LIST_INIT(m_pDataFieldProperties, Size); m_pDataFieldProperties->Count = SENSOR_DATA_FIELD_PROPERTY_COUNT; m_pDataFieldProperties->List[SENSOR_RESOLUTION].Key = PKEY_SensorDataField_Resolution; InitPropVariantFromInt64(PedometerDevice_StepCount_Resolution, &(m_pDataFieldProperties->List[SENSOR_RESOLUTION].Value)); m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Key = PKEY_SensorDataField_RangeMinimum; InitPropVariantFromUInt32(PedometerDevice_StepCount_Minimum, &(m_pDataFieldProperties->List[SENSOR_MIN_RANGE].Value)); m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Key = PKEY_SensorDataField_RangeMaximum; InitPropVariantFromUInt32(PedometerDevice_StepCount_Maximum, &(m_pDataFieldProperties->List[SENSOR_MAX_RANGE].Value)); // Set default threshold m_FirstSample = TRUE; Size = SENSOR_COLLECTION_LIST_SIZE(PEDOMETER_THRESHOLD_COUNT); MemoryHandle = NULL; WDF_OBJECT_ATTRIBUTES_INIT(&MemoryAttributes); MemoryAttributes.ParentObject = SensorInstance; Status = WdfMemoryCreate(&MemoryAttributes, PagedPool, SENSOR_POOL_TAG_PEDOMETER, Size, &MemoryHandle, reinterpret_cast<PVOID*>(&m_pThresholds)); if (!NT_SUCCESS(Status) || nullptr == m_pThresholds) { TraceError("PED %!FUNC! WdfMemoryCreate failed %!STATUS!", Status); goto Exit; } SENSOR_COLLECTION_LIST_INIT(m_pThresholds, Size); m_pThresholds->Count = PEDOMETER_THRESHOLD_COUNT; m_pThresholds->List[PEDOMETER_THRESHOLD_STEP_COUNT].Key = PKEY_SensorData_PedometerStepCount; InitPropVariantFromUInt32(Pedometer_Default_Threshold_StepCount, &(m_pThresholds->List[PEDOMETER_THRESHOLD_STEP_COUNT].Value)); m_CachedThreshold = Pedometer_Default_Threshold_StepCount; Exit: SENSOR_FunctionExit(Status); return Status; }
// This routine is called by worker thread to read a single sample, compare threshold // and push it back to CLX. It simulates hardware thresholding by only generating data // when the change of data is greater than threshold. NTSTATUS PedometerDevice::GetData( ) { PHardwareSimulator pSimulator = GetHardwareSimulatorContextFromInstance(m_SimulatorInstance); BOOLEAN DataReady = FALSE; NTSTATUS Status = STATUS_SUCCESS; ULONG CachedStepCountLimit = 0; ULONG LastStepCountLimit = 0; PedometerSample Sample = {}; SENSOR_FunctionEnter(); if (nullptr == pSimulator) { Status = STATUS_INSUFFICIENT_RESOURCES; TraceError("PED %!FUNC! GetHardwareSimulatorContextFromInstance failed %!STATUS!", Status); goto Exit; } Status = pSimulator->GetSample(&Sample); if (!NT_SUCCESS(Status)) { TraceError("PED %!FUNC! GetSample failed %!STATUS!", Status); goto Exit; } if (FALSE != m_FirstSample) { Status = GetPerformanceTime(&m_StartTime); if (!NT_SUCCESS(Status)) { m_StartTime = 0; TraceError("PED %!FUNC! GetPerformanceTime failed %!STATUS!", Status); } m_SampleCount = 0; DataReady = TRUE; } else { if (0 == m_CachedThreshold || FALSE != Sample.IsFirstAfterReset) { // Streaming mode DataReady = TRUE; } else { if (FAILED(ULongAdd(Sample.UnknownStepCount, Sample.WalkingStepCount, &CachedStepCountLimit)) || FAILED(ULongAdd(Sample.RunningStepCount, CachedStepCountLimit, &CachedStepCountLimit))) { // If an overflow happened, we assume we reached the threshold // in other words, there is no threshold value that can be larger // than an overflowed value. DataReady = TRUE; } else if (FAILED(ULongAdd(m_LastSample.UnknownStepCount, m_LastSample.WalkingStepCount, &LastStepCountLimit)) || FAILED(ULongAdd(m_LastSample.RunningStepCount, LastStepCountLimit, &LastStepCountLimit))) { // If an overflow happened, we assume we reached the threshold // in other words, there is no threshold value that can be larger // than an overflowed value. DataReady = TRUE; } else if ((LastStepCountLimit < m_CachedThreshold && CachedStepCountLimit >= m_CachedThreshold) || (FALSE != Sample.IsFirstAfterReset)) { // Compare the change of data to threshold, and only push the data back to // clx if the change exceeds threshold or if this is the first sample after reset. This is usually done in HW. DataReady = TRUE; } } } if (FALSE != DataReady) { // update last sample m_LastSample = Sample; // push to clx InitPropVariantFromBoolean(m_LastSample.IsFirstAfterReset, &(m_pData->List[PEDOMETER_DATA_FIRST_AFTER_RESET].Value)); InitPropVariantFromUInt32(PedometerStepType_Unknown, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_TYPE].Value)); InitPropVariantFromInt64(m_LastSample.UnknownStepDurationMs, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_DURATION].Value)); InitPropVariantFromUInt32(m_LastSample.UnknownStepCount, &(m_pData->List[PEDOMETER_DATA_UNKNOWN_STEP_COUNT].Value)); InitPropVariantFromUInt32(PedometerStepType_Walking, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_TYPE].Value)); InitPropVariantFromInt64(m_LastSample.WalkingStepDurationMs, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_DURATION].Value)); InitPropVariantFromUInt32(m_LastSample.WalkingStepCount, &(m_pData->List[PEDOMETER_DATA_WALKING_STEP_COUNT].Value)); InitPropVariantFromUInt32(PedometerStepType_Running, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_TYPE].Value)); InitPropVariantFromInt64(m_LastSample.RunningStepDurationMs, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_DURATION].Value)); InitPropVariantFromUInt32(m_LastSample.RunningStepCount, &(m_pData->List[PEDOMETER_DATA_RUNNING_STEP_COUNT].Value)); // reset IsFirstAfterReset m_LastSample.IsFirstAfterReset = FALSE; InitPropVariantFromFileTime(&m_LastSample.Timestamp, &(m_pData->List[PEDOMETER_DATA_TIMESTAMP].Value)); SensorsCxSensorDataReady(m_SensorInstance, m_pData); m_FirstSample = FALSE; } else { Status = STATUS_DATA_NOT_ACCEPTED; TraceInformation("PED %!FUNC! Data did NOT meet the threshold"); } SENSOR_FunctionExit(Status); Exit: return Status; }