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