1 /*
2 * Copyright (C) 2007 iptego GmbH
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.
10 *
11 * For a license to use the sems software under conditions
12 * other than those described here, or to purchase support for this
13 * software, please contact iptel.org by e-mail at the following addresses:
14 * info@iptel.org
15 *
16 * SEMS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 */
25
26 #include "AmAudioMixIn.h"
27 #include "SampleArray.h"
28
29 #define IS_FINISH_B_MIX (flags & AUDIO_MIXIN_FINISH_B_MIX)
30 #define IS_ONLY_ONCE (flags & AUDIO_MIXIN_ONCE)
31 #define IS_IMMEDIATE_START (flags & AUDIO_MIXIN_IMMEDIATE_START)
32
AmAudioMixIn(AmAudio * A,AmAudio * B,unsigned int s,double l,unsigned int flags)33 AmAudioMixIn::AmAudioMixIn(AmAudio* A, AmAudio* B,
34 unsigned int s, double l,
35 unsigned int flags)
36 : A(A),B(B), s(s), l(l),
37 flags(flags), mixing(false),
38 next_start_ts_i(false)
39 {
40 }
41
~AmAudioMixIn()42 AmAudioMixIn::~AmAudioMixIn() { }
43
get(unsigned long long system_ts,unsigned char * buffer,int output_sample_rate,unsigned int nb_samples)44 int AmAudioMixIn::get(unsigned long long system_ts, unsigned char* buffer,
45 int output_sample_rate, unsigned int nb_samples) {
46 if (!mixing) {
47 if (!next_start_ts_i) {
48 next_start_ts_i = true;
49 next_start_ts = IS_IMMEDIATE_START ?
50 system_ts : system_ts + s*WALLCLOCK_RATE;
51 }
52 if (!sys_ts_less()(system_ts, next_start_ts)) {
53 DBG("starting mix-in\n");
54 mixing = true;
55 next_start_ts = system_ts + s*WALLCLOCK_RATE;
56 }
57 }
58
59 if (NULL == A)
60 return -1;
61
62 B_mut.lock();
63
64 if (!mixing || NULL == B) {
65 B_mut.unlock();
66 return A->get(system_ts, buffer, output_sample_rate, nb_samples);
67 } else {
68 if (l < 0.01) { // epsilon
69 // only play back from B
70 int res = B->get(system_ts, buffer, output_sample_rate, nb_samples);
71 if (res <= 0) { // B empty
72 res = A->get(system_ts, buffer, output_sample_rate, nb_samples);
73 mixing = false;
74 if (IS_ONLY_ONCE) {
75 B = NULL;
76 } else {
77 AmAudioFile* B_file = dynamic_cast<AmAudioFile*>(B);
78 if (NULL != B_file) {
79 B_file->rewind();
80 }
81 }
82 }
83 B_mut.unlock();
84 return res;
85 } else { // mix the two
86 int res = 0;
87 short* pdest = (short*)buffer;
88 // get audio from A
89 int len = A->get(system_ts, (unsigned char*)mix_buf,
90 output_sample_rate, nb_samples);
91
92 if ((len<0) && !IS_FINISH_B_MIX) { // A finished
93 B_mut.unlock();
94 return len;
95 }
96 for (int i=0; i<(PCM16_B2S(len)); i++) {
97 pdest[i]=(short)(((double)mix_buf[i])*(1.0-l));
98 }
99
100 res = len;
101
102 // clear the rest
103 unsigned int len_from_a = 0;
104 if (res>0)
105 len_from_a=(unsigned int)res;
106
107 if (PCM16_S2B(nb_samples) != len_from_a)
108 memset((void*)&pdest[len_from_a>>1], 0,
109 (nb_samples<<1) - len_from_a);
110
111 // add audio from B
112 len = B->get(system_ts, (unsigned char*)mix_buf,
113 output_sample_rate, nb_samples);
114 if (len<0) { // B finished
115 mixing = false;
116
117 if (IS_ONLY_ONCE) {
118 B = NULL;
119 } else {
120 AmAudioFile* B_file = dynamic_cast<AmAudioFile*>(B);
121 if (NULL != B_file) {
122 B_file->rewind();
123 }
124 }
125 } else {
126 for (int i=0; i<(PCM16_B2S(len)); i++) {
127 pdest[i]+=(short)(((double)mix_buf[i])*l);
128 }
129 if (len>res) // audio from B is longer than from A
130 res = len;
131 }
132 B_mut.unlock();
133
134 return res;
135 }
136 }
137 }
138
put(unsigned long long system_ts,unsigned char * buffer,int input_sample_rate,unsigned int size)139 int AmAudioMixIn::put(unsigned long long system_ts, unsigned char* buffer,
140 int input_sample_rate, unsigned int size) {
141
142 ERROR("writing not supported\n");
143 return -1;
144 }
145
mixin(AmAudio * f)146 void AmAudioMixIn::mixin(AmAudio* f) {
147 B_mut.lock();
148 B = f;
149 mixing = next_start_ts_i = false; /* so that mix in will re-start */
150 B_mut.unlock();
151 }
152
153