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