diff options
Diffstat (limited to 'cras/src/libcras/cras_client.c')
-rw-r--r-- | cras/src/libcras/cras_client.c | 444 |
1 files changed, 438 insertions, 6 deletions
diff --git a/cras/src/libcras/cras_client.c b/cras/src/libcras/cras_client.c index 3fe631d5..8420db1f 100644 --- a/cras/src/libcras/cras_client.c +++ b/cras/src/libcras/cras_client.c @@ -119,7 +119,8 @@ struct thread_state { }; /* Parameters used when setting up a capture or playback stream. See comment - * above cras_client_create_stream_params in the header for descriptions. */ + * above cras_client_stream_params_create or libcras_stream_params_set in the + * header for descriptions. */ struct cras_stream_params { enum CRAS_STREAM_DIRECTION direction; size_t buffer_frames; @@ -133,6 +134,7 @@ struct cras_stream_params { cras_unified_cb_t unified_cb; cras_error_cb_t err_cb; struct cras_audio_format format; + libcras_stream_cb_t stream_cb; }; /* Represents an attached audio stream. @@ -274,6 +276,92 @@ struct cras_hotword_handle { void *user_data; }; +struct cras_stream_cb_data { + cras_stream_id_t stream_id; + enum CRAS_STREAM_DIRECTION direction; + uint8_t *buf; + unsigned int frames; + struct timespec sample_ts; + void *user_arg; +}; + +int stream_cb_get_stream_id(struct cras_stream_cb_data *data, + cras_stream_id_t *id) +{ + *id = data->stream_id; + return 0; +} + +int stream_cb_get_buf(struct cras_stream_cb_data *data, uint8_t **buf) +{ + *buf = data->buf; + return 0; +} + +int stream_cb_get_frames(struct cras_stream_cb_data *data, unsigned int *frames) +{ + *frames = data->frames; + return 0; +} + +int stream_cb_get_latency(struct cras_stream_cb_data *data, + struct timespec *latency) +{ + if (data->direction == CRAS_STREAM_INPUT) + cras_client_calc_capture_latency(&data->sample_ts, latency); + else + cras_client_calc_playback_latency(&data->sample_ts, latency); + return 0; +} + +int stream_cb_get_user_arg(struct cras_stream_cb_data *data, void **user_arg) +{ + *user_arg = data->user_arg; + return 0; +} + +struct libcras_stream_cb_data * +libcras_stream_cb_data_create(cras_stream_id_t stream_id, + enum CRAS_STREAM_DIRECTION direction, + uint8_t *buf, unsigned int frames, + struct timespec sample_ts, void *user_arg) +{ + struct libcras_stream_cb_data *data = + (struct libcras_stream_cb_data *)calloc( + 1, sizeof(struct libcras_stream_cb_data)); + if (!data) { + syslog(LOG_ERR, "cras_client: calloc: %s", strerror(errno)); + return NULL; + } + data->data_ = (struct cras_stream_cb_data *)calloc( + 1, sizeof(struct cras_stream_cb_data)); + if (!data->data_) { + syslog(LOG_ERR, "cras_client: calloc: %s", strerror(errno)); + free(data); + return NULL; + } + data->api_version = CRAS_API_VERSION; + data->get_stream_id = stream_cb_get_stream_id; + data->get_buf = stream_cb_get_buf; + data->get_frames = stream_cb_get_frames; + data->get_latency = stream_cb_get_latency; + data->get_user_arg = stream_cb_get_user_arg; + data->data_->stream_id = stream_id; + data->data_->direction = direction; + data->data_->buf = buf; + data->data_->frames = frames; + data->data_->sample_ts = sample_ts; + data->data_->user_arg = user_arg; + return data; +} + +void libcras_stream_cb_data_destroy(struct libcras_stream_cb_data *data) +{ + if (data) + free(data->data_); + free(data); +} + /* * Local Helpers */ @@ -283,6 +371,10 @@ static int client_thread_rm_stream(struct cras_client *client, static int handle_message_from_server(struct cras_client *client); static int reregister_notifications(struct cras_client *client); +static struct libcras_node_info * +libcras_node_info_create(struct cras_iodev_info *iodev, + struct cras_ionode_info *ionode); + /* * Unlock the server_state_rwlock if lock_rc is 0. * @@ -1084,6 +1176,7 @@ static int handle_capture_data_ready(struct client_stream *stream, uint8_t *captured_frames; struct timespec ts; int rc = 0; + struct libcras_stream_cb_data *data; config = stream->config; /* If this message is for an output stream, log error and drop it. */ @@ -1098,14 +1191,24 @@ static int handle_capture_data_ready(struct client_stream *stream, cras_timespec_to_timespec(&ts, &stream->shm->header->ts); - if (config->unified_cb) + if (config->stream_cb) { + data = libcras_stream_cb_data_create( + stream->id, stream->direction, captured_frames, + num_frames, ts, config->user_data); + if (!data) + return -errno; + frames = config->stream_cb(data); + libcras_stream_cb_data_destroy(data); + data = NULL; + } else if (config->unified_cb) { frames = config->unified_cb(stream->client, stream->id, captured_frames, NULL, num_frames, &ts, NULL, config->user_data); - else + } else { frames = config->aud_cb(stream->client, stream->id, captured_frames, num_frames, &ts, config->user_data); + } if (frames < 0) { send_stream_message(stream, CLIENT_STREAM_EOF); rc = frames; @@ -1152,6 +1255,7 @@ static int handle_playback_request(struct client_stream *stream, struct cras_stream_params *config; struct cras_audio_shm *shm = stream->shm; struct timespec ts; + struct libcras_stream_cb_data *data; config = stream->config; @@ -1169,13 +1273,24 @@ static int handle_playback_request(struct client_stream *stream, cras_timespec_to_timespec(&ts, &shm->header->ts); /* Get samples from the user */ - if (config->unified_cb) + if (config->stream_cb) { + data = libcras_stream_cb_data_create(stream->id, + stream->direction, buf, + num_frames, ts, + config->user_data); + if (!data) + return -errno; + frames = config->stream_cb(data); + libcras_stream_cb_data_destroy(data); + data = NULL; + } else if (config->unified_cb) { frames = config->unified_cb(stream->client, stream->id, NULL, buf, num_frames, NULL, &ts, config->user_data); - else + } else { frames = config->aud_cb(stream->client, stream->id, buf, num_frames, &ts, config->user_data); + } if (frames < 0) { send_stream_message(stream, CLIENT_STREAM_EOF); rc = frames; @@ -2255,6 +2370,7 @@ struct cras_stream_params *cras_client_stream_params_create( params->user_data = user_data; params->aud_cb = aud_cb; params->unified_cb = 0; + params->stream_cb = 0; params->err_cb = err_cb; memcpy(&(params->format), format, sizeof(*format)); return params; @@ -2328,6 +2444,7 @@ struct cras_stream_params *cras_client_unified_params_create( params->user_data = user_data; params->aud_cb = 0; params->unified_cb = unified_cb; + params->stream_cb = 0; params->err_cb = err_cb; memcpy(&(params->format), format, sizeof(*format)); @@ -2350,7 +2467,8 @@ static inline int cras_client_send_add_stream_command_message( if (client == NULL || config == NULL || stream_id_out == NULL) return -EINVAL; - if (config->aud_cb == NULL && config->unified_cb == NULL) + if (config->stream_cb == NULL && config->aud_cb == NULL && + config->unified_cb == NULL) return -EINVAL; if (config->err_cb == NULL) @@ -3815,3 +3933,317 @@ int cras_client_disable_hotword_callback(struct cras_client *client, free(handle); return 0; } + +int get_nodes(struct cras_client *client, enum CRAS_STREAM_DIRECTION direction, + struct libcras_node_info ***nodes, size_t *num) +{ + struct cras_iodev_info iodevs[CRAS_MAX_IODEVS]; + struct cras_ionode_info ionodes[CRAS_MAX_IONODES]; + size_t num_devs = CRAS_MAX_IODEVS, num_nodes = CRAS_MAX_IONODES; + int rc, i, j; + + *num = 0; + if (direction == CRAS_STREAM_INPUT) { + rc = cras_client_get_input_devices(client, iodevs, ionodes, + &num_devs, &num_nodes); + } else { + rc = cras_client_get_output_devices(client, iodevs, ionodes, + &num_devs, &num_nodes); + } + + if (rc < 0) { + syslog(LOG_ERR, "Failed to get devices: %d", rc); + return rc; + } + + *nodes = (struct libcras_node_info **)calloc( + num_nodes, sizeof(struct libcras_node_info *)); + + for (i = 0; i < num_devs; i++) { + for (j = 0; j < num_nodes; j++) { + if (iodevs[i].idx != ionodes[j].iodev_idx) + continue; + (*nodes)[*num] = libcras_node_info_create(&iodevs[i], + &ionodes[j]); + if ((*nodes)[*num] == NULL) { + rc = -errno; + goto clean; + } + (*num)++; + } + } + return 0; +clean: + for (i = 0; i < *num; i++) + libcras_node_info_destroy((*nodes)[i]); + free(*nodes); + *nodes = NULL; + *num = 0; + return rc; +} + +int get_default_output_buffer_size(struct cras_client *client, int *size) +{ + int rc = cras_client_get_default_output_buffer_size(client); + if (rc < 0) + return rc; + *size = rc; + return 0; +} + +int get_aec_group_id(struct cras_client *client, int *id) +{ + int rc = cras_client_get_aec_group_id(client); + if (rc < 0) + return rc; + *id = rc; + return 0; +} + +int get_aec_supported(struct cras_client *client, int *supported) +{ + *supported = cras_client_get_aec_supported(client); + return 0; +} + +int get_system_muted(struct cras_client *client, int *muted) +{ + *muted = cras_client_get_system_muted(client); + return 0; +} + +int get_loopback_dev_idx(struct cras_client *client, int *idx) +{ + int rc = cras_client_get_first_dev_type_idx( + client, CRAS_NODE_TYPE_POST_MIX_PRE_DSP, CRAS_STREAM_INPUT); + if (rc < 0) + return rc; + *idx = rc; + return 0; +} + +struct libcras_client *libcras_client_create() +{ + struct libcras_client *client = (struct libcras_client *)calloc( + 1, sizeof(struct libcras_client)); + if (!client) { + syslog(LOG_ERR, "cras_client: calloc failed"); + return NULL; + } + if (cras_client_create(&client->client_)) { + libcras_client_destroy(client); + return NULL; + } + client->api_version = CRAS_API_VERSION; + client->connect = cras_client_connect; + client->connect_timeout = cras_client_connect_timeout; + client->connected_wait = cras_client_connected_wait; + client->run_thread = cras_client_run_thread; + client->stop = cras_client_stop; + client->add_pinned_stream = cras_client_add_pinned_stream; + client->rm_stream = cras_client_rm_stream; + client->set_stream_volume = cras_client_set_stream_volume; + client->get_nodes = get_nodes; + client->get_default_output_buffer_size = get_default_output_buffer_size; + client->get_aec_group_id = get_aec_group_id; + client->get_aec_supported = get_aec_supported; + client->get_system_muted = get_system_muted; + client->set_system_mute = cras_client_set_system_mute; + client->get_loopback_dev_idx = get_loopback_dev_idx; + return client; +} + +void libcras_client_destroy(struct libcras_client *client) +{ + cras_client_destroy(client->client_); + free(client); +} + +int stream_params_set(struct cras_stream_params *params, + enum CRAS_STREAM_DIRECTION direction, + size_t buffer_frames, size_t cb_threshold, + enum CRAS_STREAM_TYPE stream_type, + enum CRAS_CLIENT_TYPE client_type, uint32_t flags, + void *user_data, libcras_stream_cb_t stream_cb, + cras_error_cb_t err_cb, size_t rate, + snd_pcm_format_t format, size_t num_channels) +{ + params->direction = direction; + params->buffer_frames = buffer_frames; + params->cb_threshold = cb_threshold; + params->stream_type = stream_type; + params->client_type = client_type; + params->flags = flags; + params->user_data = user_data; + params->stream_cb = stream_cb; + params->err_cb = err_cb; + params->format.frame_rate = rate; + params->format.format = format; + params->format.num_channels = num_channels; + return 0; +} + +int stream_params_set_channel_layout(struct cras_stream_params *params, + int length, const int8_t *layout) +{ + if (length != CRAS_CH_MAX) + return -EINVAL; + return cras_audio_format_set_channel_layout(¶ms->format, layout); +} + +struct libcras_stream_params *libcras_stream_params_create() +{ + struct libcras_stream_params *params = + (struct libcras_stream_params *)calloc( + 1, sizeof(struct libcras_stream_params)); + if (!params) { + syslog(LOG_ERR, "cras_client: calloc failed"); + return NULL; + } + params->params_ = (struct cras_stream_params *)calloc( + 1, sizeof(struct cras_stream_params)); + if (params->params_ == NULL) { + syslog(LOG_ERR, "cras_client: calloc failed"); + free(params->params_); + return NULL; + } + params->api_version = CRAS_API_VERSION; + params->set = stream_params_set; + params->set_channel_layout = stream_params_set_channel_layout; + params->enable_aec = cras_client_stream_params_enable_aec; + return params; +} + +void libcras_stream_params_destroy(struct libcras_stream_params *params) +{ + free(params->params_); + free(params); +} + +struct cras_node_info { + uint64_t id; + uint32_t dev_idx; + uint32_t node_idx; + uint32_t max_supported_channels; + bool plugged; + bool active; + char type[CRAS_NODE_TYPE_BUFFER_SIZE]; + char node_name[CRAS_NODE_NAME_BUFFER_SIZE]; + char dev_name[CRAS_IODEV_NAME_BUFFER_SIZE]; +}; + +int cras_node_info_get_id(struct cras_node_info *node, uint64_t *id) +{ + (*id) = node->id; + return 0; +} + +int cras_node_info_get_dev_idx(struct cras_node_info *node, uint32_t *dev_idx) +{ + (*dev_idx) = node->dev_idx; + return 0; +} + +int cras_node_info_get_node_idx(struct cras_node_info *node, uint32_t *node_idx) +{ + (*node_idx) = node->node_idx; + return 0; +} + +int cras_node_info_get_max_supported_channels(struct cras_node_info *node, + uint32_t *max_supported_channels) +{ + (*max_supported_channels) = node->max_supported_channels; + return 0; +} + +int cras_node_info_is_plugged(struct cras_node_info *node, bool *is_plugged) +{ + (*is_plugged) = node->plugged; + return 0; +} + +int cras_node_info_is_active(struct cras_node_info *node, bool *is_active) +{ + (*is_active) = node->active; + return 0; +} + +int cras_node_info_get_type(struct cras_node_info *node, char **type) +{ + (*type) = node->type; + return 0; +} + +int cras_node_info_get_node_name(struct cras_node_info *node, char **node_name) +{ + (*node_name) = node->node_name; + return 0; +} + +int cras_node_info_get_dev_name(struct cras_node_info *node, char **dev_name) +{ + (*dev_name) = node->dev_name; + return 0; +} + +struct libcras_node_info * +libcras_node_info_create(struct cras_iodev_info *iodev, + struct cras_ionode_info *ionode) +{ + struct libcras_node_info *node = (struct libcras_node_info *)calloc( + 1, sizeof(struct libcras_node_info)); + if (!node) { + syslog(LOG_ERR, "cras_client: calloc failed"); + return NULL; + } + node->node_ = (struct cras_node_info *)calloc( + 1, sizeof(struct cras_node_info)); + if (node->node_ == NULL) { + syslog(LOG_ERR, "cras_client: calloc failed"); + free(node); + return NULL; + } + node->api_version = CRAS_API_VERSION; + node->node_->id = + cras_make_node_id(ionode->iodev_idx, ionode->ionode_idx); + node->node_->dev_idx = ionode->iodev_idx; + node->node_->node_idx = ionode->ionode_idx; + node->node_->max_supported_channels = iodev->max_supported_channels; + node->node_->plugged = ionode->plugged; + node->node_->active = ionode->active; + strncpy(node->node_->type, ionode->type, CRAS_NODE_TYPE_BUFFER_SIZE); + node->node_->type[CRAS_NODE_TYPE_BUFFER_SIZE - 1] = '\0'; + strncpy(node->node_->node_name, ionode->name, + CRAS_NODE_NAME_BUFFER_SIZE); + node->node_->node_name[CRAS_NODE_NAME_BUFFER_SIZE - 1] = '\0'; + strncpy(node->node_->dev_name, iodev->name, + CRAS_IODEV_NAME_BUFFER_SIZE); + node->node_->dev_name[CRAS_IODEV_NAME_BUFFER_SIZE - 1] = '\0'; + node->get_id = cras_node_info_get_id; + node->get_dev_idx = cras_node_info_get_dev_idx; + node->get_node_idx = cras_node_info_get_node_idx; + node->get_max_supported_channels = + cras_node_info_get_max_supported_channels; + node->is_plugged = cras_node_info_is_plugged; + node->is_active = cras_node_info_is_active; + node->get_type = cras_node_info_get_type; + node->get_node_name = cras_node_info_get_node_name; + node->get_dev_name = cras_node_info_get_dev_name; + return node; +} + +void libcras_node_info_destroy(struct libcras_node_info *node) +{ + free(node->node_); + free(node); +} + +void libcras_node_info_array_destroy(struct libcras_node_info **nodes, + size_t num) +{ + int i; + for (i = 0; i < num; i++) + libcras_node_info_destroy(nodes[i]); + free(nodes); +} |