summaryrefslogtreecommitdiff
path: root/cras/src/server/cras_hfp_info.c
diff options
context:
space:
mode:
Diffstat (limited to 'cras/src/server/cras_hfp_info.c')
-rw-r--r--cras/src/server/cras_hfp_info.c868
1 files changed, 0 insertions, 868 deletions
diff --git a/cras/src/server/cras_hfp_info.c b/cras/src/server/cras_hfp_info.c
deleted file mode 100644
index fc407b29..00000000
--- a/cras/src/server/cras_hfp_info.c
+++ /dev/null
@@ -1,868 +0,0 @@
-/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <syslog.h>
-
-#include "audio_thread.h"
-#include "bluetooth.h"
-#include "byte_buffer.h"
-#include "cras_hfp_info.h"
-#include "cras_hfp_slc.h"
-#include "cras_iodev_list.h"
-#include "cras_plc.h"
-#include "cras_sbc_codec.h"
-#include "cras_server_metrics.h"
-#include "utlist.h"
-#include "packet_status_logger.h"
-
-/* The max buffer size. Note that the actual used size must set to multiple
- * of SCO packet size, and the packet size does not necessarily be equal to
- * MTU. We should keep this as common multiple of possible packet sizes, for
- * example: 48, 60, 64, 128.
- */
-#define MAX_HFP_BUF_SIZE_BYTES 28800
-
-/* rate(8kHz) * sample_size(2 bytes) * channels(1) */
-#define HFP_BYTE_RATE 16000
-
-/* Per Bluetooth Core v5.0 and HFP 1.7 specification. */
-#define MSBC_H2_HEADER_LEN 2
-#define MSBC_FRAME_LEN 57
-#define MSBC_FRAME_SIZE 59
-#define MSBC_CODE_SIZE 240
-#define MSBC_SYNC_WORD 0xAD
-
-/* For one mSBC 1 compressed wideband audio channel the HCI packets will
- * be 3 octets of HCI header + 60 octets of data. */
-#define MSBC_PKT_SIZE 60
-
-#define H2_HEADER_0 0x01
-
-/* Supported HCI SCO packet sizes. The wideband speech mSBC frame parsing
- * code ties to limited packet size values. Specifically list them out
- * to check against when setting packet size.
- *
- * Temp buffer size should be set to least common multiple of HCI SCO packet
- * size and MSBC_PKT_SIZE for optimizing buffer copy.
- * To add a new supported packet size value, add corresponding entry to the
- * lists, test the read/write msbc code, and fix the code if needed.
- */
-static const size_t wbs_supported_packet_size[] = { 60, 24, 0 };
-static const size_t wbs_hci_sco_buffer_size[] = { 60, 120, 0 };
-
-/* Second octet of H2 header is composed by 4 bits fixed 0x8 and 4 bits
- * sequence number 0000, 0011, 1100, 1111. */
-static const uint8_t h2_header_frames_count[] = { 0x08, 0x38, 0xc8, 0xf8 };
-
-/* Structure to hold variables for a HFP connection. Since HFP supports
- * bi-direction audio, two iodevs should share one hfp_info if they
- * represent two directions of the same HFP headset
- * Members:
- * fd - The file descriptor for SCO socket.
- * started - If the hfp_info has started to read/write SCO data.
- * mtu - The max transmit unit reported from BT adapter.
- * packet_size - The size of SCO packet to read/write preferred by
- * adapter, could be different than mtu.
- * capture_buf - The buffer to hold samples read from SCO socket.
- * playback_buf - The buffer to hold samples about to write to SCO socket.
- * msbc_read - mSBC codec to decode input audio in wideband speech mode.
- * msbc_write - mSBC codec to encode output audio in wideband speech mode.
- * msbc_plc - PLC component to handle the packet loss of input audio in
- * wideband speech mode.
- * msbc_num_out_frames - Number of total written mSBC frames.
- * msbc_num_in_frames - Number of total read mSBC frames.
- * msbc_num_lost_frames - Number of total lost mSBC frames.
- * read_cb - Callback to call when SCO socket can read. It returns the
- * number of PCM bytes read.
- * write_cb - Callback to call when SCO socket can write.
- * write_buf - Temp buffer for writeing HCI SCO packet in wideband.
- * read_buf - Temp buffer for reading HCI SCO packet in wideband.
- * input_format_bytes - The audio format bytes for input device. 0 means
- * there is no input device for the hfp_info.
- * output_format_bytes - The audio format bytes for output device. 0 means
- * there is no output device for the hfp_info.
- * write_wp - Write pointer of write_buf.
- * write_rp - Read pointer of write_buf.
- * read_wp - Write pointer of read_buf.
- * read_rp - Read pointer of read_buf.
- * read_align_cb - Callback used to align mSBC frame reading with read buf.
- * msbc_read_current_corrupted - Flag to mark if the current mSBC frame
- * read is corrupted.
- * wbs_logger - The logger for packet status in WBS.
- */
-struct hfp_info {
- int fd;
- int started;
- unsigned int mtu;
- unsigned int packet_size;
- struct byte_buffer *capture_buf;
- struct byte_buffer *playback_buf;
- struct cras_audio_codec *msbc_read;
- struct cras_audio_codec *msbc_write;
- struct cras_msbc_plc *msbc_plc;
- unsigned int msbc_num_out_frames;
- unsigned int msbc_num_in_frames;
- unsigned int msbc_num_lost_frames;
- int (*read_cb)(struct hfp_info *info);
- int (*write_cb)(struct hfp_info *info);
- uint8_t *write_buf;
- uint8_t *read_buf;
- size_t input_format_bytes;
- size_t output_format_bytes;
- size_t write_wp;
- size_t write_rp;
- size_t read_wp;
- size_t read_rp;
- int (*read_align_cb)(uint8_t *buf);
- bool msbc_read_current_corrupted;
- struct packet_status_logger *wbs_logger;
-};
-
-int hfp_info_add_iodev(struct hfp_info *info,
- enum CRAS_STREAM_DIRECTION direction,
- struct cras_audio_format *format)
-{
- if (direction == CRAS_STREAM_OUTPUT) {
- if (info->output_format_bytes)
- goto invalid;
- info->output_format_bytes = cras_get_format_bytes(format);
-
- buf_reset(info->playback_buf);
- } else if (direction == CRAS_STREAM_INPUT) {
- if (info->input_format_bytes)
- goto invalid;
- info->input_format_bytes = cras_get_format_bytes(format);
-
- buf_reset(info->capture_buf);
- }
-
- return 0;
-
-invalid:
- return -EINVAL;
-}
-
-int hfp_info_rm_iodev(struct hfp_info *info,
- enum CRAS_STREAM_DIRECTION direction)
-{
- if (direction == CRAS_STREAM_OUTPUT && info->output_format_bytes) {
- memset(info->playback_buf->bytes, 0,
- info->playback_buf->used_size);
- info->output_format_bytes = 0;
- } else if (direction == CRAS_STREAM_INPUT && info->input_format_bytes) {
- info->input_format_bytes = 0;
- } else {
- return -EINVAL;
- }
-
- return 0;
-}
-
-int hfp_info_has_iodev(struct hfp_info *info)
-{
- return info->output_format_bytes || info->input_format_bytes;
-}
-
-void hfp_buf_acquire(struct hfp_info *info,
- enum CRAS_STREAM_DIRECTION direction, uint8_t **buf,
- unsigned *count)
-{
- size_t format_bytes;
- unsigned int buf_avail;
-
- if (direction == CRAS_STREAM_OUTPUT && info->output_format_bytes) {
- *buf = buf_write_pointer_size(info->playback_buf, &buf_avail);
- format_bytes = info->output_format_bytes;
- } else if (direction == CRAS_STREAM_INPUT && info->input_format_bytes) {
- *buf = buf_read_pointer_size(info->capture_buf, &buf_avail);
- format_bytes = info->input_format_bytes;
- } else {
- *count = 0;
- return;
- }
-
- if (*count * format_bytes > buf_avail)
- *count = buf_avail / format_bytes;
-}
-
-int hfp_buf_size(struct hfp_info *info, enum CRAS_STREAM_DIRECTION direction)
-{
- if (direction == CRAS_STREAM_OUTPUT && info->output_format_bytes)
- return info->playback_buf->used_size /
- info->output_format_bytes;
- else if (direction == CRAS_STREAM_INPUT && info->input_format_bytes)
- return info->capture_buf->used_size / info->input_format_bytes;
- return 0;
-}
-
-void hfp_buf_release(struct hfp_info *info,
- enum CRAS_STREAM_DIRECTION direction,
- unsigned written_frames)
-{
- if (direction == CRAS_STREAM_OUTPUT && info->output_format_bytes)
- buf_increment_write(info->playback_buf,
- written_frames * info->output_format_bytes);
- else if (direction == CRAS_STREAM_INPUT && info->input_format_bytes)
- buf_increment_read(info->capture_buf,
- written_frames * info->input_format_bytes);
- else
- written_frames = 0;
-}
-
-int hfp_buf_queued(struct hfp_info *info, enum CRAS_STREAM_DIRECTION direction)
-{
- if (direction == CRAS_STREAM_OUTPUT && info->output_format_bytes)
- return buf_queued(info->playback_buf) /
- info->output_format_bytes;
- else if (direction == CRAS_STREAM_INPUT && info->input_format_bytes)
- return buf_queued(info->capture_buf) / info->input_format_bytes;
- else
- return 0;
-}
-
-int hfp_fill_output_with_zeros(struct hfp_info *info, unsigned int nframes)
-{
- unsigned int buf_avail;
- unsigned int nbytes;
- uint8_t *buf;
- int i;
- int ret = 0;
-
- if (info->output_format_bytes) {
- nbytes = nframes * info->output_format_bytes;
- /* Loop twice to make sure ring buffer is filled. */
- for (i = 0; i < 2; i++) {
- buf = buf_write_pointer_size(info->playback_buf,
- &buf_avail);
- if (buf_avail == 0)
- break;
- buf_avail = MIN(nbytes, buf_avail);
- memset(buf, 0, buf_avail);
- buf_increment_write(info->playback_buf, buf_avail);
- nbytes -= buf_avail;
- ret += buf_avail / info->output_format_bytes;
- }
- }
- return ret;
-}
-
-void hfp_force_output_level(struct hfp_info *info, unsigned int level)
-{
- if (info->output_format_bytes) {
- level *= info->output_format_bytes;
- level = MIN(level, MAX_HFP_BUF_SIZE_BYTES);
- buf_adjust_readable(info->playback_buf, level);
- }
-}
-
-int hfp_write_msbc(struct hfp_info *info)
-{
- size_t encoded;
- int err;
- int pcm_encoded;
- unsigned int pcm_avail, to_write;
- uint8_t *samples;
- uint8_t *wp;
-
- if (info->write_rp + info->packet_size <= info->write_wp)
- goto msbc_send_again;
-
- /* Make sure there are MSBC_CODE_SIZE bytes to encode. */
- samples = buf_read_pointer_size(info->playback_buf, &pcm_avail);
- if (pcm_avail < MSBC_CODE_SIZE) {
- to_write = MSBC_CODE_SIZE - pcm_avail;
- /*
- * Size of playback_buf is multiple of MSBC_CODE_SIZE so we
- * are safe to prepare the buffer by appending some zero bytes.
- */
- wp = buf_write_pointer_size(info->playback_buf, &pcm_avail);
- memset(wp, 0, to_write);
- buf_increment_write(info->playback_buf, to_write);
-
- samples = buf_read_pointer_size(info->playback_buf, &pcm_avail);
- if (pcm_avail < MSBC_CODE_SIZE)
- return -EINVAL;
- }
-
- /* Encode the next MSBC_CODE_SIZE of bytes. */
- wp = info->write_buf + info->write_wp;
- wp[0] = H2_HEADER_0;
- wp[1] = h2_header_frames_count[info->msbc_num_out_frames % 4];
- pcm_encoded = info->msbc_write->encode(
- info->msbc_write, samples, pcm_avail, wp + MSBC_H2_HEADER_LEN,
- MSBC_PKT_SIZE - MSBC_H2_HEADER_LEN, &encoded);
- if (pcm_encoded < 0) {
- syslog(LOG_ERR, "msbc encoding err: %s", strerror(pcm_encoded));
- return pcm_encoded;
- }
- buf_increment_read(info->playback_buf, pcm_encoded);
- pcm_avail -= pcm_encoded;
- info->write_wp += MSBC_PKT_SIZE;
- info->msbc_num_out_frames++;
-
- if (info->write_rp + info->packet_size > info->write_wp)
- return 0;
-
-msbc_send_again:
- err = send(info->fd, info->write_buf + info->write_rp,
- info->packet_size, 0);
- if (err < 0) {
- if (errno == EINTR)
- goto msbc_send_again;
- return err;
- }
- if (err != (int)info->packet_size) {
- syslog(LOG_ERR, "Partially write %d bytes for mSBC", err);
- return -1;
- }
- info->write_rp += info->packet_size;
- if (info->write_rp == info->write_wp) {
- info->write_rp = 0;
- info->write_wp = 0;
- }
-
- return err;
-}
-
-int hfp_write(struct hfp_info *info)
-{
- int err = 0;
- unsigned to_send;
- uint8_t *samples;
-
- /* Write something */
- samples = buf_read_pointer_size(info->playback_buf, &to_send);
- if (to_send < info->packet_size)
- return 0;
- to_send = info->packet_size;
-
-send_sample:
- err = send(info->fd, samples, to_send, 0);
- if (err < 0) {
- if (errno == EINTR)
- goto send_sample;
-
- return err;
- }
-
- if (err != (int)info->packet_size) {
- syslog(LOG_ERR,
- "Partially write %d bytes for SCO packet size %u", err,
- info->packet_size);
- return -1;
- }
-
- buf_increment_read(info->playback_buf, to_send);
-
- return err;
-}
-
-static int h2_header_get_seq(const uint8_t *p)
-{
- int i;
- for (i = 0; i < 4; i++) {
- if (*p == h2_header_frames_count[i])
- return i;
- }
- return -1;
-}
-
-/*
- * Extract mSBC frame from SCO socket input bytes, given that the mSBC frame
- * could be lost or corrupted.
- * Args:
- * input - Pointer to input bytes read from SCO socket.
- * len - Length of input bytes.
- * seq_out - To be filled by the sequence number of mSBC packet.
- * Returns:
- * The starting position of mSBC frame if found.
- */
-static const uint8_t *extract_msbc_frame(const uint8_t *input, int len,
- unsigned int *seq_out)
-{
- int rp = 0;
- int seq = -1;
- while (len - rp >= MSBC_FRAME_SIZE) {
- if ((input[rp] != H2_HEADER_0) ||
- (input[rp + 2] != MSBC_SYNC_WORD)) {
- rp++;
- continue;
- }
- seq = h2_header_get_seq(input + rp + 1);
- if (seq < 0) {
- rp++;
- continue;
- }
- // `seq` is guaranteed to be positive now.
- *seq_out = (unsigned int)seq;
- return input + rp;
- }
- return NULL;
-}
-
-/* Log value 0 when packet is received. */
-static void log_wbs_packet_received(struct hfp_info *info)
-{
- if (info->wbs_logger)
- packet_status_logger_update(info->wbs_logger, 0);
-}
-
-/* Log value 1 when packet is lost. */
-static void log_wbs_packet_lost(struct hfp_info *info)
-{
- if (info->wbs_logger)
- packet_status_logger_update(info->wbs_logger, 1);
-}
-
-/*
- * Handle the case when mSBC frame is considered lost.
- * Args:
- * info - The hfp_info instance holding mSBC codec and PLC objects.
- */
-static int handle_packet_loss(struct hfp_info *info)
-{
- int decoded;
- unsigned int pcm_avail;
- uint8_t *in_bytes;
-
- /* It's possible client doesn't consume data causing overrun. In that
- * case we treat it as one mSBC frame read but dropped. */
- info->msbc_num_in_frames++;
- info->msbc_num_lost_frames++;
-
- log_wbs_packet_lost(info);
-
- in_bytes = buf_write_pointer_size(info->capture_buf, &pcm_avail);
- if (pcm_avail < MSBC_CODE_SIZE)
- return 0;
-
- decoded = cras_msbc_plc_handle_bad_frames(info->msbc_plc,
- info->msbc_read, in_bytes);
- if (decoded < 0)
- return decoded;
-
- buf_increment_write(info->capture_buf, decoded);
-
- return decoded;
-}
-
-/* Checks if mSBC frame header aligns with the beginning of buffer. */
-static int msbc_frame_align(uint8_t *buf)
-{
- if ((buf[0] != H2_HEADER_0) || (buf[2] != MSBC_SYNC_WORD)) {
- syslog(LOG_DEBUG, "Waiting for valid mSBC frame head");
- return 0;
- }
- return 1;
-}
-
-int hfp_read_msbc(struct hfp_info *info)
-{
- int err = 0;
- unsigned int pcm_avail = 0;
- int decoded;
- size_t pcm_decoded = 0;
- size_t pcm_read = 0;
- uint8_t *capture_buf;
- const uint8_t *frame_head = NULL;
- unsigned int seq;
-
- struct msghdr msg = { 0 };
- struct iovec iov;
- struct cmsghdr *cmsg;
- const unsigned int control_size = CMSG_SPACE(sizeof(int));
- char control[control_size];
- uint8_t pkt_status;
-
- memset(control, 0, sizeof(control));
-recv_msbc_bytes:
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- iov.iov_base = info->read_buf + info->read_wp;
- iov.iov_len = info->packet_size;
- msg.msg_control = control;
- msg.msg_controllen = control_size;
-
- err = recvmsg(info->fd, &msg, 0);
- if (err < 0) {
- syslog(LOG_ERR, "HCI SCO packet read err %s", strerror(errno));
- if (errno == EINTR)
- goto recv_msbc_bytes;
- return err;
- }
- /*
- * Treat return code 0 (socket shutdown) as error here. BT stack
- * shall send signal to main thread for device disconnection.
- */
- if (err != (int)info->packet_size) {
- syslog(LOG_ERR, "Partially read %d bytes for mSBC packet", err);
- return -1;
- }
-
- /* Offset in input data breaks mSBC frame parsing. Discard this packet
- * until read alignment succeed. */
- if (info->read_align_cb) {
- if (!info->read_align_cb(info->read_buf))
- return 0;
- else
- info->read_align_cb = NULL;
- }
- info->read_wp += err;
-
- pkt_status = 0;
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == SOL_BLUETOOTH &&
- cmsg->cmsg_type == BT_SCM_PKT_STATUS) {
- size_t len = cmsg->cmsg_len - sizeof(*cmsg);
- memcpy(&pkt_status, CMSG_DATA(cmsg), len);
- }
- }
-
- /*
- * HCI SCO packet status flag:
- * 0x00 - correctly received data.
- * 0x01 - possibly invalid data.
- * 0x10 - No data received.
- * 0x11 - Data partially lost.
- *
- * If the latest SCO packet read doesn't cross the boundary of a mSBC
- * frame, the packet status flag can be used to derive if the current
- * mSBC frame is corrupted.
- */
- if (info->read_rp + MSBC_PKT_SIZE >= info->read_wp)
- info->msbc_read_current_corrupted |= (pkt_status > 0);
-
- /* Read buffer not enough to parse another mSBC frame. */
- if (info->read_rp + MSBC_PKT_SIZE > info->read_wp)
- return 0;
-
- if (info->msbc_read_current_corrupted) {
- syslog(LOG_DEBUG, "mSBC frame corrputed from packet status");
- info->msbc_read_current_corrupted = 0;
- frame_head = NULL;
- } else {
- frame_head =
- extract_msbc_frame(info->read_buf + info->read_rp,
- info->read_wp - info->read_rp, &seq);
- if (!frame_head)
- syslog(LOG_DEBUG, "Failed to extract msbc frame");
- }
-
- /*
- * Done with parsing the raw bytes just read. If mSBC frame head not
- * found, we shall handle it as packet loss.
- */
- info->read_rp += MSBC_PKT_SIZE;
- if (info->read_rp == info->read_wp) {
- info->read_rp = 0;
- info->read_wp = 0;
- }
- if (!frame_head)
- return handle_packet_loss(info);
-
- /*
- * Consider packet loss when found discontinuity in sequence number.
- */
- while (seq != (info->msbc_num_in_frames % 4)) {
- syslog(LOG_DEBUG, "SCO packet seq unmatch");
- err = handle_packet_loss(info);
- if (err < 0)
- return err;
- pcm_read += err;
- }
-
- /* Check if there's room for more PCM. */
- capture_buf = buf_write_pointer_size(info->capture_buf, &pcm_avail);
- if (pcm_avail < MSBC_CODE_SIZE)
- return pcm_read;
-
- decoded = info->msbc_read->decode(info->msbc_read,
- frame_head + MSBC_H2_HEADER_LEN,
- MSBC_FRAME_LEN, capture_buf,
- pcm_avail, &pcm_decoded);
- if (decoded < 0) {
- /*
- * If mSBC frame cannot be decoded, consider this packet is
- * corrupted and lost.
- */
- syslog(LOG_ERR, "mSBC decode failed");
- err = handle_packet_loss(info);
- if (err < 0)
- return err;
- pcm_read += err;
- } else {
- /* Good mSBC frame decoded. */
- log_wbs_packet_received(info);
- buf_increment_write(info->capture_buf, pcm_decoded);
- info->msbc_num_in_frames++;
- cras_msbc_plc_handle_good_frames(info->msbc_plc, capture_buf,
- capture_buf);
- pcm_read += pcm_decoded;
- }
- return pcm_read;
-}
-
-int hfp_read(struct hfp_info *info)
-{
- int err = 0;
- unsigned to_read;
- uint8_t *capture_buf;
-
- capture_buf = buf_write_pointer_size(info->capture_buf, &to_read);
-
- if (to_read < info->packet_size)
- return 0;
- to_read = info->packet_size;
-
-recv_sample:
- err = recv(info->fd, capture_buf, to_read, 0);
- if (err < 0) {
- syslog(LOG_ERR, "Read error %s", strerror(errno));
- if (errno == EINTR)
- goto recv_sample;
-
- return err;
- }
-
- if (err != (int)info->packet_size) {
- /* Allow the SCO packet size be modified from the default MTU
- * value to the size of SCO data we first read. This is for
- * some adapters who prefers a different value than MTU for
- * transmitting SCO packet.
- */
- if (err && (info->packet_size == info->mtu)) {
- info->packet_size = err;
- } else {
- syslog(LOG_ERR,
- "Partially read %d bytes for %u size SCO packet",
- err, info->packet_size);
- return -1;
- }
- }
-
- buf_increment_write(info->capture_buf, err);
-
- return err;
-}
-
-/* Callback function to handle sample read and write.
- * Note that we poll the SCO socket for read sample, since it reflects
- * there is actual some sample to read while the socket always reports
- * writable even when device buffer is full.
- * The strategy is to synchronize read & write operations:
- * 1. Read one chunk of MTU bytes of data.
- * 2. When input device not attached, ignore the data just read.
- * 3. When output device attached, write one chunk of MTU bytes of data.
- */
-static int hfp_info_callback(void *arg, int revents)
-{
- struct hfp_info *info = (struct hfp_info *)arg;
- int err = 0;
-
- if (!info->started)
- return 0;
-
- /* Allow last read before handling error or hang-up events. */
- if (revents & POLLIN) {
- err = info->read_cb(info);
- if (err < 0) {
- syslog(LOG_ERR, "Read error");
- goto read_write_error;
- }
- }
- /* Ignore the bytes just read if input dev not in present */
- if (!info->input_format_bytes)
- buf_increment_read(info->capture_buf, err);
-
- if (revents & (POLLERR | POLLHUP)) {
- syslog(LOG_ERR, "Error polling SCO socket, revent %d", revents);
- goto read_write_error;
- }
-
- /* Without output stream's presence, we shall still send zero packets
- * to HF. This is required for some HF devices to start sending non-zero
- * data to AG.
- */
- if (!info->output_format_bytes)
- buf_increment_write(info->playback_buf,
- info->msbc_write ? err : info->packet_size);
-
- err = info->write_cb(info);
- if (err < 0) {
- syslog(LOG_ERR, "Write error");
- goto read_write_error;
- }
-
- return 0;
-
-read_write_error:
- /*
- * This callback is executing in audio thread, so it's safe to
- * unregister itself by audio_thread_rm_callback().
- */
- audio_thread_rm_callback(info->fd);
- close(info->fd);
- info->fd = 0;
- info->started = 0;
-
- return 0;
-}
-
-struct hfp_info *hfp_info_create()
-{
- struct hfp_info *info;
- info = (struct hfp_info *)calloc(1, sizeof(*info));
- if (!info)
- goto error;
-
- info->capture_buf = byte_buffer_create(MAX_HFP_BUF_SIZE_BYTES);
- if (!info->capture_buf)
- goto error;
-
- info->playback_buf = byte_buffer_create(MAX_HFP_BUF_SIZE_BYTES);
- if (!info->playback_buf)
- goto error;
-
- return info;
-
-error:
- if (info) {
- if (info->capture_buf)
- byte_buffer_destroy(&info->capture_buf);
- if (info->playback_buf)
- byte_buffer_destroy(&info->playback_buf);
- free(info);
- }
- return NULL;
-}
-
-void hfp_info_set_wbs_logger(struct hfp_info *info,
- struct packet_status_logger *wbs_logger)
-{
- info->wbs_logger = wbs_logger;
-}
-
-int hfp_info_running(struct hfp_info *info)
-{
- return info->started;
-}
-
-int hfp_info_start(int fd, unsigned int mtu, int codec, struct hfp_info *info)
-{
- info->fd = fd;
- info->mtu = mtu;
-
- /* Initialize to MTU, it may change when actually read the socket. */
- info->packet_size = mtu;
- buf_reset(info->playback_buf);
- buf_reset(info->capture_buf);
-
- if (codec == HFP_CODEC_ID_MSBC) {
- int i;
- for (i = 0; wbs_supported_packet_size[i] != 0; i++) {
- if (info->packet_size == wbs_supported_packet_size[i])
- break;
- }
- /* In case of unsupported value, error log and fallback to
- * MSBC_PKT_SIZE(60). */
- if (wbs_supported_packet_size[i] == 0) {
- syslog(LOG_ERR, "Unsupported packet size %u",
- info->packet_size);
- i = 0;
- }
- info->packet_size = wbs_supported_packet_size[i];
- info->write_buf = (uint8_t *)malloc(wbs_hci_sco_buffer_size[i]);
- info->read_buf = (uint8_t *)malloc(wbs_hci_sco_buffer_size[i]);
-
- info->write_cb = hfp_write_msbc;
- info->read_cb = hfp_read_msbc;
- info->msbc_read = cras_msbc_codec_create();
- info->msbc_write = cras_msbc_codec_create();
- info->msbc_plc = cras_msbc_plc_create();
-
- packet_status_logger_init(info->wbs_logger);
- } else {
- info->write_cb = hfp_write;
- info->read_cb = hfp_read;
- }
-
- audio_thread_add_events_callback(info->fd, hfp_info_callback, info,
- POLLIN | POLLERR | POLLHUP);
-
- info->started = 1;
- info->msbc_num_out_frames = 0;
- info->msbc_num_in_frames = 0;
- info->msbc_num_lost_frames = 0;
- info->write_rp = 0;
- info->write_wp = 0;
- info->read_rp = 0;
- info->read_wp = 0;
-
- /* Mark as aligned if packet size equals to MSBC_PKT_SIZE. */
- info->read_align_cb =
- (info->packet_size == MSBC_PKT_SIZE) ? NULL : msbc_frame_align;
- info->msbc_read_current_corrupted = 0;
-
- return 0;
-}
-
-int hfp_info_stop(struct hfp_info *info)
-{
- if (!info->started)
- return 0;
-
- audio_thread_rm_callback_sync(cras_iodev_list_get_audio_thread(),
- info->fd);
-
- close(info->fd);
- info->fd = 0;
- info->started = 0;
-
- /* Unset the write/read callbacks. */
- info->write_cb = NULL;
- info->read_cb = NULL;
-
- if (info->write_buf)
- free(info->write_buf);
- if (info->read_buf)
- free(info->read_buf);
-
- if (info->msbc_read) {
- cras_sbc_codec_destroy(info->msbc_read);
- info->msbc_read = NULL;
- }
- if (info->msbc_write) {
- cras_sbc_codec_destroy(info->msbc_write);
- info->msbc_write = NULL;
- }
- if (info->msbc_plc) {
- cras_msbc_plc_destroy(info->msbc_plc);
- info->msbc_plc = NULL;
- }
-
- if (info->msbc_num_in_frames) {
- cras_server_metrics_hfp_packet_loss(
- (float)info->msbc_num_lost_frames /
- info->msbc_num_in_frames);
- }
-
- return 0;
-}
-
-void hfp_info_destroy(struct hfp_info *info)
-{
- if (info->capture_buf)
- byte_buffer_destroy(&info->capture_buf);
-
- if (info->playback_buf)
- byte_buffer_destroy(&info->playback_buf);
-
- free(info);
-}