1 /*
2 * real_audio_enc.cc --
3 *
4 * FIXME: This file needs a description here.
5 *
6 * Copyright (c) 1991-2002 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * A. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 * B. Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution.
17 * C. Neither the names of the copyright holders nor the names of its
18 * contributors may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
22 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * This is the Virtual Device abstraction to grab raw PCM from an audio stream.
36 *
37 */
38
39
40 //#include <osfcn.h>
41 #include <fcntl.h>
42 #include "audio.h"
43 #include "mulaw.h"
44 #include "tclcl.h"
45 #include "real_encoder.h"
46
47 #define ULAW_ZERO 0x7f
48
49 // and encoder that takes that PCM audio and gives it to a Real Networks
50 // encoding engine.
51
52 class RealAudioEnc : public Audio {
53 public:
54 RealAudioEnc();
55 ~RealAudioEnc();
56 virtual int FrameReady();
57 virtual u_char* Read();
58 virtual void Write(u_char *);
59 virtual void SetRGain(int);
60 virtual void SetPGain(int);
61 virtual void OutputPort(int);
62 virtual void InputPort(int);
63 virtual void Obtain();
64 virtual void Release();
65 int command(int argc, const char*const* argv);
66 protected:
67 void WriteHelper(u_char *);
68 int droppedPackets;
69 int interval;
70 int intervalPos;
71
72 RealWindow* encoder;
73 int bufferSize;
74 u_char* dummyReadBuf;
75 u_short* WriteBuf0;
76 u_short* WriteBuf1;
77 ULONG32 TimeCode;
78 int currentBuf;
79 int bufferPosition;
80 int timerFlag;
81 int secondReadFlag;
82 };
83
84 static class RealAudioEncClass : public TclClass {
85 public:
86 RealAudioEncClass() : TclClass("Audio/RealAudioVirtualDevice") {}
87 TclObject* create(int, const char*const*) {
88 return (new RealAudioEnc);
89 }
90 } real_audio_enc_class;
91
92 int RealAudioEnc::command(int argc, const char*const* argv) {
93 int howOften = 1000; // in milliseconds
94 int temp;
95
96 if (argc == 2) {
97 Tcl& tcl = Tcl::instance();
98 if (strcmp(argv[1], "start_output") == 0) {
99 tcl.evalf("after %d %s start_output", howOften, name());
100 temp = ((50*howOften)/1000); // this is the number of blocks per interval.
101
102 if (droppedPackets <= 0)
103 interval = temp*2; // big so that it doesn't inject a blank when not needed.
104 else if (droppedPackets > 16) {
105 while (droppedPackets > 5) {
106 Write(dummyReadBuf);
107 secondReadFlag = 0;
108 // printf("blank audio here\n");
109 }
110 interval = temp/droppedPackets;
111 } else
112 interval = temp/droppedPackets;
113
114 intervalPos = 0;
115 droppedPackets = droppedPackets + temp;
116 return (TCL_OK);
117 } else if (strcmp(argv[1], "grab_audio") == 0) {
118 tcl.evalf("after %d %s grab_audio", 10, name());
119 timerFlag = 1;
120 return (TCL_OK);
121 } else if (strcmp(argv[1], "stop_output") == 0) {
122 encoder = 0;
123 return (TCL_OK);
124 }
125 }
126 if (argc == 3) {
127 if (strcmp(argv[1], "linkEncoder") == 0) {
128 encoder = (RealWindow*)TclObject::lookup(argv[2]);
129 return (TCL_OK);
130 }
131 }
132 return Audio::command(argc,argv);
133 }
134
135 RealAudioEnc::RealAudioEnc() : droppedPackets(0), interval(100), intervalPos(0), encoder(0), bufferSize(0), TimeCode(0), currentBuf(0), bufferPosition(0), timerFlag(0), secondReadFlag(0) {
136 /*
137 * The only way to determine if the device is full duplex
138 * or not is by actually opening it. Unfortunately, we might
139 * not be able to open it because some other process is
140 * using it. Assume half-duplex. Obtain() will override
141 * if appropriate.
142 */
143 duplex_ = 0;
144
145 dummyReadBuf = new u_char[blksize_];
146
147 memset(dummyReadBuf, ULAW_ZERO, blksize_);
148
149 input_names_ = "mike";
150 output_names_ = "speaker";
151 }
152
153 RealAudioEnc::~RealAudioEnc() {
154 Tcl& tcl = Tcl::instance();
155 tcl.evalf("after cancel %s start_output", name());
156 delete dummyReadBuf;
157 }
158
159 void RealAudioEnc::Obtain() {
160 // printf("Obtain is called\n");
161
162 Tcl& tcl = Tcl::instance();
163 tcl.evalf("after %d %s start_output", 100, name());
164
165 if (haveaudio())
166 abort();
167
168 if (duplex_ == 0) {
169 fd_ = 9;
170 notify();
171 } else {
172 // this is a hack, this should never happen.
173 fd_ = open("/dev/audio", O_RDWR );
174 Audio::Obtain();
175 tcl.evalf("after %d %s grab_audio", 1000, name());
176 }
177 }
178
179
180 void RealAudioEnc::Release() {
181 // printf("called release\n");
182 if (haveaudio()) {
183 notify();
184 }
185 }
186
187 // write data to the encoder (encode data and send to server)
188 void RealAudioEnc::Write(u_char *cp) {
189 //printf("got a packet to the virtual device, num is: %d!\n", (int)cp[0]);
190 u_char cp2[blksize_];
191 u_int i, j;
192
193 if (secondReadFlag)
194 return;
195 else
196 secondReadFlag = 1;
197
198 if (encoder == 0)
199 return;
200
201 if (bufferSize == 0) {
202 // this only happens at the start, to initialize the encoder.
203 bufferSize = encoder->SuggestAudioBufferSize();
204 bufferSize = (bufferSize - (bufferSize % (blksize_*2)))/2;
205 if (bufferSize == 0) {
206 encoder->setup_encoder();
207 return;
208 }
209 WriteBuf0 = new u_short[bufferSize];
210 WriteBuf1 = new u_short[bufferSize];
211 }
212
213 if (intervalPos >= interval) {
214 // we need to elongate samples to fill in for lost data...
215 // shouldn't happen often.
216 // printf("making up, interval is: %d, position is: %d\n", interval, intervalPos);
217 intervalPos = 0;
218 j = blksize_/2;
219 for (i=0; i< j; i++) {
220 cp2[(2*i)] = cp[i];
221 cp2[(2*i)+1] = cp[i];
222 }
223 for (i=0; j< blksize_; j++,i+=2) {
224 cp[i] = cp[j];
225 cp[i+1] = cp[j];
226 }
227 WriteHelper(cp2);
228 }
229 WriteHelper(cp);
230 intervalPos++;
231 }
232
233 // this is the function that actually writes the data to the Real engine.
234 void RealAudioEnc::WriteHelper(u_char* cp){
235 u_short* writeBuf;
236
237 droppedPackets--;
238
239 if (currentBuf == 0)
240 writeBuf = WriteBuf0;
241 else
242 writeBuf = WriteBuf1;
243
244 if (bufferPosition == 0)
245 TimeCode = GetTime();
246
247 for (u_int i=0; i< blksize_; i++)
248 writeBuf[i+bufferPosition] = mulawtolin[cp[i]] ;
249
250 bufferPosition += blksize_;
251
252 if (bufferPosition == bufferSize) {
253 currentBuf = (currentBuf+1)%2;
254 bufferPosition = 0;
255 encoder->encodeAudio(writeBuf, (2*bufferSize), TimeCode);
256 }
257 }
258
259 u_char* RealAudioEnc::Read() {
260 // printf("Read was called\n");
261 secondReadFlag = 0;
262 return dummyReadBuf;
263 }
264
265 void RealAudioEnc::SetRGain(int level)
266 {
267 // printf("setRgain() called\n");
268 }
269
270 void RealAudioEnc::SetPGain(int level)
271 {
272 // printf("SetPgain() called\n");
273 }
274
275 void RealAudioEnc::OutputPort(int p)
276 {
277
278 printf("outputPort() called\n");
279 oport_ = p;
280 }
281
282 void RealAudioEnc::InputPort(int p)
283 {
284 printf("inputPort() called for %d\n",p);
285 }
286
287 /*
288 * FrameReady must return 0 every so often, or the system will keep
289 * processing mike data and not other events.
290 *
291 * This should never get called because we are not going in duplex mode.
292 */
293 int RealAudioEnc::FrameReady() {
294 printf("in FrameReady\n");
295 if (timerFlag == 1) {
296 timerFlag = 0;
297 return 1;
298 }
299 return 0;
300 }
301
302 /*** end of file ***/
303
304
305
306
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.