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 rfu;
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,int * nchannels,int * nsamples)45 int lc3bin_read_header(FILE *fp,
46     int *frame_us, int *srate_hz, int *nchannels, int *nsamples)
47 {
48     struct lc3bin_header hdr;
49 
50     if (fread(&hdr, sizeof(hdr), 1, fp) != 1
51             || hdr.file_id != LC3_FILE_ID)
52         return -1;
53 
54     *nchannels = hdr.channels;
55     *frame_us = hdr.frame_10us * 10;
56     *srate_hz = hdr.srate_100hz * 100;
57     *nsamples = hdr.nsamples_low | (hdr.nsamples_high << 16);
58 
59     fseek(fp, SEEK_SET, hdr.header_size);
60 
61     return 0;
62 }
63 
64 /**
65  * Read LC3 block of data
66  */
lc3bin_read_data(FILE * fp,int nchannels,void * buffer)67 int lc3bin_read_data(FILE *fp, int nchannels, void *buffer)
68 {
69     uint16_t nbytes;
70 
71     if (fread(&nbytes, sizeof(nbytes), 1, fp) < 1
72             || nbytes > nchannels * LC3_MAX_FRAME_BYTES
73             || nbytes % nchannels
74             || fread(buffer, nbytes, 1, fp) < 1)
75         return -1;
76 
77     return nbytes / nchannels;
78 }
79 
80 /**
81  * Write LC3 binary header
82  */
lc3bin_write_header(FILE * fp,int frame_us,int srate_hz,int bitrate,int nchannels,int nsamples)83 void lc3bin_write_header(FILE *fp,
84     int frame_us, int srate_hz, int bitrate, int nchannels, int nsamples)
85 {
86     struct lc3bin_header hdr = {
87         .file_id = LC3_FILE_ID,
88         .header_size = sizeof(struct lc3bin_header),
89         .srate_100hz = srate_hz / 100,
90         .bitrate_100bps = bitrate / 100,
91         .channels = nchannels,
92         .frame_10us = frame_us / 10,
93         .nsamples_low = nsamples & 0xffff,
94         .nsamples_high = nsamples >> 16,
95     };
96 
97     fwrite(&hdr, sizeof(hdr), 1, fp);
98 }
99 
100 /**
101  * Write LC3 block of data
102  */
lc3bin_write_data(FILE * fp,const void * data,int nchannels,int frame_bytes)103 void lc3bin_write_data(FILE *fp,
104     const void *data, int nchannels, int frame_bytes)
105 {
106     uint16_t nbytes = nchannels * frame_bytes;
107     fwrite(&nbytes, sizeof(nbytes), 1, fp);
108 
109     fwrite(data, 1, nbytes, fp);
110 }
111