• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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