diff options
Diffstat (limited to 'cras/src/server/cras_hfp_iodev.c')
-rw-r--r-- | cras/src/server/cras_hfp_iodev.c | 371 |
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); -} |