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