/* Copyright 2015 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 <errno.h> #include <stdint.h> #include <sys/param.h> #include "cras_client.h" #include "cras_util.h" struct buffer_data { const uint8_t *buffer; unsigned int offset; unsigned int frame_bytes; unsigned int len; }; static int play_buffer_callback(struct cras_client *client, cras_stream_id_t stream_id, uint8_t *captured_samples, uint8_t *playback_samples, unsigned int frames, const struct timespec *captured_time, const struct timespec *playback_time, void *user_arg) { struct buffer_data *data = (struct buffer_data *)user_arg; int to_copy = data->len - data->offset; if (to_copy <= 0) { free(user_arg); return EOF; } to_copy = MIN(to_copy, frames * data->frame_bytes); memcpy(playback_samples, data->buffer + data->offset, to_copy); data->offset += to_copy; return to_copy / data->frame_bytes; } static int play_buffer_error(struct cras_client *client, cras_stream_id_t stream_id, int error, void *user_arg) { free(user_arg); return 0; } int cras_helper_create_connect_async(struct cras_client **client, cras_connection_status_cb_t connection_cb, void *user_arg) { int rc; rc = cras_client_create(client); if (rc < 0) return rc; cras_client_set_connection_status_cb(*client, connection_cb, user_arg); rc = cras_client_run_thread(*client); if (rc < 0) goto client_start_error; rc = cras_client_connect_async(*client); if (rc < 0) goto client_start_error; return 0; client_start_error: cras_client_destroy(*client); return rc; } int cras_helper_create_connect(struct cras_client **client) { int rc; rc = cras_client_create(client); if (rc < 0) return rc; rc = cras_client_connect(*client); if (rc < 0) goto client_start_error; rc = cras_client_run_thread(*client); if (rc < 0) goto client_start_error; rc = cras_client_connected_wait(*client); if (rc < 0) goto client_start_error; return 0; client_start_error: cras_client_destroy(*client); return rc; } int cras_helper_add_stream_simple(struct cras_client *client, enum CRAS_STREAM_DIRECTION direction, void *user_data, cras_unified_cb_t unified_cb, cras_error_cb_t err_cb, snd_pcm_format_t format, unsigned int frame_rate, unsigned int num_channels, int dev_idx, cras_stream_id_t *stream_id_out) { struct cras_audio_format *aud_format; struct cras_stream_params *params; int rc; aud_format = cras_audio_format_create(format, frame_rate, num_channels); if (!aud_format) return -ENOMEM; params = cras_client_unified_params_create(CRAS_STREAM_OUTPUT, 2048, CRAS_STREAM_TYPE_DEFAULT, 0, user_data, unified_cb, err_cb, aud_format); if (!params) { rc = -ENOMEM; goto done_add_stream; } if (dev_idx < 0) dev_idx = NO_DEVICE; rc = cras_client_add_pinned_stream(client, dev_idx, stream_id_out, params); done_add_stream: cras_audio_format_destroy(aud_format); cras_client_stream_params_destroy(params); return rc; } int cras_helper_play_buffer(struct cras_client *client, const void *buffer, unsigned int frames, snd_pcm_format_t format, unsigned int frame_rate, unsigned int num_channels, int dev_idx) { struct buffer_data *data; cras_stream_id_t stream_id; data = malloc(sizeof(*data)); data->buffer = buffer; data->frame_bytes = num_channels * PCM_FORMAT_WIDTH(format) / 8; data->offset = 0; data->len = frames * data->frame_bytes; return cras_helper_add_stream_simple(client, CRAS_STREAM_OUTPUT, data, play_buffer_callback, play_buffer_error, format, frame_rate, num_channels, dev_idx, &stream_id); }