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