Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2021 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 | #ifndef AUDIO_TEST_UTILS_H_ |
| 18 | #define AUDIO_TEST_UTILS_H_ |
| 19 | |
| 20 | #include <sys/stat.h> |
| 21 | #include <unistd.h> |
| 22 | #include <atomic> |
| 23 | #include <chrono> |
| 24 | #include <cinttypes> |
| 25 | #include <deque> |
| 26 | #include <memory> |
| 27 | #include <mutex> |
| 28 | #include <thread> |
| 29 | |
| 30 | #include <binder/MemoryDealer.h> |
Ram Mohan | 1b120aa | 2021-12-14 21:53:44 +0530 | [diff] [blame] | 31 | #include <libxml/parser.h> |
| 32 | #include <libxml/xinclude.h> |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 33 | #include <media/AidlConversion.h> |
| 34 | #include <media/AudioRecord.h> |
| 35 | #include <media/AudioTrack.h> |
| 36 | |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 37 | using namespace android; |
| 38 | |
Ram Mohan | 1b120aa | 2021-12-14 21:53:44 +0530 | [diff] [blame] | 39 | struct MixPort { |
| 40 | std::string name; |
| 41 | std::string role; |
| 42 | std::string flags; |
| 43 | }; |
| 44 | |
| 45 | struct Route { |
| 46 | std::string name; |
| 47 | std::string sources; |
| 48 | std::string sink; |
| 49 | }; |
| 50 | |
| 51 | status_t parse_audio_policy_configuration_xml(std::vector<std::string>& attachedDevices, |
| 52 | std::vector<MixPort>& mixPorts, |
| 53 | std::vector<Route>& routes); |
Ram Mohan | 236a762 | 2022-02-01 11:31:58 +0530 | [diff] [blame] | 54 | status_t listAudioPorts(std::vector<audio_port_v7>& portsVec); |
| 55 | status_t listAudioPatches(std::vector<struct audio_patch>& patchesVec); |
| 56 | status_t getPortByAttributes(audio_port_role_t role, audio_port_type_t type, |
Ram Mohan | def29f5 | 2022-11-15 21:26:01 +0530 | [diff] [blame] | 57 | audio_devices_t deviceType, const std::string& address, |
| 58 | audio_port_v7& port); |
Ram Mohan | 236a762 | 2022-02-01 11:31:58 +0530 | [diff] [blame] | 59 | status_t getPatchForOutputMix(audio_io_handle_t audioIo, audio_patch& patch); |
| 60 | status_t getPatchForInputMix(audio_io_handle_t audioIo, audio_patch& patch); |
| 61 | bool patchContainsOutputDevice(audio_port_handle_t deviceId, audio_patch patch); |
| 62 | bool patchContainsInputDevice(audio_port_handle_t deviceId, audio_patch patch); |
| 63 | bool checkPatchPlayback(audio_io_handle_t audioIo, audio_port_handle_t deviceId); |
| 64 | bool checkPatchCapture(audio_io_handle_t audioIo, audio_port_handle_t deviceId); |
| 65 | std::string dumpPort(const audio_port_v7& port); |
| 66 | std::string dumpPortConfig(const audio_port_config& port); |
| 67 | std::string dumpPatch(const audio_patch& patch); |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 68 | |
| 69 | class OnAudioDeviceUpdateNotifier : public AudioSystem::AudioDeviceCallback { |
| 70 | public: |
| 71 | audio_io_handle_t mAudioIo = AUDIO_IO_HANDLE_NONE; |
| 72 | audio_port_handle_t mDeviceId = AUDIO_PORT_HANDLE_NONE; |
| 73 | std::mutex mMutex; |
| 74 | std::condition_variable mCondition; |
| 75 | |
| 76 | void onAudioDeviceUpdate(audio_io_handle_t audioIo, audio_port_handle_t deviceId); |
Ram Mohan | 93df3d5 | 2022-11-15 14:24:33 +0530 | [diff] [blame] | 77 | status_t waitForAudioDeviceCb(audio_port_handle_t expDeviceId = AUDIO_PORT_HANDLE_NONE); |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 78 | }; |
| 79 | |
| 80 | // Simple AudioPlayback class. |
Atneya Nair | eb57617 | 2022-04-21 18:24:01 -0400 | [diff] [blame] | 81 | class AudioPlayback : public AudioTrack::IAudioTrackCallback { |
Ram Mohan | 4679822 | 2022-05-10 19:26:03 +0530 | [diff] [blame] | 82 | friend sp<AudioPlayback>; |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 83 | AudioPlayback(uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, |
| 84 | audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE, |
| 85 | audio_session_t sessionId = AUDIO_SESSION_NONE, |
| 86 | AudioTrack::transfer_type transferType = AudioTrack::TRANSFER_SHARED, |
Ram Mohan | 4679822 | 2022-05-10 19:26:03 +0530 | [diff] [blame] | 87 | audio_attributes_t* attributes = nullptr, audio_offload_info_t* info = nullptr); |
| 88 | |
Atneya Nair | eb57617 | 2022-04-21 18:24:01 -0400 | [diff] [blame] | 89 | public: |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 90 | status_t loadResource(const char* name); |
| 91 | status_t create(); |
| 92 | sp<AudioTrack> getAudioTrackHandle(); |
| 93 | status_t start(); |
Ram Mohan | ba55d5a | 2022-01-11 20:23:44 +0530 | [diff] [blame] | 94 | status_t waitForConsumption(bool testSeek = false); |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 95 | status_t fillBuffer(); |
Ram Mohan | ba55d5a | 2022-01-11 20:23:44 +0530 | [diff] [blame] | 96 | status_t onProcess(bool testSeek = false); |
Atneya Nair | eb57617 | 2022-04-21 18:24:01 -0400 | [diff] [blame] | 97 | virtual void onBufferEnd() override; |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 98 | void stop(); |
| 99 | |
| 100 | bool mStopPlaying; |
| 101 | std::mutex mMutex; |
| 102 | std::condition_variable mCondition; |
| 103 | |
| 104 | enum State { |
| 105 | PLAY_NO_INIT, |
| 106 | PLAY_READY, |
| 107 | PLAY_STARTED, |
| 108 | PLAY_STOPPED, |
| 109 | }; |
| 110 | |
| 111 | private: |
Atneya Nair | eb57617 | 2022-04-21 18:24:01 -0400 | [diff] [blame] | 112 | ~AudioPlayback(); |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 113 | const uint32_t mSampleRate; |
| 114 | const audio_format_t mFormat; |
| 115 | const audio_channel_mask_t mChannelMask; |
| 116 | const audio_output_flags_t mFlags; |
| 117 | const audio_session_t mSessionId; |
| 118 | const AudioTrack::transfer_type mTransferType; |
| 119 | const audio_attributes_t* mAttributes; |
Ram Mohan | 4679822 | 2022-05-10 19:26:03 +0530 | [diff] [blame] | 120 | const audio_offload_info_t* mOffloadInfo; |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 121 | |
| 122 | size_t mBytesUsedSoFar; |
| 123 | State mState; |
| 124 | size_t mMemCapacity; |
| 125 | sp<MemoryDealer> mMemoryDealer; |
| 126 | sp<IMemory> mMemory; |
| 127 | |
| 128 | sp<AudioTrack> mTrack; |
| 129 | }; |
| 130 | |
| 131 | // hold pcm data sent by AudioRecord |
| 132 | class RawBuffer { |
| 133 | public: |
| 134 | RawBuffer(int64_t ptsPipeline = -1, int64_t ptsManual = -1, int32_t capacity = 0); |
| 135 | |
| 136 | std::unique_ptr<uint8_t[]> mData; |
| 137 | int64_t mPtsPipeline; |
| 138 | int64_t mPtsManual; |
| 139 | int32_t mCapacity; |
| 140 | }; |
| 141 | |
| 142 | // Simple AudioCapture |
| 143 | class AudioCapture : public AudioRecord::IAudioRecordCallback { |
| 144 | public: |
| 145 | AudioCapture(audio_source_t inputSource, uint32_t sampleRate, audio_format_t format, |
| 146 | audio_channel_mask_t channelMask, |
| 147 | audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE, |
| 148 | audio_session_t sessionId = AUDIO_SESSION_ALLOCATE, |
Ram Mohan | 93df3d5 | 2022-11-15 14:24:33 +0530 | [diff] [blame] | 149 | AudioRecord::transfer_type transferType = AudioRecord::TRANSFER_CALLBACK, |
| 150 | const audio_attributes_t* attributes = nullptr); |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 151 | ~AudioCapture(); |
| 152 | size_t onMoreData(const AudioRecord::Buffer& buffer) override; |
| 153 | void onOverrun() override; |
| 154 | void onMarker(uint32_t markerPosition) override; |
| 155 | void onNewPos(uint32_t newPos) override; |
| 156 | void onNewIAudioRecord() override; |
| 157 | status_t create(); |
Ram Mohan | 93df3d5 | 2022-11-15 14:24:33 +0530 | [diff] [blame] | 158 | status_t setRecordDuration(float durationInSec); |
| 159 | status_t enableRecordDump(); |
| 160 | std::string getRecordDumpFileName() const { return mFileName; } |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 161 | sp<AudioRecord> getAudioRecordHandle(); |
| 162 | status_t start(AudioSystem::sync_event_t event = AudioSystem::SYNC_EVENT_NONE, |
| 163 | audio_session_t triggerSession = AUDIO_SESSION_NONE); |
| 164 | status_t obtainBufferCb(RawBuffer& buffer); |
| 165 | status_t obtainBuffer(RawBuffer& buffer); |
| 166 | status_t audioProcess(); |
| 167 | status_t stop(); |
| 168 | |
| 169 | uint32_t mFrameCount; |
| 170 | uint32_t mNotificationFrames; |
| 171 | int64_t mNumFramesToRecord; |
| 172 | int64_t mNumFramesReceived; |
| 173 | int64_t mNumFramesLost; |
| 174 | uint32_t mMarkerPosition; |
| 175 | uint32_t mMarkerPeriod; |
| 176 | uint32_t mReceivedCbMarkerAtPosition; |
| 177 | uint32_t mReceivedCbMarkerCount; |
| 178 | bool mBufferOverrun; |
| 179 | |
| 180 | enum State { |
| 181 | REC_NO_INIT, |
| 182 | REC_READY, |
| 183 | REC_STARTED, |
| 184 | REC_STOPPED, |
| 185 | }; |
| 186 | |
| 187 | private: |
| 188 | const audio_source_t mInputSource; |
| 189 | const uint32_t mSampleRate; |
| 190 | const audio_format_t mFormat; |
| 191 | const audio_channel_mask_t mChannelMask; |
| 192 | const audio_input_flags_t mFlags; |
| 193 | const audio_session_t mSessionId; |
| 194 | const AudioRecord::transfer_type mTransferType; |
Ram Mohan | 93df3d5 | 2022-11-15 14:24:33 +0530 | [diff] [blame] | 195 | const audio_attributes_t* mAttributes; |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 196 | |
| 197 | size_t mMaxBytesPerCallback = 2048; |
| 198 | sp<AudioRecord> mRecord; |
| 199 | State mState; |
| 200 | bool mStopRecording; |
Ram Mohan | 93df3d5 | 2022-11-15 14:24:33 +0530 | [diff] [blame] | 201 | std::string mFileName; |
Shivaansh Agrawal | d7da8b4 | 2021-12-15 20:47:56 +0530 | [diff] [blame] | 202 | int mOutFileFd = -1; |
| 203 | |
| 204 | std::mutex mMutex; |
| 205 | std::condition_variable mCondition; |
| 206 | std::deque<RawBuffer> mBuffersReceived; |
| 207 | }; |
| 208 | |
| 209 | #endif // AUDIO_TEST_UTILS_H_ |