summaryrefslogtreecommitdiff
path: root/cras/src/server/cras_hfp_iodev.c
diff options
context:
space:
mode:
Diffstat (limited to 'cras/src/server/cras_hfp_iodev.c')
-rw-r--r--cras/src/server/cras_hfp_iodev.c371
1 files changed, 0 insertions, 371 deletions
diff --git a/cras/src/server/cras_hfp_iodev.c b/cras/src/server/cras_hfp_iodev.c
deleted file mode 100644
index 6a4ced04..00000000
--- a/cras/src/server/cras_hfp_iodev.c
+++ /dev/null
@@ -1,371 +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 <stdbool.h>
-#include <sys/param.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <syslog.h>
-
-#include "cras_audio_area.h"
-#include "cras_hfp_ag_profile.h"
-#include "cras_hfp_iodev.h"
-#include "cras_hfp_info.h"
-#include "cras_hfp_slc.h"
-#include "cras_iodev.h"
-#include "cras_system_state.h"
-#include "cras_util.h"
-#include "utlist.h"
-
-/* Implementation of bluetooth hands-free profile iodev.
- * Members:
- * base - The cras_iodev structure base class.
- * device - The assciated bt_device.
- * slc - Handle to the HFP service level connection.
- * info - hfp_info taking care of SCO data read/write.
- * drain_complete - Flag to indicate if valid samples are drained
- * in no stream state. Only used for output.
- * filled_zeros - Number of zero data in frames have been filled
- * to buffer of hfp_info in no stream state. Only used for output
- */
-struct hfp_io {
- struct cras_iodev base;
- struct cras_bt_device *device;
- struct hfp_slc_handle *slc;
- struct hfp_info *info;
- bool drain_complete;
- unsigned int filled_zeros;
-};
-
-static int update_supported_formats(struct cras_iodev *iodev)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
-
- free(iodev->supported_rates);
- iodev->supported_rates = (size_t *)malloc(2 * sizeof(size_t));
-
- /* 16 bit, mono, 8kHz for narrowband and 16KHz for wideband */
- iodev->supported_rates[0] =
- (hfp_slc_get_selected_codec(hfpio->slc) == HFP_CODEC_ID_MSBC) ?
- 16000 :
- 8000;
- iodev->supported_rates[1] = 0;
-
- free(iodev->supported_channel_counts);
- iodev->supported_channel_counts = (size_t *)malloc(2 * sizeof(size_t));
- iodev->supported_channel_counts[0] = 1;
- iodev->supported_channel_counts[1] = 0;
-
- free(iodev->supported_formats);
- iodev->supported_formats =
- (snd_pcm_format_t *)malloc(2 * sizeof(snd_pcm_format_t));
- iodev->supported_formats[0] = SND_PCM_FORMAT_S16_LE;
- iodev->supported_formats[1] = 0;
-
- return 0;
-}
-
-static int no_stream(struct cras_iodev *iodev, int enable)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
- struct timespec hw_tstamp;
- unsigned int hw_level;
- unsigned int level_target;
-
- if (iodev->direction != CRAS_STREAM_OUTPUT)
- return 0;
-
- hw_level = iodev->frames_queued(iodev, &hw_tstamp);
- if (enable) {
- if (!hfpio->drain_complete && (hw_level <= hfpio->filled_zeros))
- hfpio->drain_complete = 1;
- hfpio->filled_zeros += hfp_fill_output_with_zeros(
- hfpio->info, iodev->buffer_size);
- return 0;
- }
-
- /* Leave no stream state.*/
- level_target = iodev->min_cb_level;
- if (hfpio->drain_complete) {
- hfp_force_output_level(hfpio->info, level_target);
- } else {
- unsigned int valid_samples = 0;
- if (hw_level > hfpio->filled_zeros)
- valid_samples = hw_level - hfpio->filled_zeros;
- level_target = MAX(level_target, valid_samples);
-
- if (level_target > hw_level)
- hfp_fill_output_with_zeros(hfpio->info,
- level_target - hw_level);
- else
- hfp_force_output_level(hfpio->info, level_target);
- }
- hfpio->drain_complete = 0;
- hfpio->filled_zeros = 0;
-
- return 0;
-}
-
-static int frames_queued(const struct cras_iodev *iodev,
- struct timespec *tstamp)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
-
- if (!hfp_info_running(hfpio->info))
- return -1;
-
- /* Do not enable timestamp mechanism on HFP device because last time
- * stamp might be a long time ago and it is not really useful. */
- clock_gettime(CLOCK_MONOTONIC_RAW, tstamp);
- return hfp_buf_queued(hfpio->info, iodev->direction);
-}
-
-static int output_underrun(struct cras_iodev *iodev)
-{
- /* Handle it the same way as cras_iodev_output_underrun(). */
- return cras_iodev_fill_odev_zeros(iodev, iodev->min_cb_level);
-}
-
-static int configure_dev(struct cras_iodev *iodev)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
- int sk, err, mtu;
-
- /* Assert format is set before opening device. */
- if (iodev->format == NULL)
- return -EINVAL;
-
- iodev->format->format = SND_PCM_FORMAT_S16_LE;
- cras_iodev_init_audio_area(iodev, iodev->format->num_channels);
-
- if (hfp_info_running(hfpio->info))
- goto add_dev;
-
- /*
- * Might require a codec negotiation before building the sco connection.
- */
- hfp_slc_codec_connection_setup(hfpio->slc);
-
- sk = cras_bt_device_sco_connect(hfpio->device,
- hfp_slc_get_selected_codec(hfpio->slc));
- if (sk < 0)
- goto error;
-
- mtu = cras_bt_device_sco_packet_size(
- hfpio->device, sk, hfp_slc_get_selected_codec(hfpio->slc));
-
- /* Start hfp_info */
- err = hfp_info_start(sk, mtu, hfp_slc_get_selected_codec(hfpio->slc),
- hfpio->info);
- if (err)
- goto error;
-
- hfpio->drain_complete = 0;
- hfpio->filled_zeros = 0;
-add_dev:
- hfp_info_add_iodev(hfpio->info, iodev->direction, iodev->format);
- hfp_set_call_status(hfpio->slc, 1);
-
- iodev->buffer_size = hfp_buf_size(hfpio->info, iodev->direction);
-
- return 0;
-error:
- syslog(LOG_ERR, "Failed to open HFP iodev");
- return -1;
-}
-
-static int close_dev(struct cras_iodev *iodev)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
-
- hfp_info_rm_iodev(hfpio->info, iodev->direction);
- if (hfp_info_running(hfpio->info) && !hfp_info_has_iodev(hfpio->info)) {
- hfp_info_stop(hfpio->info);
- hfp_set_call_status(hfpio->slc, 0);
- }
-
- cras_iodev_free_format(iodev);
- cras_iodev_free_audio_area(iodev);
- return 0;
-}
-
-static void set_hfp_volume(struct cras_iodev *iodev)
-{
- size_t volume;
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
-
- volume = cras_system_get_volume();
- if (iodev->active_node)
- volume = cras_iodev_adjust_node_volume(iodev->active_node,
- volume);
-
- hfp_event_speaker_gain(hfpio->slc, volume);
-}
-
-static int delay_frames(const struct cras_iodev *iodev)
-{
- struct timespec tstamp;
-
- return frames_queued(iodev, &tstamp);
-}
-
-static int get_buffer(struct cras_iodev *iodev, struct cras_audio_area **area,
- unsigned *frames)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
- uint8_t *dst = NULL;
-
- if (!hfp_info_running(hfpio->info))
- return -1;
-
- hfp_buf_acquire(hfpio->info, iodev->direction, &dst, frames);
-
- iodev->area->frames = *frames;
- /* HFP is mono only. */
- iodev->area->channels[0].step_bytes =
- cras_get_format_bytes(iodev->format);
- iodev->area->channels[0].buf = dst;
-
- *area = iodev->area;
- return 0;
-}
-
-static int put_buffer(struct cras_iodev *iodev, unsigned nwritten)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
-
- if (!hfp_info_running(hfpio->info))
- return -1;
-
- hfp_buf_release(hfpio->info, iodev->direction, nwritten);
- return 0;
-}
-
-static int flush_buffer(struct cras_iodev *iodev)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
- unsigned nframes;
-
- if (iodev->direction == CRAS_STREAM_INPUT) {
- nframes = hfp_buf_queued(hfpio->info, iodev->direction);
- hfp_buf_release(hfpio->info, iodev->direction, nframes);
- }
- return 0;
-}
-
-static void update_active_node(struct cras_iodev *iodev, unsigned node_idx,
- unsigned dev_enabled)
-{
-}
-
-int hfp_iodev_is_hsp(struct cras_iodev *iodev)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
- return hfp_slc_is_hsp(hfpio->slc);
-}
-
-void hfp_free_resources(struct hfp_io *hfpio)
-{
- struct cras_ionode *node;
- node = hfpio->base.active_node;
- if (node) {
- cras_iodev_rm_node(&hfpio->base, node);
- free(node);
- }
- free(hfpio->base.supported_channel_counts);
- free(hfpio->base.supported_rates);
- free(hfpio->base.supported_formats);
- cras_iodev_free_resources(&hfpio->base);
-}
-
-struct cras_iodev *hfp_iodev_create(enum CRAS_STREAM_DIRECTION dir,
- struct cras_bt_device *device,
- struct hfp_slc_handle *slc,
- enum cras_bt_device_profile profile,
- struct hfp_info *info)
-{
- struct hfp_io *hfpio;
- struct cras_iodev *iodev;
- struct cras_ionode *node;
- const char *name;
-
- hfpio = (struct hfp_io *)calloc(1, sizeof(*hfpio));
- if (!hfpio)
- goto error;
-
- iodev = &hfpio->base;
- iodev->direction = dir;
-
- hfpio->device = device;
- hfpio->slc = slc;
-
- /* Set iodev's name to device readable name or the address. */
- name = cras_bt_device_name(device);
- if (!name)
- name = cras_bt_device_object_path(device);
-
- snprintf(iodev->info.name, sizeof(iodev->info.name), "%s", name);
- iodev->info.name[ARRAY_SIZE(iodev->info.name) - 1] = 0;
- iodev->info.stable_id = cras_bt_device_get_stable_id(device);
-
- iodev->configure_dev = configure_dev;
- iodev->frames_queued = frames_queued;
- iodev->delay_frames = delay_frames;
- iodev->get_buffer = get_buffer;
- iodev->put_buffer = put_buffer;
- iodev->flush_buffer = flush_buffer;
- iodev->no_stream = no_stream;
- iodev->close_dev = close_dev;
- iodev->update_supported_formats = update_supported_formats;
- iodev->update_active_node = update_active_node;
- iodev->set_volume = set_hfp_volume;
- iodev->output_underrun = output_underrun;
-
- node = (struct cras_ionode *)calloc(1, sizeof(*node));
- node->dev = iodev;
- strcpy(node->name, iodev->info.name);
-
- node->plugged = 1;
- /* If headset mic doesn't support the wideband speech, report a
- * different node type so UI can set different plug priority. */
- node->type = CRAS_NODE_TYPE_BLUETOOTH;
- if (!hfp_slc_get_wideband_speech_supported(hfpio->slc) &&
- (dir == CRAS_STREAM_INPUT))
- node->type = CRAS_NODE_TYPE_BLUETOOTH_NB_MIC;
-
- node->volume = 100;
- gettimeofday(&node->plugged_time, NULL);
-
- /* Prepare active node before append, so bt_io can extract correct
- * info from HFP iodev and node. */
- cras_iodev_add_node(iodev, node);
- cras_iodev_set_active_node(iodev, node);
- cras_bt_device_append_iodev(device, iodev, profile);
-
- hfpio->info = info;
-
- /* Record max supported channels into cras_iodev_info. */
- iodev->info.max_supported_channels = 1;
-
- ewma_power_disable(&iodev->ewma);
-
- return iodev;
-
-error:
- if (hfpio) {
- hfp_free_resources(hfpio);
- free(hfpio);
- }
- return NULL;
-}
-
-void hfp_iodev_destroy(struct cras_iodev *iodev)
-{
- struct hfp_io *hfpio = (struct hfp_io *)iodev;
-
- cras_bt_device_rm_iodev(hfpio->device, iodev);
- hfp_free_resources(hfpio);
- free(hfpio);
-}