• 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 
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