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
16 #include "audio_service.h"
17
18 #include <thread>
19
20 #include "audio_errors.h"
21 #include "audio_log.h"
22 #include "remote_audio_renderer_sink.h"
23 #include "policy_handler.h"
24
25 namespace OHOS {
26 namespace AudioStandard {
GetInstance()27 AudioService *AudioService::GetInstance()
28 {
29 static AudioService AudioService;
30
31 return &AudioService;
32 }
33
AudioService()34 AudioService::AudioService()
35 {
36 AUDIO_INFO_LOG("AudioService()");
37 }
38
~AudioService()39 AudioService::~AudioService()
40 {
41 AUDIO_INFO_LOG("~AudioService()");
42 }
43
OnProcessRelease(IAudioProcessStream * process)44 int32_t AudioService::OnProcessRelease(IAudioProcessStream *process)
45 {
46 std::lock_guard<std::mutex> lock(processListMutex_);
47 bool isFind = false;
48 int32_t ret = ERROR;
49 auto paired = linkedPairedList_.begin();
50 std::string endpointName;
51 bool needRelease = false;
52 while (paired != linkedPairedList_.end()) {
53 if ((*paired).first == process) {
54 ret = UnlinkProcessToEndpoint((*paired).first, (*paired).second);
55 linkedPairedList_.erase(paired);
56 isFind = true;
57 if ((*paired).second->GetStatus() == AudioEndpoint::EndpointStatus::UNLINKED) {
58 needRelease = true;
59 endpointName = (*paired).second->GetEndpointName();
60 }
61 break;
62 } else {
63 paired++;
64 }
65 }
66 if (isFind) {
67 AUDIO_INFO_LOG("OnProcessRelease find and release process result %{public}d", ret);
68 } else {
69 AUDIO_INFO_LOG("OnProcessRelease can not find target process, maybe already released.");
70 }
71
72 if (needRelease) {
73 AUDIO_INFO_LOG("OnProcessRelease find endpoint unlink, call delay release.");
74 int32_t delayTime = 10000;
75 std::thread releaseEndpointThread(&AudioService::DelayCallReleaseEndpoint, this, endpointName, delayTime);
76 releaseEndpointThread.detach();
77 }
78
79 return SUCCESS;
80 }
81
GetAudioProcess(const AudioProcessConfig & config)82 sptr<AudioProcessInServer> AudioService::GetAudioProcess(const AudioProcessConfig &config)
83 {
84 AUDIO_INFO_LOG("GetAudioProcess dump %{public}s", ProcessConfig::DumpProcessConfig(config).c_str());
85
86 DeviceInfo deviceInfo = GetDeviceInfoForProcess(config);
87 std::shared_ptr<AudioEndpoint> audioEndpoint = GetAudioEndpointForDevice(deviceInfo);
88 CHECK_AND_RETURN_RET_LOG(audioEndpoint != nullptr, nullptr, "no endpoint found for the process");
89
90 uint32_t totalSizeInframe = 0;
91 uint32_t spanSizeInframe = 0;
92 audioEndpoint->GetPreferBufferInfo(totalSizeInframe, spanSizeInframe);
93
94 std::lock_guard<std::mutex> lock(processListMutex_);
95 sptr<AudioProcessInServer> process = AudioProcessInServer::Create(config, this);
96 CHECK_AND_RETURN_RET_LOG(process != nullptr, nullptr, "AudioProcessInServer create failed.");
97
98 int32_t ret = process->ConfigProcessBuffer(totalSizeInframe, spanSizeInframe);
99 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, nullptr, "ConfigProcessBuffer failed");
100
101 ret = LinkProcessToEndpoint(process, audioEndpoint);
102 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, nullptr, "LinkProcessToEndpoint failed");
103
104 linkedPairedList_.push_back(std::make_pair(process, audioEndpoint));
105 return process;
106 }
107
LinkProcessToEndpoint(sptr<AudioProcessInServer> process,std::shared_ptr<AudioEndpoint> endpoint)108 int32_t AudioService::LinkProcessToEndpoint(sptr<AudioProcessInServer> process,
109 std::shared_ptr<AudioEndpoint> endpoint)
110 {
111 int32_t ret = endpoint->LinkProcessStream(process);
112 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "LinkProcessStream failed");
113
114 ret = process->AddProcessStatusListener(endpoint);
115 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "AddProcessStatusListener failed");
116
117 releaseEndpointCV_.notify_all();
118 return SUCCESS;
119 }
120
UnlinkProcessToEndpoint(sptr<AudioProcessInServer> process,std::shared_ptr<AudioEndpoint> endpoint)121 int32_t AudioService::UnlinkProcessToEndpoint(sptr<AudioProcessInServer> process,
122 std::shared_ptr<AudioEndpoint> endpoint)
123 {
124 int32_t ret = endpoint->UnlinkProcessStream(process);
125 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "UnlinkProcessStream failed");
126
127 ret = process->RemoveProcessStatusListener(endpoint);
128 CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, ERR_OPERATION_FAILED, "RemoveProcessStatusListener failed");
129
130 return SUCCESS;
131 }
132
DelayCallReleaseEndpoint(std::string endpointName,int32_t delayInMs)133 void AudioService::DelayCallReleaseEndpoint(std::string endpointName, int32_t delayInMs)
134 {
135 AUDIO_INFO_LOG("Delay release endpoint [%{public}s] start.", endpointName.c_str());
136 if (!endpointList_.count(endpointName)) {
137 AUDIO_ERR_LOG("Find no such endpoint: %{public}s", endpointName.c_str());
138 return;
139 }
140 std::unique_lock<std::mutex> lock(releaseEndpointMutex_);
141 releaseEndpointCV_.wait_for(lock, std::chrono::milliseconds(delayInMs), [this, endpointName] {
142 if (endpointName == reusingEndpoint_) {
143 AUDIO_INFO_LOG("Delay release endpoint break when reuse: %{public}s", endpointName.c_str());
144 return true;
145 }
146 AUDIO_INFO_LOG("Wake up but keep release endpoint %{public}s in delay", endpointName.c_str());
147 return false;
148 });
149 // todo: add break operation
150 std::shared_ptr<AudioEndpoint> temp = nullptr;
151 if (endpointList_.find(endpointName) == endpointList_.end() || endpointList_[endpointName] == nullptr) {
152 AUDIO_ERR_LOG("Endpoint %{public}s not available, stop call release", endpointName.c_str());
153 return;
154 }
155 temp = endpointList_[endpointName];
156 if (temp->GetStatus() == AudioEndpoint::EndpointStatus::UNLINKED) {
157 AUDIO_INFO_LOG("%{public}s not in use anymore, call release!", endpointName.c_str());
158 temp->Release();
159 temp = nullptr;
160 endpointList_.erase(endpointName);
161 return;
162 }
163 AUDIO_WARNING_LOG("%{public}s is not unlinked, stop call release", endpointName.c_str());
164 return;
165 }
166
GetDeviceInfoForProcess(const AudioProcessConfig & config)167 DeviceInfo AudioService::GetDeviceInfoForProcess(const AudioProcessConfig &config)
168 {
169 // send the config to AudioPolicyServera and get the device info.
170 DeviceInfo deviceInfo;
171 bool ret = PolicyHandler::GetInstance().GetProcessDeviceInfo(config, deviceInfo);
172 if (ret) {
173 AUDIO_INFO_LOG("Get DeviceInfo from policy server success, deviceType is%{public}d", deviceInfo.deviceType);
174 return deviceInfo;
175 } else {
176 AUDIO_WARNING_LOG("GetProcessDeviceInfo from audio policy server failed!");
177 }
178
179 if (config.audioMode == AUDIO_MODE_RECORD) {
180 deviceInfo.deviceId = 1;
181 deviceInfo.networkId = LOCAL_NETWORK_ID;
182 deviceInfo.deviceRole = INPUT_DEVICE;
183 deviceInfo.deviceType = DEVICE_TYPE_MIC;
184 } else {
185 deviceInfo.deviceId = 6; // 6 for test
186 deviceInfo.networkId = LOCAL_NETWORK_ID;
187 deviceInfo.deviceRole = OUTPUT_DEVICE;
188 deviceInfo.deviceType = DEVICE_TYPE_SPEAKER;
189 }
190 AudioStreamInfo targetStreamInfo = {SAMPLE_RATE_48000, ENCODING_PCM, SAMPLE_S16LE, STEREO}; // note: read from xml
191 deviceInfo.audioStreamInfo = targetStreamInfo;
192 deviceInfo.deviceName = "mmap_device";
193 return deviceInfo;
194 }
195
GetAudioEndpointForDevice(DeviceInfo deviceInfo)196 std::shared_ptr<AudioEndpoint> AudioService::GetAudioEndpointForDevice(DeviceInfo deviceInfo)
197 {
198 // temp method to get deivce key
199 std::string deviceKey = deviceInfo.networkId + std::to_string(deviceInfo.deviceId);
200 if (endpointList_.find(deviceKey) != endpointList_.end()) {
201 AUDIO_INFO_LOG("AudioService find endpoint already exist for deviceKey:%{public}s", deviceKey.c_str());
202 reusingEndpoint_ = deviceKey;
203 return endpointList_[deviceKey];
204 }
205 std::shared_ptr<AudioEndpoint> endpoint = AudioEndpoint::GetInstance(AudioEndpoint::EndpointType::TYPE_MMAP,
206 deviceInfo);
207 if (endpoint == nullptr) {
208 AUDIO_ERR_LOG("Find no endpoint for the process");
209 return nullptr;
210 }
211 endpointList_[deviceKey] = endpoint;
212 return endpoint;
213 }
214
Dump(std::stringstream & dumpStringStream)215 void AudioService::Dump(std::stringstream &dumpStringStream)
216 {
217 AUDIO_INFO_LOG("AudioService dump begin");
218 // dump process
219 for (auto paired : linkedPairedList_) {
220 paired.first->Dump(dumpStringStream);
221 }
222 // dump endpoint
223 for (auto item : endpointList_) {
224 dumpStringStream << std::endl << "Endpoint device id:" << item.first << std::endl;
225 item.second->Dump(dumpStringStream);
226 }
227 PolicyHandler::GetInstance().Dump(dumpStringStream);
228 }
229 } // namespace AudioStandard
230 } // namespace OHOS
231