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