1c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir/* Copyright 2015 The Chromium OS Authors. All rights reserved. 21d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid * Use of this source code is governed by a BSD-style license that can be 31d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid * found in the LICENSE file. 41d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid */ 51d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 60ed19cea24e1694478eddc84e1bb8ccacff920a0Chinyue Chen#include <errno.h> 71d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid#include <stdint.h> 81d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid#include <sys/param.h> 91d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 101d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid#include "cras_client.h" 111d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid#include "cras_util.h" 121d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 131d21d2f9bb82889781b4be087ad65ba488608866Dylan Reidstruct buffer_data { 14a6de2464f12ba758ee978ebe6b104c59757464a8Nathan Bullock const uint8_t *buffer; 151d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unsigned int offset; 161d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unsigned int frame_bytes; 171d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unsigned int len; 181d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid}; 191d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 201d21d2f9bb82889781b4be087ad65ba488608866Dylan Reidstatic int play_buffer_callback(struct cras_client *client, 211d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid cras_stream_id_t stream_id, 221d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid uint8_t *captured_samples, 231d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid uint8_t *playback_samples, 241d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unsigned int frames, 251d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid const struct timespec *captured_time, 261d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid const struct timespec *playback_time, 271d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid void *user_arg) 281d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid{ 291d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid struct buffer_data *data = (struct buffer_data *)user_arg; 301d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid int to_copy = data->len - data->offset; 311d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 321d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid if (to_copy <= 0) { 331d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid free(user_arg); 341d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid return EOF; 351d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid } 361d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 371d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid to_copy = MIN(to_copy, frames * data->frame_bytes); 381d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 391d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid memcpy(playback_samples, data->buffer + data->offset, to_copy); 401d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 411d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid data->offset += to_copy; 421d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 431d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid return to_copy / data->frame_bytes; 441d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid} 451d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 461d21d2f9bb82889781b4be087ad65ba488608866Dylan Reidstatic int play_buffer_error(struct cras_client *client, 471d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid cras_stream_id_t stream_id, 481d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid int error, 491d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid void *user_arg) 501d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid{ 511d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid free(user_arg); 521d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid return 0; 531d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid} 541d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 55c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muirint cras_helper_create_connect_async(struct cras_client **client, 56c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir cras_connection_status_cb_t connection_cb, 57c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir void *user_arg) 58c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir{ 59c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir int rc; 60c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir 61c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir rc = cras_client_create(client); 62c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir if (rc < 0) 63c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir return rc; 64c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir 65c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir cras_client_set_connection_status_cb(*client, connection_cb, user_arg); 66c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir 67c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir rc = cras_client_run_thread(*client); 68c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir if (rc < 0) 69c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir goto client_start_error; 70c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir 71c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir rc = cras_client_connect_async(*client); 72c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir if (rc < 0) 73c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir goto client_start_error; 74c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir 75c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir return 0; 76c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir 77c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muirclient_start_error: 78c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir cras_client_destroy(*client); 79c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir return rc; 80c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir} 81c25746a605e85e60bfe3c7bc6b304d4967f3b53dJohn Muir 821d21d2f9bb82889781b4be087ad65ba488608866Dylan Reidint cras_helper_create_connect(struct cras_client **client) 831d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid{ 841d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid int rc; 851d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 861d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid rc = cras_client_create(client); 871d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid if (rc < 0) 881d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid return rc; 891d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 901d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid rc = cras_client_connect(*client); 911d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid if (rc < 0) 921d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid goto client_start_error; 931d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 941d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid rc = cras_client_run_thread(*client); 951d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid if (rc < 0) 961d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid goto client_start_error; 971d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 981d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid rc = cras_client_connected_wait(*client); 991d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid if (rc < 0) 1001d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid goto client_start_error; 1011d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1021d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid return 0; 1031d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1041d21d2f9bb82889781b4be087ad65ba488608866Dylan Reidclient_start_error: 1051d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid cras_client_destroy(*client); 1061d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid return rc; 1071d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid} 1081d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1091d21d2f9bb82889781b4be087ad65ba488608866Dylan Reidint cras_helper_add_stream_simple(struct cras_client *client, 1101d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid enum CRAS_STREAM_DIRECTION direction, 1111d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid void *user_data, 1121d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid cras_unified_cb_t unified_cb, 1131d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid cras_error_cb_t err_cb, 1141d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid snd_pcm_format_t format, 1151d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unsigned int frame_rate, 1161d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unsigned int num_channels, 1171d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid int dev_idx, 1181d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid cras_stream_id_t *stream_id_out) 1191d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid{ 1201d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid struct cras_audio_format *aud_format; 1211d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid struct cras_stream_params *params; 1221d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid int rc; 1231d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1241d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid aud_format = cras_audio_format_create(format, frame_rate, num_channels); 1251d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid if (!aud_format) 1261d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid return -ENOMEM; 1271d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1281d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid params = cras_client_unified_params_create(CRAS_STREAM_OUTPUT, 1291d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 2048, CRAS_STREAM_TYPE_DEFAULT, 0, user_data, 1301d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unified_cb, err_cb, aud_format); 1311d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid if (!params) { 1321d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid rc = -ENOMEM; 1331d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid goto done_add_stream; 1341d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid } 1351d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1361d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid if (dev_idx < 0) 1371d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid dev_idx = NO_DEVICE; 1381d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid rc = cras_client_add_pinned_stream(client, dev_idx, stream_id_out, 1391d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid params); 1401d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1411d21d2f9bb82889781b4be087ad65ba488608866Dylan Reiddone_add_stream: 1421d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid cras_audio_format_destroy(aud_format); 1431d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid cras_client_stream_params_destroy(params); 1441d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid return rc; 1451d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid} 1461d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1471d21d2f9bb82889781b4be087ad65ba488608866Dylan Reidint cras_helper_play_buffer(struct cras_client *client, 148a6de2464f12ba758ee978ebe6b104c59757464a8Nathan Bullock const void *buffer, 1491d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unsigned int frames, 1501d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid snd_pcm_format_t format, 1511d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unsigned int frame_rate, 1521d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid unsigned int num_channels, 1531d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid int dev_idx) 1541d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid{ 1551d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid struct buffer_data *data; 1561d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid cras_stream_id_t stream_id; 1571d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1581d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid data = malloc(sizeof(*data)); 1591d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1601d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid data->buffer = buffer; 161a4f4b29e4331b5368446cc9abe2db26e41b47aceChinyue Chen data->frame_bytes = num_channels * PCM_FORMAT_WIDTH(format) / 8; 1621d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid data->offset = 0; 1631d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid data->len = frames * data->frame_bytes; 1641d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid 1651d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid return cras_helper_add_stream_simple(client, CRAS_STREAM_OUTPUT, data, 1661d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid play_buffer_callback, play_buffer_error, format, 1671d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid frame_rate, num_channels, dev_idx, &stream_id); 1681d21d2f9bb82889781b4be087ad65ba488608866Dylan Reid} 169