hc
2023-11-06 e3e12f52b214121840b44c91de5b3e5af5d3eb84
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
diff --git a/src/rfcomm.c b/src/rfcomm.c
index 86c0d4d..00dd9ab 100644
--- a/src/rfcomm.c
+++ b/src/rfcomm.c
@@ -417,23 +417,39 @@ static int rfcomm_handler_bcs_set_cb(struct rfcomm_conn *c, const struct bt_at *
 
 static int rfcomm_handler_resp_bcs_ok_cb(struct rfcomm_conn *c, const struct bt_at *at) {
     struct ba_transport * const t = c->t;
-    struct ba_transport *t_sco;
-    struct bt_voice voice = {
-        .setting = BT_VOICE_CVSD_16BIT,
+
+    /* XXX: this param should be read from rtl8xxx_config */
+    struct pcmif_param {
+        uint8_t pcmifctrl1[2];
+        uint8_t pcmifctrl2[2];
+        uint8_t pcmifctrl3[2];
+        uint8_t pcmconv;
+        uint8_t scoconv;
+        uint8_t hci_ext_codec;
+    } pcmif = {
+        0x83, 0x10,
+        0x00, 0x00,
+        0x12, 0x80,
+        0x00,
+        0x00,
+        0x01
     };
 
     if (rfcomm_handler_resp_ok_cb(c, at) != 0)
         return -1;
 
-    /* Change voice setting according to codec */
-    if (t->rfcomm.sco->codec == HFP_CODEC_MSBC)
-        voice.setting = BT_VOICE_TRANSPARENT;
-    t_sco = t->rfcomm.sco;
-    if (setsockopt(t_sco->sco.listen_fd, SOL_BLUETOOTH, BT_VOICE,
-               &voice, sizeof(voice)) == -1) {
-        error("setsockopt BT_VOICE error %d, %s", errno,
-              strerror(errno));
-        return 0;
+    if (t->rfcomm.sco->codec == HFP_CODEC_MSBC) {
+        pcmif.hci_ext_codec = 0x41;
+        pcmif.pcmifctrl3[1] = 0x04;
+    } else if (t->rfcomm.sco->codec == HFP_CODEC_CVSD) {
+        pcmif.hci_ext_codec = 0x01;
+        pcmif.pcmifctrl3[1] = 0x80;
+    }
+
+    if (hci_submit_cmd_wait(0x3f, 0x93, (uint8_t *)&pcmif,
+                sizeof(pcmif)) < 0) {
+        error("Couldn't set controller pcm interface");
+        return -1;
     }
 
     /* When codec selection is completed, notify connected clients, that
@@ -451,8 +467,24 @@ static int rfcomm_handler_bcs_resp_cb(struct rfcomm_conn *c, const struct bt_at
         AT_TYPE_RESP, "", rfcomm_handler_resp_bcs_ok_cb };
     struct ba_transport * const t = c->t;
     const int fd = t->bt_fd;
+    struct ba_transport *t_sco;
+    struct bt_voice voice = {
+        .setting = BT_VOICE_CVSD_16BIT,
+    };
 
     t->rfcomm.sco->codec = atoi(at->value);
+
+    /* Change voice setting according to codec */
+    if (t->rfcomm.sco->codec == HFP_CODEC_MSBC)
+        voice.setting = 0x0063;
+    t_sco = t->rfcomm.sco;
+    if (setsockopt(t_sco->sco.listen_fd, SOL_BLUETOOTH, BT_VOICE,
+               &voice, sizeof(voice)) == -1) {
+        error("setsockopt BT_VOICE error %d, %s", errno,
+              strerror(errno));
+        return 0;
+    }
+
     if (rfcomm_write_at(fd, AT_TYPE_CMD_SET, "+BCS", at->value) == -1)
         return -1;
 
@@ -679,7 +711,7 @@ void *rfcomm_thread(void *arg) {
                 case HFP_SLC_BRSF_SET_OK:
                     if (t->rfcomm.hfp_features & HFP_AG_FEAT_CODEC) {
                         /* XXX: If mSBC is supported, please change 1 to 1,2 */
-                        if (rfcomm_write_at(pfds[1].fd, AT_TYPE_CMD_SET, "+BAC", "1") == -1)
+                        if (rfcomm_write_at(pfds[1].fd, AT_TYPE_CMD_SET, "+BAC", "1,2") == -1)
                             goto ioerror;
                         conn.handler = &rfcomm_handler_resp_ok;
                         break;
diff --git a/src/utils.c b/src/utils.c
index 70d069e..6b36829 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -138,6 +138,42 @@ fail:
     return -1;
 }
 
+int hci_submit_cmd_wait(uint16_t ogf, uint16_t ocf, uint8_t *params,
+            uint8_t plen)
+{
+    int fd;
+    uint16_t index = 0;
+    uint8_t status;
+    int ret;
+    struct hci_request rq;
+
+    fd = hci_open_dev(index);
+    if (fd < 0) {
+        error("Couldn't open device: %s(%d)\n", strerror(errno), errno);
+        return -1;
+    }
+
+    memset(&rq, 0, sizeof(rq));
+    rq.ogf = ogf;
+    rq.ocf = ocf;
+    rq.cparam = params;
+    rq.clen = plen;
+    rq.rparam = &status;
+    rq.rlen = 1;
+
+    ret = hci_send_req(fd, &rq, 1000);
+    if (status || ret < 0) {
+        error("Can't send cmd for hci%d: %s (%d)\n", index,
+                strerror(errno), errno);
+        hci_close_dev(fd);
+        return -1;
+    }
+
+    hci_close_dev(fd);
+
+    return 0;
+}
+
 /**
  * Get BlueZ D-Bus object path for given profile and codec.
  *
diff --git a/src/utils.h b/src/utils.h
index a15625f..46da2eb 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -28,6 +28,8 @@ int a2dp_sbc_default_bitpool(int freq, int mode);
 
 int hci_devlist(struct hci_dev_info **di, int *num);
 int hci_open_sco(const struct hci_dev_info *di, const bdaddr_t *ba, bool transparent);
+int hci_submit_cmd_wait(uint16_t ogf, uint16_t ocf, uint8_t *params,
+            uint8_t plen);
 
 const char *bluetooth_profile_to_string(enum bluetooth_profile profile);
 const char *bluetooth_a2dp_codec_to_string(uint16_t codec);
-- 
2.17.1