1 //
2 // Copyright (C) 2020 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 #include "host/commands/modem_simulator/call_service.h"
17
18 #include <android-base/logging.h>
19
20 #include <chrono>
21 #include <iostream>
22 #include <thread>
23
24 #include "host/commands/modem_simulator/nvram_config.h"
25
26 namespace cuttlefish {
27
CallService(int32_t service_id,ChannelMonitor * channel_monitor,ThreadLooper * thread_looper)28 CallService::CallService(int32_t service_id, ChannelMonitor* channel_monitor,
29 ThreadLooper* thread_looper)
30 : ModemService(service_id, this->InitializeCommandHandlers(),
31 channel_monitor, thread_looper) {
32 InitializeServiceState();
33 }
34
InitializeServiceState()35 void CallService::InitializeServiceState() {
36 auto nvram_config = NvramConfig::Get();
37 auto instance = nvram_config->ForInstance(service_id_);
38 in_emergency_mode_ = instance.emergency_mode();
39
40 last_active_call_index_ = 1;
41 mute_on_ = false;
42 }
43
SetupDependency(SimService * sim,NetworkService * net)44 void CallService::SetupDependency(SimService* sim, NetworkService* net) {
45 sim_service_ = sim;
46 network_service_ = net;
47 }
48
InitializeCommandHandlers()49 std::vector<CommandHandler> CallService::InitializeCommandHandlers() {
50 std::vector<CommandHandler> command_handlers = {
51 CommandHandler("D",
52 [this](const Client& client, std::string& cmd) {
53 this->HandleDial(client, cmd);
54 }),
55 CommandHandler(
56 "A",
57 [this](const Client& client) { this->HandleAcceptCall(client); }),
58 CommandHandler(
59 "H",
60 [this](const Client& client) { this->HandleRejectCall(client); }),
61 CommandHandler(
62 "+CLCC",
63 [this](const Client& client) { this->HandleCurrentCalls(client); }),
64 CommandHandler("+CHLD=",
65 [this](const Client& client, std::string& cmd) {
66 this->HandleHangup(client, cmd);
67 }),
68 CommandHandler("+CMUT",
69 [this](const Client& client, std::string& cmd) {
70 this->HandleMute(client, cmd);
71 }),
72 CommandHandler("+VTS=",
73 [this](const Client& client, std::string& cmd) {
74 this->HandleSendDtmf(client, cmd);
75 }),
76 CommandHandler("+CUSD=",
77 [this](const Client& client, std::string& cmd) {
78 this->HandleCancelUssd(client, cmd);
79 }),
80 CommandHandler("+WSOS=0",
81 [this](const Client& client, std::string& cmd) {
82 this->HandleEmergencyMode(client, cmd);
83 }),
84 CommandHandler("+REMOTECALL",
85 [this](const Client& client, std::string& cmd) {
86 this->HandleRemoteCall(client, cmd);
87 }),
88 };
89 return (command_handlers);
90 }
91
92 // This also resumes held calls
SimulatePendingCallsAnswered()93 void CallService::SimulatePendingCallsAnswered() {
94 for (auto& iter : active_calls_) {
95 if (iter.second.isCallDialing()) {
96 iter.second.SetCallActive();
97 }
98 }
99 }
100
TimerWaitingRemoteCallResponse(CallToken call_token)101 void CallService::TimerWaitingRemoteCallResponse(CallToken call_token) {
102 LOG(DEBUG) << "Dialing id: " << call_token.first
103 << ", number: " << call_token.second << "timeout, cancel";
104 auto iter = active_calls_.find(call_token.first);
105 if (iter != active_calls_.end() && iter->second.number == call_token.second) {
106 if (iter->second.remote_client != std::nullopt) {
107 CloseRemoteConnection(*(iter->second.remote_client));
108 }
109 active_calls_.erase(iter); // match
110 CallStateUpdate();
111 } // else not match, ignore
112 }
113
114 /* ATD */
HandleDial(const Client & client,const std::string & command)115 void CallService::HandleDial(const Client& client, const std::string& command) {
116 // Check the network registration state
117 auto registration_state = NetworkService::NET_REGISTRATION_UNKNOWN;
118 if (network_service_) {
119 registration_state = network_service_->GetVoiceRegistrationState();
120 }
121
122 bool emergency_only = false;
123 if (registration_state == NetworkService::NET_REGISTRATION_HOME ||
124 registration_state == NetworkService::NET_REGISTRATION_ROAMING) {
125 emergency_only = false;
126 } else if (registration_state == NetworkService::NET_REGISTRATION_EMERGENCY) {
127 emergency_only = true;
128 } else {
129 client.SendCommandResponse(kCmeErrorNoNetworkService);
130 return;
131 }
132
133 CommandParser cmd(command);
134 cmd.SkipPrefixAT();
135
136 std::string number;
137 bool emergency_number = false;
138 /**
139 * Normal dial: ATDnumber[clir];
140 * Emergency dial: ATDnumber@[category],#[clir];
141 */
142 auto pos = cmd->find_last_of('@');
143 if (pos != std::string_view::npos) {
144 emergency_number = true;
145 number = cmd->substr(1, pos -1); // Skip 'D' and ignore category, clir
146 } else { // Remove 'i' or 'I' or ';'
147 pos = cmd->find_last_of('i');
148 if (pos == std::string_view::npos) {
149 pos = cmd->find_last_of('I');
150 if (pos == std::string_view::npos) {
151 pos = cmd->find_last_of(';');
152 }
153 }
154 if (pos == std::string_view::npos) {
155 number = cmd->substr(1);
156 } else {
157 number = cmd->substr(1, pos -1);
158 }
159 }
160
161 // Check the number is valid digits or not
162 if (strspn(number.c_str(), "1234567890") != number.size()) {
163 client.SendCommandResponse(kCmeErrorInCorrectParameters);
164 return;
165 }
166
167 if (emergency_only && !emergency_number) {
168 client.SendCommandResponse(kCmeErrorNetworkNotAllowedEmergencyCallsOnly);
169 return;
170 }
171
172 // If the number is not emergency number, FDN enabled and the number is not in
173 // the fdn list, return kCmeErrorFixedDialNumberOnlyAllowed.
174 if (!emergency_number && sim_service_->IsFDNEnabled() &&
175 !sim_service_->IsFixedDialNumber(number)) {
176 client.SendCommandResponse(kCmeErrorFixedDialNumberOnlyAllowed);
177 return;
178 }
179
180 int port = 0;
181 if (number.length() == 11) {
182 port = std::stoi(number.substr(7));
183 } else if (number.length() == 4) {
184 port = std::stoi(number);
185 }
186
187 if (port >= kRemotePortRange.first &&
188 port <= kRemotePortRange.second) { // May be a remote call
189 std::stringstream ss;
190 ss << port;
191 auto remote_port = ss.str();
192 auto remote_client = ConnectToRemoteCvd(remote_port);
193 if (!remote_client->IsOpen()) {
194 client.SendCommandResponse(kCmeErrorNoNetworkService);
195 return;
196 }
197 auto local_host_port = GetHostPort();
198 if (local_host_port == remote_port) {
199 client.SendCommandResponse(kCmeErrorOperationNotAllowed);
200 return;
201 }
202
203 if (channel_monitor_) {
204 channel_monitor_->SetRemoteClient(remote_client, false);
205 }
206
207 ss.clear();
208 ss.str("");
209 ss << "AT+REMOTECALL=4,0,0,\"" << local_host_port << "\",129";
210
211 SendCommandToRemote(remote_client, "REM0");
212 SendCommandToRemote(remote_client, ss.str());
213
214 CallStatus call_status(remote_port);
215 call_status.is_remote_call = true;
216 call_status.is_mobile_terminated = false;
217 call_status.call_state = CallStatus::CALL_STATE_DIALING;
218 call_status.remote_client = remote_client;
219 int index = last_active_call_index_++;
220
221 auto call_token = std::make_pair(index, call_status.number);
222 call_status.timeout_serial = thread_looper_->PostWithDelay(
223 std::chrono::minutes(1),
224 makeSafeCallback<CallService>(this, [call_token](CallService* me) {
225 me->TimerWaitingRemoteCallResponse(call_token);
226 }));
227
228 active_calls_[index] = call_status;
229 } else {
230 CallStatus call_status(number);
231 call_status.is_mobile_terminated = false;
232 call_status.call_state = CallStatus::CALL_STATE_DIALING;
233 auto index = last_active_call_index_++;
234 active_calls_[index] = call_status;
235
236 if (emergency_number) {
237 in_emergency_mode_ = true;
238 SendUnsolicitedCommand("+WSOS: 1");
239 }
240 thread_looper_->PostWithDelay(std::chrono::seconds(1),
241 makeSafeCallback(this, &CallService::SimulatePendingCallsAnswered));
242 }
243
244 client.SendCommandResponse("OK");
245 std::this_thread::sleep_for(std::chrono::seconds(2));
246 }
247
SendCallStatusToRemote(CallStatus & call,CallStatus::CallState state)248 void CallService::SendCallStatusToRemote(CallStatus& call,
249 CallStatus::CallState state) {
250 if (call.is_remote_call && call.remote_client != std::nullopt) {
251 std::stringstream ss;
252 ss << "AT+REMOTECALL=" << state << ","
253 << call.is_voice_mode << ","
254 << call.is_multi_party << ",\""
255 << GetHostPort() << "\","
256 << call.is_international;
257
258 SendCommandToRemote(*(call.remote_client), ss.str());
259 if (state == CallStatus::CALL_STATE_HANGUP) {
260 CloseRemoteConnection(*(call.remote_client));
261 }
262 }
263 }
264
265 /* ATA */
HandleAcceptCall(const Client & client)266 void CallService::HandleAcceptCall(const Client& client) {
267 for (auto& iter : active_calls_) {
268 if (iter.second.isCallIncoming()) {
269 iter.second.SetCallActive();
270 SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_ACTIVE);
271 } else if (iter.second.isCallActive()) {
272 iter.second.SetCallBackground();
273 SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_HELD);
274 }
275 }
276
277 client.SendCommandResponse("OK");
278 }
279
280 /* ATH */
HandleRejectCall(const Client & client)281 void CallService::HandleRejectCall(const Client& client) {
282 for (auto iter = active_calls_.begin(); iter != active_calls_.end();) {
283 /* ATH: hangup, since user is busy */
284 if (iter->second.isCallIncoming()) {
285 SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
286 iter = active_calls_.erase(iter);
287 } else {
288 ++iter;
289 }
290 }
291
292 client.SendCommandResponse("OK");
293 }
294
295 /**
296 * AT+CLCC
297 * Returns list of current calls of MT. If command succeeds but no
298 * calls are available, no information response is sent to TE.
299 *
300 * command Possible response(s)
301 * AT+CLCC [+CLCC: <ccid1>,<dir>,<stat>,<mode>,<mpty>
302 * [,<number>,<type>[,<alpha>[,<priority>
303 * [,<CLI validity>]]]][<CR><LF>
304 * +CLCC: <ccid2>,<dir>,<stat>,<mode>,<mpty>
305 * [,<number>,<type>[,<alpha>[,<priority>[,<CLI validity>]]]]
306 * +CME ERROR: <err>
307 *
308 * <ccidx>: integer type. This number can be used in +CHLD command
309 * operations. Value range is from 1 to N. N, the maximum number of
310 * simultaneous call control processes is implementation specific.
311 * <dir>: integer type
312 * 0 mobile originated (MO) call
313 1 mobile terminated (MT) call
314 * <stat>: integer type (state of the call)
315 * 0 active
316 * 1 held
317 * 2 dialing (MO call)
318 * 3 alerting (MO call)
319 * 4 incoming (MT call)
320 * 5 waiting (MT call)
321 * <mode>: integer type (bearer/teleservice)
322 * 0 voice
323 * 1 data
324 * 2 fax
325 * 3 voice followed by data, voice mode
326 * 4 alternating voice/data, voice mode
327 * 5 alternating voice/fax, voice mode
328 * 6 voice followed by data, data mode
329 * 7 alternating voice/data, data mode
330 * 8 alternating voice/fax, fax mode
331 * 9 unknown
332 * <mpty>: integer type
333 * 0 call is not one of multiparty (conference) call parties
334 * 1 call is one of multiparty (conference) call parties
335 * <number>: string type phone number in format specified by <type>.
336 * <type>: type of address octet in integer format
337 *
338 *see RIL_REQUEST_GET_CURRENT_CALLS in RIL
339 */
HandleCurrentCalls(const Client & client)340 void CallService::HandleCurrentCalls(const Client& client) {
341 std::vector<std::string> responses;
342 std::stringstream ss;
343
344 // AT+CLCC
345 // [+CLCC: <ccid1>,<dir>,<stat>,<mode>,<mpty>[,<number>,<type>[,<alpha>[,<priority>[,<CLI validity>]]]]
346 // [+CLCC: <ccid2>,<dir>,<stat>,<mode>,<mpty>[,<number>,<type>[,<alpha>[,<priority>[,<CLI validity>]]]]
347 // [...]]]
348 for (auto iter = active_calls_.begin(); iter != active_calls_.end(); ++iter) {
349 int index = iter->first;
350 int dir = iter->second.is_mobile_terminated;
351 CallStatus::CallState call_state = iter->second.call_state;
352 int mode = iter->second.is_voice_mode;
353 int mpty = iter->second.is_multi_party;
354 int type = iter->second.is_international ? 145 : 129;
355 std::string number = iter->second.number;
356
357 ss.clear();
358 ss << "+CLCC: " << index << "," << dir << "," << call_state << ","
359 << mode << "," << mpty << "," << number<< "," << type;
360 responses.push_back(ss.str());
361 ss.str("");
362 }
363
364 responses.push_back("OK");
365 client.SendCommandResponse(responses);
366 }
367
368 /**
369 * AT+CHLD
370 * This command allows the control of the following call related services:
371 * 1) a call can be temporarily disconnected from the MT but the connection
372 * is retained by the network;
373 * 2) multiparty conversation (conference calls);
374 * 3) the served subscriber who has two calls (one held and the other
375 * either active or alerting) can connect the other parties and release
376 * the served subscriber's own connection.
377 *
378 * Calls can be put on hold, recovered, released, added to conversation,
379 * and transferred similarly.
380 *
381 * command Possible response(s)
382 * +CHLD=<n> +CME ERROR: <err>
383 *
384 * +CHLD=? +CHLD: (list of supported <n>s)
385 * e.g. +CHLD: (0,1,1x,2,2x,3,4)
386 *
387 *
388 * see RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND
389 * RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
390 * RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE
391 * RIL_REQUEST_CONFERENCE
392 * RIL_REQUEST_SEPARATE_CONNECTION
393 * RIL_REQUEST_HANGUP
394 * RIL_REQUEST_UDUB in RIL
395 */
HandleHangup(const Client & client,const std::string & command)396 void CallService::HandleHangup(const Client& client,
397 const std::string& command) {
398 std::vector<std::string> responses;
399 CommandParser cmd(command);
400 cmd.SkipPrefix();
401
402 std::string action(*cmd);
403 int n = std::stoi(action.substr(0, 1));
404 int index = -1;
405 if (cmd->length() > 1) {
406 index = std::stoi(action.substr(1));
407 }
408
409 switch (n) {
410 case 0: // Release all held calls or set User Determined User Busy(UDUB) for a waiting call
411 for (auto iter = active_calls_.begin(); iter != active_calls_.end();) {
412 if (iter->second.isCallIncoming() ||
413 iter->second.isCallBackground() ||
414 iter->second.isCallWaiting()) {
415 SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
416 iter = active_calls_.erase(iter);
417 } else {
418 ++iter;
419 }
420 }
421 break;
422 case 1:
423 if (index == -1) { // Release all active calls and accepts the other(hold or waiting) call
424 for (auto iter = active_calls_.begin(); iter != active_calls_.end();) {
425 if (iter->second.isCallActive()) {
426 SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
427 iter = active_calls_.erase(iter);
428 continue;
429 } else if (iter->second.isCallBackground() ||
430 iter->second.isCallWaiting()) {
431 iter->second.SetCallActive();
432 SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_ACTIVE);
433 }
434 ++iter;
435 }
436 } else { // Release a specific active call
437 auto iter = active_calls_.find(index);
438 if (iter != active_calls_.end()) {
439 SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
440 active_calls_.erase(iter);
441 }
442 }
443 break;
444 case 2:
445 if (index == -1) { // Place all active calls and the waiting calls, activates all held calls
446 for (auto& iter : active_calls_) {
447 if (iter.second.isCallActive() || iter.second.isCallWaiting()) {
448 iter.second.SetCallBackground();
449 SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_HELD);
450 } else if (iter.second.isCallBackground()) {
451 iter.second.SetCallActive();
452 SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_ACTIVE);
453 }
454 }
455 } else { // Disconnect a call from the conversation
456 auto iter = active_calls_.find(index);
457 if (iter != active_calls_.end()) {
458 SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
459 active_calls_.erase(iter);
460 }
461 }
462 break;
463 case 3: // Adds an held call to the conversation
464 for (auto iter = active_calls_.begin(); iter != active_calls_.end(); ++iter) {
465 if (iter->second.isCallBackground()) {
466 iter->second.SetCallActive();
467 SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_ACTIVE);
468 }
469 }
470 break;
471 case 4: // Connect the two calls
472 for (auto iter = active_calls_.begin(); iter != active_calls_.end(); ++iter) {
473 if (iter->second.isCallBackground()) {
474 iter->second.SetCallActive();
475 SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_ACTIVE);
476 }
477 }
478 break;
479 default:
480 client.SendCommandResponse(kCmeErrorOperationNotAllowed);
481 return;
482 }
483 client.SendCommandResponse("OK");
484 }
485
486 /**
487 * AT+CMUT
488 * This command is used to enable and disable the uplink voice muting
489 * during a voice call.
490 * Read command returns the current value of <n>.
491 *
492 * Command Possible response(s)
493 * +CMUT=[<n>] +CME ERROR: <err>
494 * +CMUT? +CMUT: <n>
495 * +CME ERROR: <err>
496 *
497 * <n>: integer type
498 * 0 mute off
499 * 1 mute on
500 *
501 * see RIL_REQUEST_SET_MUTE or RIL_REQUEST_GET_MUTE in RIL
502 */
HandleMute(const Client & client,const std::string & command)503 void CallService::HandleMute(const Client& client, const std::string& command) {
504 std::vector<std::string> responses;
505 std::stringstream ss;
506
507 CommandParser cmd(command);
508 cmd.SkipPrefix(); // If AT+CMUT?, it remains AT+CMUT?
509
510 if (cmd == "AT+CMUT?") {
511 ss << "+CMUT: " << mute_on_;
512 responses.push_back(ss.str());
513 } else { // AT+CMUT = <n>
514 int n = cmd.GetNextInt();
515 switch (n) {
516 case 0: // Mute off
517 mute_on_ = false;
518 break;
519 case 1: // Mute on
520 mute_on_ = true;
521 break;
522 default:
523 client.SendCommandResponse(kCmeErrorInCorrectParameters);
524 return;
525 }
526 }
527 responses.push_back("OK");
528 client.SendCommandResponse(responses);
529 }
530
531 /**
532 * AT+VTS
533 * This command transmits DTMF, after a successful call connection.
534 * Setting Command is used to send one or more ASCII characters which make
535 * MSC (Mobile Switching Center) send DTMF tone to remote User.
536 *
537 * Command Possible response(s)
538 * AT+VTS=<dtmf>[,<duration>] +CME ERROR: <err>
539 *
540 * <dtmf>
541 * A single ASCII character in the set { 0 -9, #, *, A – D}.
542 * <duration>
543 * Refer to duration value range of +VTD command
544 *
545 * see RIL_REQUEST_DTMF in RIL
546 */
HandleSendDtmf(const Client & client,const std::string &)547 void CallService::HandleSendDtmf(const Client& client,
548 const std::string& /*command*/) {
549 client.SendCommandResponse("OK");
550 }
551
HandleCancelUssd(const Client & client,const std::string &)552 void CallService::HandleCancelUssd(const Client& client,
553 const std::string& /*command*/) {
554 client.SendCommandResponse("OK");
555 }
556
557 /**
558 * AT+WSOS
559 *
560 * Command Possible response(s)
561 * +WSOS=[<n>] +CME ERROR: <err>
562 * +WSOS? +WSOS: <n>
563 * +CME ERROR: <err>
564 *
565 * <n>: integer type
566 * 0 enter emergency mode
567 * 1 exit emergency mode
568 *
569 * see RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE
570 * RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE
571 * RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE in RIL
572 */
HandleEmergencyMode(const Client & client,const std::string & command)573 void CallService::HandleEmergencyMode(const Client& client,
574 const std::string& command) {
575 std::vector<std::string> responses;
576 CommandParser cmd(command);
577 cmd.SkipPrefix();
578
579 if (cmd == "AT+WSOS?") {
580 std::stringstream ss;
581 ss << "+WSOS: " << in_emergency_mode_;
582 responses.push_back(ss.str());
583 } else {
584 int n = cmd.GetNextInt();
585 switch (n) {
586 case 0: // Exit
587 in_emergency_mode_ = false;
588 break;
589 case 1: // Enter
590 in_emergency_mode_ = true;
591 break;
592 default:
593 client.SendCommandResponse(kCmeErrorInCorrectParameters);
594 return;
595 }
596 auto nvram_config = NvramConfig::Get();
597 auto instance = nvram_config->ForInstance(service_id_);
598 instance.set_emergency_mode(in_emergency_mode_);
599 NvramConfig::SaveToFile();
600 }
601 client.SendCommandResponse("OK");
602 }
603
CallStateUpdate()604 void CallService::CallStateUpdate() {
605 SendUnsolicitedCommand("RING");
606 }
607
608 /**
609 * AT+REMOTECALL=<dir>,<stat>,<mode>,<mpty>,<number>,<num_type>
610 * This command allows to dial a remote voice call with another cuttlefish
611 * emulator. If request is successful, the remote emulator can simulate hold on,
612 * hang up, reject and so on.
613 *
614 * e.g. AT+REMOTECALL=4,0,0,6521,129
615 *
616 * <stat>: integer type (state of the call)
617 * 0 active
618 * 1 held
619 * 2 dialing (MO call)
620 * 3 alerting (MO call)
621 * 4 incoming (MT call)
622 * 5 waiting (MT call)
623 * <mode>: integer type
624 * 0 voice
625 * 1 data
626 * 2 fax
627 * 3 voice followed by data, voice mode
628 * 4 alternating voice/data, voice mode
629 * 5 alternating voice/fax, voice mode
630 * 6 voice followed by data, data mode
631 * 7 alternating voice/data, data mode
632 * 8 alternating voice/fax, fax mode
633 * 9 unknown
634 * <mpty>: integer type
635 * 0 call is not one of multiparty (conference) call parties
636 * 1 call is one of multiparty (conference) call parties
637 * <number>: string here maybe remote port
638 * <num_type>: type of address octet in integer format
639 *
640 * Note: reason should be added to indicate why hang up. Since not realizing
641 * RIL_LAST_CALL_FAIL_CAUSE, delay to be implemented.
642 */
HandleRemoteCall(const Client & client,const std::string & command)643 void CallService::HandleRemoteCall(const Client& client,
644 const std::string& command) {
645 CommandParser cmd(command);
646 cmd.SkipPrefix();
647
648 int state = cmd.GetNextInt();
649 int mode = cmd.GetNextInt();
650 int mpty = cmd.GetNextInt();
651 auto number = cmd.GetNextStr();
652 int num_type = cmd.GetNextInt();
653
654 // According to the number to determine whether it is a existing call
655 auto iter = active_calls_.begin();
656 for (; iter != active_calls_.end(); ++iter) {
657 if (iter->second.number == number) {
658 break;
659 }
660 }
661
662 switch (state) {
663 case CallStatus::CALL_STATE_ACTIVE: {
664 if (iter != active_calls_.end()) {
665 iter->second.SetCallActive();
666 if (iter->second.timeout_serial != std::nullopt) {
667 thread_looper_->CancelSerial(*(iter->second.timeout_serial));
668 }
669 }
670 break;
671 }
672 case CallStatus::CALL_STATE_HELD:
673 if (iter != active_calls_.end()) {
674 iter->second.SetCallBackground();
675 if (iter->second.timeout_serial != std::nullopt) {
676 thread_looper_->CancelSerial(*(iter->second.timeout_serial));
677 }
678 }
679 break;
680 case CallStatus::CALL_STATE_HANGUP:
681 if (iter != active_calls_.end()) {
682 auto client = iter->second.remote_client;
683 if (client != std::nullopt) {
684 CloseRemoteConnection(*client);
685 }
686 if (iter->second.timeout_serial != std::nullopt) {
687 thread_looper_->CancelSerial(*(iter->second.timeout_serial));
688 }
689 active_calls_.erase(iter);
690 }
691 break;
692 case CallStatus::CALL_STATE_INCOMING: {
693 if (network_service_) {
694 if (network_service_->isRadioOff()) {
695 LOG(DEBUG) << " radio is off, reject incoming call from: " << number;
696 client.client_fd->Close();
697 return;
698 }
699 }
700 CallStatus call_status(number);
701 call_status.is_remote_call = true;
702 call_status.is_voice_mode = mode;
703 call_status.is_multi_party = mpty;
704 call_status.is_mobile_terminated = true;
705 call_status.is_international = num_type;
706 call_status.remote_client = client.client_fd;
707 call_status.call_state = CallStatus::CALL_STATE_INCOMING;
708
709 auto index = last_active_call_index_++;
710 active_calls_[index] = call_status;
711 break;
712 }
713 default: // Unsupported call state
714 return;
715 }
716 thread_looper_->Post(makeSafeCallback(this, &CallService::CallStateUpdate));
717 }
718
719 } // namespace cuttlefish
720