1 /* Copyright 2015 The Chromium OS Authors. All rights reserved.
2  * Use of this source code is governed by a BSD-style license that can be
3  * found in the LICENSE file.
4  */
5 
6 #include <errno.h>
7 #include <stdint.h>
8 #include <sys/param.h>
9 
10 #include "cras_client.h"
11 #include "cras_util.h"
12 
13 struct buffer_data {
14 	const uint8_t *buffer;
15 	unsigned int offset;
16 	unsigned int frame_bytes;
17 	unsigned int len;
18 };
19 
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)20 static int play_buffer_callback(struct cras_client *client,
21 				cras_stream_id_t stream_id,
22 				uint8_t *captured_samples,
23 				uint8_t *playback_samples,
24 				unsigned int frames,
25 				const struct timespec *captured_time,
26 				const struct timespec *playback_time,
27 				void *user_arg)
28 {
29 	struct buffer_data *data = (struct buffer_data *)user_arg;
30 	int to_copy = data->len - data->offset;
31 
32 	if (to_copy <= 0) {
33 		free(user_arg);
34 		return EOF;
35 	}
36 
37 	to_copy = MIN(to_copy, frames * data->frame_bytes);
38 
39 	memcpy(playback_samples, data->buffer + data->offset, to_copy);
40 
41 	data->offset += to_copy;
42 
43 	return to_copy / data->frame_bytes;
44 }
45 
play_buffer_error(struct cras_client * client,cras_stream_id_t stream_id,int error,void * user_arg)46 static int play_buffer_error(struct cras_client *client,
47 			     cras_stream_id_t stream_id,
48 			     int error,
49 			     void *user_arg)
50 {
51 	free(user_arg);
52 	return 0;
53 }
54 
cras_helper_create_connect_async(struct cras_client ** client,cras_connection_status_cb_t connection_cb,void * user_arg)55 int cras_helper_create_connect_async(struct cras_client **client,
56 				     cras_connection_status_cb_t connection_cb,
57 				     void *user_arg)
58 {
59 	int rc;
60 
61 	rc = cras_client_create(client);
62 	if (rc < 0)
63 		return rc;
64 
65 	cras_client_set_connection_status_cb(*client, connection_cb, user_arg);
66 
67 	rc = cras_client_run_thread(*client);
68 	if (rc < 0)
69 		goto client_start_error;
70 
71 	rc = cras_client_connect_async(*client);
72 	if (rc < 0)
73 		goto client_start_error;
74 
75 	return 0;
76 
77 client_start_error:
78 	cras_client_destroy(*client);
79 	return rc;
80 }
81 
cras_helper_create_connect(struct cras_client ** client)82 int cras_helper_create_connect(struct cras_client **client)
83 {
84 	int rc;
85 
86 	rc = cras_client_create(client);
87 	if (rc < 0)
88 		return rc;
89 
90 	rc = cras_client_connect(*client);
91 	if (rc < 0)
92 		goto client_start_error;
93 
94 	rc = cras_client_run_thread(*client);
95 	if (rc < 0)
96 		goto client_start_error;
97 
98 	rc = cras_client_connected_wait(*client);
99 	if (rc < 0)
100 		goto client_start_error;
101 
102 	return 0;
103 
104 client_start_error:
105 	cras_client_destroy(*client);
106 	return rc;
107 }
108 
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)109 int cras_helper_add_stream_simple(struct cras_client *client,
110 				  enum CRAS_STREAM_DIRECTION direction,
111 				  void *user_data,
112 				  cras_unified_cb_t unified_cb,
113 				  cras_error_cb_t err_cb,
114 				  snd_pcm_format_t format,
115 				  unsigned int frame_rate,
116 				  unsigned int num_channels,
117 				  int dev_idx,
118 				  cras_stream_id_t *stream_id_out)
119 {
120 	struct cras_audio_format *aud_format;
121 	struct cras_stream_params *params;
122 	int rc;
123 
124 	aud_format = cras_audio_format_create(format, frame_rate, num_channels);
125 	if (!aud_format)
126 		return -ENOMEM;
127 
128 	params = cras_client_unified_params_create(CRAS_STREAM_OUTPUT,
129 			2048, CRAS_STREAM_TYPE_DEFAULT, 0, user_data,
130 			unified_cb, err_cb, aud_format);
131 	if (!params) {
132 		rc = -ENOMEM;
133 		goto done_add_stream;
134 	}
135 
136 	if (dev_idx < 0)
137 		dev_idx = NO_DEVICE;
138 	rc = cras_client_add_pinned_stream(client, dev_idx, stream_id_out,
139 					   params);
140 
141 done_add_stream:
142 	cras_audio_format_destroy(aud_format);
143 	cras_client_stream_params_destroy(params);
144 	return rc;
145 }
146 
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)147 int cras_helper_play_buffer(struct cras_client *client,
148 			    const void *buffer,
149 			    unsigned int frames,
150 			    snd_pcm_format_t format,
151 			    unsigned int frame_rate,
152 			    unsigned int num_channels,
153 			    int dev_idx)
154 {
155 	struct buffer_data *data;
156 	cras_stream_id_t stream_id;
157 
158 	data = malloc(sizeof(*data));
159 
160 	data->buffer = buffer;
161 	data->frame_bytes = num_channels * PCM_FORMAT_WIDTH(format) / 8;
162 	data->offset = 0;
163 	data->len = frames * data->frame_bytes;
164 
165 	return cras_helper_add_stream_simple(client, CRAS_STREAM_OUTPUT, data,
166 			play_buffer_callback, play_buffer_error, format,
167 			frame_rate, num_channels, dev_idx, &stream_id);
168 }
169