Coverage Report

Created: 2026-01-27 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/adhd/cras/src/server/cras_hfp_slc.c
Line
Count
Source
1
/* Copyright 2013 The ChromiumOS Authors
2
 * Use of this source code is governed by a BSD-style license that can be
3
 * found in the LICENSE file.
4
 */
5
6
#include "cras/src/server/cras_hfp_slc.h"
7
8
#include <errno.h>
9
#include <stdbool.h>
10
#include <stdint.h>
11
#include <stdio.h>
12
#include <stdlib.h>
13
#include <string.h>
14
#include <sys/poll.h>
15
#include <syslog.h>
16
#include <time.h>
17
#include <unistd.h>
18
19
#include "cras/src/common/cras_string.h"
20
#include "cras/src/server/cras_bt_device.h"
21
#include "cras/src/server/cras_bt_log.h"
22
#include "cras/src/server/cras_observer.h"
23
#include "cras/src/server/cras_server_metrics.h"
24
#include "cras/src/server/cras_system_state.h"
25
#include "cras/src/server/cras_telephony.h"
26
#include "cras/src/server/cras_tm.h"
27
#include "cras_types.h"
28
#include "cras_util.h"
29
30
// Message start and end with "\r\n". refer to spec 4.33.
31
1.29k
#define AT_CMD(cmd) "\r\n" cmd "\r\n"
32
33
// The timeout between event reporting and HF indicator commands
34
0
#define HF_INDICATORS_TIMEOUT_MS 2000
35
/* The sleep time before reading and processing the following AT commands during
36
 * codec connection setup.
37
 */
38
0
#define CODEC_CONN_SLEEP_TIME_US 2000
39
2.60k
#define SLC_BUF_SIZE_BYTES 256
40
41
/* Indicator update command response and indicator indices.
42
 * Note that indicator index starts from '1', index 0 is used for CRAS to record
43
 * if the event report has been enabled or not.
44
 */
45
1.34k
#define CRAS_INDICATOR_ENABLE_INDEX 0
46
1.33k
#define BATTERY_IND_INDEX 1
47
0
#define SIGNAL_IND_INDEX 2
48
0
#define SERVICE_IND_INDEX 3
49
154
#define CALL_IND_INDEX 4
50
176
#define CALLSETUP_IND_INDEX 5
51
62
#define CALLHELD_IND_INDEX 6
52
#define ROAM_IND_INDEX 7
53
10.5k
#define INDICATOR_IND_MAX 8
54
#define INDICATOR_UPDATE_RSP \
55
  "+CIND: "                  \
56
  "(\"battchg\",(0-5)),"     \
57
  "(\"signal\",(0-5)),"      \
58
  "(\"service\",(0,1)),"     \
59
  "(\"call\",(0,1)),"        \
60
  "(\"callsetup\",(0-3)),"   \
61
  "(\"callheld\",(0-2)),"    \
62
  "(\"roam\",(0,1))"         \
63
  ""
64
/* Mode values for standard event reporting activation/deactivation AT
65
 * command AT+CMER. Used for indicator events reporting in HFP. */
66
36
#define FORWARD_UNSOLICIT_RESULT_CODE 3
67
68
/* Handle object to hold required info to initialize and maintain
69
 * an HFP service level connection.
70
 */
71
struct hfp_slc_handle {
72
  // Buffer hold received commands.
73
  char buf[SLC_BUF_SIZE_BYTES];
74
  // Read index for buf.
75
  int buf_read_idx;
76
  // Write index for buf.
77
  int buf_write_idx;
78
  // File descriptor for the established RFCOMM connection.
79
  int rfcomm_fd;
80
  // Callback to be triggered when an SLC is initialized.
81
  hfp_slc_init_cb init_cb;
82
  hfp_slc_disconnect_cb disconnect_cb;
83
  // Calling line identification notification is enabled or not.
84
  int cli_active;
85
  // Current battery level of AG stored in SLC.
86
  int battery;
87
  // Current signal strength of AG stored in SLC.
88
  int signal;
89
  // Current service availability of AG stored in SLC.
90
  int service;
91
  // Current callheld status of AG stored in SLC.
92
  int callheld;
93
  // Activate statuses of indicator events reporting.
94
  int ind_event_reports[INDICATOR_IND_MAX];
95
  // Supported AG features bitmap.
96
  int ag_supported_features;
97
  bool hf_codec_supported[HFP_MAX_CODECS];
98
  // Bit map of HF supported features.
99
  int hf_supported_features;
100
  // Bit map of battery indicator support of
101
  // connected HF.
102
  int hf_supports_battery_indicator;
103
  // Current battery level of HF reported by the HF. The data
104
  // range should be 0 ~ 100. Use -1 for no battery level reported.
105
  int hf_battery;
106
  // CVSD or mSBC based on the situation and strategy. This
107
  // needs not to be equal to selected_codec because codec negotiation
108
  // process may fail.
109
  int preferred_codec;
110
  // The codec id defaults to HFP_CODEC_UNUSED and changes
111
  // only if codec negotiation is supported and the negotiation flow
112
  // has completed.
113
  int selected_codec;
114
  // The associated bt device.
115
  struct cras_bt_device* device;
116
  struct cras_timer* timer;
117
118
  // A reference of current telephony handle.
119
  struct cras_telephony_handle* telephony;
120
};
121
122
// AT command exchanges between AG(Audio gateway) and HF(Hands-free device)
123
struct at_command {
124
  const char* cmd;
125
  int (*callback)(struct hfp_slc_handle* handle, const char* cmd);
126
};
127
128
// Sends a response or command to HF
129
1.31k
static int hfp_send(struct hfp_slc_handle* handle, const char* buf) {
130
1.31k
  int written, err, len;
131
132
1.31k
  if (handle->rfcomm_fd < 0) {
133
0
    return -EIO;
134
0
  }
135
136
1.31k
  len = strlen(buf);
137
1.31k
  written = 0;
138
2.63k
  while (written < len) {
139
1.31k
    err = write(handle->rfcomm_fd, buf + written, len - written);
140
1.31k
    if (err < 0) {
141
0
      return -errno;
142
0
    }
143
1.31k
    written += err;
144
1.31k
  }
145
146
1.31k
  return 0;
147
1.31k
}
148
149
// Sends a response for indicator event reporting.
150
static int hfp_send_ind_event_report(struct hfp_slc_handle* handle,
151
                                     int ind_index,
152
30
                                     int value) {
153
30
  char cmd[64];
154
155
30
  if (!handle->ind_event_reports[CRAS_INDICATOR_ENABLE_INDEX] ||
156
30
      !handle->ind_event_reports[ind_index]) {
157
30
    return 0;
158
30
  }
159
160
30
  snprintf(cmd, 64, AT_CMD("+CIEV: %d,%d"), ind_index, value);
161
0
  return hfp_send(handle, cmd);
162
30
}
163
164
/* Sends calling line identification unsolicited result code and
165
 * standard call waiting notification. */
166
static int hfp_send_calling_line_identification(struct hfp_slc_handle* handle,
167
                                                const char* number,
168
0
                                                int type) {
169
0
  char cmd[64];
170
171
0
  if (handle->telephony->call) {
172
0
    snprintf(cmd, 64, AT_CMD("+CCWA: \"%s\",%d"), number, type);
173
0
  } else {
174
0
    snprintf(cmd, 64, AT_CMD("+CLIP: \"%s\",%d"), number, type);
175
0
  }
176
0
  return hfp_send(handle, cmd);
177
0
}
178
179
// ATA command to accept an incoming call. Mandatory support per spec 4.13.
180
3
static int answer_call(struct hfp_slc_handle* handle, const char* cmd) {
181
3
  int rc;
182
3
  rc = hfp_send(handle, AT_CMD("OK"));
183
3
  if (rc) {
184
0
    return rc;
185
0
  }
186
187
3
  return cras_telephony_event_answer_call();
188
3
}
189
190
/* AT+CCWA command to enable the "Call Waiting notification" function.
191
 * Mandatory support per spec 4.21. */
192
1
static int call_waiting_notify(struct hfp_slc_handle* handle, const char* buf) {
193
1
  return hfp_send(handle, AT_CMD("OK"));
194
1
}
195
196
/* AT+CLIP command to enable the "Calling Line Identification notification"
197
 * function. Mandatory per spec 4.23.
198
 */
199
22
static int cli_notification(struct hfp_slc_handle* handle, const char* cmd) {
200
22
  if (strlen(cmd) < 9) {
201
2
    syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
202
2
    return hfp_send(handle, AT_CMD("ERROR"));
203
2
  }
204
20
  handle->cli_active = (cmd[8] == '1');
205
20
  return hfp_send(handle, AT_CMD("OK"));
206
22
}
207
208
/* ATDdd...dd command to place call with supplied number, or ATD>nnn...
209
 * command to dial the number stored at memory location. Mandatory per
210
 * spec 4.18 and 4.19.
211
 */
212
64
static int dial_number(struct hfp_slc_handle* handle, const char* cmd) {
213
64
  int rc, cmd_len;
214
215
64
  cmd_len = strlen(cmd);
216
64
  if (cmd_len < 4) {
217
1
    goto error_out;
218
1
  }
219
220
63
  if (cmd[3] == '>') {
221
    /* Handle memory dial. Extract memory location from command
222
     * ATD>nnn...; and lookup. */
223
36
    int memory_location;
224
36
    memory_location = strtol(cmd + 4, NULL, 0);
225
36
    if (handle->telephony->dial_number == NULL || memory_location != 1) {
226
35
      return hfp_send(handle, AT_CMD("ERROR"));
227
35
    }
228
36
  } else {
229
    // ATDddddd; Store dial number to the only memory slot.
230
27
    cras_telephony_store_dial_number(cmd_len - 3 - 1, cmd + 3);
231
27
  }
232
233
28
  rc = hfp_send(handle, AT_CMD("OK"));
234
28
  if (rc) {
235
0
    return rc;
236
0
  }
237
238
28
  handle->telephony->callsetup = 2;
239
28
  return hfp_send_ind_event_report(handle, CALLSETUP_IND_INDEX, 2);
240
241
1
error_out:
242
1
  syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
243
1
  return hfp_send(handle, AT_CMD("ERROR"));
244
28
}
245
246
// AT+VTS command to generate a DTMF code. Mandatory per spec 4.27.
247
1
static int dtmf_tone(struct hfp_slc_handle* handle, const char* buf) {
248
1
  return hfp_send(handle, AT_CMD("OK"));
249
1
}
250
251
/* Sends +BCS command to tell HF about our preferred codec. This shall
252
 * be called only if codec negotiation is supported.
253
 */
254
0
static void select_preferred_codec(struct hfp_slc_handle* handle) {
255
0
  char buf[64];
256
0
  snprintf(buf, 64, AT_CMD("+BCS:%d"), handle->preferred_codec);
257
0
  hfp_send(handle, buf);
258
0
  BTLOG(btlog, BT_CODEC_SELECTION, 0, handle->preferred_codec);
259
0
}
260
261
// Marks SLC handle as initialized and trigger HFP AG's init_cb.
262
35
static void initialize_slc_handle(struct cras_timer* timer, void* arg) {
263
35
  struct hfp_slc_handle* handle = (struct hfp_slc_handle*)arg;
264
35
  if (timer) {
265
0
    handle->timer = NULL;
266
0
  }
267
268
35
  if (handle->init_cb) {
269
0
    handle->init_cb(handle);
270
0
    handle->init_cb = NULL;
271
0
  }
272
35
}
273
274
/* Handles the event that headset request to start a codec connection
275
 * procedure.
276
 */
277
static int bluetooth_codec_connection(struct hfp_slc_handle* handle,
278
1
                                      const char* cmd) {
279
  /* Reset current selected codec to force a new codec connection
280
   * procedure when the next hfp_slc_codec_connection_setup is called.
281
   */
282
1
  handle->selected_codec = HFP_CODEC_UNUSED;
283
1
  return hfp_send(handle, AT_CMD("OK"));
284
1
}
285
286
// Handles the event that headset request to select specific codec.
287
static int bluetooth_codec_selection(struct hfp_slc_handle* handle,
288
72
                                     const char* cmd) {
289
72
  char* tokens = strdup(cmd);
290
72
  char* codec;
291
72
  int id, err;
292
293
72
  strtok(tokens, "=");
294
72
  codec = strtok(NULL, ",");
295
72
  if (!codec) {
296
1
    goto bcs_cmd_cleanup;
297
1
  }
298
71
  int rc = parse_int(codec, &id);
299
71
  if ((rc < 0 || id <= HFP_CODEC_UNUSED) || (id >= HFP_MAX_CODECS)) {
300
69
    syslog(LOG_WARNING, "%s: invalid codec id: '%s'", __func__, cmd);
301
69
    free(tokens);
302
69
    return hfp_send(handle, AT_CMD("ERROR"));
303
69
  }
304
305
2
  if (id != handle->preferred_codec) {
306
1
    syslog(LOG_WARNING, "%s: inconsistent codec id: '%s'", __func__, cmd);
307
1
  }
308
309
2
  BTLOG(btlog, BT_CODEC_SELECTION, 1, id);
310
2
  handle->selected_codec = id;
311
312
3
bcs_cmd_cleanup:
313
3
  free(tokens);
314
3
  err = hfp_send(handle, AT_CMD("OK"));
315
3
  return err;
316
2
}
317
318
/*
319
 * AT+IPHONEACCEV command from HF to report state change.You can find details
320
 * of this command in the Accessory Design Guidelines for Apple Devices R11
321
 * section 16.1.
322
 */
323
static int apple_accessory_state_change(struct hfp_slc_handle* handle,
324
225
                                        const char* cmd) {
325
225
  char *tokens, *num, *key, *val;
326
225
  int i, level;
327
328
  /* AT+IPHONEACCEV=Number of key/value pairs,key1,val1,key2,val2,...
329
   * Number of key/value pairs: The number of parameters coming next.
330
   * key: the type of change being reported:
331
   *      1 = Battery Level
332
   *      2 = Dock State
333
   * val: the value of the change:
334
   * Battery Level: string value between '0' and '9'
335
   * Dock State: 0 = undocked, 1 = docked
336
   */
337
225
  tokens = strdup(cmd);
338
225
  strtok(tokens, "=");
339
225
  num = strtok(NULL, ",");
340
225
  if (!num) {
341
2
    free(tokens);
342
2
    return hfp_send(handle, AT_CMD("ERROR"));
343
2
  }
344
345
223
  int num_int;
346
223
  int rc = parse_int(num, &num_int);
347
223
  if (rc < 0) {
348
2
    free(tokens);
349
2
    return hfp_send(handle, AT_CMD("ERROR"));
350
2
  }
351
845
  for (i = 0; i < num_int; i++) {
352
779
    key = strtok(NULL, ",");
353
779
    val = strtok(NULL, ",");
354
779
    if (!key || !val) {
355
155
      syslog(LOG_WARNING, "IPHONEACCEV: Expected %d kv pairs but got %d",
356
155
             num_int, i);
357
155
      break;
358
155
    }
359
360
624
    int key_int;
361
624
    int rc = parse_int(key, &key_int);
362
624
    if (rc < 0) {
363
70
      syslog(LOG_WARNING, "Get invalid battery status from cmd:%s", cmd);
364
70
      continue;
365
70
    }
366
554
    rc = parse_int(val, &level);
367
554
    if (rc < 0) {
368
72
      syslog(LOG_WARNING, "Get invalid battery status from cmd:%s", cmd);
369
72
      continue;
370
72
    }
371
482
    if (key_int == 1) {
372
371
      if (level >= 0 && level < 10) {
373
174
        cras_server_metrics_hfp_battery_report(
374
174
            CRAS_HFP_BATTERY_INDICATOR_APPLE);
375
174
        level = (level + 1) * 10;
376
174
        if (handle->hf_battery != level) {
377
106
          handle->hf_battery = level;
378
106
          cras_observer_notify_bt_battery_changed(
379
106
              cras_bt_device_address(handle->device), (uint32_t)(level));
380
106
        }
381
197
      } else {
382
197
        syslog(LOG_WARNING, "Get invalid battery status from cmd:%s", cmd);
383
197
      }
384
371
    }
385
482
  }
386
221
  free(tokens);
387
221
  return hfp_send(handle, AT_CMD("OK"));
388
223
}
389
390
/*
391
 * AT+XAPL command from HF to enable Apple custom features. You can find details
392
 * of it in the Accessory Design Guidelines for Apple Devices R11 section 15.1.
393
 */
394
static int apple_supported_features(struct hfp_slc_handle* handle,
395
4
                                    const char* cmd) {
396
4
  char *tokens, *features;
397
4
  int apple_features, err;
398
4
  char buf[64];
399
400
  /* AT+XAPL=<vendorID>-<productID>-<version>,<features>
401
   * Parse <features>, the only token we care about.
402
   */
403
4
  tokens = strdup(cmd);
404
4
  strtok(tokens, "=");
405
406
4
  strtok(NULL, ",");
407
4
  features = strtok(NULL, ",");
408
4
  if (!features) {
409
1
    goto error_out;
410
1
  }
411
412
3
  int rc = parse_int(features, &apple_features);
413
3
  if (rc < 0) {
414
1
    goto error_out;
415
1
  }
416
417
2
  if (apple_features & APL_BATTERY) {
418
1
    handle->hf_supports_battery_indicator |= CRAS_HFP_BATTERY_INDICATOR_APPLE;
419
1
  }
420
421
2
  snprintf(buf, 64, AT_CMD("+XAPL=iPhone,%d"), CRAS_APL_SUPPORTED_FEATURES);
422
2
  err = hfp_send(handle, buf);
423
2
  if (err) {
424
0
    goto error_out;
425
0
  }
426
427
2
  err = hfp_send(handle, AT_CMD("OK"));
428
2
  free(tokens);
429
2
  return err;
430
431
2
error_out:
432
2
  syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
433
2
  free(tokens);
434
2
  return hfp_send(handle, AT_CMD("ERROR"));
435
2
}
436
437
// Handles the event when headset reports its available codecs list.
438
94
static int available_codecs(struct hfp_slc_handle* handle, const char* cmd) {
439
94
  char *tokens, *id_str;
440
94
  int id;
441
442
376
  for (id = 0; id < HFP_MAX_CODECS; id++) {
443
282
    handle->hf_codec_supported[id] = false;
444
282
  }
445
446
94
  tokens = strdup(cmd);
447
94
  strtok(tokens, "=");
448
94
  id_str = strtok(NULL, ",");
449
432
  while (id_str) {
450
340
    int rc = parse_int(id_str, &id);
451
340
    if (rc < 0) {
452
2
      goto error_out;
453
2
    }
454
338
    if ((id > HFP_CODEC_UNUSED) && (id < HFP_MAX_CODECS)) {
455
100
      handle->hf_codec_supported[id] = true;
456
100
      BTLOG(btlog, BT_AVAILABLE_CODECS, 0, id);
457
100
    }
458
338
    id_str = strtok(NULL, ",");
459
338
  }
460
461
92
  if (hfp_slc_get_wideband_speech_supported(handle)) {
462
0
    handle->preferred_codec = HFP_CODEC_ID_MSBC;
463
92
  } else {
464
92
    handle->preferred_codec = HFP_CODEC_ID_CVSD;
465
92
  }
466
467
92
  free(tokens);
468
92
  return hfp_send(handle, AT_CMD("OK"));
469
470
2
error_out:
471
2
  syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
472
2
  free(tokens);
473
2
  return hfp_send(handle, AT_CMD("ERROR"));
474
94
}
475
476
/* AT+CMER command enables the registration status update function in AG.
477
 * The service level connection is consider initialized when successfully
478
 * responded OK to the AT+CMER command. Mandatory support per spec 4.4.
479
 */
480
40
static int event_reporting(struct hfp_slc_handle* handle, const char* cmd) {
481
40
  char *tokens, *mode, *tmp;
482
40
  int err = 0;
483
484
  /* AT+CMER=[<mode>[,<keyp>[,<disp>[,<ind> [,<bfr>]]]]]
485
   * Parse <ind>, the only token we care about.
486
   */
487
40
  tokens = strdup(cmd);
488
40
  strtok(tokens, "=");
489
490
40
  mode = strtok(NULL, ",");
491
40
  tmp = strtok(NULL, ",");
492
40
  tmp = strtok(NULL, ",");
493
40
  tmp = strtok(NULL, ",");
494
495
  /* mode = 3 for forward unsolicited result codes.
496
   * AT+CMER=3,0,0,1 activates “indicator events reporting”.
497
   * The service level connection is considered established after
498
   * successfully responded with OK, regardless of the indicator
499
   * events reporting status.
500
   */
501
40
  if (!mode || !tmp) {
502
2
    syslog(LOG_WARNING, "Invalid event reporting” cmd %s", cmd);
503
2
    err = -EINVAL;
504
2
    goto event_reporting_done;
505
2
  }
506
38
  int mode_int;
507
38
  int rc = parse_int(mode, &mode_int);
508
38
  if (rc < 0) {
509
2
    syslog(LOG_WARNING, "Invalid event reporting” cmd %s", cmd);
510
2
    err = rc;
511
2
    goto event_reporting_done;
512
2
  }
513
36
  if (mode_int == FORWARD_UNSOLICIT_RESULT_CODE) {
514
3
    rc =
515
3
        parse_int(tmp, &handle->ind_event_reports[CRAS_INDICATOR_ENABLE_INDEX]);
516
3
    if (rc < 0) {
517
2
      syslog(LOG_WARNING, "Invalid event reporting” cmd %s", cmd);
518
2
      err = rc;
519
2
      goto event_reporting_done;
520
2
    }
521
3
  }
522
34
  err = hfp_send(handle, AT_CMD("OK"));
523
34
  if (err) {
524
0
    syslog(LOG_WARNING, "Error sending response for command %s", cmd);
525
0
    goto event_reporting_done;
526
0
  }
527
528
  /*
529
   * Wait for HF to retrieve information about HF indicators and consider
530
   * the Service Level Connection to be fully initialized, and thereby
531
   * established, if HF doesn't support HF indicators.
532
   */
533
34
  if (hfp_slc_get_hf_hf_indicators_supported(handle)) {
534
0
    handle->timer = cras_tm_create_timer(cras_system_state_get_tm(),
535
0
                                         HF_INDICATORS_TIMEOUT_MS,
536
0
                                         initialize_slc_handle, handle);
537
0
  }
538
  /*
539
   * Otherwise, regard the Service Level Connection to be fully
540
   * initialized and ready for the potential codec negotiation.
541
   */
542
34
  else {
543
34
    initialize_slc_handle(NULL, (void*)handle);
544
34
  }
545
546
40
event_reporting_done:
547
40
  free(tokens);
548
40
  return err;
549
34
}
550
551
/* AT+CMEE command to set the "Extended Audio Gateway Error Result Code".
552
 * Mandatory per spec 4.9.
553
 */
554
1
static int extended_errors(struct hfp_slc_handle* handle, const char* buf) {
555
1
  return hfp_send(handle, AT_CMD("OK"));
556
1
}
557
558
/* AT+CKPD command to handle the user initiated action from headset profile
559
 * device.
560
 */
561
4
static int key_press(struct hfp_slc_handle* handle, const char* buf) {
562
4
  hfp_send(handle, AT_CMD("OK"));
563
564
  // Release the call and connection.
565
4
  if (handle->telephony->call || handle->telephony->callsetup) {
566
2
    cras_telephony_event_terminate_call();
567
2
    handle->disconnect_cb(handle);
568
2
    return -EIO;
569
2
  }
570
2
  return 0;
571
4
}
572
573
/* AT+BLDN command to re-dial the last number. Mandatory support
574
 * per spec 4.20.
575
 */
576
2
static int last_dialed_number(struct hfp_slc_handle* handle, const char* buf) {
577
2
  int rc;
578
579
2
  if (!handle->telephony->dial_number) {
580
0
    return hfp_send(handle, AT_CMD("ERROR"));
581
0
  }
582
583
2
  rc = hfp_send(handle, AT_CMD("OK"));
584
2
  if (rc) {
585
0
    return rc;
586
0
  }
587
588
2
  handle->telephony->callsetup = 2;
589
2
  return hfp_send_ind_event_report(handle, CALLSETUP_IND_INDEX, 2);
590
2
}
591
592
/* AT+CLCC command to query list of current calls. Mandatory support
593
 * per spec 4.31.
594
 *
595
 * +CLCC: <idx>,<direction>,<status>,<mode>,<multiparty>
596
 */
597
2
static int list_current_calls(struct hfp_slc_handle* handle, const char* cmd) {
598
2
  char buf[64];
599
600
2
  int idx = 1;
601
2
  int rc;
602
  /* Fake the call list base on callheld and call status
603
   * since we have no API exposed to manage call list.
604
   * This is a hack to pass qualification test which ask us to
605
   * handle the basic case that one call is active and
606
   * the other is on hold. */
607
2
  if (handle->telephony->callheld) {
608
0
    snprintf(buf, 64, AT_CMD("+CLCC: %d,1,1,0,0"), idx++);
609
0
    rc = hfp_send(handle, buf);
610
0
    if (rc) {
611
0
      return rc;
612
0
    }
613
0
  }
614
615
2
  if (handle->telephony->call) {
616
1
    snprintf(buf, 64, AT_CMD("+CLCC: %d,1,0,0,0"), idx++);
617
1
    rc = hfp_send(handle, buf);
618
1
    if (rc) {
619
0
      return rc;
620
0
    }
621
1
  }
622
623
2
  return hfp_send(handle, AT_CMD("OK"));
624
2
}
625
626
/* AT+COPS command to query currently selected operator or set name format.
627
 * Mandatory support per spec 4.8.
628
 */
629
20
static int operator_selection(struct hfp_slc_handle* handle, const char* cmd) {
630
20
  int rc;
631
632
20
  if (strlen(cmd) < 8) {
633
1
    syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
634
1
    return hfp_send(handle, AT_CMD("ERROR"));
635
1
  }
636
637
19
  if (cmd[7] == '?') {
638
    /* HF sends AT+COPS? command to find current network operator.
639
     * AG responds with +COPS:<mode>,<format>,<operator>, where
640
     * the mode=0 means automatic for network selection. If no
641
     * operator is selected, <format> and <operator> are omitted.
642
     */
643
3
    rc = hfp_send(handle, AT_CMD("+COPS: 0"));
644
3
    if (rc) {
645
0
      return rc;
646
0
    }
647
3
  }
648
649
19
  return hfp_send(handle, AT_CMD("OK"));
650
19
}
651
652
/* The AT+CHLD command is used to control call hold, release, and multiparty
653
 * states.
654
 */
655
29
static int call_hold(struct hfp_slc_handle* handle, const char* cmd) {
656
29
  int rc;
657
658
29
  if (strlen(cmd) < 9) {
659
2
    syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
660
2
    return hfp_send(handle, AT_CMD("ERROR"));
661
2
  }
662
663
  // Chrome OS doesn't yet support CHLD features but we need to reply
664
  // the query with an empty feature list rather than "ERROR" to increase
665
  // interoperability with certain devices (b/172413440).
666
27
  if (cmd[7] == '=' && cmd[8] == '?') {
667
1
    rc = hfp_send(handle, AT_CMD("+CHLD:"));
668
1
    if (rc) {
669
0
      return rc;
670
0
    }
671
1
    return hfp_send(handle, AT_CMD("OK"));
672
1
  }
673
674
26
  return hfp_send(handle, AT_CMD("ERROR"));
675
27
}
676
677
/* AT+CIND command retrieves the supported indicator and its corresponding
678
 * range and order index or read current status of indicators. Mandatory
679
 * support per spec 4.2.
680
 */
681
24
static int report_indicators(struct hfp_slc_handle* handle, const char* cmd) {
682
24
  int err;
683
24
  char buf[64];
684
685
24
  if (strlen(cmd) < 8) {
686
1
    syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
687
1
    return hfp_send(handle, AT_CMD("ERROR"));
688
1
  }
689
690
23
  if (cmd[7] == '=') {
691
    // Indicator update test command "AT+CIND=?"
692
2
    err = hfp_send(handle, AT_CMD(INDICATOR_UPDATE_RSP));
693
21
  } else {
694
    /* Indicator update read command "AT+CIND?".
695
     * Respond with current status of AG indicators,
696
     * the values must be listed in the indicator order declared
697
     * in INDICATOR_UPDATE_RSP.
698
     * +CIND: <signal>,<service>,<call>,
699
     *        <callsetup>,<callheld>,<roam>
700
     */
701
21
    snprintf(buf, 64, AT_CMD("+CIND: %d,%d,%d,%d,%d,%d,0"), handle->battery,
702
21
             handle->signal, handle->service, handle->telephony->call,
703
21
             handle->telephony->callsetup, handle->telephony->callheld);
704
21
    err = hfp_send(handle, buf);
705
21
  }
706
707
23
  if (err < 0) {
708
0
    return err;
709
0
  }
710
711
23
  return hfp_send(handle, AT_CMD("OK"));
712
23
}
713
714
/* AT+BIA command to change the subset of indicators that shall be
715
 * sent by the AG.
716
 */
717
static int indicator_activation(struct hfp_slc_handle* handle,
718
27
                                const char* cmd) {
719
27
  char* ptr;
720
27
  int idx = BATTERY_IND_INDEX;
721
722
  /* AT+BIA=[[<indrep 1>][,[<indrep 2>][,...[,[<indrep n>]]]]]
723
   * According to the spec:
724
   * - The indicator state can be omitted and the current reporting
725
   *   states of the indicator shall not change.
726
   *     Ex: AT+BIA=,1,,0
727
   *         Only the 2nd and 4th indicators may be affected.
728
   * - HF can provide fewer indicators than AG and states not provided
729
   *   shall not change.
730
   *     Ex: CRAS supports 7 indicators and gets AT+BIA=1,0,1
731
   *         Only the first three indicators may be affected.
732
   * - Call, Call Setup and Held Call are mandatory and should be always
733
   *   on no matter what state HF set.
734
   */
735
27
  ptr = strchr(cmd, '=');
736
104
  while (ptr && idx < INDICATOR_IND_MAX) {
737
77
    if (idx != CALL_IND_INDEX && idx != CALLSETUP_IND_INDEX &&
738
62
        idx != CALLHELD_IND_INDEX) {
739
56
      if (*(ptr + 1) == '1') {
740
12
        handle->ind_event_reports[idx] = 1;
741
44
      } else if (*(ptr + 1) == '0') {
742
10
        handle->ind_event_reports[idx] = 0;
743
10
      }
744
56
    }
745
77
    ptr = strchr(ptr + 1, ',');
746
77
    idx++;
747
77
  }
748
27
  return hfp_send(handle, AT_CMD("OK"));
749
27
}
750
751
/* AT+BIND command to report, query and activate Generic Status Indicators.
752
 * It is sent by the HF if both AG and HF support the HF indicator feature.
753
 */
754
72
static int indicator_support(struct hfp_slc_handle* handle, const char* cmd) {
755
72
  char *tokens, *key;
756
72
  int err, cmd_len;
757
758
72
  cmd_len = strlen(cmd);
759
72
  if (cmd_len < 8) {
760
1
    goto error_out;
761
1
  }
762
763
71
  if (cmd[7] == '=') {
764
    // AT+BIND=? (Read AG supported indicators)
765
58
    if (cmd_len > 8 && cmd[8] == '?') {
766
      /* +BIND: (<a>,<b>,<c>,...,<n>) (Response to AT+BIND=?)
767
       * <a> ... <n>: 0-65535, entered as decimal unsigned
768
       * integer values without leading zeros, referencing an
769
       * HF indicator assigned number.
770
       * 1 is for Enhanced Driver Status.
771
       * 2 is for Battery Level.
772
       * For the list of HF indicator assigned number, you can
773
       * check the  Bluetooth SIG Assigned Numbers web page.
774
       */
775
1
      BTLOG(btlog, BT_HFP_HF_INDICATOR, 1, 0);
776
      /* "2" is for HF Battery Level that we support. We don't
777
       * support "1" but this is a workaround for Pixel Buds 2
778
       * which expects this exact combination for battery
779
       * reporting (HFP 1.7 standard) to work. This workaround
780
       * is fine since we don't enable Safety Drive with
781
       * +BIND: 1,1 (b/172680041).
782
       */
783
1
      err = hfp_send(handle, AT_CMD("+BIND: (1,2)"));
784
1
      if (err < 0) {
785
0
        return err;
786
0
      }
787
1
    }
788
    // AT+BIND=<a>,<b>,...,<n>(List HF supported indicators)
789
57
    else {
790
57
      tokens = strdup(cmd);
791
57
      strtok(tokens, "=");
792
57
      key = strtok(NULL, ",");
793
265
      while (key != NULL) {
794
215
        int key_int = 0;
795
215
        err = parse_int(key, &key_int);
796
215
        if (err < 0) {
797
7
          free(tokens);
798
7
          return err;
799
7
        }
800
208
        if (key_int == 2) {
801
98
          handle->hf_supports_battery_indicator |=
802
98
              CRAS_HFP_BATTERY_INDICATOR_HFP;
803
98
        }
804
208
        key = strtok(NULL, ",");
805
208
      }
806
50
      free(tokens);
807
50
    }
808
58
  }
809
  // AT+BIND? (Read AG enabled/disabled status of indicators)
810
13
  else if (cmd[7] == '?') {
811
    /* +BIND: <a>,<state> (Unsolicited or Response to AT+BIND?)
812
     * This response enables the AG to notify the HF which HF
813
     * indicators are supported and their state, enabled or
814
     * disabled.
815
     * <a>: 1 or 2, referencing an HF indicator assigned number.
816
     * <state>: 0-1, entered as integer values, where
817
     * 0 = disabled, no value changes shall be sent for this
818
     * indicator
819
     * 1 = enabled, value changes may be sent for this indicator
820
     */
821
822
    /* We don't support Enhanced Driver Status, so explicitly
823
     * disable it (b/172680041).
824
     */
825
1
    err = hfp_send(handle, AT_CMD("+BIND: 1,0"));
826
1
    if (err < 0) {
827
0
      return err;
828
0
    }
829
830
1
    BTLOG(btlog, BT_HFP_HF_INDICATOR, 0, 0);
831
832
1
    err = hfp_send(handle, AT_CMD("+BIND: 2,1"));
833
1
    if (err < 0) {
834
0
      return err;
835
0
    }
836
837
1
    err = hfp_send(handle, AT_CMD("OK"));
838
1
    if (err) {
839
0
      return err;
840
0
    }
841
    /*
842
     * Consider the Service Level Connection to be fully initialized
843
     * and thereby established, after successfully responded with OK
844
     */
845
1
    initialize_slc_handle(NULL, (void*)handle);
846
1
    return 0;
847
12
  } else {
848
12
    goto error_out;
849
12
  }
850
  /* This OK reply is required after both +BIND AT commands. It also
851
   * covers the AT+BIND= <a>,<b>,...,<n> case.
852
   */
853
51
  return hfp_send(handle, AT_CMD("OK"));
854
855
13
error_out:
856
13
  syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
857
13
  return hfp_send(handle, AT_CMD("ERROR"));
858
71
}
859
860
/* AT+BIEV command reports updated values of enabled HF indicators to the AG.
861
 */
862
static int indicator_state_change(struct hfp_slc_handle* handle,
863
125
                                  const char* cmd) {
864
125
  char *tokens, *key, *val;
865
125
  int level;
866
  /* AT+BIEV= <assigned number>,<value> (Update value of indicator)
867
   * CRAS only supports battery level, which is with assigned number 2.
868
   * Battery level should range from 0 to 100 defined by the spec.
869
   */
870
125
  tokens = strdup(cmd);
871
125
  strtok(tokens, "=");
872
125
  key = strtok(NULL, ",");
873
125
  if (!key) {
874
1
    goto error_out;
875
1
  }
876
877
124
  int key_int;
878
124
  int rc = parse_int(key, &key_int);
879
124
  if (rc < 0) {
880
2
    goto error_out;
881
2
  }
882
883
122
  if (key_int == 2) {
884
89
    val = strtok(NULL, ",");
885
89
    if (!val) {
886
1
      goto error_out;
887
1
    }
888
88
    rc = parse_int(val, &level);
889
88
    if (rc < 0) {
890
2
      goto error_out;
891
2
    }
892
86
    if (level >= 0 && level <= 100) {
893
14
      cras_server_metrics_hfp_battery_report(CRAS_HFP_BATTERY_INDICATOR_HFP);
894
14
      if (handle->hf_battery != level) {
895
14
        handle->hf_battery = level;
896
14
        cras_observer_notify_bt_battery_changed(
897
14
            cras_bt_device_address(handle->device), (uint32_t)(level));
898
14
      }
899
72
    } else {
900
72
      syslog(LOG_WARNING, "Get invalid battery status from cmd:%s", cmd);
901
72
    }
902
86
  } else {
903
33
    goto error_out;
904
33
  }
905
906
86
  free(tokens);
907
86
  return hfp_send(handle, AT_CMD("OK"));
908
909
39
error_out:
910
39
  syslog(LOG_WARNING, "%s: invalid command: '%s'", __func__, cmd);
911
39
  free(tokens);
912
39
  return hfp_send(handle, AT_CMD("ERROR"));
913
122
}
914
915
/* AT+VGM and AT+VGS command reports the current mic and speaker gain
916
 * level respectively. Optional support per spec 4.28.
917
 */
918
97
static int signal_gain_setting(struct hfp_slc_handle* handle, const char* cmd) {
919
97
  int gain;
920
921
97
  if (strlen(cmd) < 8) {
922
2
    syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
923
2
    return hfp_send(handle, AT_CMD("ERROR"));
924
2
  }
925
926
  /* Map 0 to the smallest non-zero scale 6/100, and 15 to
927
   * 100/100 full. */
928
95
  if (cmd[5] == 'S') {
929
82
    int rc = parse_int(&cmd[7], &gain);
930
82
    if (rc < 0) {
931
1
      syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
932
1
      return hfp_send(handle, AT_CMD("ERROR"));
933
1
    }
934
81
    if (gain < 0 || gain > 15) {
935
73
      syslog(LOG_WARNING,
936
73
             "signal_gain_setting: gain %d is not between 0 and 15", gain);
937
73
      return hfp_send(handle, AT_CMD("ERROR"));
938
73
    }
939
8
    BTLOG(btlog, BT_HFP_UPDATE_SPEAKER_GAIN, gain, 0);
940
8
    cras_bt_device_update_hardware_volume(handle->device, (gain + 1) * 100 / 16,
941
8
                                          CRAS_BT_FLAG_HFP);
942
8
  }
943
944
21
  return hfp_send(handle, AT_CMD("OK"));
945
95
}
946
947
/* AT+CNUM command to query the subscriber number. Mandatory support
948
 * per spec 4.30.
949
 */
950
1
static int subscriber_number(struct hfp_slc_handle* handle, const char* buf) {
951
1
  return hfp_send(handle, AT_CMD("OK"));
952
1
}
953
954
/* AT+BRSF command notifies the HF(Hands-free device) supported features
955
 * and retrieves the AG(Audio gateway) supported features. Mandatory
956
 * support per spec 4.2.
957
 */
958
23
static int supported_features(struct hfp_slc_handle* handle, const char* cmd) {
959
23
  int err;
960
23
  char response[128];
961
23
  char *tokens = NULL, *features;
962
963
23
  if (strlen(cmd) < 9) {
964
2
    goto error_out;
965
2
  }
966
967
21
  tokens = strdup(cmd);
968
21
  strtok(tokens, "=");
969
21
  features = strtok(NULL, ",");
970
21
  if (!features) {
971
2
    goto error_out;
972
2
  }
973
974
19
  int rc = parse_int(features, &(handle->hf_supported_features));
975
19
  if (rc < 0) {
976
16
    goto error_out;
977
16
  }
978
3
  BTLOG(btlog, BT_HFP_SUPPORTED_FEATURES, 0, handle->hf_supported_features);
979
980
  /* AT+BRSF=<feature> command received, ignore the HF supported feature
981
   * for now. Respond with +BRSF:<feature> to notify mandatory supported
982
   * features in AG(audio gateway).
983
   */
984
3
  BTLOG(btlog, BT_HFP_SUPPORTED_FEATURES, 1, handle->ag_supported_features);
985
3
  snprintf(response, 128, AT_CMD("+BRSF: %d"), handle->ag_supported_features);
986
3
  err = hfp_send(handle, response);
987
3
  free(tokens);
988
3
  if (err < 0) {
989
0
    return err;
990
0
  }
991
3
  return hfp_send(handle, AT_CMD("OK"));
992
993
20
error_out:
994
20
  free(tokens);
995
20
  syslog(LOG_WARNING, "%s: malformed command: '%s'", __func__, cmd);
996
20
  return hfp_send(handle, AT_CMD("ERROR"));
997
3
}
998
999
0
int hfp_event_speaker_gain(struct hfp_slc_handle* handle, int gain) {
1000
0
  char command[128];
1001
1002
  // Normailize gain value to 0-15
1003
0
  gain = gain * 15 / 100;
1004
0
  BTLOG(btlog, BT_HFP_SET_SPEAKER_GAIN, gain, 0);
1005
0
  snprintf(command, 128, AT_CMD("+VGS=%d"), gain);
1006
1007
0
  return hfp_send(handle, command);
1008
0
}
1009
1010
/* AT+CHUP command to terminate current call. Mandatory support
1011
 * per spec 4.15.
1012
 */
1013
2
static int terminate_call(struct hfp_slc_handle* handle, const char* cmd) {
1014
2
  int rc;
1015
2
  rc = hfp_send(handle, AT_CMD("OK"));
1016
2
  if (rc) {
1017
0
    return rc;
1018
0
  }
1019
1020
2
  return cras_telephony_event_terminate_call();
1021
2
}
1022
1023
/* AT+XEVENT is defined by Android to support vendor specific features.
1024
 * Currently, the only known supported case for CrOS is the battery event sent
1025
 * by some Plantronics headsets.
1026
 */
1027
static int vendor_specific_features(struct hfp_slc_handle* handle,
1028
217
                                    const char* cmd) {
1029
217
  char *tokens, *event, *level_str, *num_of_level_str;
1030
217
  int level, num_of_level;
1031
1032
217
  tokens = strdup(cmd);
1033
217
  strtok(tokens, "=");
1034
217
  event = strtok(NULL, ",");
1035
217
  if (!event) {
1036
1
    goto error_out;
1037
1
  }
1038
1039
  /* AT+XEVENT=BATTERY,Level,NumberOfLevel,MinutesOfTalkTime,IsCharging
1040
   * Level: The charge level with a zero-based integer.
1041
   * NumberOfLevel: How many charging levels there are.
1042
   * MinuteOfTalkTime: The estimated number of talk minutes remaining.
1043
   * IsCharging: A 0 or 1 value.
1044
   *
1045
   * We only support the battery level and thus only care about the first
1046
   * 3 arguments.
1047
   */
1048
216
  if (!strncmp(event, "BATTERY", 7)) {
1049
159
    level_str = strtok(NULL, ",");
1050
159
    num_of_level_str = strtok(NULL, ",");
1051
159
    if (!level_str || !num_of_level_str) {
1052
3
      goto error_out;
1053
3
    }
1054
1055
156
    int rc = parse_int(level_str, &level);
1056
156
    if (rc < 0) {
1057
2
      goto error_out;
1058
2
    }
1059
154
    rc = parse_int(num_of_level_str, &num_of_level);
1060
154
    if (rc < 0 || level < 0 || num_of_level <= 1 || level >= num_of_level) {
1061
122
      goto error_out;
1062
122
    }
1063
1064
32
    level = (int64_t)level * 100 / (num_of_level - 1);
1065
32
    if (handle->hf_battery != level) {
1066
32
      handle->hf_supports_battery_indicator |=
1067
32
          CRAS_HFP_BATTERY_INDICATOR_PLANTRONICS;
1068
32
      cras_server_metrics_hfp_battery_report(
1069
32
          CRAS_HFP_BATTERY_INDICATOR_PLANTRONICS);
1070
32
      handle->hf_battery = level;
1071
32
      cras_observer_notify_bt_battery_changed(
1072
32
          cras_bt_device_address(handle->device), (uint32_t)(level));
1073
32
    }
1074
32
  }
1075
1076
89
  free(tokens);
1077
  /* For Plantronic headsets, it is required to reply "OK" for the first
1078
   * AT+XEVENT=USER-AGENT... command to tell the headset our support of
1079
   * the xevent protocol. Otherwise, all following events including
1080
   * BATTERY won't be sent.
1081
   */
1082
89
  return hfp_send(handle, AT_CMD("OK"));
1083
1084
128
error_out:
1085
128
  syslog(LOG_WARNING, "%s: malformed vendor specific command: '%s'", __func__,
1086
128
         cmd);
1087
128
  free(tokens);
1088
128
  return hfp_send(handle, AT_CMD("ERROR"));
1089
216
}
1090
1091
/* AT commands to support in order to conform HFP specification.
1092
 *
1093
 * An initialized service level connection is the pre-condition for all
1094
 * call related procedures. Note that for the call related commands,
1095
 * we are good to just respond with a meaningless "OK".
1096
 *
1097
 * The procedure to establish a service level connection is described below:
1098
 *
1099
 * 1. HF notifies AG about its own supported features and AG responds
1100
 * with its supported feature.
1101
 *
1102
 * HF(hands-free)                             AG(audio gateway)
1103
 *                     AT+BRSF=<HF supported feature> -->
1104
 *                 <-- +BRSF:<AG supported feature>
1105
 *                 <-- OK
1106
 *
1107
 * 2. HF retrieves the information about the indicators supported in AG.
1108
 *
1109
 * HF(hands-free)                             AG(audio gateway)
1110
 *                     AT+CIND=? -->
1111
 *                 <-- +CIND:...
1112
 *                 <-- OK
1113
 *
1114
 * 3. The HF requests the current status of the indicators in AG.
1115
 *
1116
 * HF(hands-free)                             AG(audio gateway)
1117
 *                     AT+CIND -->
1118
 *                 <-- +CIND:...
1119
 *                 <-- OK
1120
 *
1121
 * 4. HF requests enabling indicator status update in the AG.
1122
 *
1123
 * HF(hands-free)                             AG(audio gateway)
1124
 *                     AT+CMER= -->
1125
 *                 <-- OK
1126
 */
1127
static struct at_command at_commands[] = {
1128
    {"ATA", answer_call},
1129
    {"ATD", dial_number},
1130
    {"AT+BAC", available_codecs},
1131
    {"AT+BCC", bluetooth_codec_connection},
1132
    {"AT+BCS", bluetooth_codec_selection},
1133
    {"AT+BIA", indicator_activation},
1134
    {"AT+BIEV", indicator_state_change},
1135
    {"AT+BIND", indicator_support},
1136
    {"AT+BLDN", last_dialed_number},
1137
    {"AT+BRSF", supported_features},
1138
    {"AT+CCWA", call_waiting_notify},
1139
    {"AT+CHUP", terminate_call},
1140
    {"AT+CIND", report_indicators},
1141
    {"AT+CKPD", key_press},
1142
    {"AT+CLCC", list_current_calls},
1143
    {"AT+CLIP", cli_notification},
1144
    {"AT+CMEE", extended_errors},
1145
    {"AT+CMER", event_reporting},
1146
    {"AT+CNUM", subscriber_number},
1147
    {"AT+COPS", operator_selection},
1148
    {"AT+IPHONEACCEV", apple_accessory_state_change},
1149
    {"AT+VG", signal_gain_setting},
1150
    {"AT+VTS", dtmf_tone},
1151
    {"AT+XAPL", apple_supported_features},
1152
    {"AT+XEVENT", vendor_specific_features},
1153
    {"AT+CHLD", call_hold},
1154
    {0}};
1155
1156
static int handle_at_command(struct hfp_slc_handle* slc_handle,
1157
1.29k
                             const char* cmd) {
1158
1.29k
  struct at_command* atc;
1159
1160
21.0k
  for (atc = at_commands; atc->cmd; atc++) {
1161
20.9k
    if (!strncmp(cmd, atc->cmd, strlen(atc->cmd))) {
1162
1.17k
      return atc->callback(slc_handle, cmd);
1163
1.17k
    }
1164
20.9k
  }
1165
1166
1.29k
  syslog(LOG_DEBUG, "AT command %s not supported", cmd);
1167
122
  return hfp_send(slc_handle, AT_CMD("ERROR"));
1168
1.29k
}
1169
1170
void handle_at_command_for_test(struct hfp_slc_handle* slc_handle,
1171
1.30k
                                const char* cmd) {
1172
1.30k
  char buf[SLC_BUF_SIZE_BYTES];
1173
1.30k
  size_t copied = strlcpy(buf, cmd, SLC_BUF_SIZE_BYTES);
1174
2.60k
  while (copied > 0) {
1175
1.29k
    handle_at_command(slc_handle, buf);
1176
    // advance pointer down test data
1177
1.29k
    cmd += copied;
1178
1.29k
    copied = strlcpy(buf, cmd, SLC_BUF_SIZE_BYTES);
1179
1.29k
  }
1180
1.30k
}
1181
1182
0
static int process_at_commands(struct hfp_slc_handle* handle) {
1183
0
  ssize_t bytes_read;
1184
0
  int err;
1185
1186
0
  bytes_read = read(handle->rfcomm_fd, &handle->buf[handle->buf_write_idx],
1187
0
                    SLC_BUF_SIZE_BYTES - handle->buf_write_idx - 1);
1188
0
  if (bytes_read < 0) {
1189
0
    return bytes_read;
1190
0
  }
1191
1192
0
  handle->buf_write_idx += bytes_read;
1193
0
  handle->buf[handle->buf_write_idx] = '\0';
1194
1195
0
  while (handle->buf_read_idx != handle->buf_write_idx) {
1196
0
    char* end_char;
1197
0
    end_char = strchr(&handle->buf[handle->buf_read_idx], '\r');
1198
0
    if (end_char == NULL) {
1199
0
      break;
1200
0
    }
1201
1202
0
    *end_char = '\0';
1203
0
    err = handle_at_command(handle, &handle->buf[handle->buf_read_idx]);
1204
0
    if (err < 0) {
1205
0
      return 0;
1206
0
    }
1207
1208
    // Shift the read index
1209
0
    handle->buf_read_idx = 1 + end_char - handle->buf;
1210
0
    if (handle->buf_read_idx == handle->buf_write_idx) {
1211
0
      handle->buf_read_idx = 0;
1212
0
      handle->buf_write_idx = 0;
1213
0
    }
1214
0
  }
1215
1216
  // Handle the case when buffer is full and no command found.
1217
0
  if (handle->buf_write_idx == SLC_BUF_SIZE_BYTES - 1) {
1218
0
    if (handle->buf_read_idx) {
1219
0
      memmove(handle->buf, &handle->buf[handle->buf_read_idx],
1220
0
              handle->buf_write_idx - handle->buf_read_idx);
1221
0
      handle->buf_write_idx -= handle->buf_read_idx;
1222
0
      handle->buf_read_idx = 0;
1223
0
    } else {
1224
0
      syslog(LOG_WARNING, "Parse SLC command error, clean up buffer");
1225
0
      handle->buf_write_idx = 0;
1226
0
    }
1227
0
  }
1228
0
  return bytes_read;
1229
0
}
1230
1231
0
static void slc_watch_callback(void* arg, int revents) {
1232
0
  struct hfp_slc_handle* handle = (struct hfp_slc_handle*)arg;
1233
0
  int err;
1234
1235
0
  err = process_at_commands(handle);
1236
0
  if (err < 0) {
1237
0
    syslog(LOG_WARNING, "Error reading slc command %s", cras_strerror(errno));
1238
0
    cras_system_rm_select_fd(handle->rfcomm_fd);
1239
0
    handle->disconnect_cb(handle);
1240
0
  }
1241
0
  return;
1242
0
}
1243
1244
// Exported interfaces
1245
1246
struct hfp_slc_handle* hfp_slc_create(int fd,
1247
                                      int ag_supported_features,
1248
                                      struct cras_bt_device* device,
1249
                                      hfp_slc_init_cb init_cb,
1250
1.30k
                                      hfp_slc_disconnect_cb disconnect_cb) {
1251
1.30k
  struct hfp_slc_handle* handle;
1252
1.30k
  int i;
1253
1254
1.30k
  if (!disconnect_cb) {
1255
0
    return NULL;
1256
0
  }
1257
1258
1.30k
  handle = (struct hfp_slc_handle*)calloc(1, sizeof(*handle));
1259
1.30k
  if (!handle) {
1260
0
    return NULL;
1261
0
  }
1262
1263
1.30k
  handle->rfcomm_fd = fd;
1264
1.30k
  handle->ag_supported_features = ag_supported_features;
1265
1.30k
  handle->hf_supported_features = 0;
1266
1.30k
  handle->device = device;
1267
1.30k
  handle->init_cb = init_cb;
1268
1.30k
  handle->disconnect_cb = disconnect_cb;
1269
1.30k
  handle->cli_active = 0;
1270
1.30k
  handle->battery = 5;
1271
1.30k
  handle->signal = 5;
1272
1.30k
  handle->service = 1;
1273
1.30k
  handle->ind_event_reports[CRAS_INDICATOR_ENABLE_INDEX] = 0;
1274
10.4k
  for (i = BATTERY_IND_INDEX; i < INDICATOR_IND_MAX; i++) {
1275
9.15k
    handle->ind_event_reports[i] = 1;
1276
9.15k
  }
1277
1.30k
  handle->telephony = cras_telephony_get();
1278
1.30k
  handle->preferred_codec = HFP_CODEC_ID_CVSD;
1279
1.30k
  handle->selected_codec = HFP_CODEC_UNUSED;
1280
1.30k
  handle->hf_supports_battery_indicator = CRAS_HFP_BATTERY_INDICATOR_NONE;
1281
1.30k
  handle->hf_battery = -1;
1282
1.30k
  cras_system_add_select_fd(handle->rfcomm_fd, slc_watch_callback, handle,
1283
1.30k
                            POLLIN | POLLERR | POLLHUP);
1284
1285
1.30k
  return handle;
1286
1.30k
}
1287
1288
1.30k
void hfp_slc_destroy(struct hfp_slc_handle* slc_handle) {
1289
1.30k
  cras_system_rm_select_fd(slc_handle->rfcomm_fd);
1290
1.30k
  if (slc_handle->timer) {
1291
0
    cras_tm_cancel_timer(cras_system_state_get_tm(), slc_handle->timer);
1292
0
  }
1293
1.30k
  close(slc_handle->rfcomm_fd);
1294
1.30k
  free(slc_handle);
1295
1.30k
}
1296
1297
0
int hfp_slc_get_selected_codec(struct hfp_slc_handle* handle) {
1298
  /* If codec negotiation is not supported on HF, or the negotiation
1299
   * process never completed. Fallback to the preferred codec. */
1300
0
  if (handle->selected_codec == HFP_CODEC_UNUSED) {
1301
0
    return handle->preferred_codec;
1302
0
  } else {
1303
0
    return handle->selected_codec;
1304
0
  }
1305
0
}
1306
1307
0
int hfp_slc_codec_connection_setup(struct hfp_slc_handle* handle) {
1308
  // The time we wait for codec selection response.
1309
0
  static struct timespec timeout = {0, 300000000};
1310
0
  struct pollfd poll_fd;
1311
0
  int rc = 0;
1312
0
  struct timespec ts = timeout;
1313
1314
  /*
1315
   * Codec negotiation is not required, if either AG or HF doesn't support
1316
   * it or it has been done once.
1317
   */
1318
0
  if (!hfp_slc_get_hf_codec_negotiation_supported(handle) ||
1319
0
      !hfp_slc_get_ag_codec_negotiation_supported(handle) ||
1320
0
      handle->selected_codec == handle->preferred_codec) {
1321
0
    return 0;
1322
0
  }
1323
1324
0
redo_codec_conn:
1325
0
  select_preferred_codec(handle);
1326
1327
0
  poll_fd.fd = handle->rfcomm_fd;
1328
0
  poll_fd.events = POLLIN;
1329
1330
0
  ts = timeout;
1331
0
  while (rc <= 0) {
1332
0
    rc = cras_poll(&poll_fd, 1, &ts, NULL);
1333
0
    if (rc == -ETIMEDOUT) {
1334
      /*
1335
       * Catch the case that the first initial codec
1336
       * negotiation timeout. At this point we're not sure
1337
       * if HF is good with the preferred codec from AG.
1338
       * Fallback to CVSD doesn't help because very likely
1339
       * HF won't reply that either. The best thing we can
1340
       * do is just leave a warning log.
1341
       */
1342
0
      if (handle->selected_codec == HFP_CODEC_UNUSED) {
1343
0
        syslog(LOG_WARNING, "Proceed using codec %d without HF reply",
1344
0
               handle->preferred_codec);
1345
0
      }
1346
0
      return rc;
1347
0
    }
1348
0
  }
1349
1350
0
  if (rc > 0) {
1351
0
    do {
1352
0
      usleep(CODEC_CONN_SLEEP_TIME_US);
1353
0
      rc = process_at_commands(handle);
1354
0
    } while (rc == -EAGAIN);
1355
1356
0
    if (rc <= 0) {
1357
0
      return rc;
1358
0
    }
1359
0
    if (handle->selected_codec != handle->preferred_codec) {
1360
0
      goto redo_codec_conn;
1361
0
    }
1362
0
  }
1363
1364
0
  return 0;
1365
0
}
1366
1367
0
int hfp_set_call_status(struct hfp_slc_handle* handle, int call) {
1368
0
  int old_call = handle->telephony->call;
1369
1370
0
  if (old_call == call) {
1371
0
    return 0;
1372
0
  }
1373
1374
0
  handle->telephony->call = call;
1375
0
  return hfp_event_update_call(handle);
1376
0
}
1377
1378
/* Procedure to setup a call when AG sees incoming call.
1379
 *
1380
 * HF(hands-free)                             AG(audio gateway)
1381
 *                                                     <-- Incoming call
1382
 *                 <-- +CIEV: (callsetup = 1)
1383
 *                 <-- RING (ALERT)
1384
 */
1385
int hfp_event_incoming_call(struct hfp_slc_handle* handle,
1386
                            const char* number,
1387
0
                            int type) {
1388
0
  int rc;
1389
1390
0
  if (handle->cli_active) {
1391
0
    rc = hfp_send_calling_line_identification(handle, number, type);
1392
0
    if (rc) {
1393
0
      return rc;
1394
0
    }
1395
0
  }
1396
1397
0
  if (handle->telephony->call) {
1398
0
    return 0;
1399
0
  } else {
1400
0
    return hfp_send(handle, AT_CMD("RING"));
1401
0
  }
1402
0
}
1403
1404
0
int hfp_event_update_call(struct hfp_slc_handle* handle) {
1405
0
  return hfp_send_ind_event_report(handle, CALL_IND_INDEX,
1406
0
                                   handle->telephony->call);
1407
0
}
1408
1409
0
int hfp_event_update_callsetup(struct hfp_slc_handle* handle) {
1410
0
  return hfp_send_ind_event_report(handle, CALLSETUP_IND_INDEX,
1411
0
                                   handle->telephony->callsetup);
1412
0
}
1413
1414
0
int hfp_event_update_callheld(struct hfp_slc_handle* handle) {
1415
0
  return hfp_send_ind_event_report(handle, CALLHELD_IND_INDEX,
1416
0
                                   handle->telephony->callheld);
1417
0
}
1418
1419
0
int hfp_event_set_battery(struct hfp_slc_handle* handle, int level) {
1420
0
  handle->battery = level;
1421
0
  return hfp_send_ind_event_report(handle, BATTERY_IND_INDEX, level);
1422
0
}
1423
1424
0
int hfp_event_set_signal(struct hfp_slc_handle* handle, int level) {
1425
0
  handle->signal = level;
1426
0
  return hfp_send_ind_event_report(handle, SIGNAL_IND_INDEX, level);
1427
0
}
1428
1429
0
int hfp_event_set_service(struct hfp_slc_handle* handle, int avail) {
1430
  /* Convert to 0 or 1.
1431
   * Since the value must be either 1 or 0. (service presence or not) */
1432
0
  handle->service = !!avail;
1433
0
  return hfp_send_ind_event_report(handle, SERVICE_IND_INDEX, avail);
1434
0
}
1435
1436
92
int hfp_slc_get_ag_codec_negotiation_supported(struct hfp_slc_handle* handle) {
1437
92
  return handle->ag_supported_features & AG_CODEC_NEGOTIATION;
1438
92
}
1439
1440
31
int hfp_slc_get_hf_codec_negotiation_supported(struct hfp_slc_handle* handle) {
1441
31
  return handle->hf_supported_features & HF_CODEC_NEGOTIATION;
1442
31
}
1443
1444
34
int hfp_slc_get_hf_hf_indicators_supported(struct hfp_slc_handle* handle) {
1445
34
  return handle->hf_supported_features & HF_HF_INDICATORS;
1446
34
}
1447
1448
92
bool hfp_slc_get_wideband_speech_supported(struct hfp_slc_handle* handle) {
1449
92
  return hfp_slc_get_ag_codec_negotiation_supported(handle) &&
1450
31
         hfp_slc_get_hf_codec_negotiation_supported(handle) &&
1451
0
         handle->hf_codec_supported[HFP_CODEC_ID_MSBC];
1452
92
}
1453
1454
0
int hfp_slc_get_hf_supports_battery_indicator(struct hfp_slc_handle* handle) {
1455
0
  return handle->hf_supports_battery_indicator;
1456
0
}