1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef LOG_TAG
16 #define LOG_TAG "LinearPosTimeModel"
17 #endif
18
19 #include "linear_pos_time_model.h"
20
21 #include <cinttypes>
22
23 #include "audio_errors.h"
24 #include "audio_service_log.h"
25 #include "audio_utils.h"
26
27 namespace OHOS {
28 namespace AudioStandard {
29 namespace {
30 static constexpr int64_t NANO_COUNT_PER_SECOND = 1000000000;
31 static constexpr int32_t MAX_SUPPORT_SAMPLE_RETE = 384000;
32 static constexpr int32_t MAX_STATISTICS_COUNT = 5;
33 static constexpr int64_t REASONABLE_DELTA_BOUND_IN_NANO = 3000000; // 3ms
34 static constexpr int64_t REASONABLE_BOUND_IN_NANO = 10000000; // 10ms
35 }
LinearPosTimeModel()36 LinearPosTimeModel::LinearPosTimeModel()
37 {
38 AUDIO_INFO_LOG("New LinearPosTimeModel");
39 }
40
ConfigSampleRate(int32_t sampleRate)41 bool LinearPosTimeModel::ConfigSampleRate(int32_t sampleRate)
42 {
43 AUDIO_INFO_LOG("ConfigSampleRate:%{public}d", sampleRate);
44 CHECK_AND_RETURN_RET_LOG(!isConfiged, false, "SampleRate already set:%{public}d", sampleRate_);
45 sampleRate_ = sampleRate;
46 if (sampleRate_ <= 0 || sampleRate_ > MAX_SUPPORT_SAMPLE_RETE) {
47 AUDIO_ERR_LOG("Invalid sample rate!");
48 return false;
49 } else {
50 nanoTimePerFrame_ = NANO_COUNT_PER_SECOND / sampleRate;
51 }
52 isConfiged = true;
53 return true;
54 }
55
ResetFrameStamp(uint64_t frame,int64_t nanoTime)56 void LinearPosTimeModel::ResetFrameStamp(uint64_t frame, int64_t nanoTime)
57 {
58 AUDIO_INFO_LOG("Reset frame:%{public}" PRIu64" with time:%{public}" PRId64".", frame, nanoTime);
59 posTimeVec_.clear();
60 stampFrame_ = frame;
61 stampNanoTime_ = nanoTime;
62 return;
63 }
64
IsReasonable(uint64_t frame,int64_t nanoTime)65 bool LinearPosTimeModel::IsReasonable(uint64_t frame, int64_t nanoTime)
66 {
67 if (frame == stampFrame_ && nanoTime == stampNanoTime_) {
68 return true;
69 }
70 int64_t deltaFrame = 0;
71 int64_t reasonableDeltaTime = 0;
72 if (frame > stampFrame_) {
73 deltaFrame = static_cast<int64_t>(frame - stampFrame_);
74 } else {
75 deltaFrame = -static_cast<int64_t>(stampFrame_ - frame);
76 }
77 reasonableDeltaTime = stampNanoTime_ + deltaFrame * NANO_COUNT_PER_SECOND / (int64_t)sampleRate_;
78
79 // note: compare it with current time?
80 if (nanoTime <= (reasonableDeltaTime + REASONABLE_BOUND_IN_NANO) &&
81 nanoTime >= (reasonableDeltaTime - REASONABLE_BOUND_IN_NANO)) {
82 return true;
83 }
84 return false;
85 }
86
CheckReasonable(uint64_t frame,int64_t nanoTime)87 CheckPosTimeRes LinearPosTimeModel::CheckReasonable(uint64_t frame, int64_t nanoTime)
88 {
89 posTimeVec_.push_back(std::make_pair(frame, nanoTime));
90 if (posTimeVec_.size() < MAX_STATISTICS_COUNT) {
91 return CHECK_FAILED;
92 }
93
94 for (size_t i = 0; i < posTimeVec_.size() - 1; i++) {
95 if (!CheckPosTimeReasonable(posTimeVec_[i], posTimeVec_[i + 1])) {
96 Trace trace("LinearPosTimeModel::CheckReasonable Fail");
97 AUDIO_WARNING_LOG("Unreasonable data pos: %{public}zu", i);
98 posTimeVec_.clear();
99 return CHECK_FAILED;
100 }
101 }
102
103 // todo: add DFX
104 Trace trace("LinearPosTimeModel::CheckReasonable Success");
105 AUDIO_ERR_LOG("Updata new frame:%{public}" PRIu64" with time:%{public}" PRId64".", frame, nanoTime);
106 return NEED_MODIFY;
107 }
108
CheckPosTimeReasonable(std::pair<uint64_t,int64_t> & pre,std::pair<uint64_t,int64_t> & next)109 bool LinearPosTimeModel::CheckPosTimeReasonable(std::pair<uint64_t, int64_t> &pre, std::pair<uint64_t, int64_t> &next)
110 {
111 if (pre.first >= next.first) {
112 return false;
113 }
114 int64_t deltaFrame = static_cast<int64_t>(next.first - pre.first);
115 int64_t deltaFrameTime = deltaFrame * NANO_COUNT_PER_SECOND / (int64_t)sampleRate_;
116 int64_t deltaTime = next.second - pre.second - deltaFrameTime;
117
118 return std::abs(deltaTime) < REASONABLE_DELTA_BOUND_IN_NANO;
119 }
120
UpdataFrameStamp(uint64_t frame,int64_t nanoTime)121 CheckPosTimeRes LinearPosTimeModel::UpdataFrameStamp(uint64_t frame, int64_t nanoTime)
122 {
123 if (IsReasonable(frame, nanoTime)) {
124 AUDIO_DEBUG_LOG("Updata frame:%{public}" PRIu64" with time:%{public}" PRId64".", frame, nanoTime);
125 stampFrame_ = frame;
126 stampNanoTime_ = nanoTime;
127 posTimeVec_.clear();
128 return CHECK_SUCCESS;
129 }
130
131 AUDIO_WARNING_LOG("Unreasonable pos-time[ %{public}" PRIu64" %{public}" PRId64"] "
132 " stamp pos-time[ %{public}" PRIu64" %{public}" PRId64"].", frame, nanoTime, stampFrame_, stampNanoTime_);
133
134 return CheckReasonable(frame, nanoTime);
135 }
136
GetFrameStamp(uint64_t & frame,int64_t & nanoTime)137 bool LinearPosTimeModel::GetFrameStamp(uint64_t &frame, int64_t &nanoTime)
138 {
139 CHECK_AND_RETURN_RET_LOG(isConfiged, false, "GetFrameStamp is not configed!");
140 frame = stampFrame_;
141 nanoTime = stampNanoTime_;
142 return true;
143 }
144
SetSpanCount(uint64_t spanCountInFrame)145 void LinearPosTimeModel::SetSpanCount(uint64_t spanCountInFrame)
146 {
147 AUDIO_INFO_LOG("New spanCountInFrame:%{public}" PRIu64".", spanCountInFrame);
148 spanCountInFrame_ = spanCountInFrame;
149 return;
150 }
151
GetTimeOfPos(uint64_t posInFrame)152 int64_t LinearPosTimeModel::GetTimeOfPos(uint64_t posInFrame)
153 {
154 int64_t deltaFrame = 0;
155 int64_t invalidTime = -1;
156 CHECK_AND_RETURN_RET_LOG(isConfiged, invalidTime, "SampleRate is not configed!");
157 if (posInFrame >= stampFrame_) {
158 if (posInFrame - stampFrame_ >= (uint64_t)sampleRate_) {
159 AUDIO_WARNING_LOG("posInFrame %{public}" PRIu64" is too"
160 " large, stampFrame: %{public}" PRIu64"", posInFrame, stampFrame_);
161 }
162 deltaFrame = static_cast<int64_t>(posInFrame - stampFrame_);
163 return stampNanoTime_ + deltaFrame * NANO_COUNT_PER_SECOND / (int64_t)sampleRate_;
164 } else {
165 if (stampFrame_ - posInFrame >= (uint64_t)sampleRate_) {
166 AUDIO_WARNING_LOG("posInFrame %{public}" PRIu64" is too"
167 " small, stampFrame: %{public}" PRIu64"", posInFrame, stampFrame_);
168 }
169 deltaFrame = static_cast<int64_t>(stampFrame_ - posInFrame);
170 return stampNanoTime_ - deltaFrame * NANO_COUNT_PER_SECOND / (int64_t)sampleRate_;
171 }
172 return invalidTime;
173 }
174 } // namespace AudioStandard
175 } // namespace OHOS
176
177