Coverage Report

Created: 2025-10-29 06:49

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