• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 2013 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 <netinet/in.h>
7 #include <sbc/sbc.h>
8 #include <syslog.h>
9 
10 #include "cras_a2dp_info.h"
11 #include "cras_sbc_codec.h"
12 #include "cras_types.h"
13 #include "rtp.h"
14 
init_a2dp(struct a2dp_info * a2dp,a2dp_sbc_t * sbc)15 int init_a2dp(struct a2dp_info *a2dp, a2dp_sbc_t *sbc)
16 {
17 	uint8_t frequency = 0, mode = 0, subbands = 0, allocation, blocks = 0,
18 		bitpool;
19 
20 	if (sbc->frequency & SBC_SAMPLING_FREQ_48000)
21 		frequency = SBC_FREQ_48000;
22 	else if (sbc->frequency & SBC_SAMPLING_FREQ_44100)
23 		frequency = SBC_FREQ_44100;
24 	else if (sbc->frequency & SBC_SAMPLING_FREQ_32000)
25 		frequency = SBC_FREQ_32000;
26 	else if (sbc->frequency & SBC_SAMPLING_FREQ_16000)
27 		frequency = SBC_FREQ_16000;
28 
29 	if (sbc->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
30 		mode = SBC_MODE_JOINT_STEREO;
31 	else if (sbc->channel_mode & SBC_CHANNEL_MODE_STEREO)
32 		mode = SBC_MODE_STEREO;
33 	else if (sbc->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
34 		mode = SBC_MODE_DUAL_CHANNEL;
35 	else if (sbc->channel_mode & SBC_CHANNEL_MODE_MONO)
36 		mode = SBC_MODE_MONO;
37 
38 	if (sbc->allocation_method & SBC_ALLOCATION_LOUDNESS)
39 		allocation = SBC_AM_LOUDNESS;
40 	else
41 		allocation = SBC_AM_SNR;
42 
43 	switch (sbc->subbands) {
44 	case SBC_SUBBANDS_4:
45 		subbands = SBC_SB_4;
46 		break;
47 	case SBC_SUBBANDS_8:
48 		subbands = SBC_SB_8;
49 		break;
50 	}
51 
52 	switch (sbc->block_length) {
53 	case SBC_BLOCK_LENGTH_4:
54 		blocks = SBC_BLK_4;
55 		break;
56 	case SBC_BLOCK_LENGTH_8:
57 		blocks = SBC_BLK_8;
58 		break;
59 	case SBC_BLOCK_LENGTH_12:
60 		blocks = SBC_BLK_12;
61 		break;
62 	case SBC_BLOCK_LENGTH_16:
63 		blocks = SBC_BLK_16;
64 		break;
65 	}
66 
67 	bitpool = sbc->max_bitpool;
68 
69 	a2dp->codec = cras_sbc_codec_create(frequency, mode, subbands,
70 					    allocation, blocks, bitpool);
71 	if (!a2dp->codec)
72 		return -1;
73 
74 	/* SBC info */
75 	a2dp->codesize = cras_sbc_get_codesize(a2dp->codec);
76 	a2dp->frame_length = cras_sbc_get_frame_length(a2dp->codec);
77 
78 	a2dp->a2dp_buf_used = sizeof(struct rtp_header)
79 			+ sizeof(struct rtp_payload);
80 	a2dp->frame_count = 0;
81 	a2dp->seq_num = 0;
82 	a2dp->samples = 0;
83 
84 	return 0;
85 }
86 
destroy_a2dp(struct a2dp_info * a2dp)87 void destroy_a2dp(struct a2dp_info *a2dp)
88 {
89 	cras_sbc_codec_destroy(a2dp->codec);
90 }
91 
a2dp_codesize(struct a2dp_info * a2dp)92 int a2dp_codesize(struct a2dp_info *a2dp)
93 {
94 	return a2dp->codesize;
95 }
96 
a2dp_block_size(struct a2dp_info * a2dp,int a2dp_bytes)97 int a2dp_block_size(struct a2dp_info *a2dp, int a2dp_bytes)
98 {
99 	return a2dp_bytes / a2dp->frame_length * a2dp->codesize;
100 }
101 
a2dp_queued_frames(const struct a2dp_info * a2dp)102 int a2dp_queued_frames(const struct a2dp_info *a2dp)
103 {
104 	return a2dp->samples;
105 }
106 
a2dp_drain(struct a2dp_info * a2dp)107 void a2dp_drain(struct a2dp_info *a2dp)
108 {
109 	a2dp->a2dp_buf_used = sizeof(struct rtp_header)
110 			+ sizeof(struct rtp_payload);
111 	a2dp->samples = 0;
112 	a2dp->seq_num = 0;
113 	a2dp->frame_count = 0;
114 }
115 
avdtp_write(int stream_fd,struct a2dp_info * a2dp)116 static int avdtp_write(int stream_fd, struct a2dp_info *a2dp)
117 {
118 	int err, samples;
119 	struct rtp_header *header;
120 	struct rtp_payload *payload;
121 
122 	header = (struct rtp_header *)a2dp->a2dp_buf;
123 	payload = (struct rtp_payload *)(a2dp->a2dp_buf + sizeof(*header));
124 	memset(a2dp->a2dp_buf, 0, sizeof(*header) + sizeof(*payload));
125 
126 	payload->frame_count = a2dp->frame_count;
127 	header->v = 2;
128 	header->pt = 1;
129 	header->sequence_number = htons(a2dp->seq_num);
130 	header->timestamp = htonl(a2dp->nsamples);
131 	header->ssrc = htonl(1);
132 
133 	err = send(stream_fd, a2dp->a2dp_buf, a2dp->a2dp_buf_used,
134 		   MSG_DONTWAIT);
135 	if (err < 0)
136 		return -errno;
137 
138 	/* Returns the number of samples in frame. */
139 	samples = a2dp->samples;
140 
141 	/* Reset some data */
142 	a2dp->a2dp_buf_used = sizeof(*header) + sizeof(*payload);
143 	a2dp->frame_count = 0;
144 	a2dp->samples = 0;
145 	a2dp->seq_num++;
146 
147 	return samples;
148 }
149 
a2dp_encode(struct a2dp_info * a2dp,const void * pcm_buf,int pcm_buf_size,int format_bytes,size_t link_mtu)150 int a2dp_encode(struct a2dp_info *a2dp, const void *pcm_buf, int pcm_buf_size,
151 		int format_bytes, size_t link_mtu)
152 {
153 	int processed;
154 	size_t out_encoded;
155 
156 	if (link_mtu > A2DP_BUF_SIZE_BYTES)
157 		link_mtu = A2DP_BUF_SIZE_BYTES;
158 	if (link_mtu == a2dp->a2dp_buf_used)
159 		return 0;
160 
161 	processed = a2dp->codec->encode(a2dp->codec, pcm_buf, pcm_buf_size,
162 					a2dp->a2dp_buf + a2dp->a2dp_buf_used,
163 					link_mtu - a2dp->a2dp_buf_used,
164 					&out_encoded);
165 	if (processed < 0) {
166 		syslog(LOG_ERR, "a2dp encode error %d", processed);
167 		return processed;
168 	}
169 
170 	if (a2dp->codesize > 0)
171 		a2dp->frame_count += processed / a2dp->codesize;
172 	a2dp->a2dp_buf_used += out_encoded;
173 
174 	a2dp->samples += processed / format_bytes;
175 	a2dp->nsamples += processed / format_bytes;
176 
177 	return processed;
178 }
179 
a2dp_write(struct a2dp_info * a2dp,int stream_fd,size_t link_mtu)180 int a2dp_write(struct a2dp_info *a2dp, int stream_fd, size_t link_mtu)
181 {
182 	/* Do avdtp write when the max number of SBC frames is reached. */
183 	if (a2dp->a2dp_buf_used + a2dp->frame_length >
184 	    link_mtu - sizeof(struct rtp_header) - sizeof(struct rtp_payload))
185 		return avdtp_write(stream_fd, a2dp);
186 
187 	return 0;
188 }
189