<div dir="ltr">Hi Luiz,<br><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Aug 15, 2018 at 1:21 AM, Luiz Augusto von Dentz <span dir="ltr"><<a href="mailto:luiz.dentz@gmail.com" target="_blank">luiz.dentz@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Sathish,<br>
<div><div class="h5">On Tue, Aug 14, 2018 at 5:15 PM Sathish Narasimman <<a href="mailto:nsathish41@gmail.com">nsathish41@gmail.com</a>> wrote:<br>
><br>
> mSBC-encoded streams for HFP. The wideband speec encoding and decoding<br>
> is implemeted with this patch. This patch was refered from original<br>
> patch of Joao Paula Rechi Vita and was verified with the supported<br>
> bluetooth controller.<br>
><br>
> Signed-off-by: Sathish Narasimman <<a href="mailto:sathish.narasimman@intel.com">sathish.narasimman@intel.com</a>><br>
> ---<br>
>  src/modules/bluetooth/backend-<wbr>ofono.c        |  20 +-<br>
>  src/modules/bluetooth/module-<wbr>bluez5-device.c | 371 ++++++++++++++++++++++++++-<br>
>  2 files changed, 377 insertions(+), 14 deletions(-)<br>
><br>
> diff --git a/src/modules/bluetooth/<wbr>backend-ofono.c b/src/modules/bluetooth/<wbr>backend-ofono.c<br>
> index 1f0efe9..a836779 100644<br>
> --- a/src/modules/bluetooth/<wbr>backend-ofono.c<br>
> +++ b/src/modules/bluetooth/<wbr>backend-ofono.c<br>
> @@ -164,7 +164,7 @@ static int card_acquire(struct hf_audio_card *card) {<br>
>                                        DBUS_TYPE_BYTE, &codec,<br>
>                                        DBUS_TYPE_INVALID) == true)) {<br>
>          dbus_message_unref(r);<br>
> -        if (codec != HFP_AUDIO_CODEC_CVSD) {<br>
> +        if (codec != HFP_AUDIO_CODEC_CVSD && codec != HFP_AUDIO_CODEC_MSBC) {<br>
>              pa_log_error("Invalid codec: %u", codec);<br>
>              /* shutdown to make sure connection is dropped immediately */<br>
>              shutdown(fd, SHUT_RDWR);<br>
> @@ -250,10 +250,17 @@ static int hf_audio_agent_transport_<wbr>acquire(pa_bluetooth_transport *t, bool opti<br>
>       * value from the Isoc USB endpoint in use by btusb and should be<br>
>       * made available to userspace by the Bluetooth kernel subsystem.<br>
>       * Meanwhile the empiric value 48 will be used. */<br>
> -    if (imtu)<br>
> -        *imtu = 48;<br>
> -    if (omtu)<br>
> -        *omtu = 48;<br>
> +    if (t->codec == HFP_AUDIO_CODEC_MSBC) {<br>
> +        if (imtu)<br>
> +            *imtu = 60;<br>
> +        if (omtu)<br>
> +            *omtu = 60;<br>
> +    } else {<br>
> +        if (imtu)<br>
> +            *imtu = 48;<br>
> +        if (omtu)<br>
> +            *omtu = 48;<br>
> +   }<br>
><br>
>      err = socket_accept(card->fd);<br>
>      if (err < 0) {<br>
> @@ -464,6 +471,7 @@ static void hf_audio_agent_register(pa_<wbr>bluetooth_backend *hf) {<br>
>      pa_assert_se(m = dbus_message_new_method_call(<wbr>OFONO_SERVICE, "/", HF_AUDIO_MANAGER_INTERFACE, "Register"));<br>
><br>
>      codecs[ncodecs++] = HFP_AUDIO_CODEC_CVSD;<br>
> +    codecs[ncodecs++] = HFP_AUDIO_CODEC_MSBC;<br>
><br>
>      pa_assert_se(dbus_message_<wbr>append_args(m, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &pcodecs, ncodecs,<br>
>                                            DBUS_TYPE_INVALID));<br>
> @@ -611,7 +619,7 @@ static DBusMessage *hf_audio_agent_new_<wbr>connection(DBusConnection *c, DBusMessage<br>
><br>
>      card->connecting = false;<br>
><br>
> -    if (!card || codec != HFP_AUDIO_CODEC_CVSD || card->fd >= 0) {<br>
> +    if (!card || (codec != HFP_AUDIO_CODEC_CVSD && codec != HFP_AUDIO_CODEC_MSBC) || card->fd >= 0) {<br>
>          pa_log_warn("New audio connection invalid arguments (path=%s fd=%d, codec=%d)", path, fd, codec);<br>
>          pa_assert_se(r = dbus_message_new_error(m, "org.ofono.Error.<wbr>InvalidArguments", "Invalid arguments in method call"));<br>
>          shutdown(fd, SHUT_RDWR);<br>
> diff --git a/src/modules/bluetooth/<wbr>module-bluez5-device.c b/src/modules/bluetooth/<wbr>module-bluez5-device.c<br>
> index 9dbdca3..c9b88bd 100644<br>
> --- a/src/modules/bluetooth/<wbr>module-bluez5-device.c<br>
> +++ b/src/modules/bluetooth/<wbr>module-bluez5-device.c<br>
> @@ -57,6 +57,9 @@ PA_MODULE_LOAD_ONCE(false);<br>
>  PA_MODULE_USAGE("path=<device object path>"<br>
>                  "autodetect_mtu=<boolean>");<br>
><br>
> +#define HFP_AUDIO_CODEC_CVSD    0x01<br>
> +#define HFP_AUDIO_CODEC_MSBC    0x02<br>
> +<br>
>  #define FIXED_LATENCY_PLAYBACK_A2DP (25 * PA_USEC_PER_MSEC)<br>
>  #define FIXED_LATENCY_PLAYBACK_SCO  (25 * PA_USEC_PER_MSEC)<br>
>  #define FIXED_LATENCY_RECORD_A2DP   (25 * PA_USEC_PER_MSEC)<br>
> @@ -106,6 +109,27 @@ typedef struct sbc_info {<br>
>      size_t buffer_size;                  /* Size of the buffer */<br>
>  } sbc_info_t;<br>
><br>
> +struct msbc_parser {<br>
> +    int len;<br>
> +    uint8_t buffer[60];<br>
> +};<br>
> +<br>
> +typedef struct msbc_info {<br>
> +    bool msbc_initialized;               /* Keep track if the encoder is initialized */<br>
> +    sbc_t sbcenc;                        /* Encoder data */<br>
> +    uint8_t *ebuffer;                    /* Codec transfer buffer */<br>
> +    size_t ebuffer_size;                 /* Size of the buffer */<br>
> +    size_t ebuffer_start;                /* start of encoding data */<br>
> +    size_t ebuffer_end;                  /* end of encoding data */<br>
> +<br>
> +    struct msbc_parser parser;           /* mSBC parser for concatenating frames */<br>
> +    sbc_t sbcdec;                        /* Decoder data */<br>
> +<br>
> +    size_t msbc_frame_size;<br>
> +    size_t decoded_frame_size;<br>
> +<br>
> +} msbc_info_t;<br>
<br>
</div></div>Have you though about putting this into libsbc?<br></blockquote><div>I didn't thought about it. But yes we can but it in libsbc.</div><div>I will comment this to be added into libsbc and we can submit a patch to sbc. once it is merged can we remove this from PA?</div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><div class="h5"><br>
>  struct userdata {<br>
>      pa_module *module;<br>
>      pa_core *core;<br>
> @@ -147,6 +171,7 @@ struct userdata {<br>
>      pa_memchunk write_memchunk;<br>
>      pa_sample_spec sample_spec;<br>
>      struct sbc_info sbc_info;<br>
> +    struct msbc_info msbc_info;<br>
>  };<br>
><br>
>  typedef enum pa_bluetooth_form_factor {<br>
> @@ -251,6 +276,215 @@ static void connect_ports(struct userdata *u, void *new_data, pa_direction_t dir<br>
>  }<br>
><br>
>  /* Run from IO thread */<br>
> +static void msbc_parser_reset(struct msbc_parser *p) {<br>
> +    p->len = 0;<br>
> +}<br>
> +<br>
> +/* Run from IO thread */<br>
> +static int msbc_state_machine(struct msbc_parser *p, uint8_t byte) {<br>
> +    pa_assert(p->len < 60);<br>
> +<br>
> +    switch (p->len) {<br>
> +    case 0:<br>
> +        if (byte == 0x01)<br>
> +            goto copy;<br>
> +        return 0;<br>
> +    case 1:<br>
> +        if (byte == 0x08 || byte == 0x38 || byte == 0xC8 || byte == 0xF8)<br>
> +            goto copy;<br>
> +        break;<br>
> +    case 2:<br>
> +        if (byte == 0xAD)<br>
> +            goto copy;<br>
> +        break;<br>
> +    case 3:<br>
> +        if (byte == 0x00)<br>
> +            goto copy;<br>
> +        break;<br>
> +    case 4:<br>
> +        if (byte == 0x00)<br>
> +            goto copy;<br>
> +        break;<br>
> +    default:<br>
> +        goto copy;<br>
> +    }<br>
> +<br>
> +    p->len = 0;<br>
> +    return 0;<br>
> +copy:<br>
> +    p->buffer[p->len] = byte;<br>
> +    p->len ++;<br>
> +<br>
> +    return p->len;<br>
> +}<br>
> +<br>
> +/* Run from IO thread */<br>
> +static size_t msbc_parse(sbc_t *sbcdec, struct msbc_parser *p, uint8_t *data, int len, uint8_t *out, int outlen, int *bytes) {<br>
> +    size_t totalwritten = 0;<br>
> +    size_t written = 0;<br>
> +    int i;<br>
> +    *bytes = 0;<br>
> +<br>
> +    for (i = 0; i < len; i++) {<br>
> +        if (msbc_state_machine(p, data[i]) == 60) {<br>
> +            int decoded = 0;<br>
> +<br>
> +            /* Decode the recived data from the socket */<br>
> +            decoded = sbc_decode(sbcdec,<br>
> +                                 p->buffer + 2, p->len - 2 - 1,<br>
> +                                 out, outlen,<br>
> +                                 &written);<br>
> +<br>
> +            if (decoded > 0) {<br>
> +                totalwritten += written;<br>
> +                *bytes += decoded;<br>
> +            } else {<br>
> +                pa_log_debug("Error while decoding: %d\n", decoded);<br>
> +            }<br>
> +            msbc_parser_reset(p);<br>
> +        }<br>
> +    }<br>
> +    return totalwritten;<br>
> +}<br>
> +<br>
> +/* Run from IO thread */<br>
> +static void hsp_prepare_buffer(struct userdata *u) {<br>
> +<br>
> +    pa_assert(u);<br>
> +<br>
> +    /* Initialize sbc codec if not already done */<br>
> +    if (!u->msbc_info.msbc_<wbr>initialized) {<br>
> +        sbc_init_msbc(&u->msbc_info.<wbr>sbcenc, 0);<br>
> +        sbc_init_msbc(&u->msbc_info.<wbr>sbcdec, 0);<br>
> +        u->msbc_info.msbc_frame_size = 2 + sbc_get_frame_length(&u->msbc_<wbr>info.sbcenc) + 1;<br>
> +        u->msbc_info.decoded_frame_<wbr>size = sbc_get_codesize(&u->msbc_<wbr>info.sbcenc);<br>
> +        u->msbc_info.msbc_initialized = 1;<br>
> +        msbc_parser_reset(&u->msbc_<wbr>info.parser);<br>
> +    }<br>
> +<br>
> +    /* Allocate a buffer for encoding, and a tmp buffer for sending */<br>
> +    if (u->msbc_info.ebuffer_size < u->msbc_info.msbc_frame_size) {<br>
> +        pa_xfree(u->msbc_info.ebuffer)<wbr>;<br>
> +        u->msbc_info.ebuffer_size = u->msbc_info.msbc_frame_size * 4; /* 5 * 48 = 10 * 24 = 4 * 60 */<br>
> +        u->msbc_info.ebuffer = pa_xmalloc(u->msbc_info.<wbr>ebuffer_size);<br>
> +        u->msbc_info.ebuffer_start = 0;<br>
> +        u->msbc_info.ebuffer_end = 0;<br>
> +    }<br>
> +}<br>
> +<br>
> +static const char sntable[4] = { 0x08, 0x38, 0xC8, 0xF8 };<br>
> +<br>
> +/* Run from IO thread */<br>
> +static int sco_process_render_msbc(struct userdata *u) {<br>
> +<br>
> +    int ret = 0;<br>
> +    size_t to_write, to_encode;<br>
> +<br>
> +    pa_assert(u);<br>
> +    pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HEADSET_<wbr>HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_<wbr>AUDIO_GATEWAY);<br>
> +    pa_assert(u->sink);<br>
> +<br>
> +    hsp_prepare_buffer(u);<br>
> +<br>
> +    /* First, render some data */<br>
> +    if (!u->write_memchunk.memblock)<br>
> +        pa_sink_render_full(u->sink, u->msbc_info.decoded_frame_<wbr>size, &u->write_memchunk);<br>
> +<br>
> +    for (;;) {<br>
> +        int l = 0;<br>
> +        bool wrote = false;<br>
> +        const void *p;<br>
> +        void *d;<br>
> +        ssize_t written = 0;<br>
> +        ssize_t encoded;<br>
> +        uint8_t *h2 = u->msbc_info.ebuffer + u->msbc_info.ebuffer_end;<br>
> +        static int sn = 0;<br>
> +<br>
> +        /* Now write that data to the socket. The socket is of type<br>
> +         * SEQPACKET, and we generated the data of the MTU size, so this<br>
> +         * should just work. */<br>
> +<br>
> +        p = (const uint8_t *) pa_memblock_acquire_chunk(&u-><wbr>write_memchunk);<br>
> +        to_encode = u->write_memchunk.length;<br>
> +<br>
> +        d = ((uint8_t *)u->msbc_info.ebuffer) + u->msbc_info.ebuffer_end + 2;<br>
> +        to_write = u->msbc_info.ebuffer_size - u->msbc_info.ebuffer_end - 2;<br>
> +<br>
> +        h2[0] = 0x01;<br>
> +        h2[1] = sntable[sn];<br>
> +        h2[59] = 0x00;<br>
> +        sn = (sn + 1) % 4;<br>
> +<br>
> +        pa_assert(u->msbc_info.<wbr>ebuffer_end + u->msbc_info.msbc_frame_size <= u->msbc_info.ebuffer_size);<br>
> +<br>
> +        encoded = sbc_encode(&u->msbc_info.<wbr>sbcenc, p, to_encode, d, to_write, &written);<br>
> +<br>
> +        if (PA_UNLIKELY(encoded <= 0)) {<br>
> +            pa_log_error("MSBC encoding error (%li)", (long) encoded);<br>
> +            pa_memblock_release(u->write_<wbr>memchunk.memblock);<br>
> +            return -1;<br>
> +        }<br>
> +<br>
> +        written += 2 /* H2 */ + 1 /* 0x00 */;<br>
> +        pa_assert((size_t)written == u->msbc_info.msbc_frame_size);<br>
> +        u->msbc_info.ebuffer_end += written;<br>
> +<br>
> +        /* Send MTU bytes of it, if there is more it will send later */<br>
> +        while (u->msbc_info.ebuffer_start + u->write_link_mtu <= u->msbc_info.ebuffer_end) {<br>
> +            l = pa_write(u->stream_fd,<br>
> +                         u->msbc_info.ebuffer + u->msbc_info.ebuffer_start,<br>
> +                         u->write_link_mtu,<br>
> +                         &u->stream_write_type);<br>
> +<br>
> +            wrote = true;<br>
> +            if (l <= 0) {<br>
> +                pa_log_debug("Error while writing: l %d, errno %d", l, errno);<br>
> +                break;<br>
> +            }<br>
> +<br>
> +            u->msbc_info.ebuffer_start += l;<br>
> +            if (u->msbc_info.ebuffer_start >= u->msbc_info.ebuffer_end)<br>
> +                u->msbc_info.ebuffer_start = u->msbc_info.ebuffer_end = 0;<br>
> +        }<br>
> +<br>
> +        pa_memblock_release(u->write_<wbr>memchunk.memblock);<br>
> +<br>
> +        if (wrote && l < 0) {<br>
> +<br>
> +            if (errno == EINTR)<br>
> +                /* Retry right away if we got interrupted */<br>
> +                continue;<br>
> +<br>
> +            else if (errno == EAGAIN)<br>
> +                /* Hmm, apparently the socket was not writable, give up for now */<br>
> +                break;<br>
> +<br>
> +            pa_log_error("Failed to write data to SCO socket: %s", pa_cstrerror(errno));<br>
> +            ret = -1;<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        if ((size_t) l != (size_t)u->write_link_mtu) {<br>
> +            pa_log_error("Wrote memory block to socket only partially! %llu written, wanted to write %llu.",<br>
> +                        (unsigned long long) l,<br>
> +                        (unsigned long long) u->write_link_mtu);<br>
> +            ret = -1;<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        u->write_index += (uint64_t) u->write_memchunk.length;<br>
> +<br>
> +        pa_memblock_unref(u->write_<wbr>memchunk.memblock);<br>
> +        pa_memchunk_reset(&u->write_<wbr>memchunk);<br>
> +<br>
> +        ret = 1;<br>
> +        break;<br>
> +    }<br>
> +<br>
> +    return ret;<br>
> +}<br>
> +<br>
> +/* Run from IO thread */<br>
>  static int sco_process_render(struct userdata *u) {<br>
>      ssize_t l;<br>
>      pa_memchunk memchunk;<br>
> @@ -318,6 +552,108 @@ static int sco_process_render(struct userdata *u) {<br>
>  }<br>
><br>
>  /* Run from IO thread */<br>
> +static int sco_process_push_msbc(struct userdata *u) {<br>
> +<br>
> +    int ret = 0;<br>
> +    pa_memchunk memchunk;<br>
> +<br>
> +    pa_assert(u);<br>
> +    pa_assert(u->profile == PA_BLUETOOTH_PROFILE_HEADSET_<wbr>HEAD_UNIT ||<br>
> +                u->profile == PA_BLUETOOTH_PROFILE_HEADSET_<wbr>AUDIO_GATEWAY);<br>
> +    pa_assert(u->source);<br>
> +    pa_assert(u->read_smoother);<br>
> +<br>
> +    /*Prepare the buffer before allocating memory*/<br>
> +    hsp_prepare_buffer(u);<br>
> +<br>
> +    u->read_block_size = u->msbc_info.decoded_frame_<wbr>size;<br>
> +    memchunk.memblock = pa_memblock_new(u->core-><wbr>mempool, u->read_block_size);<br>
> +    memchunk.index = memchunk.length = 0;<br>
> +<br>
> +    for (;;) {<br>
> +        ssize_t l;<br>
> +        void *p;<br>
> +        struct msghdr m;<br>
> +        struct cmsghdr *cm;<br>
> +        uint8_t aux[1024];<br>
> +        struct iovec iov;<br>
> +        bool found_tstamp = false;<br>
> +        pa_usec_t tstamp;<br>
> +        int decoded = 0;<br>
> +        size_t written;<br>
> +        uint8_t *tmpbuf = pa_xmalloc(u->read_link_mtu);<br>
> +<br>
> +        pa_zero(m);<br>
> +        pa_zero(aux);<br>
> +        pa_zero(iov);<br>
> +<br>
> +        m.msg_iov = &iov;<br>
> +        m.msg_iovlen = 1;<br>
> +        m.msg_control = aux;<br>
> +        m.msg_controllen = sizeof(aux);<br>
> +        iov.iov_base = tmpbuf;<br>
> +        iov.iov_len = u->read_link_mtu;<br>
> +<br>
> +        /* Receive data from the socket */<br>
> +        l = recvmsg(u->stream_fd, &m, 0);<br>
> +<br>
> +        if (l <= 0) {<br>
> +<br>
> +            if (l < 0 && errno == EINTR)<br>
> +                /* Retry right away if we got interrupted */<br>
> +                continue;<br>
> +<br>
> +            else if (l < 0 && errno == EAGAIN)<br>
> +                /* Hmm, apparently the socket was not readable, give up for now. */<br>
> +                break;<br>
> +<br>
> +            pa_log_error("Failed to read data from SCO socket: %s", l < 0 ? pa_cstrerror(errno) : "EOF");<br>
> +            ret = -1;<br>
> +            break;<br>
> +        }<br>
> +<br>
> +        p = pa_memblock_acquire(memchunk.<wbr>memblock);<br>
> +        written = msbc_parse(&u->msbc_info.<wbr>sbcdec, &u->msbc_info.parser, tmpbuf, l, p, pa_memblock_get_length(<wbr>memchunk.memblock), &decoded);<br>
> +        pa_memblock_release(memchunk.<wbr>memblock);<br>
> +<br>
> +        pa_xfree(tmpbuf);<br>
> +<br>
> +        memchunk.length = (size_t) written;<br>
> +<br>
> +        u->read_index += (uint64_t) decoded;<br>
> +<br>
> +        for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm)) {<br>
> +            if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SO_TIMESTAMP) {<br>
> +                struct timeval *tv = (struct timeval*) CMSG_DATA(cm);<br>
> +                pa_rtclock_from_wallclock(tv);<br>
> +                tstamp = pa_timeval_load(tv);<br>
> +                found_tstamp = true;<br>
> +                break;<br>
> +            }<br>
> +        }<br>
> +<br>
> +        if (!found_tstamp) {<br>
> +            pa_log_warn("Couldn't find SO_TIMESTAMP data in auxiliary recvmsg() data!");<br>
> +            tstamp = pa_rtclock_now();<br>
> +        }<br>
> +<br>
> +        pa_smoother_put(u->read_<wbr>smoother, tstamp, pa_bytes_to_usec(u->read_<wbr>index, &u->sample_spec));<br>
> +        pa_smoother_resume(u->read_<wbr>smoother, tstamp, true);<br>
> +<br>
> +        if (memchunk.length > 0) {<br>
> +            pa_source_post(u->source, &memchunk);<br>
> +        }<br>
> +<br>
> +        ret = decoded;<br>
> +        break;<br>
> +    }<br>
> +<br>
> +    pa_memblock_unref(memchunk.<wbr>memblock);<br>
> +<br>
> +    return ret;<br>
> +}<br>
> +<br>
> +/* Run from IO thread */<br>
>  static int sco_process_push(struct userdata *u) {<br>
>      ssize_t l;<br>
>      pa_memchunk memchunk;<br>
> @@ -1294,7 +1630,7 @@ static void transport_config(struct userdata *u) {<br>
>      if (u->profile == PA_BLUETOOTH_PROFILE_HEADSET_<wbr>HEAD_UNIT || u->profile == PA_BLUETOOTH_PROFILE_HEADSET_<wbr>AUDIO_GATEWAY) {<br>
>          u->sample_spec.format = PA_SAMPLE_S16LE;<br>
>          u->sample_spec.channels = 1;<br>
> -        u->sample_spec.rate = 8000;<br>
> +        u->sample_spec.rate = (u->transport->codec == HFP_AUDIO_CODEC_CVSD) ? 8000 : 16000;<br>
>      } else {<br>
>          sbc_info_t *sbc_info = &u->sbc_info;<br>
>          a2dp_sbc_t *config;<br>
> @@ -1481,8 +1817,16 @@ static int write_block(struct userdata *u) {<br>
>          if ((n_written = a2dp_process_render(u)) < 0)<br>
>              return -1;<br>
>      } else {<br>
> -        if ((n_written = sco_process_render(u)) < 0)<br>
> -            return -1;<br>
> +        if (u->transport->codec == HFP_AUDIO_CODEC_CVSD) {<br>
> +            if ((n_written = sco_process_render(u)) < 0)<br>
> +                return -1;<br>
> +        } else if (u->transport->codec == HFP_AUDIO_CODEC_MSBC) {<br>
> +            if ((n_written = sco_process_render_msbc(u)) < 0)<br>
> +                return -1;<br>
> +        } else {<br>
> +            n_written = -1;<br>
> +            pa_log("Invalid codec for encoding: %d", u->transport->codec);<br>
> +        }<br>
>      }<br>
><br>
>      return n_written;<br>
> @@ -1550,11 +1894,21 @@ static void thread_func(void *userdata) {<br>
>                  /* If we got woken up by POLLIN let's do some reading */<br>
>                  if (pollfd->revents & POLLIN) {<br>
>                      int n_read;<br>
> -<br>
>                      if (u->profile == PA_BLUETOOTH_PROFILE_A2DP_<wbr>SOURCE)<br>
>                          n_read = a2dp_process_push(u);<br>
> -                    else<br>
> -                        n_read = sco_process_push(u);<br>
> +                    else {<br>
> +                         switch(u->transport->codec) {<br>
> +                            case HFP_AUDIO_CODEC_CVSD:<br>
> +                                n_read = sco_process_push(u);<br>
> +                                break;<br>
> +                            case HFP_AUDIO_CODEC_MSBC:<br>
> +                                n_read = sco_process_push_msbc(u);<br>
> +                                break;<br>
> +                            default:<br>
> +                                pa_log_error("Invalid codec for encoding %d", u->transport->codec);<br>
> +                                n_read = -1;<br>
> +                        }<br>
> +                    }<br>
><br>
>                      if (n_read < 0)<br>
>                          goto fail;<br>
> @@ -1604,9 +1958,10 @@ static void thread_func(void *userdata) {<br>
>                          if (blocks_to_write > 0)<br>
>                              writable = false;<br>
>                      }<br>
> +                }<br>
><br>
> -                /* There is no source, we have to use the system clock for timing */<br>
> -                } else {<br>
> +                /* There is no source or audio codec was MSBC, we have to use the system clock for timing */<br>
> +                if ((u->transport->codec == HFP_AUDIO_CODEC_MSBC) || !have_source){<br>
<br>
</div></div>Was this the reason we were not in sync?</blockquote><div>The main reason is that the USB ALT 6 setting was not completed in controller at that moment and Now it was ready and we have working iBT.<br></div><div>There was confusion between Controller and Pulseaudio sync caused the upstream delayed.</div><div><br></div><div>And yes this is also a reason.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> </blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<span class=""><br>
>                      bool have_written = false;<br>
>                      pa_usec_t time_passed = 0;<br>
>                      pa_usec_t audio_sent = 0;<br>
> --<br>
> 2.7.4<br>
><br>
</span>> ______________________________<wbr>_________________<br>
> pulseaudio-discuss mailing list<br>
> <a href="mailto:pulseaudio-discuss@lists.freedesktop.org">pulseaudio-discuss@lists.<wbr>freedesktop.org</a><br>
> <a href="https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/pulseaudio-<wbr>discuss</a><br>
<span class=""><br>
<br>
<br>
-- <br>
Luiz Augusto von Dentz<br>
</span>______________________________<wbr>_________________<br>
pulseaudio-discuss mailing list<br>
<a href="mailto:pulseaudio-discuss@lists.freedesktop.org">pulseaudio-discuss@lists.<wbr>freedesktop.org</a><br>
<a href="https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss" rel="noreferrer" target="_blank">https://lists.freedesktop.org/<wbr>mailman/listinfo/pulseaudio-<wbr>discuss</a><br>
</blockquote></div><br></div></div>