1 /*
2 * Copyright (C) 2002-2003 Fhg Fokus
3 *
4 * This file is part of SEMS, a free SIP media server.
5 *
6 * SEMS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version. This program is released under
10 * the GPL with the additional exemption that compiling, linking,
11 * and/or using OpenSSL is allowed.
12 *
13 * For a license to use the SEMS software under conditions
14 * other than those described here, or to purchase support for this
15 * software, please contact iptel.org by e-mail at the following addresses:
16 * info@iptel.org
17 *
18 * SEMS is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 */
27
28 #include "AmBufferedAudio.h"
29
AmBufferedAudio(size_t output_buffer_size,size_t low_buffer_thresh,size_t full_buffer_thresh)30 AmBufferedAudio::AmBufferedAudio(size_t output_buffer_size,
31 size_t low_buffer_thresh,
32 size_t full_buffer_thresh)
33 : output_buffer_size(output_buffer_size),
34 low_buffer_thresh(low_buffer_thresh), full_buffer_thresh(full_buffer_thresh),
35 r(0), w(0), eof(false), err_code(0)
36 {
37 allocateBuffer();
38 }
39
~AmBufferedAudio()40 AmBufferedAudio::~AmBufferedAudio() {
41 releaseBuffer();
42 }
43
allocateBuffer()44 void AmBufferedAudio::allocateBuffer() {
45 if (output_buffer_size != 0)
46 output_buffer = new unsigned char[output_buffer_size];
47 else
48 output_buffer = NULL;
49 }
50
releaseBuffer()51 void AmBufferedAudio::releaseBuffer() {
52 if (output_buffer)
53 delete[] output_buffer;
54 }
55
56 // WARNING: do not call this while device is in use! buffer is not locked!
setBufferSize(size_t _output_buffer_size,size_t _low_buffer_thresh,size_t _full_buffer_thresh)57 void AmBufferedAudio::setBufferSize(size_t _output_buffer_size,
58 size_t _low_buffer_thresh,
59 size_t _full_buffer_thresh) {
60
61 DBG("set output buffer size to %zd low thresh %zd, fill thresh %zd\n",
62 _output_buffer_size, _low_buffer_thresh, _full_buffer_thresh);
63
64 bool reset_buffer = output_buffer_size != _output_buffer_size;
65 output_buffer_size = _output_buffer_size;
66 low_buffer_thresh = _low_buffer_thresh;
67 full_buffer_thresh = _full_buffer_thresh;
68
69 if (reset_buffer) {
70 releaseBuffer();
71 allocateBuffer();
72 }
73 }
74
clearBufferEOF()75 void AmBufferedAudio::clearBufferEOF() {
76 eof = false;
77 err_code = 0;
78 }
79
get(unsigned long long system_ts,unsigned char * buffer,int output_sample_rate,unsigned int nb_samples)80 int AmBufferedAudio::get(unsigned long long system_ts, unsigned char* buffer,
81 int output_sample_rate, unsigned int nb_samples)
82 {
83 if (!output_buffer_size)
84 return AmAudio::get(system_ts, buffer, output_sample_rate, nb_samples);
85
86 if (w-r < low_buffer_thresh && !eof) {
87 input_get_audio(system_ts);
88 }
89
90 size_t nget = PCM16_S2B(nb_samples * getSampleRate() / output_sample_rate);
91 if (w-r < nget)
92 nget = w-r;
93
94 if (!nget) {
95 // empty buffer and input error
96 if (eof)
97 return err_code;
98
99 // empty buffer but no input error
100 return 0;
101 }
102
103 memcpy((unsigned char*)samples,&output_buffer[r],nget);
104 r+=nget;
105
106 int size = resampleOutput(samples,nget,getSampleRate(),output_sample_rate);
107 memcpy(buffer, (unsigned char*)samples,size);
108
109 return size;
110 }
111
input_get_audio(unsigned int user_ts)112 void AmBufferedAudio::input_get_audio(unsigned int user_ts) {
113 if (r && (r != w)) {
114 // move contents to beginning of buffer
115 memmove(output_buffer, &output_buffer[r], w-r);
116 w -= r;
117 r = 0;
118 }
119 while (w < full_buffer_thresh) {
120 int size = calcBytesToRead(PCM16_B2S(output_buffer_size - w));
121
122 // DBG("calc %d bytes to read\n", size);
123
124 // resync might be delayed until buffer empty // (but output resync never happens)
125 size = read(user_ts + PCM16_B2S(w-r),size);
126 // DBG("read returned size = %d\n",size);
127 if(size <= 0){
128 err_code = size;
129 eof = true;
130 return;
131 }
132
133 size = decode(size);
134 if(size < 0) {
135 // DBG("decode returned %i\n",size);
136 err_code = size;
137 eof = true;
138 return;
139 }
140
141 // DBG("decode returned %i\n",size);
142 size = downMix(size);
143
144 if(size>0) {
145 memcpy(&output_buffer[w],(unsigned char*)samples,size);
146 w+=size;
147 }
148 }
149 }
150