1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *  * Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  *  * Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in
12  *    the documentation and/or other materials provided with the
13  *    distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <malloc.h>
30 #include <stdio.h>
31 #include <stdint.h>
32 #include <string.h>
33 #include <assert.h>
34 
35 #include "gsmamr_dec.h"
36 #include <audio_utils/sndfile.h>
37 
38 // Constants for AMR-NB
39 enum {
40     kInputBufferSize = 64,
41     kSamplesPerFrame = 160,
42     kBitsPerSample = 16,
43     kOutputBufferSize = kSamplesPerFrame * kBitsPerSample/8,
44     kSampleRate = 8000,
45     kChannels = 1,
46     kFileHeaderSize = 6
47 };
48 const uint32_t kFrameSizes[] = {12, 13, 15, 17, 19, 20, 26, 31};
49 
50 
main(int argc,char * argv[])51 int main(int argc, char *argv[]) {
52 
53     if(argc != 3) {
54         fprintf(stderr, "Usage %s <input file> <output file>\n", argv[0]);
55         return 1;
56     }
57 
58     // Open the input file
59     FILE* fpInput = fopen(argv[1], "rb");
60     if (!fpInput) {
61         fprintf(stderr, "Could not open %s\n", argv[1]);
62         return 1;
63     }
64 
65     // Validate the input AMR file
66     char header[kFileHeaderSize];
67     int bytesRead = fread(header, 1, kFileHeaderSize, fpInput);
68     if (bytesRead != kFileHeaderSize || memcmp(header, "#!AMR\n", kFileHeaderSize)) {
69         fprintf(stderr, "Invalid AMR-NB file\n");
70         fclose(fpInput);
71         return 1;
72     }
73 
74     // Open the output file
75     SF_INFO sfInfo;
76     memset(&sfInfo, 0, sizeof(SF_INFO));
77     sfInfo.channels = kChannels;
78     sfInfo.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
79     sfInfo.samplerate = kSampleRate;
80     SNDFILE *handle = sf_open(argv[2], SFM_WRITE, &sfInfo);
81     if(!handle){
82         fprintf(stderr, "Could not create %s\n", argv[2]);
83         fclose(fpInput);
84         return 1;
85     }
86 
87     // Create AMR-NB decoder instance
88     void* amrHandle;
89     int err = GSMInitDecode(&amrHandle, (Word8*)"AMRNBDecoder");
90     if(err != 0){
91         fprintf(stderr, "Error creating AMR-NB decoder instance\n");
92         fclose(fpInput);
93         sf_close(handle);
94         return 1;
95     }
96 
97     //Allocate input buffer
98     void *inputBuf = malloc(kInputBufferSize);
99     assert(inputBuf != NULL);
100 
101     //Allocate output buffer
102     void *outputBuf = malloc(kOutputBufferSize);
103     assert(outputBuf != NULL);
104 
105 
106     // Decode loop
107     uint32_t retVal = 0;
108     while (1) {
109         // Read mode
110         uint8_t mode;
111         bytesRead = fread(&mode, 1, 1, fpInput);
112         if (bytesRead != 1) break;
113 
114         // Find frame type
115         Frame_Type_3GPP frameType = (Frame_Type_3GPP)((mode >> 3) & 0x0f);
116         if (frameType >= AMR_SID){
117             fprintf(stderr, "Frame type %d not supported\n",frameType);
118             retVal = 1;
119             break;
120         }
121 
122         // Find frame type
123         int32_t frameSize = kFrameSizes[frameType];
124         bytesRead = fread(inputBuf, 1, frameSize, fpInput);
125         if (bytesRead != frameSize) break;
126 
127         //Decode frame
128         int32_t decodeStatus;
129         decodeStatus = AMRDecode(amrHandle, frameType, (uint8_t*)inputBuf,
130                                  (int16_t*)outputBuf, MIME_IETF);
131         if(decodeStatus == -1) {
132             fprintf(stderr, "Decoder encountered error\n");
133             retVal = 1;
134             break;
135         }
136 
137         //Write output to wav
138         sf_writef_short(handle, (int16_t*)outputBuf, kSamplesPerFrame);
139 
140     }
141 
142     // Close input and output file
143     fclose(fpInput);
144     sf_close(handle);
145 
146     //Free allocated memory
147     free(inputBuf);
148     free(outputBuf);
149 
150     // Close decoder instance
151     GSMDecodeFrameExit(&amrHandle);
152 
153     return retVal;
154 }
155