1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include "SyncEvent.h" 20 21 #pragma push_macro("LOG_TAG") 22 #undef LOG_TAG 23 #define LOG_TAG "SynchronizedRecordState" 24 25 namespace android::audioflinger { 26 27 class SynchronizedRecordState { 28 public: SynchronizedRecordState(uint32_t sampleRate)29 explicit SynchronizedRecordState(uint32_t sampleRate) 30 : mSampleRate(sampleRate) 31 {} 32 clear()33 void clear() { 34 std::lock_guard lg(mLock); 35 clear_l(); 36 } 37 38 // Called by the RecordThread when recording is starting. startRecording(const sp<SyncEvent> & event)39 void startRecording(const sp<SyncEvent>& event) { 40 std::lock_guard lg(mLock); 41 mSyncStartEvent = event; 42 // Sync event can be cancelled by the trigger session if the track is not in a 43 // compatible state in which case we start record immediately 44 if (mSyncStartEvent->isCancelled()) { 45 clear_l(); 46 } else { 47 mFramesToDrop = -(ssize_t) 48 ((AudioSystem::kSyncRecordStartTimeOutMs * mSampleRate) / 1000); 49 } 50 } 51 52 // Invoked by SyncEvent callback. 53 void onPlaybackFinished(const sp<SyncEvent>& event, size_t framesToDrop = 1) { 54 std::lock_guard lg(mLock); 55 if (event == mSyncStartEvent) { 56 mFramesToDrop = framesToDrop; // compute this 57 ALOGV("%s: framesToDrop:%zd", __func__, mFramesToDrop); 58 } 59 } 60 61 // Returns the current FramesToDrop counter 62 // 63 // if <0 waiting (drop the frames) 64 // if >0 draining (drop the frames) 65 // else if ==0 proceed to record. updateRecordFrames(size_t frames)66 ssize_t updateRecordFrames(size_t frames) { 67 std::lock_guard lg(mLock); 68 if (mFramesToDrop > 0) { 69 // we've been triggered, we count down for start delay 70 ALOGV("%s: trigger countdown %zd by %zu frames", __func__, mFramesToDrop, frames); 71 mFramesToDrop -= (ssize_t)frames; 72 if (mFramesToDrop <= 0) clear_l(); 73 } else if (mFramesToDrop < 0) { 74 // we're waiting to be triggered. 75 // ALOGD("%s: timeout countup %zd with %zu frames", __func__, mFramesToDrop, frames); 76 mFramesToDrop += (ssize_t)frames; 77 if (mFramesToDrop >= 0 || !mSyncStartEvent || mSyncStartEvent->isCancelled()) { 78 ALOGW("Synced record %s, trigger session %d", 79 (mFramesToDrop >= 0) ? "timed out" : "cancelled", 80 (mSyncStartEvent) ? mSyncStartEvent->triggerSession() 81 : AUDIO_SESSION_NONE); 82 clear_l(); 83 } 84 } 85 return mFramesToDrop; 86 } 87 88 private: 89 const uint32_t mSampleRate; 90 91 std::mutex mLock; 92 // number of captured frames to drop after the start sync event has been received. 93 // when < 0, maximum frames to drop before starting capture even if sync event is 94 // not received 95 ssize_t mFramesToDrop GUARDED_BY(mLock) = 0; 96 97 // sync event triggering actual audio capture. Frames read before this event will 98 // be dropped and therefore not read by the application. 99 sp<SyncEvent> mSyncStartEvent GUARDED_BY(mLock); 100 clear_l()101 void clear_l() REQUIRES(mLock) { 102 if (mSyncStartEvent) { 103 mSyncStartEvent->cancel(); 104 mSyncStartEvent.clear(); 105 } 106 mFramesToDrop = 0; 107 } 108 }; 109 110 } // namespace android::audioflinger 111 112 #pragma pop_macro("LOG_TAG") 113