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