Browse code

initial import

git-svn-id: http://svn.berlios.de/svnroot/repos/sems/trunk@1 8eb893ce-cfd4-0310-b710-fb5ebe64c474

Raphael Coeffic authored on 27/09/2005 07:54:58
Showing 299 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,228 @@
1
+/*
2
+ * $Id: AmAdvancedAudio.cpp,v 1.1.2.3 2005/06/01 12:00:24 rco Exp $
3
+ *
4
+ * Copyright (C) 2002-2003 Fhg Fokus
5
+ *
6
+ * This file is part of sems, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser 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 "AmAdvancedAudio.h"
29
+
30
+#include <set>
31
+using std::set;
32
+
33
+#include "math.h"
34
+
35
+/* AudioQueue */
36
+AmAudioQueue::AmAudioQueue() 
37
+    : AmAudio(new AmAudioSimpleFormat(CODEC_PCM16)) // we get and put in this (internal) fmt
38
+{
39
+	sarr.clear_all();
40
+}
41
+
42
+AmAudioQueue::~AmAudioQueue() { 
43
+    set<AmAudio*> deleted_audios; // don't delete them twice
44
+    for (list<AudioQueueEntry>::iterator it = inputQueue.begin();it != inputQueue.end(); it++) {
45
+	if (deleted_audios.find(it->audio) == deleted_audios.end()) {
46
+	    deleted_audios.insert(it->audio);
47
+	    delete it->audio;
48
+	}
49
+    }
50
+	
51
+    for (list<AudioQueueEntry>::iterator it = outputQueue.begin();it != outputQueue.end(); it++) {
52
+	if (deleted_audios.find(it->audio) == deleted_audios.end()) {
53
+	    deleted_audios.insert(it->audio);
54
+	    delete it->audio;
55
+	}
56
+    }
57
+}
58
+
59
+int AmAudioQueue::write(unsigned int user_ts, unsigned int size) {
60
+    inputQueue_mut.lock();
61
+    unsigned int size_trav = size;
62
+    for (list<AudioQueueEntry>::iterator it = inputQueue.begin(); it != inputQueue.end(); it++) {
63
+	if (it->put) {
64
+	    if ((size_trav = it->audio->put(user_ts, samples, size_trav)) < 0)
65
+		break;
66
+	}
67
+	if (it->get) {
68
+	    if ((size_trav = it->audio->get(user_ts, samples, size_trav >> 1)) < 0)
69
+		break;
70
+	}
71
+    }
72
+    inputQueue_mut.unlock();
73
+    return size_trav;
74
+}
75
+
76
+int AmAudioQueue::read(unsigned int user_ts, unsigned int size) {
77
+    outputQueue_mut.lock();
78
+    unsigned int size_trav = size;
79
+    for (list<AudioQueueEntry>::iterator it = outputQueue.begin(); it != outputQueue.end(); it++) {
80
+	if (it->put) {
81
+	    if ((size_trav = it->audio->put(user_ts, samples, size_trav)) < 0)
82
+		break;
83
+	}
84
+	if (it->get) {
85
+	    if ((size_trav = it->audio->get(user_ts, samples, size_trav >> 1)) < 0)
86
+		break;
87
+	}
88
+    }
89
+    outputQueue_mut.unlock();
90
+    return size_trav;
91
+}
92
+
93
+void AmAudioQueue::pushAudio(AmAudio* audio, QueueType type, Pos pos, bool write, bool read) {
94
+    AmMutex* q_mut; 
95
+    list<AudioQueueEntry>* q; 
96
+    switch (type) {
97
+	case OutputQueue: 
98
+	    q_mut = &outputQueue_mut;
99
+	    q = &outputQueue;
100
+	    break;
101
+	case InputQueue: 
102
+	default:  q_mut = &inputQueue_mut;
103
+	    q = &inputQueue;
104
+	    break;
105
+    };
106
+    q_mut->lock();
107
+    if (pos == Front)
108
+	q->push_front(AudioQueueEntry(audio, write, read));
109
+    else
110
+	q->push_back(AudioQueueEntry(audio, write, read));
111
+    q_mut->unlock();
112
+}
113
+
114
+int AmAudioQueue::popAudio(QueueType type, Pos pos) {
115
+    AmAudio* audio = popAndGetAudio(type, pos);
116
+    if (audio) {
117
+	delete audio;
118
+	return 0;
119
+    }
120
+    return -1; // error
121
+}
122
+
123
+AmAudio* AmAudioQueue::popAndGetAudio(QueueType type, Pos pos) {
124
+    AmMutex* q_mut; 
125
+    list<AudioQueueEntry>* q; 
126
+    switch (type) {
127
+	case OutputQueue: 
128
+	    q_mut = &outputQueue_mut;
129
+	    q = &outputQueue;
130
+	    break;
131
+	case InputQueue: 
132
+	default:  q_mut = &inputQueue_mut;
133
+	    q = &inputQueue;
134
+	    break;
135
+    };
136
+    q_mut->lock();
137
+    if (q->empty()) {
138
+	q_mut->unlock();
139
+	return 0;
140
+    }
141
+
142
+    AmAudio* audio;
143
+    if (pos == Front) {
144
+	audio = q->front().audio;
145
+	q->pop_front();
146
+    }  else {
147
+	audio = q->back().audio;
148
+	q->pop_back();
149
+    }
150
+    q_mut->unlock();
151
+    return audio;
152
+}
153
+
154
+int AmAudioQueue::removeAudio(AmAudio* audio) {
155
+    bool found = false;
156
+    outputQueue_mut.lock();
157
+    for (list<AudioQueueEntry>::iterator it = outputQueue.begin(); 
158
+	 it != outputQueue.end(); it++) {
159
+	if (it->audio == audio) {
160
+	    found = true;
161
+	    outputQueue.erase(it);
162
+	    break;
163
+	}
164
+	    
165
+    }
166
+    outputQueue_mut.unlock();
167
+    if (found)
168
+	return 0;
169
+    inputQueue_mut.lock();
170
+    for (list<AudioQueueEntry>::iterator it = inputQueue.begin(); 
171
+	 it != inputQueue.end(); it++) {
172
+	if (it->audio == audio) {
173
+	    found = true;
174
+	    inputQueue.erase(it);
175
+	    break;
176
+	}
177
+	    
178
+    }
179
+    inputQueue_mut.unlock();
180
+    if (found)
181
+	return 0;
182
+    else {
183
+	ERROR("could not find audio in queue\n");
184
+	return -1; // error
185
+    }
186
+}
187
+
188
+
189
+/* AudioBridge */
190
+AmAudioBridge::AmAudioBridge()
191
+    : AmAudio(new AmAudioSimpleFormat(CODEC_PCM16))
192
+{
193
+	sarr.clear_all();
194
+}
195
+
196
+AmAudioBridge::~AmAudioBridge() { 
197
+}
198
+
199
+int AmAudioBridge::write(unsigned int user_ts, unsigned int size) {  
200
+	sarr.write(user_ts, (short*) ((unsigned char*) samples), size >> 1); 
201
+	return size; 
202
+}
203
+
204
+int AmAudioBridge::read(unsigned int user_ts, unsigned int size) { 
205
+    sarr.read(user_ts, (short*) ((unsigned char*) samples), size >> 1); 
206
+    return size;
207
+}
208
+
209
+/* AudioDelay */
210
+AmAudioDelay::AmAudioDelay(float delay_sec)
211
+    : AmAudio(new AmAudioSimpleFormat(CODEC_PCM16))
212
+{
213
+	sarr.clear_all();
214
+	delay = delay_sec;
215
+}
216
+
217
+AmAudioDelay::~AmAudioDelay() { 
218
+}
219
+
220
+int AmAudioDelay::write(unsigned int user_ts, unsigned int size) {  
221
+    sarr.write(user_ts,(short*) ((unsigned char*) samples), size >> 1); 
222
+    return size; 
223
+}
224
+
225
+int AmAudioDelay::read(unsigned int user_ts, unsigned int size) { 
226
+    sarr.read((unsigned int) (user_ts  - delay*8000.0), (short*)  ((unsigned char*) samples), size >> 1); 
227
+    return size;
228
+}
0 229
new file mode 100644
... ...
@@ -0,0 +1,113 @@
1
+/*
2
+ * $Id: AmAdvancedAudio.h,v 1.1.2.2 2005/03/14 20:58:23 sayer Exp $
3
+ *
4
+ * Copyright (C) 2002-2003 Fhg Fokus
5
+ *
6
+ * This file is part of sems, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser 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
+#ifndef _AmAdvancedAudio_h_
29
+#define _AmAdvancedAudio_h_
30
+
31
+#include "AmAudio.h"
32
+#include "AmThread.h"
33
+#include "amci/codecs.h"
34
+
35
+#include <list>
36
+using namespace std;
37
+#include "SampleArray.h"
38
+
39
+struct AudioQueueEntry {
40
+    AmAudio* audio;
41
+    bool put;
42
+    bool get;
43
+    AudioQueueEntry(AmAudio* _audio, bool _put, bool _get) 
44
+	: audio(_audio), put(_put), get(_get) { }
45
+};
46
+
47
+/**
48
+ * AmAudioQueue can hold AmAudios in input and output queue.
49
+ * 
50
+ * Audio will be read through the whole output queue,
51
+ * and written through the whole input queue.
52
+ */
53
+
54
+class AmAudioQueue : public AmAudio {
55
+    SampleArrayShort sarr;
56
+
57
+    AmMutex inputQueue_mut;
58
+    list<AudioQueueEntry> inputQueue;
59
+    AmMutex outputQueue_mut;
60
+    list<AudioQueueEntry> outputQueue;
61
+public:
62
+    AmAudioQueue();
63
+    ~AmAudioQueue();
64
+
65
+    enum QueueType { OutputQueue, InputQueue };
66
+    enum Pos { Front, Back };
67
+
68
+    /** add an audio to a queue */
69
+    void pushAudio(AmAudio* audio, QueueType type, Pos pos, bool write, bool read); 
70
+    /** pop an audio from queue and delete it @return 0 on success, -1 on failure */
71
+    int popAudio(QueueType type, Pos pos); 
72
+    /** pop an audio from queue @return pointer to the audio */
73
+    AmAudio* popAndGetAudio(QueueType type, Pos pos); 
74
+    /** this removes the audio if it is in on of the queues and does not
75
+        delete them */
76
+    int removeAudio(AmAudio* audio);
77
+
78
+protected:
79
+    int write(unsigned int user_ts, unsigned int size);
80
+    int read(unsigned int user_ts, unsigned int size);
81
+};
82
+
83
+/**
84
+ *  AmAudioBridge simply connects input and output
85
+ *  This is useful e.g. at the end of a AudioQueue
86
+ */
87
+class AmAudioBridge : public AmAudio {
88
+    SampleArrayShort sarr;
89
+public:
90
+    AmAudioBridge();
91
+    ~AmAudioBridge();
92
+protected:
93
+    int write(unsigned int user_ts, unsigned int size);
94
+    int read(unsigned int user_ts, unsigned int size);
95
+};
96
+
97
+/**
98
+ * delays delay_sec seconds (up to ~2)
99
+ */
100
+class AmAudioDelay : public AmAudio {
101
+    SampleArrayShort sarr;
102
+    float delay;
103
+public:
104
+    AmAudioDelay(float delay_sec);
105
+    ~AmAudioDelay();
106
+protected:
107
+
108
+    int write(unsigned int user_ts, unsigned int size);
109
+    int read(unsigned int user_ts, unsigned int size);
110
+};
111
+
112
+#endif // _AmAdvancedAudio_h_
113
+
0 114
new file mode 100644
... ...
@@ -0,0 +1,145 @@
1
+/*
2
+ * $Id: AmApi.cpp,v 1.9.2.1 2005/08/03 21:00:30 sayer Exp $
3
+ *
4
+ * Copyright (C) 2002-2003 Fhg Fokus
5
+ *
6
+ * This file is part of sems, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser 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 "AmApi.h"
29
+#include "log.h"
30
+
31
+AmStateFactory::AmStateFactory(const string& _app_name)
32
+  : app_name(_app_name)
33
+{
34
+}
35
+
36
+int AmStateFactory::onLoad()
37
+{
38
+    return 0;
39
+}
40
+
41
+AmDialogState::AmDialogState()
42
+    : AmEventQueue(this)
43
+{
44
+}
45
+
46
+void AmDialogState::process(AmEvent* event)
47
+{   
48
+    AmSessionEvent* session_event = dynamic_cast<AmSessionEvent*>(event);
49
+    if(session_event){
50
+
51
+	DBG("in-dialog event received: %s\n",
52
+	    session_event->request.cmd.method.c_str());
53
+
54
+	if(session_event->event_id == AmSessionEvent::Bye)
55
+	    onBye(&session_event->request);
56
+	else if(onSessionEvent(session_event))
57
+	    ERROR("while processing session event (ID=%i).\n",session_event->event_id);
58
+
59
+	return;
60
+	
61
+    } 
62
+
63
+    //  AmRequestUACStatusEvent?
64
+    AmRequestUACStatusEvent* status_event = 
65
+	dynamic_cast<AmRequestUACStatusEvent*>(event);
66
+    
67
+    if(status_event){
68
+	DBG("in-dialog RequestUAC Staus event received: "
69
+	    "method=%s, cseq = %d, \n\t\tcode = %d, reason = %s\n",
70
+	    status_event->request.cmd.method.c_str(), status_event->request.cmd.cseq, 
71
+	    status_event->code, status_event->reason.c_str());
72
+	
73
+	if(onUACRequestStatus(status_event))
74
+	    ERROR("while processing session event (ID=%i).\n", 
75
+		  session_event->event_id);
76
+
77
+	return;
78
+    } 
79
+
80
+    AmAudioEvent* audio_event = dynamic_cast<AmAudioEvent*>(event);
81
+    if(audio_event && (audio_event->event_id == AmAudioEvent::cleared)){
82
+	stopSession();
83
+	return;
84
+    }
85
+    
86
+    ERROR("AmSession: invalid event received.\n");
87
+    return;
88
+}
89
+
90
+void AmDialogState::onError(unsigned int code, const string& reason)
91
+{
92
+}
93
+
94
+void AmDialogState::onBeforeCallAccept(AmRequest*)
95
+{
96
+}
97
+
98
+int AmDialogState::onSessionEvent(AmSessionEvent* event)
99
+{
100
+    if(!event->processed){
101
+	switch(event->event_id){
102
+	case AmSessionEvent::Refer:
103
+	    event->request.reply(488,"Not acceptable here");
104
+	    break;
105
+	case AmSessionEvent::ReInvite:
106
+	    getSession()->negotiate(&event->request);
107
+	    break;
108
+	}
109
+    }
110
+    
111
+    return 0;
112
+}
113
+
114
+int AmDialogState::onUACRequestStatus(AmRequestUACStatusEvent* event) 
115
+{ 
116
+    if(!event->processed){
117
+	switch(event->event_id){
118
+	    case AmRequestUACStatusEvent::Accepted:
119
+		DBG("UAC Request Status: Accepted (method %s, seqnr %d)\n", 
120
+		    event->request.cmd.method.c_str(), event->request.cmd.cseq);
121
+		break;
122
+	    case AmRequestUACStatusEvent::Error:
123
+		DBG("UAC Request Status: Error (method %s, seqnr %d)\n",
124
+		    event->request.cmd.method.c_str(), event->request.cmd.cseq);
125
+		break;
126
+	}
127
+	event->processed = true;
128
+    }
129
+    
130
+    return 0;
131
+}
132
+
133
+void AmDialogState::onDtmf(int event, int duration_msec)
134
+{
135
+}
136
+
137
+AmStateFactory* AmDialogState::getStateFactory() 
138
+{ 
139
+    return state_factory; 
140
+}
141
+
142
+AmSession* AmDialogState::getSession() 
143
+{ 
144
+    return session; 
145
+}
0 146
new file mode 100644
... ...
@@ -0,0 +1,179 @@
1
+/*
2
+ * $Id: AmApi.h,v 1.9.2.1 2005/06/01 12:00:24 rco Exp $
3
+ *
4
+ * Copyright (C) 2002-2003 Fhg Fokus
5
+ *
6
+ * This file is part of sems, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser 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
+#ifndef _AmApi_h_
28
+#define _AmApi_h_
29
+
30
+#include "AmRequest.h"
31
+#include "AmThread.h"
32
+#include "AmSession.h"
33
+
34
+#include <string>
35
+#include <map>
36
+using std::map;
37
+using std::string;
38
+
39
+class AmSession;
40
+class AmSessionEvent;
41
+class AmDialogState;
42
+
43
+#define FACTORY_EXPORT_NAME app_state_factory
44
+#define FACTORY_EXPORT_STR  "app_state_factory"
45
+#define EXPORT_FACTORY(class_name,app_name) class_name FACTORY_EXPORT_NAME (app_name)
46
+
47
+class AmStateFactory
48
+{
49
+public:
50
+    string app_name;
51
+    AmStateFactory(const string& _app_name);
52
+    virtual ~AmStateFactory() {}
53
+
54
+    /**
55
+     * Enables the plug-in to initialize whatever it needs.
56
+     * Ex. load the configuration.
57
+     * @return 0 everything was ok.
58
+     * @return 1 on error.
59
+     */
60
+    virtual int onLoad();
61
+
62
+    /**
63
+     * Creates a dialog state on new request.
64
+     * @return 0 if the request is not acceptable.
65
+     *
66
+     * Warning:
67
+     *   This method should not make any expensive
68
+     *   processing as it would block the server.
69
+     */
70
+    virtual AmDialogState* onInvite(AmCmd& cmd) = 0;
71
+};
72
+
73
+/** 
74
+ * All your dialog relevant datas should be 
75
+ * contained in a class inherited from ApiDialogState 
76
+ */
77
+
78
+class AmDialogState: public AmEventQueue, public AmEventHandler
79
+{
80
+    AmStateFactory* state_factory;
81
+    AmSession*      session;
82
+
83
+protected:
84
+    /** @see AmEventHandler::process(AmEvent* event) */
85
+    void process(AmEvent* event);
86
+
87
+public:
88
+    AmDialogState();
89
+    virtual ~AmDialogState() {}
90
+
91
+    AmStateFactory* getStateFactory();
92
+    AmSession* getSession();
93
+
94
+    /**
95
+     * This must be called at the end of the application
96
+     * so that the session can end and later be destroyed.
97
+     */
98
+    void stopSession() { getSession()->setStopped(); }
99
+
100
+    bool sessionStopped() { return getSession()->getStopped(); }
101
+
102
+    /**
103
+     * onBeforeCallAccept will be called on incoming 
104
+     * request before the call gets definitely established.
105
+     * 
106
+     * Throw AmSession::Exception if you want to 
107
+     * signal any error.
108
+     */
109
+    virtual void onBeforeCallAccept(AmRequest* req);
110
+
111
+    /**
112
+     * onSessionStart will be called after call setup.
113
+     *
114
+     * Throw AmSession::Exception if you want to 
115
+     * signal any error.
116
+     * 
117
+     * Warning:
118
+     *   The session ends with this method. 
119
+     *   Sems will NOT send any BYE on his own.
120
+     */
121
+    virtual void onSessionStart(AmRequest* req)=0;
122
+
123
+    /**
124
+     * onBye will be called if a BYE has been 
125
+     * sent or received.
126
+     *
127
+     * Warning:
128
+     *   This method should not make any expensive
129
+     *   processing as it would block the session 
130
+     *   cleaner.
131
+     */
132
+    virtual void onBye(AmRequest* req)=0;
133
+
134
+    /**
135
+     * onError will be called if an error
136
+     * occured during call setup.
137
+     */
138
+    virtual void onError(unsigned int code, const string& reason);
139
+
140
+    /**
141
+     * onOther will be called on any other
142
+     * event (ex. REFER).
143
+     *
144
+     * Warning:
145
+     *   This method should not make any expensive
146
+     *   processing as it would block the session.
147
+     *
148
+     * @return !=0 if any error occured.
149
+     */
150
+    virtual int onSessionEvent(AmSessionEvent* event);
151
+
152
+    /**
153
+     * onUACRequestStatus will be called on the result of a 
154
+     * RequestUAC  (ex. REFER).
155
+     *
156
+     * Warning:
157
+     *   This method should not make any expensive
158
+     *   processing as it would block the session.
159
+     *
160
+     * @return !=0 if any error occured.
161
+     */
162
+    virtual int onUACRequestStatus(AmRequestUACStatusEvent* event);
163
+
164
+    virtual void onDtmf(int event, int duration_msec);
165
+
166
+    // needed for session creation
167
+    friend void AmSessionContainer::startSession(const string& hash_str, 
168
+						 string& sess_key,
169
+						 AmRequestUAS* req);
170
+
171
+    friend AmSession* AmSessionContainer::createSession(const string& app_name, 
172
+							AmRequest* req);
173
+
174
+};
175
+
176
+#endif
177
+// Local Variables:
178
+// mode:C++
179
+// End:
0 180
new file mode 100644
... ...
@@ -0,0 +1,590 @@
1
+/*
2
+ * $Id: AmAudio.cpp,v 1.23.2.8 2005/08/31 13:54:29 rco Exp $
3
+ *
4
+ * Copyright (C) 2002-2003 Fhg Fokus
5
+ *
6
+ * This file is part of sems, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser 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 "AmAudio.h"
29
+#include "AmPlugIn.h"
30
+#include "AmUtils.h"
31
+#include "amci/codecs.h"
32
+#include "log.h"
33
+
34
+#include <stdlib.h>
35
+#include <string.h>
36
+#include <assert.h>
37
+
38
+#include <typeinfo>
39
+
40
+AmAudioRtpFormat::AmAudioRtpFormat(int payload, string format_parameters)
41
+  : AmAudioFormat(), payload(payload), amci_pl(0)
42
+{
43
+  sdp_format_parameters = format_parameters;
44
+  codec = getCodec();
45
+ 
46
+  amci_payload_t* pl = getPayloadP();
47
+  if(pl && codec){
48
+    sample = codec->sample_size;
49
+    channels = pl->channels;
50
+    rate = pl->sample_rate;
51
+  } else {
52
+    ERROR("Could not find payload <%i>\n",payload);
53
+  } 
54
+}
55
+
56
+AmAudioFormat::AmAudioFormat()
57
+  : sample(-1), channels(-1), rate(-1), codec(0),
58
+    frame_length(20), frame_size(160), frame_encoded_size(320)
59
+{
60
+
61
+}
62
+
63
+AmAudioSimpleFormat::AmAudioSimpleFormat(int codec_id)
64
+    : AmAudioFormat(), codec_id(codec_id)
65
+{
66
+    codec = getCodec();
67
+    sample = codec->sample_size;
68
+    rate = 8000;
69
+    channels = 1;
70
+}
71
+
72
+AmAudioFileFormat::AmAudioFileFormat(const string& name, int subtype)
73
+    : name(name), subtype(subtype), p_subtype(0)
74
+{
75
+    getSubtype();
76
+    codec = getCodec();
77
+    
78
+    if(p_subtype && codec){
79
+	sample = codec->sample_size;
80
+	rate = p_subtype->sample_rate;
81
+	channels = p_subtype->channels;
82
+	subtype = p_subtype->type;
83
+    } 
84
+}
85
+
86
+AmAudioFormat::~AmAudioFormat()
87
+{
88
+    destroyCodec();
89
+}
90
+
91
+bool AmAudioFormat::operator == (const AmAudioFormat& r) const
92
+{
93
+    return ( codec && r.codec
94
+	     && (r.codec->id == codec->id) 
95
+	     && (r.sample == sample)
96
+	     && (r.channels == channels)
97
+	     && (r.rate == rate));
98
+}
99
+
100
+bool AmAudioFormat::operator != (const AmAudioFormat& r) const
101
+{
102
+    return !(this->operator == (r));
103
+}
104
+
105
+void AmAudioFormat::initCodec()
106
+{
107
+  amci_codec_fmt_info_t fmt_i[4];
108
+
109
+  fmt_i[0].id=0;
110
+
111
+  if( codec && codec->init ) {
112
+    if ((h_codec = (*codec->init)(sdp_format_parameters.c_str(), fmt_i)) == -1) {
113
+      ERROR("could not initialize codec %i\n",codec->id);
114
+    } else {
115
+      string s; 
116
+      int i=0;
117
+	while (fmt_i[i].id) {
118
+	  switch (fmt_i[i].id) {
119
+	  case AMCI_FMT_FRAME_LENGTH : {
120
+	    frame_length=fmt_i[i].value; 
121
+	  } break;
122
+	  case AMCI_FMT_FRAME_SIZE: {
123
+	    frame_size=fmt_i[i].value; 
124
+	  } break;
125
+	  case AMCI_FMT_ENCODED_FRAME_SIZE: {
126
+	    frame_encoded_size=fmt_i[i].value; 
127
+	  } break;
128
+	  default: {
129
+	    DBG("Unknown codec format descriptor: %d\n", fmt_i[i].id);
130
+	  } break;
131
+	  }
132
+	  i++;
133
+      }
134
+    }  
135
+  } 
136
+}
137
+
138
+void AmAudioFormat::destroyCodec()
139
+{
140
+    if( codec && codec->destroy ){
141
+	(*codec->destroy)(h_codec);
142
+	h_codec = 0;
143
+    }
144
+}
145
+
146
+amci_subtype_t*  AmAudioFileFormat::getSubtype()
147
+{
148
+    if(!p_subtype && !name.empty()){
149
+
150
+	amci_inoutfmt_t* iofmt = AmPlugIn::instance()->fileFormat(name.c_str());
151
+	if(!iofmt){
152
+	    ERROR("AmAudioFileFormat::getSubtype: file format '%s' does not exist\n",
153
+		  name.c_str());
154
+	    throw string("AmAudioFileFormat::getSubtype: file format '%s' does not exist\n");
155
+	}
156
+	else {
157
+	    p_subtype = AmPlugIn::instance()->subtype(iofmt,subtype);
158
+	    if(!p_subtype)
159
+		ERROR("AmAudioFileFormat::getSubtype: subtype %i in format '%s' does not exist\n",
160
+		      subtype,iofmt->name);
161
+	    subtype = p_subtype->type;
162
+	}
163
+    }
164
+    return p_subtype;
165
+}
166
+
167
+
168
+amci_codec_t* AmAudioFormat::getCodec()
169
+{
170
+
171
+    if(!codec){
172
+	int codec_id = getCodecId();
173
+	codec = AmPlugIn::instance()->codec(codec_id);
174
+
175
+	initCodec();
176
+    }
177
+    
178
+    return codec;
179
+}
180
+
181
+long AmAudioFormat::getHCodec()
182
+{
183
+    if(!codec)
184
+	getCodec();
185
+    return h_codec;
186
+}
187
+
188
+AmAudio::AmAudio()
189
+    : fmt(0),
190
+      max_rec_time(-1),
191
+      rec_time(0)
192
+{
193
+}
194
+
195
+AmAudio::AmAudio(AmAudioFormat *_fmt)
196
+    : fmt(_fmt),
197
+      max_rec_time(-1),
198
+      rec_time(0)
199
+{
200
+}
201
+
202
+AmAudio::~AmAudio()
203
+{
204
+}
205
+
206
+void AmAudio::close()
207
+{
208
+}
209
+
210
+// returns bytes read, else -1 if error (0 is OK)
211
+int AmAudio::get(unsigned int user_ts, unsigned char* buffer, unsigned int nb_samples)
212
+{
213
+    int size = nb_samples * fmt->sample * fmt->channels;
214
+
215
+    size = read(user_ts,size);
216
+    //DBG("size = %d\n",size);
217
+    if(size <= 0){
218
+	return size;
219
+    }
220
+
221
+    size = decode(size);
222
+    if(size < 0) {
223
+	DBG("decode returned %i\n",size);
224
+	return -1; 
225
+    }
226
+    size = downMix(size);
227
+    
228
+    if(size>0)
229
+	memcpy(buffer,(unsigned char*)samples,size);
230
+
231
+    return size;
232
+}
233
+
234
+// returns bytes written, else -1 if error (0 is OK)
235
+int AmAudio::put(unsigned int user_ts, unsigned char* buffer, unsigned int size)
236
+{
237
+    if(!size){
238
+	return 0;
239
+    }
240
+
241
+    if(max_rec_time > -1 && rec_time >= max_rec_time)
242
+	return -1;
243
+
244
+
245
+    memcpy((unsigned char*)samples,buffer,size);
246
+
247
+    unsigned int s = encode(size);
248
+    if(s>0){
249
+	//DBG("%s\n",typeid(this).name());
250
+	incRecordTime(size);
251
+	return write(user_ts,(unsigned int)s);
252
+    }
253
+    else{
254
+	return s;
255
+    }
256
+}
257
+
258
+void AmAudio::stereo2mono(unsigned char* out_buf,unsigned char* in_buf,unsigned int& size)
259
+{
260
+    short* in  = (short*)in_buf;
261
+    short* end = (short*)(in_buf + size);
262
+    short* out = (short*)out_buf;
263
+    
264
+    while(in != end){
265
+	*(out++) = (*in + *(in+1)) / 2;
266
+	in += 2;
267
+    }
268
+
269
+    size /= 2;
270
+}
271
+
272
+int AmAudio::decode(unsigned int size)
273
+{
274
+    int s = size;
275
+
276
+    if(!fmt.get()){
277
+	DBG("no fmt !\n");
278
+	return s;
279
+    }
280
+
281
+    amci_codec_t* codec = fmt->getCodec();
282
+    long h_codec = fmt->getHCodec();
283
+
284
+    if(!codec){
285
+	ERROR("audio format set, but no codec has been loaded\n");
286
+	abort();
287
+	return -1;
288
+    }
289
+
290
+    if(codec->decode){
291
+	s = (*codec->decode)(samples.back_buffer(),samples,s,
292
+				 fmt->channels,fmt->rate,h_codec);
293
+	if(s<0) return s;
294
+	samples.swap();
295
+    }
296
+    
297
+    return s;
298
+}
299
+
300
+int AmAudio::encode(unsigned int size)
301
+{
302
+    if(!fmt.get()){
303
+	DBG("no encode fmt\n");
304
+	return 0;
305
+    }
306
+
307
+    amci_codec_t* codec = fmt->getCodec();
308
+    int s = size;
309
+    long h_codec = fmt->getHCodec();
310
+
311
+    if(codec->encode){
312
+	s = (*codec->encode)(samples.back_buffer(),samples,(unsigned int) size,
313
+				      fmt->channels,fmt->rate,h_codec);
314
+	if(s<0) return s;
315
+	samples.swap();
316
+    }
317
+    
318
+    return s;
319
+}
320
+
321
+unsigned int AmAudio::downMix(unsigned int size)
322
+{
323
+    unsigned int s = size;
324
+    if(fmt->channels == 2)
325
+	stereo2mono(samples.back_buffer(),(unsigned char*)samples,s);
326
+
327
+    samples.swap();
328
+    return s;
329
+}
330
+
331
+unsigned int AmAudio::getFrameSize()
332
+{
333
+    assert(fmt.get());
334
+    return fmt->frame_size;
335
+}
336
+
337
+unsigned int AmAudio::samples2bytes(unsigned int nb_samples)
338
+{
339
+    return nb_samples * fmt->sample * fmt->channels;
340
+}
341
+
342
+void AmAudio::setRecordTime(unsigned int ms)
343
+{
344
+    max_rec_time = ms * (fmt->rate / 1000);
345
+}
346
+
347
+int AmAudio::incRecordTime(unsigned int samples)
348
+{
349
+    return rec_time += samples;
350
+}
351
+
352
+
353
+DblBuffer::DblBuffer()
354
+    : active_buf(0)
355
+{ 
356
+}
357
+
358
+DblBuffer::operator unsigned char*()
359
+{
360
+    return samples + (active_buf ? AUDIO_BUFFER_SIZE : 0);
361
+}
362
+
363
+unsigned char* DblBuffer::back_buffer()
364
+{
365
+    return samples + (active_buf ? 0 : AUDIO_BUFFER_SIZE);
366
+}
367
+
368
+void DblBuffer::swap()
369
+{
370
+    active_buf = !active_buf;
371
+}
372
+
373
+// returns 0 if everything's OK
374
+// return -1 if error
375
+int  AmAudioFile::open(const string& filename, OpenMode mode)
376
+{
377
+    close();
378
+
379
+    AmAudioFileFormat* f_fmt = fileName2Fmt(filename);
380
+    if(!f_fmt){
381
+	ERROR("while trying to the format of '%s'\n",filename.c_str());
382
+	return -1;
383
+    }
384
+    fmt.reset(f_fmt);
385
+
386
+    open_mode = mode;
387
+    fp = fopen(filename.c_str(),mode == AmAudioFile::Read ? "rb" : "wb");
388
+    if(!fp){
389
+	if(mode == AmAudioFile::Read)
390
+	    ERROR("file not found: %s\n",filename.c_str());
391
+	else
392
+	    ERROR("could not create/overwrite file: %s\n",filename.c_str());
393
+	return -1;
394
+    }
395
+
396
+    amci_file_desc_t fd;
397
+    int ret = -1;
398
+
399
+    if(open_mode == AmAudioFile::Write){
400
+
401
+ 	if (f_fmt->channels<0 || f_fmt->rate<0) {
402
+	    if (f_fmt->channels<0)
403
+		ERROR("channel count must be set for output file.\n");
404
+	    if (f_fmt->rate<0)
405
+		ERROR("sampling rate must be set for output file.\n");
406
+	    close();
407
+	    return -1;
408
+ 	}
409
+    }
410
+
411
+    fd.subtype = f_fmt->getSubtypeId();
412
+    fd.sample = f_fmt->sample;
413
+    fd.channels = f_fmt->channels;
414
+    fd.rate = f_fmt->rate;
415
+
416
+    if( iofmt->open && !(ret = (*iofmt->open)(fp,&fd,mode, f_fmt->getHCodecNoInit())) ) {
417
+	if (mode == AmAudioFile::Read) {
418
+	    f_fmt->setSubtypeId(fd.subtype);
419
+	    f_fmt->sample = fd.sample;
420
+	    f_fmt->channels = fd.channels;
421
+	    f_fmt->rate = fd.rate;
422
+	}
423
+	begin = ftell(fp);
424
+    }
425
+    else {
426
+	if(!iofmt->open)
427
+	    ERROR("no open function\n");
428
+	else
429
+	    ERROR("open returned %d\n",ret);
430
+	close();
431
+	return ret;
432
+    }
433
+
434
+    if(open_mode == AmAudioFile::Write){
435
+
436
+	DBG("After open:\n");
437
+	DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
438
+	DBG("fmt::sample = %i\n",f_fmt->sample);
439
+	DBG("fmt::channels = %i\n",f_fmt->channels);
440
+	DBG("fmt::rate = %i\n",f_fmt->rate);
441
+    }
442
+
443
+    return ret;
444
+}
445
+
446
+AmAudioFile::AmAudioFile()
447
+    : AmAudio(), data_size(0), 
448
+      fp(0), begin(0), loop(false)
449
+{
450
+}
451
+
452
+AmAudioFile::~AmAudioFile()
453
+{
454
+    close();
455
+}
456
+
457
+void AmAudioFile::close()
458
+{
459
+    if(fp){
460
+
461
+	AmAudioFileFormat* f_fmt = 
462
+	    dynamic_cast<AmAudioFileFormat*>(fmt.get());
463
+
464
+	if(f_fmt){
465
+	    amci_file_desc_t fmt_desc = { f_fmt->getSubtypeId(), 
466
+					  f_fmt->sample, 
467
+					  f_fmt->rate, 
468
+					  f_fmt->channels, 
469
+					  data_size };
470
+	    
471
+	    if(!iofmt){
472
+		ERROR("file format pointer not initialized: on_close will not be called\n");
473
+	    }
474
+	    else if(iofmt->on_close)
475
+		(*iofmt->on_close)(fp,&fmt_desc,open_mode, fmt->getHCodecNoInit());
476
+	}
477
+
478
+	if(open_mode == AmAudioFile::Write){
479
+
480
+	    DBG("After close:\n");
481
+	    DBG("fmt::subtype = %i\n",f_fmt->getSubtypeId());
482
+	    DBG("fmt::sample = %i\n",f_fmt->sample);
483
+	    DBG("fmt::channels = %i\n",f_fmt->channels);
484
+	    DBG("fmt::rate = %i\n",f_fmt->rate);
485
+	}
486
+
487
+	fclose(fp);
488
+	fp = 0;
489
+    }
490
+}
491
+
492
+string AmAudioFile::getMimeType()
493
+{
494
+    if(!iofmt)
495
+	return "";
496
+    
497
+    return iofmt->email_content_type;
498
+}
499
+
500
+
501
+int AmAudioFile::read(unsigned int user_ts, unsigned int size)
502
+{
503
+    if(!fp){
504
+	ERROR("AmAudioFile::read: file is not opened\n");
505
+	return -1;
506
+    }
507
+
508
+    int s = fread((void*)((unsigned char*)samples),1,size,fp);
509
+    int ret = (!ferror(fp) ? s : -1);
510
+
511
+    //DBG("s = %i; ret = %i\n",s,ret);
512
+    if(loop.get() && (ret <= 0) && feof(fp)){
513
+
514
+	DBG("rewinding audio file...\n");
515
+	fseek(fp,begin,SEEK_SET);
516
+	s = fread((void*)((unsigned char*)samples),1,size,fp);
517
+	ret = (!ferror(fp) ? s : -1);
518
+    }
519
+
520
+    if(ret > 0 && s > 0 && (unsigned int)s < size){
521
+	DBG("0-stuffing packet: adding %i bytes (packet size=%i)\n",size-s,size);
522
+	memset((unsigned char*)samples + s,0,size-s);
523
+	return size;
524
+    }
525
+
526
+    return (feof(fp) && !loop.get() ? -2 : ret);
527
+}
528
+
529
+int AmAudioFile::write(unsigned int user_ts, unsigned int size)
530
+{
531
+    if(!fp){
532
+	ERROR("AmAudioFile::write: file is not opened\n");
533
+	return -1;
534
+    }
535
+
536
+    int s = fwrite((void*)((unsigned char*)samples),1,size,fp);
537
+    if(s>0)
538
+	data_size += s;
539
+    return (!ferror(fp) ? s : -1);
540
+}
541
+
542
+AmAudioFileFormat* AmAudioFile::fileName2Fmt(const string& name)
543
+{
544
+    string ext = file_extension(name);
545
+    if(ext == ""){
546
+	ERROR("fileName2Fmt: file name has no extension (%s)",name.c_str());
547
+	return NULL;
548
+    }
549
+
550
+    iofmt = AmPlugIn::instance()->fileFormat("",ext);
551
+    if(!iofmt){
552
+	ERROR("fileName2Fmt: could not find a format with that extension: '%s'",ext.c_str());
553
+	return NULL;
554
+    }
555
+
556
+    return new AmAudioFileFormat(iofmt->name);
557
+}
558
+
559
+
560
+int AmAudioFileFormat::getCodecId()
561
+{
562
+  if(!name.empty()){
563
+      getSubtype();
564
+	if(p_subtype)
565
+	  return p_subtype->codec_id;
566
+  }
567
+    
568
+  return -1;
569
+}
570
+
571
+
572
+amci_payload_t* AmAudioRtpFormat::getPayloadP()
573
+{
574
+    if(!amci_pl)
575
+	amci_pl = AmPlugIn::instance()->payload(payload);
576
+
577
+    return amci_pl;
578
+}
579
+
580
+int AmAudioRtpFormat::getCodecId()
581
+{
582
+    amci_payload_t* pl = getPayloadP();
583
+    if(!pl){
584
+	ERROR("AmAudioRtpFormat::getCodecId: could not find payload %i\n",payload);
585
+	return -1;
586
+    }
587
+    else 
588
+	return pl->codec_id;
589
+}
590
+
0 591
new file mode 100644
... ...
@@ -0,0 +1,393 @@
1
+/*
2
+ * $Id: AmAudio.h,v 1.16.2.5 2005/08/31 13:54:29 rco Exp $
3
+ *
4
+ * Copyright (C) 2002-2003 Fhg Fokus
5
+ *
6
+ * This file is part of sems, a free SIP media server.
7
+ *
8
+ * sems is free software; you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation; either version 2 of the License, or
11
+ * (at your option) any later version
12
+ *
13
+ * For a license to use the ser 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
+#ifndef _AmAudio_h_
29
+#define _AmAudio_h_
30
+
31
+#include "AmThread.h"
32
+#include "amci/amci.h"
33
+#include "AmEventQueue.h"
34
+
35
+#include <stdio.h>
36
+
37
+#include <memory>
38
+using std::auto_ptr;
39
+#include <string>
40
+using std::string;
41
+
42
+
43
+class AmAudioEvent: public AmEvent
44
+{
45
+public:
46
+    enum EventType {
47
+	
48
+	noAudio, // Audio class has nothing to play and/or record anymore
49
+
50
+	// Audio input & output have been cleared: 
51
+	// !!! sent only from AmSession !!!
52
+	cleared  
53
+    };
54
+
55
+    AmAudioEvent(int id):AmEvent(id){}
56
+};
57
+
58
+
59
+/**
60
+ * Implements double buffering.
61
+ */
62
+
63
+class DblBuffer
64
+{
65
+    /** Buffer. */
66
+    unsigned char samples[AUDIO_BUFFER_SIZE * 2];
67
+    /** 0 for first buffer, 1 for the second. */
68
+    int active_buf;
69
+
70
+public:
71
+    /** Constructs a double buffer. */
72
+    DblBuffer();
73
+    /** Returns a pointer to the current front buffer. */
74
+    operator unsigned char*();
75
+    /** Returns a pointer to the current back buffer. */
76
+    unsigned char* back_buffer();
77
+    /** swaps front and back buffer. */
78
+    void swap();
79
+};
80
+
81
+struct amci_codec_t;
82
+struct amci_inoutfmt_t;
83
+struct amci_file_desc_t;
84
+struct amci_subtype_t;
85
+
86
+class AmAudio;
87
+
88
+/**
89
+ * Audio format structure.
90
+ * Holds a description of the format.
91
+ * @todo Create two child class: