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