Home | History | Annotate | Download | only in libcras
      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 
     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 
     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 
     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 
     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 
    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 
    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