1/**********
2This library is free software; you can redistribute it and/or modify it under
3the terms of the GNU Lesser General Public License as published by the
4Free Software Foundation; either version 3 of the License, or (at your
5option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.)
6
7This library is distributed in the hope that it will be useful, but WITHOUT
8ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
10more details.
11
12You should have received a copy of the GNU Lesser General Public License
13along with this library; if not, write to the Free Software Foundation, Inc.,
1451 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15**********/
16// "liveMedia"
17// Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved.
18// AMR Audio File sinks
19// Implementation
20
21#include "AMRAudioFileSink.hh"
22#include "AMRAudioSource.hh"
23#include "OutputFile.hh"
24
25////////// AMRAudioFileSink //////////
26
27AMRAudioFileSink
28::AMRAudioFileSink(UsageEnvironment& env, FILE* fid, unsigned bufferSize,
29 char const* perFrameFileNamePrefix)
30 : FileSink(env, fid, bufferSize, perFrameFileNamePrefix),
31 fHaveWrittenHeader(False) {
32}
33
34AMRAudioFileSink::~AMRAudioFileSink() {
35}
36
37AMRAudioFileSink*
38AMRAudioFileSink::createNew(UsageEnvironment& env, char const* fileName,
39 unsigned bufferSize, Boolean oneFilePerFrame) {
40 do {
41 FILE* fid;
42 char const* perFrameFileNamePrefix;
43 if (oneFilePerFrame) {
44 // Create the fid for each frame
45 fid = NULL;
46 perFrameFileNamePrefix = fileName;
47 } else {
48 // Normal case: create the fid once
49 fid = OpenOutputFile(env, fileName);
50 if (fid == NULL) break;
51 perFrameFileNamePrefix = NULL;
52 }
53
54 return new AMRAudioFileSink(env, fid, bufferSize, perFrameFileNamePrefix);
55 } while (0);
56
57 return NULL;
58}
59
60Boolean AMRAudioFileSink::sourceIsCompatibleWithUs(MediaSource& source) {
61 // The input source must be a AMR Audio source:
62 return source.isAMRAudioSource();
63}
64
65void AMRAudioFileSink::afterGettingFrame(unsigned frameSize,
66 unsigned numTruncatedBytes,
67 struct timeval presentationTime) {
68 AMRAudioSource* source = (AMRAudioSource*)fSource;
69 if (source == NULL) return; // sanity check
70
71 if (!fHaveWrittenHeader && fPerFrameFileNameBuffer == NULL) {
72 // Output the appropriate AMR header to the start of the file.
73 // This header is defined in RFC 4867, section 5.
74 // (However, we don't do this if we're creating one file per frame.)
75 char headerBuffer[100];
76 sprintf(headerBuffer, "#!AMR%s%s\n",
77 source->isWideband() ? "-WB" : "",
78 source->numChannels() > 1 ? "_MC1.0" : "");
79 unsigned headerLength = strlen(headerBuffer);
80 if (source->numChannels() > 1) {
81 // Also add a 32-bit channel description field:
82 headerBuffer[headerLength++] = 0;
83 headerBuffer[headerLength++] = 0;
84 headerBuffer[headerLength++] = 0;
85 headerBuffer[headerLength++] = source->numChannels();
86 }
87
88 addData((unsigned char*)headerBuffer, headerLength, presentationTime);
89 }
90 fHaveWrittenHeader = True;
91
92 // Add the 1-byte header, before writing the file data proper:
93 // (Again, we don't do this if we're creating one file per frame.)
94 if (fPerFrameFileNameBuffer == NULL) {
95 u_int8_t frameHeader = source->lastFrameHeader();
96 addData(&frameHeader, 1, presentationTime);
97 }
98
99 // Call the parent class to complete the normal file write with the input data:
100 FileSink::afterGettingFrame(frameSize, numTruncatedBytes, presentationTime);
101}
102