1 /******************************************************************************
2 *
3 * Copyright 2022 Google LLC
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include <stdint.h>
20 #include "lc3bin.h"
21
22
23 /**
24 * LC3 binary header
25 */
26
27 #define LC3_FILE_ID (0x1C | (0xCC << 8))
28
29 struct lc3bin_header {
30 uint16_t file_id;
31 uint16_t header_size;
32 uint16_t srate_100hz;
33 uint16_t bitrate_100bps;
34 uint16_t channels;
35 uint16_t frame_10us;
36 uint16_t epmode;
37 uint16_t nsamples_low;
38 uint16_t nsamples_high;
39 };
40
41
42 /**
43 * Read LC3 binary header
44 */
lc3bin_read_header(FILE * fp,int * frame_us,int * srate_hz,bool * hrmode,int * nchannels,int * nsamples)45 int lc3bin_read_header(FILE *fp,
46 int *frame_us, int *srate_hz, bool *hrmode, int *nchannels, int *nsamples)
47 {
48 struct lc3bin_header hdr;
49 uint16_t hdr_hrmode = 0;
50
51 if (fread(&hdr, sizeof(hdr), 1, fp) != 1
52 || hdr.file_id != LC3_FILE_ID
53 || hdr.header_size < sizeof(hdr))
54 return -1;
55
56 int num_extended_params = (hdr.header_size - sizeof(hdr)) / sizeof(uint16_t);
57 if (num_extended_params >= 1 &&
58 fread(&hdr_hrmode, sizeof(hdr_hrmode), 1, fp) != 1)
59 return -1;
60
61 *nchannels = hdr.channels;
62 *frame_us = hdr.frame_10us * 10;
63 *srate_hz = hdr.srate_100hz * 100;
64 *nsamples = hdr.nsamples_low | (hdr.nsamples_high << 16);
65 *hrmode = hdr_hrmode != 0;
66
67 if (hdr.epmode)
68 return -1;
69
70 fseek(fp, hdr.header_size, SEEK_SET);
71
72 return 0;
73 }
74
75 /**
76 * Read LC3 block of data
77 */
lc3bin_read_data(FILE * fp,int nchannels,void * buffer)78 int lc3bin_read_data(FILE *fp, int nchannels, void *buffer)
79 {
80 uint16_t nbytes;
81
82 if (fread(&nbytes, sizeof(nbytes), 1, fp) < 1
83 || nbytes > nchannels * LC3_HR_MAX_FRAME_BYTES
84 || fread(buffer, nbytes, 1, fp) < 1)
85 return -1;
86
87 return nbytes;
88 }
89
90 /**
91 * Write LC3 binary header
92 */
lc3bin_write_header(FILE * fp,int frame_us,int srate_hz,bool hrmode,int bitrate,int nchannels,int nsamples)93 void lc3bin_write_header(FILE *fp,
94 int frame_us, int srate_hz, bool hrmode,
95 int bitrate, int nchannels, int nsamples)
96 {
97 uint16_t hdr_hrmode = (hrmode != 0);
98
99 struct lc3bin_header hdr = {
100 .file_id = LC3_FILE_ID,
101 .header_size = sizeof(struct lc3bin_header) +
102 (hrmode ? sizeof(hdr_hrmode) : 0),
103 .srate_100hz = srate_hz / 100,
104 .bitrate_100bps = bitrate / 100,
105 .channels = nchannels,
106 .frame_10us = frame_us / 10,
107 .nsamples_low = nsamples & 0xffff,
108 .nsamples_high = nsamples >> 16,
109 };
110
111 fwrite(&hdr, sizeof(hdr), 1, fp);
112
113 if (hrmode)
114 fwrite(&hdr_hrmode, sizeof(hdr_hrmode), 1, fp);
115 }
116
117 /**
118 * Write LC3 block of data
119 */
lc3bin_write_data(FILE * fp,const void * data,int nbytes)120 void lc3bin_write_data(FILE *fp, const void *data, int nbytes)
121 {
122 uint16_t hdr_nbytes = nbytes;
123 fwrite(&hdr_nbytes, sizeof(hdr_nbytes), 1, fp);
124
125 fwrite(data, 1, nbytes, fp);
126 }
127