summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/jabber/jingle/libjingle/talk/session
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commitbcb704366cb5e333a626c18c308c7e0448a8e69f (patch)
treef0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /kopete/protocols/jabber/jingle/libjingle/talk/session
downloadtdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz
tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kopete/protocols/jabber/jingle/libjingle/talk/session')
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am3
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am18
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc119
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h73
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc258
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h97
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc203
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h81
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc170
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h75
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h55
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h95
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc267
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h122
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc331
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h69
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc331
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h129
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h72
-rw-r--r--kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h111
20 files changed, 2679 insertions, 0 deletions
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am
new file mode 100644
index 00000000..6cfc5b24
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/Makefile.am
@@ -0,0 +1,3 @@
+noinst_HEADERS = receiver.h sessionsendtask.h
+SUBDIRS = phone
+
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am
new file mode 100644
index 00000000..b2acbf81
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/Makefile.am
@@ -0,0 +1,18 @@
+libcricketsessionphone_la_SOURCES = audiomonitor.cc \
+ channelmanager.cc \
+ voicechannel.cc \
+ call.cc \
+ phonesessionclient.cc \
+ linphonemediaengine.cc
+
+noinst_HEADERS = audiomonitor.h \
+ channelmanager.h \
+ linphonemediaengine.h \
+ mediaengine.h \
+ phonesessionclient.h \
+ voicechannel.h \
+ call.h \
+ mediachannel.h
+
+AM_CPPFLAGS = -DPOSIX $(ORTP_CFLAGS) $(ILBC_CFLAGS) -I$(srcdir)/../../../talk/third_party/mediastreamer -I$(srcdir)/../../.. $(GLIB_CFLAGS) $(SPEEX_CFLAGS)
+noinst_LTLIBRARIES = libcricketsessionphone.la
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc
new file mode 100644
index 00000000..c1b63d1b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.cc
@@ -0,0 +1,119 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/session/phone/audiomonitor.h"
+#include "talk/session/phone/voicechannel.h"
+#include <cassert>
+
+namespace cricket {
+
+const uint32 MSG_MONITOR_POLL = 1;
+const uint32 MSG_MONITOR_START = 2;
+const uint32 MSG_MONITOR_STOP = 3;
+const uint32 MSG_MONITOR_SIGNAL = 4;
+
+AudioMonitor::AudioMonitor(VoiceChannel *voice_channel, Thread *monitor_thread) {
+ voice_channel_ = voice_channel;
+ monitoring_thread_ = monitor_thread;
+ monitoring_ = false;
+}
+
+AudioMonitor::~AudioMonitor() {
+ voice_channel_->worker_thread()->Clear(this);
+ monitoring_thread_->Clear(this);
+}
+
+void AudioMonitor::Start(int milliseconds) {
+ rate_ = milliseconds;
+ if (rate_ < 100)
+ rate_ = 100;
+ voice_channel_->worker_thread()->Post(this, MSG_MONITOR_START);
+}
+
+void AudioMonitor::Stop() {
+ voice_channel_->worker_thread()->Post(this, MSG_MONITOR_STOP);
+}
+
+void AudioMonitor::OnMessage(Message *message) {
+ CritScope cs(&crit_);
+
+ switch (message->message_id) {
+ case MSG_MONITOR_START:
+ assert(Thread::Current() == voice_channel_->worker_thread());
+ if (!monitoring_) {
+ monitoring_ = true;
+ PollVoiceChannel();
+ }
+ break;
+
+ case MSG_MONITOR_STOP:
+ assert(Thread::Current() == voice_channel_->worker_thread());
+ if (monitoring_) {
+ monitoring_ = false;
+ voice_channel_->worker_thread()->Clear(this);
+ }
+ break;
+
+ case MSG_MONITOR_POLL:
+ assert(Thread::Current() == voice_channel_->worker_thread());
+ PollVoiceChannel();
+ break;
+
+ case MSG_MONITOR_SIGNAL:
+ {
+ assert(Thread::Current() == monitoring_thread_);
+ AudioInfo info = audio_info_;
+ crit_.Leave();
+ SignalUpdate(this, audio_info_);
+ crit_.Enter();
+ }
+ break;
+ }
+}
+
+void AudioMonitor::PollVoiceChannel() {
+ CritScope cs(&crit_);
+ assert(Thread::Current() == voice_channel_->worker_thread());
+
+ // Gather connection infos
+ audio_info_.input_level = voice_channel_->GetInputLevel_w();
+ audio_info_.output_level = voice_channel_->GetOutputLevel_w();
+
+ // Signal the monitoring thread, start another poll timer
+ monitoring_thread_->Post(this, MSG_MONITOR_SIGNAL);
+ voice_channel_->worker_thread()->PostDelayed(rate_, this, MSG_MONITOR_POLL);
+}
+
+VoiceChannel *AudioMonitor::voice_channel() {
+ return voice_channel_;
+}
+
+Thread *AudioMonitor::monitor_thread() {
+ return monitoring_thread_;
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h
new file mode 100644
index 00000000..96b95bd7
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/audiomonitor.h
@@ -0,0 +1,73 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CRICKET_PHONE_AUDIOMONITOR_H_
+#define _CRICKET_PHONE_AUDIOMONITOR_H_
+
+#include "talk/base/thread.h"
+#include "talk/base/sigslot.h"
+#include "talk/p2p/base/port.h"
+#include <vector>
+
+namespace cricket {
+
+class VoiceChannel;
+
+
+struct AudioInfo {
+ int input_level;
+ int output_level;
+};
+
+class AudioMonitor : public MessageHandler, public sigslot::has_slots<> {
+public:
+ AudioMonitor(VoiceChannel* voice_channel, Thread *monitor_thread);
+ ~AudioMonitor();
+
+ void Start(int cms);
+ void Stop();
+
+ VoiceChannel* voice_channel();
+ Thread *monitor_thread();
+
+ sigslot::signal2<AudioMonitor*, const AudioInfo&> SignalUpdate;
+
+protected:
+ void OnMessage(Message *message);
+ void PollVoiceChannel();
+
+ AudioInfo audio_info_;
+ VoiceChannel* voice_channel_;
+ Thread* monitoring_thread_;
+ CriticalSection crit_;
+ uint32 rate_;
+ bool monitoring_;
+};
+
+}
+
+#endif // _CRICKET_PHONE_AUDIOMONITOR_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc
new file mode 100644
index 00000000..31b12e92
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.cc
@@ -0,0 +1,258 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/thread.h"
+#include "talk/p2p/base/helpers.h"
+#include "talk/session/phone/call.h"
+
+namespace cricket {
+
+const uint32 MSG_CHECKAUTODESTROY = 1;
+
+Call::Call(PhoneSessionClient *session_client) : muted_(false) {
+ session_client_ = session_client;
+ id_ = CreateRandomId();
+}
+
+Call::~Call() {
+ while (sessions_.begin() != sessions_.end()) {
+ Session *session = sessions_[0];
+ RemoveSession(session);
+ session_client_->session_manager()->DestroySession(session);
+ }
+ Thread::Current()->Clear(this);
+}
+
+Session *Call::InitiateSession(const buzz::Jid &jid) {
+ Session *session = session_client_->CreateSession(this);
+ AddSession(session);
+ session->Initiate(jid.Str(), session_client_->CreateOfferSessionDescription());
+ return session;
+}
+
+void Call::AcceptSession(Session *session) {
+ std::vector<Session *>::iterator it;
+ it = std::find(sessions_.begin(), sessions_.end(), session);
+ assert(it != sessions_.end());
+ if (it != sessions_.end())
+ session->Accept(session_client_->CreateAcceptSessionDescription(session->remote_description()));
+}
+
+void Call::RedirectSession(Session *session, const buzz::Jid &to) {
+ std::vector<Session *>::iterator it;
+ it = std::find(sessions_.begin(), sessions_.end(), session);
+ assert(it != sessions_.end());
+ if (it != sessions_.end())
+ session->Redirect(to.Str());
+}
+
+void Call::RejectSession(Session *session) {
+ std::vector<Session *>::iterator it;
+ it = std::find(sessions_.begin(), sessions_.end(), session);
+ assert(it != sessions_.end());
+ if (it != sessions_.end())
+ session->Reject();
+}
+
+void Call::TerminateSession(Session *session) {
+ assert(std::find(sessions_.begin(), sessions_.end(), session) != sessions_.end());
+ std::vector<Session *>::iterator it;
+ it = std::find(sessions_.begin(), sessions_.end(), session);
+ if (it != sessions_.end())
+ (*it)->Terminate();
+}
+
+void Call::Terminate() {
+ // There may be more than one session to terminate
+ std::vector<Session *>::iterator it = sessions_.begin();
+ for (it = sessions_.begin(); it != sessions_.end(); it++)
+ TerminateSession(*it);
+}
+
+void Call::OnMessage(Message *message) {
+ switch (message->message_id) {
+ case MSG_CHECKAUTODESTROY:
+ // If no more sessions for this call, delete it
+ if (sessions_.size() == 0)
+ session_client_->DestroyCall(this);
+ break;
+ }
+}
+
+const std::vector<Session *> &Call::sessions() {
+ return sessions_;
+}
+
+void Call::AddSession(Session *session) {
+ // Add session to list, create voice channel for this session
+ sessions_.push_back(session);
+ session->SignalState.connect(this, &Call::OnSessionState);
+ session->SignalError.connect(this, &Call::OnSessionError);
+
+ VoiceChannel *channel = session_client_->channel_manager()->CreateVoiceChannel(session);
+ channel_map_[session->id()] = channel;
+
+ // If this call has the focus, enable this channel
+ if (session_client_->GetFocus() == this)
+ channel->Enable(true);
+
+ // Signal client
+ SignalAddSession(this, session);
+}
+
+void Call::RemoveSession(Session *session) {
+ // Remove session from list
+ std::vector<Session *>::iterator it_session;
+ it_session = std::find(sessions_.begin(), sessions_.end(), session);
+ if (it_session == sessions_.end())
+ return;
+ sessions_.erase(it_session);
+
+ // Destroy session channel
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = it_channel->second;
+ channel_map_.erase(it_channel);
+ session_client_->channel_manager()->DestroyVoiceChannel(channel);
+ }
+
+ // Signal client
+ SignalRemoveSession(this, session);
+
+ // The call auto destroys when the lass session is removed
+ Thread::Current()->Post(this, MSG_CHECKAUTODESTROY);
+}
+
+VoiceChannel* Call::GetChannel(Session* session) {
+ std::map<SessionID, VoiceChannel *>::iterator it = channel_map_.find(session->id());
+ assert(it != channel_map_.end());
+ return it->second;
+}
+
+void Call::EnableChannels(bool enable) {
+ std::vector<Session *>::iterator it;
+ for (it = sessions_.begin(); it != sessions_.end(); it++) {
+ VoiceChannel *channel = channel_map_[(*it)->id()];
+ if (channel != NULL)
+ channel->Enable(enable);
+ }
+}
+
+void Call::Mute(bool mute) {
+ muted_ = mute;
+ std::vector<Session *>::iterator it;
+ for (it = sessions_.begin(); it != sessions_.end(); it++) {
+ VoiceChannel *channel = channel_map_[(*it)->id()];
+ if (channel != NULL)
+ channel->Mute(mute);
+ }
+}
+
+void Call::Join(Call *call, bool enable) {
+ while (call->sessions_.size() != 0) {
+ // Move session
+ Session *session = call->sessions_[0];
+ call->sessions_.erase(call->sessions_.begin());
+ sessions_.push_back(session);
+ session->SignalState.connect(this, &Call::OnSessionState);
+ session->SignalError.connect(this, &Call::OnSessionError);
+
+ // Move channel
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = call->channel_map_.find(session->id());
+ if (it_channel != call->channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ call->channel_map_.erase(it_channel);
+ channel_map_[session->id()] = channel;
+ channel->Enable(enable);
+ }
+ }
+}
+
+void Call::StartConnectionMonitor(Session *session, int cms) {
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ channel->SignalConnectionMonitor.connect(this, &Call::OnConnectionMonitor);
+ channel->StartConnectionMonitor(cms);
+ }
+}
+
+void Call::StopConnectionMonitor(Session *session) {
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ channel->StopConnectionMonitor();
+ channel->SignalConnectionMonitor.disconnect(this);
+ }
+}
+
+void Call::StartAudioMonitor(Session *session, int cms) {
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ channel->SignalAudioMonitor.connect(this, &Call::OnAudioMonitor);
+ channel->StartAudioMonitor(cms);
+ }
+}
+
+void Call::StopAudioMonitor(Session *session) {
+ std::map<SessionID, VoiceChannel *>::iterator it_channel;
+ it_channel = channel_map_.find(session->id());
+ if (it_channel != channel_map_.end()) {
+ VoiceChannel *channel = (*it_channel).second;
+ channel->StopAudioMonitor();
+ channel->SignalAudioMonitor.disconnect(this);
+ }
+}
+
+
+void Call::OnConnectionMonitor(VoiceChannel *channel, const std::vector<ConnectionInfo> &infos) {
+ SignalConnectionMonitor(this, channel->session(), infos);
+}
+
+void Call::OnAudioMonitor(VoiceChannel *channel, const AudioInfo& info) {
+ SignalAudioMonitor(this, channel->session(), info);
+}
+
+uint32 Call::id() {
+ return id_;
+}
+
+void Call::OnSessionState(Session *session, Session::State state) {
+ SignalSessionState(this, session, state);
+}
+
+void Call::OnSessionError(Session *session, Session::Error error) {
+ SignalSessionError(this, session, error);
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h
new file mode 100644
index 00000000..209e13c9
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/call.h
@@ -0,0 +1,97 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CALL_H_
+#define _CALL_H_
+
+#include "talk/base/messagequeue.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/client/socketmonitor.h"
+#include "talk/xmpp/jid.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/session/phone/voicechannel.h"
+#include "talk/session/phone/audiomonitor.h"
+
+#include <map>
+#include <vector>
+
+namespace cricket {
+
+class PhoneSessionClient;
+
+class Call : public MessageHandler, public sigslot::has_slots<> {
+public:
+ Call(PhoneSessionClient *session_client);
+ ~Call();
+
+ Session *InitiateSession(const buzz::Jid &jid);
+ void AcceptSession(Session *session);
+ void RedirectSession(Session *session, const buzz::Jid &to);
+ void RejectSession(Session *session);
+ void TerminateSession(Session *session);
+ void Terminate();
+ void StartConnectionMonitor(Session *session, int cms);
+ void StopConnectionMonitor(Session *session);
+ void StartAudioMonitor(Session *session, int cms);
+ void StopAudioMonitor(Session *session);
+ void Mute(bool mute);
+
+ const std::vector<Session *> &sessions();
+ uint32 id();
+ bool muted() const { return muted_; }
+
+ sigslot::signal2<Call *, Session *> SignalAddSession;
+ sigslot::signal2<Call *, Session *> SignalRemoveSession;
+ sigslot::signal3<Call *, Session *, Session::State> SignalSessionState;
+ sigslot::signal3<Call *, Session *, Session::Error> SignalSessionError;
+ sigslot::signal3<Call *, Session *, const std::vector<ConnectionInfo> &> SignalConnectionMonitor;
+ sigslot::signal3<Call *, Session *, const AudioInfo&> SignalAudioMonitor;
+
+private:
+ void OnMessage(Message *message);
+ void OnSessionState(Session *session, Session::State state);
+ void OnSessionError(Session *session, Session::Error error);
+ void AddSession(Session *session);
+ void RemoveSession(Session *session);
+ void EnableChannels(bool enable);
+ void Join(Call *call, bool enable);
+ void OnConnectionMonitor(VoiceChannel *channel, const std::vector<ConnectionInfo> &infos);
+ void OnAudioMonitor(VoiceChannel *channel, const AudioInfo& info);
+ VoiceChannel* GetChannel(Session* session);
+
+ uint32 id_;
+ PhoneSessionClient *session_client_;
+ std::vector<Session *> sessions_;
+ std::map<SessionID, VoiceChannel *> channel_map_;
+ bool muted_;
+
+ friend class PhoneSessionClient;
+};
+
+}
+
+#endif // _CALL_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc
new file mode 100644
index 00000000..98634b12
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.cc
@@ -0,0 +1,203 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef HAVE_GIPS
+#include "talk/session/phone/gipsmediaengine.h"
+#else
+#include "talk/session/phone/linphonemediaengine.h"
+#endif
+#include "channelmanager.h"
+#include <cassert>
+#include <iostream>
+namespace cricket {
+
+const uint32 MSG_CREATEVOICECHANNEL = 1;
+const uint32 MSG_DESTROYVOICECHANNEL = 2;
+const uint32 MSG_SETAUDIOOPTIONS = 3;
+
+ChannelManager::ChannelManager(Thread *worker_thread) {
+#ifdef HAVE_GIPS
+ media_engine_ = new GipsMediaEngine();
+#else
+ media_engine_ = new LinphoneMediaEngine();
+#endif
+ worker_thread_ = worker_thread;
+ initialized_ = false;
+ Init();
+}
+
+ChannelManager::~ChannelManager() {
+ Exit();
+}
+
+MediaEngine *ChannelManager::media_engine() {
+ return media_engine_;
+}
+
+bool ChannelManager::Init() {
+ initialized_ = media_engine_->Init();
+ return initialized_;
+}
+
+void ChannelManager::Exit() {
+ if (!initialized_)
+ return;
+
+ // Need to destroy the voice channels
+
+ while (true) {
+ crit_.Enter();
+ VoiceChannel *channel = NULL;
+ if (channels_.begin() != channels_.end())
+ channel = channels_[0];
+ crit_.Leave();
+ if (channel == NULL)
+ break;
+ delete channel;
+ }
+ media_engine_->Terminate();
+}
+
+struct CreateParams {
+ Session *session;
+ VoiceChannel *channel;
+};
+
+VoiceChannel *ChannelManager::CreateVoiceChannel(Session *session) {
+ CreateParams params;
+ params.session = session;
+ params.channel = NULL;
+ TypedMessageData<CreateParams *> data(&params);
+ worker_thread_->Send(this, MSG_CREATEVOICECHANNEL, &data);
+ return params.channel;
+}
+
+VoiceChannel *ChannelManager::CreateVoiceChannel_w(Session *session) {
+ CritScope cs(&crit_);
+
+ // This is ok to alloc from a thread other than the worker thread
+ assert(initialized_);
+ MediaChannel *channel = media_engine_->CreateChannel();
+ if (channel == NULL)
+ return NULL;
+
+ VoiceChannel *voice_channel = new VoiceChannel(this, session, channel);
+ channels_.push_back(voice_channel);
+ return voice_channel;
+}
+
+void ChannelManager::DestroyVoiceChannel(VoiceChannel *voice_channel) {
+ TypedMessageData<VoiceChannel *> data(voice_channel);
+ worker_thread_->Send(this, MSG_DESTROYVOICECHANNEL, &data);
+}
+
+void ChannelManager::DestroyVoiceChannel_w(VoiceChannel *voice_channel) {
+ CritScope cs(&crit_);
+ // Destroy voice channel.
+ assert(initialized_);
+ std::vector<VoiceChannel *>::iterator it = std::find(channels_.begin(),
+ channels_.end(), voice_channel);
+ assert(it != channels_.end());
+ if (it == channels_.end())
+ return;
+
+ channels_.erase(it);
+ MediaChannel *channel = voice_channel->channel();
+ delete voice_channel;
+ delete channel;
+}
+
+void ChannelManager::SetAudioOptions(bool auto_gain_control, int wave_in_device,
+ int wave_out_device) {
+ AudioOptions options;
+ options.auto_gain_control = auto_gain_control;
+ options.wave_in_device = wave_in_device;
+ options.wave_out_device = wave_out_device;
+ TypedMessageData<AudioOptions> data(options);
+ worker_thread_->Send(this, MSG_SETAUDIOOPTIONS, &data);
+}
+
+void ChannelManager::SetAudioOptions_w(AudioOptions options) {
+ assert(worker_thread_ == Thread::Current());
+
+ // Set auto gain control on
+ if (media_engine_->SetAudioOptions(options.auto_gain_control?MediaEngine::AUTO_GAIN_CONTROL:0) != 0) {
+ // TODO: We need to log these failures.
+ }
+
+ // Set the audio devices
+ // This will fail if audio is already playing. Stop all of the media
+ // start it up again after changing the setting.
+ {
+ CritScope cs(&crit_);
+ for (VoiceChannels::iterator it = channels_.begin();
+ it < channels_.end();
+ ++it) {
+ (*it)->PauseMedia_w();
+ }
+
+ if (media_engine_->SetSoundDevices(options.wave_in_device, options.wave_out_device) == -1) {
+ // TODO: We need to log these failures.
+ }
+
+ for (VoiceChannels::iterator it = channels_.begin();
+ it < channels_.end();
+ ++it) {
+ (*it)->UnpauseMedia_w();
+ }
+ }
+}
+
+Thread *ChannelManager::worker_thread() {
+ return worker_thread_;
+}
+
+void ChannelManager::OnMessage(Message *message) {
+ switch (message->message_id) {
+ case MSG_CREATEVOICECHANNEL:
+ {
+ TypedMessageData<CreateParams *> *data = static_cast<TypedMessageData<CreateParams *> *>(message->pdata);
+ data->data()->channel = CreateVoiceChannel_w(data->data()->session);
+ }
+ break;
+
+ case MSG_DESTROYVOICECHANNEL:
+ {
+ TypedMessageData<VoiceChannel *> *data = static_cast<TypedMessageData<VoiceChannel *> *>(message->pdata);
+ DestroyVoiceChannel_w(data->data());
+ }
+ break;
+ case MSG_SETAUDIOOPTIONS:
+ {
+ TypedMessageData<AudioOptions> *data = static_cast<TypedMessageData<AudioOptions> *>(message->pdata);
+ SetAudioOptions_w(data->data());
+ }
+ break;
+ }
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h
new file mode 100644
index 00000000..7200f75e
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/channelmanager.h
@@ -0,0 +1,81 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CHANNELMANAGER_H_
+#define _CHANNELMANAGER_H_
+
+#include "talk/base/thread.h"
+#include "talk/base/criticalsection.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/base/p2psocket.h"
+#include "talk/session/phone/voicechannel.h"
+#include "talk/session/phone/mediaengine.h"
+#include <vector>
+
+namespace cricket {
+
+class VoiceChannel;
+
+class ChannelManager : public MessageHandler {
+public:
+ ChannelManager(Thread *worker_thread);
+ ~ChannelManager();
+
+ VoiceChannel *CreateVoiceChannel(Session *session);
+ void DestroyVoiceChannel(VoiceChannel *voice_channel);
+ void SetAudioOptions(bool auto_gain_control, int wave_in_device,
+ int wave_out_device);
+
+ MediaEngine *media_engine();
+ Thread *worker_thread();
+
+private:
+ VoiceChannel *CreateVoiceChannel_w(Session *session);
+ void DestroyVoiceChannel_w(VoiceChannel *voice_channel);
+ void OnMessage(Message *message);
+ bool Init();
+ void Exit();
+
+ struct AudioOptions {
+ bool auto_gain_control;
+ int wave_in_device;
+ int wave_out_device;
+ };
+ void SetAudioOptions_w(AudioOptions options);
+
+ Thread *worker_thread_;
+ MediaEngine *media_engine_;
+ bool initialized_;
+ CriticalSection crit_;
+
+ typedef std::vector<VoiceChannel*> VoiceChannels;
+ VoiceChannels channels_;
+};
+
+}
+
+#endif // _CHANNELMANAGER_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc
new file mode 100644
index 00000000..7d2305dc
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.cc
@@ -0,0 +1,170 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// LinphoneMediaEngine is a Linphone implementation of MediaEngine
+extern "C" {
+#include "talk/third_party/mediastreamer/mediastream.h"
+#ifdef HAVE_ILBC
+#include "talk/third_party/mediastreamer/msilbcdec.h"
+#endif
+#ifdef HAVE_SPEEX
+#include "talk/third_party/mediastreamer/msspeexdec.h"
+#endif
+}
+#include <ortp/ortp.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <iostream>
+#include "talk/session/phone/linphonemediaengine.h"
+
+using namespace cricket;
+
+void *thread_function(void *data)
+{
+ LinphoneMediaChannel *mc =(LinphoneMediaChannel*) data;
+ while (mc->dying() == false) {
+ MediaChannel::NetworkInterface *iface = mc->network_interface();
+ char *buf[2048];
+ int len;
+ len = read(mc->fd(), buf, sizeof(buf));
+ if (iface && (mc->mute()==FALSE))
+ iface->SendPacket(buf, len);
+ }
+}
+
+LinphoneMediaChannel::LinphoneMediaChannel() {
+ pt_ = 102;
+ dying_ = false;
+ pthread_attr_t attr;
+ audio_stream_ = NULL;
+
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+ sockaddr.sin_port = htons(3000);
+ fd_ = socket(PF_INET, SOCK_DGRAM, 0);
+ fcntl(fd_, F_SETFL, 0, O_NONBLOCK);
+ bind (fd_,(struct sockaddr*)&sockaddr, sizeof(sockaddr));
+
+ pthread_attr_init(&attr);
+ pthread_create(&thread_, &attr, &thread_function, this);
+}
+
+LinphoneMediaChannel::~LinphoneMediaChannel() {
+ dying_ = true;
+ pthread_join(thread_, NULL);
+ audio_stream_stop(audio_stream_);
+ close(fd_);
+}
+
+void LinphoneMediaChannel::SetCodec(const char *codec) {
+ if (!strcmp(codec, "iLBC"))
+ pt_ = 102;
+ else if (!strcmp(codec, "speex"))
+ pt_ = 110;
+ else
+ pt_ = 0;
+ if (audio_stream_)
+ audio_stream_stop(audio_stream_);
+ audio_stream_ = audio_stream_start(&av_profile, 2000, "127.0.0.1", 3000, pt_, 250);
+}
+
+void LinphoneMediaChannel::OnPacketReceived(const void *data, int len) {
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = AF_INET;
+ struct hostent *host = gethostbyname("localhost");
+ memcpy(&sockaddr.sin_addr.s_addr, host->h_addr, host->h_length);
+ sockaddr.sin_port = htons(2000);
+
+ char buf[2048];
+ memcpy(buf, data, len);
+
+ if (buf[1] == pt_) {
+ } else if (buf[1] == 13) {
+ } else if (buf[1] == 102) {
+ SetCodec("iLBC");
+ } else if (buf[1] == 110) {
+ SetCodec("speex");
+ } else if (buf[1] == 0) {
+ SetCodec("PCMU");
+ }
+
+ if (play_ && buf[1] != 13)
+ sendto(fd_, buf, len, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+}
+
+void LinphoneMediaChannel::SetPlayout(bool playout) {
+ play_ = playout;
+}
+
+void LinphoneMediaChannel::SetSend(bool send) {
+ mute_ = !send;
+}
+
+float LinphoneMediaChannel::GetCurrentQuality() {}
+int LinphoneMediaChannel::GetOutputLevel() {}
+
+LinphoneMediaEngine::LinphoneMediaEngine() {}
+LinphoneMediaEngine::~LinphoneMediaEngine() {}
+
+static void null_log_handler(const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data) {
+}
+
+bool LinphoneMediaEngine::Init() {
+ g_log_set_handler("MediaStreamer", G_LOG_LEVEL_MASK, null_log_handler, NULL);
+ g_log_set_handler("oRTP", G_LOG_LEVEL_MASK, null_log_handler, NULL);
+ g_log_set_handler("oRTP-stats", G_LOG_LEVEL_MASK, null_log_handler, NULL);
+ ortp_init();
+ ms_init();
+
+#ifdef HAVE_SPEEX
+ ms_speex_codec_init();
+ rtp_profile_set_payload(&av_profile, 110, &speex_wb);
+ codecs_.push_back(Codec(110, "speex", 8));
+#endif
+
+#ifdef HAVE_ILBC
+ ms_ilbc_codec_init();
+ rtp_profile_set_payload(&av_profile, 102, &payload_type_ilbc);
+ codecs_.push_back(Codec(102, "iLBC", 4));
+#endif
+
+ rtp_profile_set_payload(&av_profile, 0, &pcmu8000);
+ codecs_.push_back(Codec(0, "PCMU", 2));
+
+return true;
+}
+
+void LinphoneMediaEngine::Terminate() {
+
+}
+
+MediaChannel *LinphoneMediaEngine::CreateChannel() {
+ return new LinphoneMediaChannel();
+}
+
+int LinphoneMediaEngine::SetAudioOptions(int options) {}
+int LinphoneMediaEngine::SetSoundDevices(int wave_in_device, int wave_out_device) {}
+
+float LinphoneMediaEngine::GetCurrentQuality() {}
+int LinphoneMediaEngine::GetInputLevel() {}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h
new file mode 100644
index 00000000..ee16d2ee
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/linphonemediaengine.h
@@ -0,0 +1,75 @@
+/*
+ * Jingle call example
+ * Copyright 2004--2005, Google Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+// LinphoneMediaEngine is a Linphone implementation of MediaEngine
+
+#ifndef TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_
+#define TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_
+
+extern "C" {
+#include "talk/third_party/mediastreamer/mediastream.h"
+}
+#include "talk/session/phone/mediaengine.h"
+
+namespace cricket {
+
+class LinphoneMediaChannel : public MediaChannel {
+ public:
+ LinphoneMediaChannel();
+ virtual ~LinphoneMediaChannel();
+ virtual void SetCodec(const char *codec);
+ virtual void OnPacketReceived(const void *data, int len);
+
+ virtual void SetPlayout(bool playout);
+ virtual void SetSend(bool send);
+
+ virtual float GetCurrentQuality();
+ virtual int GetOutputLevel();
+ int fd() {return fd_;}
+ bool mute() {return mute_;}
+ bool dying() {return dying_;}
+ private:
+ AudioStream *audio_stream_;
+ pthread_t thread_;
+ int fd_;
+ int pt_;
+ bool dying_;
+ bool mute_;
+ bool play_;
+};
+
+class LinphoneMediaEngine : public MediaEngine {
+ public:
+ LinphoneMediaEngine();
+ ~LinphoneMediaEngine();
+ virtual bool Init();
+ virtual void Terminate();
+
+ virtual MediaChannel *CreateChannel();
+
+ virtual int SetAudioOptions(int options);
+ virtual int SetSoundDevices(int wave_in_device, int wave_out_device);
+
+ virtual float GetCurrentQuality();
+ virtual int GetInputLevel();
+};
+
+} // namespace cricket
+
+#endif // TALK_SESSION_PHONE_LINPHONEMEDIAENGINE_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h
new file mode 100644
index 00000000..db2f9654
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediachannel.h
@@ -0,0 +1,55 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TALK_SESSION_PHONE_MEDIACHANNEL_H_
+#define TALK_SESSION_PHONE_MEDIACHANNEL_H_
+
+namespace cricket {
+
+class MediaChannel {
+ public:
+ class NetworkInterface {
+ public:
+ virtual void SendPacket(const void *data, size_t len) = 0;
+ };
+ MediaChannel() {network_interface_ = NULL;}
+ virtual ~MediaChannel() {};
+ void SetInterface(NetworkInterface *iface) {network_interface_ = iface;}
+ virtual void SetCodec(const char *codec) = 0;
+ virtual void OnPacketReceived(const void *data, int len) = 0;
+ virtual void SetPlayout(bool playout) = 0;
+ virtual void SetSend(bool send) = 0;
+ virtual float GetCurrentQuality() = 0;
+ virtual int GetOutputLevel() = 0;
+ NetworkInterface *network_interface() {return network_interface_;}
+ protected:
+ NetworkInterface *network_interface_;
+};
+
+}; // namespace cricket
+
+#endif // TALK_SESSION_PHONE_MEDIACHANNEL_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h
new file mode 100644
index 00000000..fa07d2ec
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/mediaengine.h
@@ -0,0 +1,95 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// MediaEngine is an abstraction of a media engine which can be subclassed
+// to support different media componentry backends.
+
+#ifndef TALK_SESSION_PHONE_MEDIAENGINE_H_
+#define TALK_SESSION_PHONE_MEDIAENGINE_H_
+
+#include <string>
+#include <vector>
+#include "mediachannel.h"
+
+namespace cricket {
+
+class MediaEngine {
+ public:
+
+ struct Codec {
+ int id;
+ std::string name;
+ int preference;
+ // Creates a codec with the given parameters.
+ Codec(int pt, const std::string& nm, int pr) : id(pt), name(nm), preference(pr) {}
+ // Ranks codecs by their preferences.
+ bool operator <(const Codec& c) const { return preference > c.preference; }
+ };
+
+ // Bitmask flags for options that may be supported by the media engine implementation
+ enum MediaEngineOptions {
+ AUTO_GAIN_CONTROL = 1 << 1,
+ };
+
+ MediaEngine() {}
+
+ // Initialize
+ virtual bool Init() = 0;
+ virtual void Terminate() = 0;
+ virtual MediaChannel *CreateChannel() = 0;
+
+ virtual int SetAudioOptions(int options) = 0;
+ virtual int SetSoundDevices(int wave_in_device, int wave_out_device) = 0;
+ virtual int GetInputLevel() = 0;
+
+ std::vector<Codec> &codecs() { return codecs_; }
+
+ bool FindCodec(const char* codec) {
+ for (std::vector<Codec>::iterator i = codecs_.begin(); i < codecs_.end(); i++) {
+ if ((*i).name == codec)
+ return true;
+ }
+ return false;
+ }
+
+ bool GetCodecPreference (const char *codec, int & preference) {
+ for (std::vector<Codec>::iterator i = codecs_.begin(); i < codecs_.end(); i++) {
+ if ((*i).name == codec) {
+ preference = (*i).preference;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ protected:
+ std::vector<Codec> codecs_;
+};
+
+} // namespace cricket
+
+#endif // TALK_SESSION_PHONE_MEDIAENGINE_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc
new file mode 100644
index 00000000..d8a31df2
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.cc
@@ -0,0 +1,267 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/base/logging.h"
+#include "talk/session/receiver.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/xmllite/qname.h"
+namespace {
+
+const std::string NS_PHONE("http://www.google.com/session/phone");
+const std::string NS_EMPTY("");
+
+const buzz::QName QN_PHONE_DESCRIPTION(true, NS_PHONE, "description");
+const buzz::QName QN_PHONE_PAYLOADTYPE(true, NS_PHONE, "payload-type");
+const buzz::QName QN_PHONE_PAYLOADTYPE_ID(true, NS_EMPTY, "id");
+const buzz::QName QN_PHONE_PAYLOADTYPE_NAME(true, NS_EMPTY, "name");
+
+}
+
+namespace cricket {
+
+PhoneSessionClient::PhoneSessionClient(const buzz::Jid& jid,
+ SessionManager *manager) : jid_(jid), SessionClient(manager) {
+
+ // No call to start, and certainly no call with focus
+ focus_call_ = NULL;
+
+ // Start up the channel manager on a worker thread
+ channel_manager_ = new ChannelManager(session_manager_->worker_thread());
+}
+
+PhoneSessionClient::~PhoneSessionClient() {
+ // Destroy all calls
+ std::map<uint32, Call *>::iterator it;
+ while (calls_.begin() != calls_.end()) {
+ std::map<uint32, Call *>::iterator it = calls_.begin();
+ DestroyCall((*it).second);
+ }
+
+ // Delete channel manager. This will wait for the channels to exit
+ delete channel_manager_;
+}
+
+const std::string &PhoneSessionClient::GetSessionDescriptionName() {
+ return NS_PHONE;
+}
+
+PhoneSessionDescription* PhoneSessionClient::CreateOfferSessionDescription() {
+ PhoneSessionDescription* session_desc = new PhoneSessionDescription();
+
+ MediaEngine *me = channel_manager_->media_engine();
+ std::vector<MediaEngine::Codec> codecs = me->codecs();
+ std::vector<MediaEngine::Codec>::iterator i;
+ for (i = codecs.begin(); i < codecs.end(); i++)
+ session_desc->AddCodec(*i);
+
+ session_desc->Sort();
+ return session_desc;
+}
+
+PhoneSessionDescription* PhoneSessionClient::CreateAcceptSessionDescription(const SessionDescription* offer) {
+ const PhoneSessionDescription* offer_desc =
+ static_cast<const PhoneSessionDescription*>(offer);
+ PhoneSessionDescription* accept_desc = new PhoneSessionDescription();
+ std::vector<MediaEngine::Codec> codecs = channel_manager_->media_engine()->codecs();
+ std::vector<MediaEngine::Codec>::iterator iter;
+ for (unsigned int i = 0; i < offer_desc->codecs().size(); ++i) {
+ for (iter = codecs.begin(); iter < codecs.end(); iter++) {
+ if ((*iter).name == offer_desc->codecs()[i].name)
+ accept_desc->AddCodec(*iter);
+ }
+ }
+
+ accept_desc->Sort();
+ return accept_desc;
+}
+
+bool PhoneSessionClient::FindMediaCodec(MediaEngine* me,
+ const PhoneSessionDescription* desc,
+ const char** codec) {
+ for (size_t i = 0; i < desc->codecs().size(); ++i) {
+ if (me->FindCodec(desc->codecs()[i].name.c_str()))
+ *codec = desc->codecs()[i].name.c_str();
+ return true;
+ }
+
+ return false;
+}
+
+const SessionDescription *PhoneSessionClient::CreateSessionDescription(const buzz::XmlElement *element) {
+ PhoneSessionDescription* desc = new PhoneSessionDescription();
+
+ const buzz::XmlElement* payload_type = element->FirstNamed(QN_PHONE_PAYLOADTYPE);
+ int num_payload_types = 0;
+
+ while (payload_type) {
+ if (payload_type->HasAttr(QN_PHONE_PAYLOADTYPE_ID) &&
+ payload_type->HasAttr(QN_PHONE_PAYLOADTYPE_NAME)) {
+ int id = atoi(payload_type->Attr(QN_PHONE_PAYLOADTYPE_ID).c_str());
+ int pref = 0;
+ std::string name = payload_type->Attr(QN_PHONE_PAYLOADTYPE_NAME);
+ desc->AddCodec(MediaEngine::Codec(id, name, 0));
+ }
+
+ payload_type = payload_type->NextNamed(QN_PHONE_PAYLOADTYPE);
+ num_payload_types += 1;
+ }
+
+ // For backward compatability, we can assume the other client is (an old
+ // version of Talk) if it has no payload types at all.
+ if (num_payload_types == 0) {
+ desc->AddCodec(MediaEngine::Codec(103, "ISAC", 1));
+ desc->AddCodec(MediaEngine::Codec(0, "PCMU", 0));
+ }
+
+ return desc;
+}
+
+buzz::XmlElement *PhoneSessionClient::TranslateSessionDescription(const SessionDescription *_session_desc) {
+ const PhoneSessionDescription* session_desc =
+ static_cast<const PhoneSessionDescription*>(_session_desc);
+ buzz::XmlElement* description = new buzz::XmlElement(QN_PHONE_DESCRIPTION, true);
+
+ for (size_t i = 0; i < session_desc->codecs().size(); ++i) {
+ buzz::XmlElement* payload_type = new buzz::XmlElement(QN_PHONE_PAYLOADTYPE, true);
+
+ char buf[32];
+ sprintf(buf, "%d", session_desc->codecs()[i].id);
+ payload_type->AddAttr(QN_PHONE_PAYLOADTYPE_ID, buf);
+
+ payload_type->AddAttr(QN_PHONE_PAYLOADTYPE_NAME,
+ session_desc->codecs()[i].name.c_str());
+
+ description->AddElement(payload_type);
+ }
+
+ return description;
+}
+
+Call *PhoneSessionClient::CreateCall() {
+ Call *call = new Call(this);
+ calls_[call->id()] = call;
+ SignalCallCreate(call);
+ return call;
+}
+
+void PhoneSessionClient::OnSessionCreate(Session *session, bool received_initiate) {
+ if (received_initiate) {
+ session->SignalState.connect(this, &PhoneSessionClient::OnSessionState);
+
+ Call *call = CreateCall();
+ session_map_[session->id()] = call;
+ call->AddSession(session);
+ }
+}
+
+void PhoneSessionClient::OnSessionState(Session *session, Session::State state) {
+ if (state == Session::STATE_RECEIVEDINITIATE) {
+ // If our accept would have no codecs, then we must reject this call.
+ PhoneSessionDescription* accept_desc =
+ CreateAcceptSessionDescription(session->remote_description());
+ if (accept_desc->codecs().size() == 0) {
+ // TODO: include an error description with the rejection.
+ session->Reject();
+ }
+ delete accept_desc;
+ }
+}
+
+void PhoneSessionClient::DestroyCall(Call *call) {
+ // Change focus away, signal destruction
+
+ if (call == focus_call_)
+ SetFocus(NULL);
+ SignalCallDestroy(call);
+
+ // Remove it from calls_ map and delete
+
+ std::map<uint32, Call *>::iterator it = calls_.find(call->id());
+ if (it != calls_.end())
+ calls_.erase(it);
+
+ delete call;
+}
+
+void PhoneSessionClient::OnSessionDestroy(Session *session) {
+ // Find the call this session is in, remove it
+
+ std::map<SessionID, Call *>::iterator it = session_map_.find(session->id());
+ assert(it != session_map_.end());
+ if (it != session_map_.end()) {
+ Call *call = (*it).second;
+ session_map_.erase(it);
+ call->RemoveSession(session);
+ }
+}
+
+Call *PhoneSessionClient::GetFocus() {
+ return focus_call_;
+}
+
+void PhoneSessionClient::SetFocus(Call *call) {
+ Call *old_focus_call = focus_call_;
+ if (focus_call_ != call) {
+ if (focus_call_ != NULL)
+ focus_call_->EnableChannels(false);
+ focus_call_ = call;
+ if (focus_call_ != NULL)
+ focus_call_->EnableChannels(true);
+ SignalFocus(focus_call_, old_focus_call);
+ }
+}
+
+void PhoneSessionClient::JoinCalls(Call *call_to_join, Call *call) {
+ // Move all sessions from call to call_to_join, delete call.
+ // If call_to_join has focus, added sessions should have enabled channels.
+
+ if (focus_call_ == call)
+ SetFocus(NULL);
+ call_to_join->Join(call, focus_call_ == call_to_join);
+ DestroyCall(call);
+}
+
+Session *PhoneSessionClient::CreateSession(Call *call) {
+ Session *session = session_manager_->CreateSession(
+ GetSessionDescriptionName(), jid().Str());
+ session_map_[session->id()] = call;
+ return session;
+}
+
+ChannelManager *PhoneSessionClient::channel_manager() {
+ return channel_manager_;
+}
+
+const buzz::Jid &PhoneSessionClient::jid() const {
+ return jid_;
+}
+
+const buzz::Jid &PhoneSessionClient::GetJid() const {
+ return jid_;
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h
new file mode 100644
index 00000000..150bf34b
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/phonesessionclient.h
@@ -0,0 +1,122 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _PHONESESSIONCLIENT_H_
+#define _PHONESESSIONCLIENT_H_
+
+#include "talk/session/phone/call.h"
+#include "talk/session/phone/channelmanager.h"
+#include "talk/base/sigslot.h"
+#include "talk/base/messagequeue.h"
+#include "talk/base/thread.h"
+#include "talk/p2p/client/sessionclient.h"
+#include "talk/p2p/base/sessionmanager.h"
+#include "talk/p2p/base/session.h"
+#include "talk/p2p/base/sessiondescription.h"
+#include "talk/xmpp/xmppclient.h"
+#include <map>
+
+namespace cricket {
+
+class Call;
+class PhoneSessionDescription;
+
+class PhoneSessionClient : public SessionClient {
+public:
+ PhoneSessionClient(const buzz::Jid& jid, SessionManager *manager);
+ ~PhoneSessionClient();
+
+ const buzz::Jid &jid() const;
+
+ Call *CreateCall();
+ void DestroyCall(Call *call);
+
+ Call *GetFocus();
+ void SetFocus(Call *call);
+
+ void JoinCalls(Call *call_to_join, Call *call);
+
+ void SetAudioOptions(bool auto_gain_control, int wave_in_device,
+ int wave_out_device) {
+ if (channel_manager_)
+ channel_manager_->SetAudioOptions(auto_gain_control, wave_in_device,
+ wave_out_device);
+ }
+
+ sigslot::signal2<Call *, Call *> SignalFocus;
+ sigslot::signal1<Call *> SignalCallCreate;
+ sigslot::signal1<Call *> SignalCallDestroy;
+
+ PhoneSessionDescription* CreateOfferSessionDescription();
+ PhoneSessionDescription* CreateAcceptSessionDescription(const SessionDescription* offer);
+
+ // Returns our preference for the given codec.
+ static int GetMediaCodecPreference(const char* name);
+
+ // Returns the name of the first codec in the description that
+ // is found. Return value is false if none was found.
+ static bool FindMediaCodec(MediaEngine* gips,
+ const PhoneSessionDescription* desc,
+ const char **codec);
+
+private:
+ void OnSessionCreate(Session *session, bool received_initiate);
+ void OnSessionState(Session *session, Session::State state);
+ void OnSessionDestroy(Session *session);
+ const SessionDescription *CreateSessionDescription(const buzz::XmlElement *element);
+ buzz::XmlElement *TranslateSessionDescription(const SessionDescription *description);
+ const std::string &GetSessionDescriptionName();
+ const buzz::Jid &GetJid() const;
+ Session *CreateSession(Call *call);
+ ChannelManager *channel_manager();
+
+ buzz::Jid jid_;
+ Call *focus_call_;
+ ChannelManager *channel_manager_;
+ std::map<uint32, Call *> calls_;
+ std::map<SessionID, Call *> session_map_;
+
+ friend class Call;
+};
+
+class PhoneSessionDescription: public SessionDescription {
+public:
+ // Returns the list of codecs sorted by our preference.
+ const std::vector<MediaEngine::Codec>& codecs() const { return codecs_; }
+
+ // Adds another codec to the list.
+ void AddCodec(const MediaEngine::Codec& codec) { codecs_.push_back(codec); }
+ // Sorts the list of codecs by preference.
+ void Sort() { /* std::stable_sort(codecs_.begin(), codecs_.end());*/ }
+
+private:
+ std::vector<MediaEngine::Codec> codecs_;
+};
+
+}
+
+#endif // _PHONESESSIONCLIENT_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc
new file mode 100644
index 00000000..b65c9a20
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.cc
@@ -0,0 +1,331 @@
+#include <portaudio.h>
+#include <ortp/ortp.h>
+#include <speex.h>
+
+// Socket stuff
+#ifndef _WIN32
+#ifdef INET6
+#include <netdb.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#else
+#include <winsock32.h>
+#endif
+
+#include "talk/session/phone/mediaengine.h"
+#include "talk/session/phone/portaudiomediaengine.h"
+
+// Engine settings
+#define ENGINE_BUFFER_SIZE 2048
+
+// PortAudio settings
+#define FRAMES_PER_BUFFER 256
+#define SAMPLE_RATE 1
+
+// Speex settings
+//#define SPEEX_QUALITY 8
+
+// ORTP settings
+#define MAX_RTP_SIZE 1500 // From mediastreamer
+
+
+// -----------------------------------------------------------------------------
+
+static int portAudioCallback( void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, PaTimestamp outTime, void *channel_p )
+{
+ PortAudioMediaChannel* channel = (PortAudioMediaChannel*) channel_p;
+ channel->readOutput((float*) outputBuffer, framesPerBuffer);
+ channel->writeInput((float*) inputBuffer, framesPerBuffer);
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+
+PortAudioMediaChannel::PortAudioMediaChannel() : mute_(false), play_(false), stream_(NULL), out_buffer_(NULL), in_buffer_(NULL), speex_frame_(NULL)
+{
+ // Initialize buffers
+ out_buffer_ = new float[ENGINE_BUFFER_SIZE];
+ out_buffer_read_ = out_buffer_write_ = (float*) out_buffer_;
+ out_buffer_end_ = (float*) out_buffer_ + ENGINE_BUFFER_SIZE;
+ in_buffer_ = new float[ENGINE_BUFFER_SIZE];
+ in_buffer_read_ = in_buffer_write_ = (float*) in_buffer_;
+ in_buffer_end_ = (float*) in_buffer_ + ENGINE_BUFFER_SIZE;
+
+ // Initialize PortAudio
+ int err = Pa_OpenDefaultStream(&stream_, 1, 1, paFloat32, SAMPLE_RATE, FRAMES_PER_BUFFER, 0, portAudioCallback, this );
+ if (err != paNoError)
+ fprintf(stderr, "Error creating a PortAudio stream: %s\n", Pa_GetErrorText(err));
+
+ // Initialize Speex
+ speex_bits_init(&speex_bits_);
+ speex_enc_state_ = speex_encoder_init(&speex_nb_mode);
+ speex_dec_state_ = speex_decoder_init(&speex_nb_mode);
+ speex_decoder_ctl(speex_dec_state_, SPEEX_GET_FRAME_SIZE, &speex_frame_size_);
+ speex_frame_ = new float[speex_frame_size_];
+
+ // int quality = SPEEX_QUALITY;
+ // speex_encoder_ctl(state, SPEEX_SET_QUALITY, &quality);
+
+ // Initialize ORTP socket
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = AF_INET;
+ sockaddr.sin_addr.s_addr = INADDR_ANY;
+ sockaddr.sin_port = htons(3000);
+ rtp_socket_ = socket(PF_INET, SOCK_DGRAM, 0);
+ fcntl(rtp_socket_, F_SETFL, 0, O_NONBLOCK);
+ bind (rtp_socket_,(struct sockaddr*)&sockaddr, sizeof(sockaddr));
+
+ // Initialize ORTP Session
+ rtp_session_ = rtp_session_new(RTP_SESSION_SENDRECV);
+ rtp_session_max_buf_size_set(rtp_session_, MAX_RTP_SIZE);
+ rtp_session_set_profile(rtp_session_, &av_profile);
+ rtp_session_set_local_addr(rtp_session_, "127.0.0.1", 2000);
+ rtp_session_set_remote_addr(rtp_session_, "127.0.0.1", 3000);
+ rtp_session_set_scheduling_mode(rtp_session_, 0);
+ rtp_session_set_blocking_mode(rtp_session_, 0);
+ rtp_session_set_payload_type(rtp_session_, 110);
+ rtp_session_set_jitter_compensation(rtp_session_, 250);
+ rtp_session_enable_adaptive_jitter_compensation(rtp_session_, TRUE);
+ rtp_timestamp_ = 0;
+ //rtp_session_signal_connect(rtp_session_, "telephone-event", (RtpCallback) ortpTelephoneCallback,this);
+}
+
+PortAudioMediaChannel::~PortAudioMediaChannel()
+{
+ if (stream_) {
+ Pa_CloseStream(stream_);
+ }
+
+ // Clean up other allocated pointers
+
+ close(rtp_socket_);
+}
+
+void PortAudioMediaChannel::SetCodec(const char *codec)
+{
+ if (strcmp(codec, "speex"))
+ printf("Unsupported codec: %s\n", codec);
+}
+
+void PortAudioMediaChannel::OnPacketReceived(const void *data, int len)
+{
+ struct sockaddr_in sockaddr;
+ sockaddr.sin_family = AF_INET;
+ struct hostent *host = gethostbyname("localhost");
+ memcpy(&sockaddr.sin_addr.s_addr, host->h_addr, host->h_length);
+ sockaddr.sin_port = htons(2000);
+
+ char buf[2048];
+ memcpy(buf, data, len);
+
+ // Pass packet on to ORTP
+ if (play_) {
+ sendto(rtp_socket_, buf, len, 0, (struct sockaddr*)&sockaddr, sizeof(sockaddr));
+ }
+}
+
+void PortAudioMediaChannel::SetPlayout(bool playout)
+{
+ if (!stream_)
+ return;
+
+ if (play_ && !playout) {
+ int err = Pa_StopStream(stream_);
+ if (err != paNoError) {
+ fprintf(stderr, "Error stopping PortAudio stream: %s\n", Pa_GetErrorText(err));
+ return;
+ }
+ play_ = false;
+ }
+ else if (!play_ && playout) {
+ int err = Pa_StartStream(stream_);
+ if (err != paNoError) {
+ fprintf(stderr, "Error starting PortAudio stream: %s\n", Pa_GetErrorText(err));
+ return;
+ }
+ play_ = true;
+ }
+}
+
+void PortAudioMediaChannel::SetSend(bool send)
+{
+ mute_ = !send;
+}
+
+
+float PortAudioMediaChannel::GetCurrentQuality()
+{
+ return 0;
+}
+
+int PortAudioMediaChannel::GetOutputLevel()
+{
+ return 0;
+}
+
+void PortAudioMediaChannel::readOutput(float* buf, int len)
+{
+ //readBuffer(out_buffer_, &out_buffer_read_, out_buffer_write_, out_buffer_end_, buf, len);
+
+ // Receive a packet (if there is one)
+ mblk_t *mp;
+ mp = rtp_session_recvm_with_ts(rtp_session_,rtp_timestamp_);
+ while (mp != NULL) {
+ gint in_len = mp->b_cont->b_wptr-mp->b_cont->b_rptr;
+
+ // Decode speex stream
+ speex_bits_read_from(&speex_bits_,mp->b_cont->b_rptr, in_len);
+ speex_decode(speex_dec_state_, &speex_bits_, speex_frame_);
+ writeBuffer(out_buffer_, out_buffer_read_, &out_buffer_write_, out_buffer_end_, speex_frame_, speex_frame_size_);
+ rtp_timestamp_++;
+ mp = rtp_session_recvm_with_ts(rtp_session_,rtp_timestamp_);
+ }
+
+ // Read output
+ readBuffer(out_buffer_, &out_buffer_read_, out_buffer_write_, out_buffer_end_, buf, len);
+}
+
+void PortAudioMediaChannel::writeInput(float* buf, int len)
+{
+ //writeBuffer(in_buffer_, in_buffer_read_, &in_buffer_write_, in_buffer_end_, buf, len);
+}
+
+
+void PortAudioMediaChannel::readBuffer(float* buffer, float** buffer_read_p, float*buffer_write, float* buffer_end, float* target_buffer, int target_len)
+{
+ float *end, *tmp, *buffer_read = *buffer_read_p;
+ int remaining;
+
+ // First phase
+ tmp = buffer_read + target_len;
+ if (buffer_write < buffer_read && tmp > buffer_end) {
+ end = buffer_end;
+ remaining = tmp - buffer_end;
+ }
+ else {
+ end = (tmp > buffer_write ? buffer_write : tmp);
+ remaining = 0;
+ }
+
+ while (buffer_read < end) {
+ *target_buffer++ = *buffer_read++;
+ }
+
+ // Second phase
+ if (remaining > 0) {
+ buffer_read = buffer;
+ tmp = buffer_read + remaining;
+ end = (tmp > buffer_write ? buffer_write : tmp);
+ while (buffer_read < end) {
+ *target_buffer++ = *buffer_read++;
+ }
+ }
+
+ // Finish up
+ *buffer_read_p = buffer_read;
+}
+
+void PortAudioMediaChannel::writeBuffer(float* buffer, float* buffer_read, float**buffer_write_p, float* buffer_end, float* source_buffer, int source_len)
+{
+ float *end, *tmp, *buffer_write = *buffer_write_p;
+ int remaining;
+
+ // First phase
+ tmp = buffer_write + source_len;
+ if (buffer_write > buffer_read) {
+ if (tmp > buffer_end) {
+ end = buffer_end;
+ remaining = tmp - buffer_end;
+ }
+ else {
+ end = tmp;
+ remaining = 0;
+ }
+ }
+ else {
+ if (tmp > buffer_read) {
+ printf("Warning: Dropping frame(s)\n");
+ end = buffer_read;
+ remaining = 0;
+ }
+ else {
+ end = tmp;
+ remaining = 0;
+ }
+ }
+
+ while (buffer_write < end) {
+ *buffer_write++ = *source_buffer++;
+ }
+
+ // Second phase
+ if (remaining > 0) {
+ buffer_write = buffer;
+ tmp = buffer_write + remaining;
+ if (tmp > buffer_read) {
+ printf("Warning: Dropping frame(s)\n");
+ end = buffer_read;
+ }
+ else {
+ end = tmp;
+ }
+ while (buffer_write < end) {
+ *buffer_write++ = *source_buffer++;
+ }
+ }
+
+ // Finish up
+ *buffer_write_p = buffer_write;
+}
+
+// -----------------------------------------------------------------------------
+
+PortAudioMediaEngine::PortAudioMediaEngine()
+{
+}
+
+PortAudioMediaEngine::~PortAudioMediaEngine()
+{
+ Pa_Terminate();
+}
+
+bool PortAudioMediaEngine::Init()
+{
+ ortp_init();
+
+ int err = Pa_Initialize();
+ if (err != paNoError) {
+ fprintf(stderr,"Error initializing PortAudio: %s\n",Pa_GetErrorText(err));
+ return false;
+ }
+
+ // Speex
+ rtp_profile_set_payload(&av_profile, 110, &speex_wb);
+ codecs_.push_back(Codec(110, "speex", 8));
+
+ return true;
+}
+
+void PortAudioMediaEngine::Terminate()
+{
+}
+
+
+cricket::MediaChannel* PortAudioMediaEngine::CreateChannel()
+{
+ return new PortAudioMediaChannel();
+}
+
+int PortAudioMediaEngine::SetAudioOptions(int options)
+{
+}
+
+int PortAudioMediaEngine::SetSoundDevices(int wave_in_device, int wave_out_device)
+{
+}
+
+int PortAudioMediaEngine::GetInputLevel()
+{
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h
new file mode 100644
index 00000000..95c39a1a
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/portaudiomediaengine.h
@@ -0,0 +1,69 @@
+#ifndef PORTAUDIOMEDIAENGINE_H
+#define PORTAUDIOMEDIAENGINE_H
+
+#include <portaudio.h>
+#include <speex.h>
+#include <ortp/ortp.h>
+
+#include "talk/session/phone/mediaengine.h"
+
+class PortAudioMediaChannel : public cricket::MediaChannel
+{
+public:
+ PortAudioMediaChannel();
+ virtual ~PortAudioMediaChannel();
+ virtual void SetCodec(const char *codec);
+ virtual void OnPacketReceived(const void *data, int len);
+
+ virtual void SetPlayout(bool playout);
+ virtual void SetSend(bool send);
+
+ virtual float GetCurrentQuality();
+ virtual int GetOutputLevel();
+
+ void readOutput(float*, int);
+ void writeInput(float*, int);
+
+protected:
+ void readBuffer(float*, float**, float*, float*, float*, int);
+ void writeBuffer(float*, float*, float**, float*, float*, int);
+
+private:
+ bool mute_;
+ bool play_;
+ PortAudioStream* stream_;
+
+ // Buffers
+ float *out_buffer_, *out_buffer_read_, *out_buffer_write_, *out_buffer_end_;
+ float *in_buffer_, *in_buffer_read_, *in_buffer_write_, *in_buffer_end_;
+
+ // Speex
+ SpeexBits speex_bits_;
+ void *speex_enc_state_, *speex_dec_state_;
+ float *speex_frame_;
+ int speex_frame_size_;
+
+ // ORTP
+ int rtp_socket_;
+ RtpSession* rtp_session_;
+ int rtp_timestamp_;
+};
+
+
+class PortAudioMediaEngine : public cricket::MediaEngine
+{
+public:
+ PortAudioMediaEngine();
+ ~PortAudioMediaEngine();
+ virtual bool Init();
+ virtual void Terminate();
+
+ virtual cricket::MediaChannel *CreateChannel();
+
+ virtual int SetAudioOptions(int options);
+ virtual int SetSoundDevices(int wave_in_device, int wave_out_device);
+
+ virtual int GetInputLevel();
+};
+
+#endif
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc
new file mode 100644
index 00000000..58e1db60
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.cc
@@ -0,0 +1,331 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "talk/session/phone/voicechannel.h"
+#include "talk/session/phone/channelmanager.h"
+#include "talk/session/phone/phonesessionclient.h"
+#include "talk/base/logging.h"
+#include <cassert>
+#undef SetPort
+
+namespace {
+
+// Delay before quality estimate is meaningful.
+uint32 kQualityDelay = 5000; // in ms
+
+}
+
+namespace cricket {
+
+VoiceChannel::VoiceChannel(ChannelManager *manager, Session *session, MediaChannel *channel) {
+ channel_manager_ = manager;
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ channel_ = channel;
+ session_ = session;
+ socket_monitor_ = NULL;
+ audio_monitor_ = NULL;
+ socket_ = session_->CreateSocket("rtp");
+ socket_->SignalState.connect(this, &VoiceChannel::OnSocketState);
+ socket_->SignalReadPacket.connect(this, &VoiceChannel::OnSocketRead);
+ channel->SetInterface(this);
+ enabled_ = false;
+ paused_ = false;
+ socket_writable_ = false;
+ muted_ = false;
+ LOG(INFO) << "Created voice channel";
+ start_time_ = 0xFFFFFFFF - kQualityDelay;
+
+ session->SignalState.connect(this, &VoiceChannel::OnSessionState);
+ OnSessionState(session, session->state());
+}
+
+VoiceChannel::~VoiceChannel() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ enabled_ = false;
+ ChangeState();
+ delete socket_monitor_;
+ delete audio_monitor_;
+ Thread::Current()->Clear(this);
+ if (socket_ != NULL)
+ session_->DestroySocket(socket_);
+ LOG(INFO) << "Destroyed voice channel";
+}
+
+void VoiceChannel::OnMessage(Message *pmsg) {
+ switch (pmsg->message_id) {
+ case MSG_ENABLE:
+ EnableMedia_w();
+ break;
+
+ case MSG_DISABLE:
+ DisableMedia_w();
+ break;
+
+ case MSG_MUTE:
+ MuteMedia_w();
+ break;
+
+ case MSG_UNMUTE:
+ UnmuteMedia_w();
+ break;
+
+ case MSG_SETSENDCODEC:
+ SetSendCodec_w();
+ break;
+ }
+}
+
+void VoiceChannel::Enable(bool enable) {
+ // Can be called from thread other than worker thread
+ channel_manager_->worker_thread()->Post(this, enable ? MSG_ENABLE : MSG_DISABLE);
+}
+
+void VoiceChannel::Mute(bool mute) {
+ // Can be called from thread other than worker thread
+ channel_manager_->worker_thread()->Post(this, mute ? MSG_MUTE : MSG_UNMUTE);
+}
+
+MediaChannel * VoiceChannel::channel() {
+ return channel_;
+}
+
+void VoiceChannel::OnSessionState(Session* session, Session::State state) {
+ if ((state == Session::STATE_RECEIVEDACCEPT) ||
+ (state == Session::STATE_RECEIVEDINITIATE)) {
+ channel_manager_->worker_thread()->Post(this, MSG_SETSENDCODEC);
+ }
+}
+
+void VoiceChannel::SetSendCodec_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+
+ const PhoneSessionDescription* desc =
+ static_cast<const PhoneSessionDescription*>(session()->remote_description());
+
+ const char *codec = NULL;
+
+ if (desc->codecs().size() > 0)
+ PhoneSessionClient::FindMediaCodec(channel_manager_->media_engine(), desc, &codec);
+
+ // The other client should have returned one of the codecs that we offered.
+ // If they could not, they should have rejected the session. So, if we get
+ // into this state, we're dealing with a bad client, so we may as well just
+ // pick the mostt common format there is: payload type zero.
+ if (codec == NULL)
+ codec = "PCMU";
+
+ channel_->SetCodec(codec);
+}
+
+void VoiceChannel::OnSocketState(P2PSocket *socket, P2PSocket::State state) {
+ switch (state) {
+ case P2PSocket::STATE_WRITABLE:
+ SocketWritable_w();
+ break;
+
+ default:
+ SocketNotWritable_w();
+ break;
+ }
+}
+
+void VoiceChannel::OnSocketRead(P2PSocket *socket, const char *data, size_t len) {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ // OnSocketRead gets called from P2PSocket; now pass data to MediaEngine
+ channel_->OnPacketReceived(data, (int)len);
+}
+
+void VoiceChannel::SendPacket(const void *data, size_t len) {
+ // SendPacket gets called from MediaEngine; send to socket
+ // MediaEngine will call us on a random thread. The Send operation on the socket is
+ // special in that it can handle this.
+ socket_->Send(static_cast<const char *>(data), len);
+}
+
+void VoiceChannel::ChangeState() {
+ if (paused_ || !enabled_ || !socket_writable_) {
+ channel_->SetPlayout(false);
+ channel_->SetSend(false);
+ } else {
+ if (muted_) {
+ channel_->SetSend(false);
+ channel_->SetPlayout(true);
+ } else {
+ channel_->SetSend(true);
+ channel_->SetPlayout(true);
+ }
+ }
+}
+
+void VoiceChannel::PauseMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ assert(!paused_);
+
+ LOG(INFO) << "Voice channel paused";
+ paused_ = true;
+ ChangeState();
+}
+
+void VoiceChannel::UnpauseMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ assert(paused_);
+
+ LOG(INFO) << "Voice channel unpaused";
+ paused_ = false;
+ ChangeState();
+}
+
+void VoiceChannel::EnableMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (enabled_)
+ return;
+
+ LOG(INFO) << "Voice channel enabled";
+ enabled_ = true;
+ start_time_ = Time();
+ ChangeState();
+}
+
+void VoiceChannel::DisableMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (!enabled_)
+ return;
+
+ LOG(INFO) << "Voice channel disabled";
+ enabled_ = false;
+ ChangeState();
+}
+
+void VoiceChannel::MuteMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (muted_)
+ return;
+
+ LOG(INFO) << "Voice channel muted";
+ muted_ = true;
+ ChangeState();
+}
+
+void VoiceChannel::UnmuteMedia_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (!muted_)
+ return;
+
+ LOG(INFO) << "Voice channel unmuted";
+ muted_ = false;
+ ChangeState();
+}
+
+void VoiceChannel::SocketWritable_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (socket_writable_)
+ return;
+
+ LOG(INFO) << "Voice channel socket writable";
+ socket_writable_ = true;
+ ChangeState();
+}
+
+void VoiceChannel::SocketNotWritable_w() {
+ assert(channel_manager_->worker_thread() == Thread::Current());
+ if (!socket_writable_)
+ return;
+
+ LOG(INFO) << "Voice channel socket not writable";
+ socket_writable_ = false;
+ ChangeState();
+}
+
+void VoiceChannel::StartConnectionMonitor(int cms) {
+ delete socket_monitor_;
+ socket_monitor_ = new SocketMonitor(socket_, Thread::Current());
+ socket_monitor_
+ ->SignalUpdate.connect(this, &VoiceChannel::OnConnectionMonitorUpdate);
+ socket_monitor_->Start(cms);
+}
+
+void VoiceChannel::StopConnectionMonitor() {
+ if (socket_monitor_ != NULL) {
+ socket_monitor_->Stop();
+ socket_monitor_->SignalUpdate.disconnect(this);
+ delete socket_monitor_;
+ socket_monitor_ = NULL;
+ }
+}
+
+void VoiceChannel::OnConnectionMonitorUpdate(SocketMonitor *monitor,
+ const std::vector<ConnectionInfo> &infos) {
+ SignalConnectionMonitor(this, infos);
+}
+
+void VoiceChannel::StartAudioMonitor(int cms) {
+ delete audio_monitor_;
+ audio_monitor_ = new AudioMonitor(this, Thread::Current());
+ audio_monitor_
+ ->SignalUpdate.connect(this, &VoiceChannel::OnAudioMonitorUpdate);
+ audio_monitor_->Start(cms);
+}
+
+void VoiceChannel::StopAudioMonitor() {
+ if (audio_monitor_ != NULL) {
+ audio_monitor_ ->Stop();
+ audio_monitor_ ->SignalUpdate.disconnect(this);
+ delete audio_monitor_ ;
+ audio_monitor_ = NULL;
+ }
+}
+
+void VoiceChannel::OnAudioMonitorUpdate(AudioMonitor *monitor,
+ const AudioInfo& info) {
+ SignalAudioMonitor(this, info);
+}
+
+Session *VoiceChannel::session() {
+ return session_;
+}
+
+bool VoiceChannel::HasQuality() {
+ return Time() >= start_time_ + kQualityDelay;
+}
+
+float VoiceChannel::GetCurrentQuality() {
+ return channel_->GetCurrentQuality();
+}
+
+int VoiceChannel::GetInputLevel_w() {
+ return channel_manager_->media_engine()->GetInputLevel();
+}
+
+int VoiceChannel::GetOutputLevel_w() {
+ return channel_->GetOutputLevel();
+}
+
+Thread* VoiceChannel::worker_thread() {
+ return channel_manager_->worker_thread();
+}
+
+}
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h
new file mode 100644
index 00000000..4cfa0b11
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/phone/voicechannel.h
@@ -0,0 +1,129 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _VOICECHANNEL_H_
+#define _VOICECHANNEL_H_
+
+#include "talk/base/asyncudpsocket.h"
+#include "talk/base/network.h"
+#include "talk/base/sigslot.h"
+#include "talk/p2p/client/socketmonitor.h"
+#include "talk/p2p/base/p2psocket.h"
+#include "talk/p2p/base/session.h"
+#include "talk/session/phone/audiomonitor.h"
+#include "talk/session/phone/mediaengine.h"
+
+namespace cricket {
+
+const uint32 MSG_ENABLE = 1;
+const uint32 MSG_DISABLE = 2;
+const uint32 MSG_MUTE = 3;
+const uint32 MSG_UNMUTE = 4;
+const uint32 MSG_SETSENDCODEC = 5;
+
+class ChannelManager;
+
+class VoiceChannel
+ : public MessageHandler, public sigslot::has_slots<>,
+ public NetworkSession, public MediaChannel::NetworkInterface {
+ public:
+ VoiceChannel(ChannelManager *manager, Session *session, MediaChannel *channel);
+ ~VoiceChannel();
+
+ void Enable(bool enable);
+ void Mute(bool mute);
+ MediaChannel *channel();
+ Session *session();
+
+ // Monitoring
+
+ void StartConnectionMonitor(int cms);
+ void StopConnectionMonitor();
+ sigslot::signal2<VoiceChannel *, const std::vector<ConnectionInfo> &> SignalConnectionMonitor;
+
+ void StartAudioMonitor(int cms);
+ void StopAudioMonitor();
+ sigslot::signal2<VoiceChannel *, const AudioInfo&> SignalAudioMonitor;
+ Thread* worker_thread();
+
+ // Pausing so that the ChannelManager can change the audio devices. These
+ // should only be called from the worker thread
+ void PauseMedia_w();
+ void UnpauseMedia_w();
+
+ int GetInputLevel_w();
+ int GetOutputLevel_w();
+
+ // Gives a quality estimate to the network quality manager.
+ virtual bool HasQuality();
+ virtual float GetCurrentQuality();
+
+ // MediaEngine calls this
+ virtual void SendPacket(const void *data, size_t len);
+
+private:
+ void ChangeState();
+ void EnableMedia_w();
+ void DisableMedia_w();
+ void MuteMedia_w();
+ void UnmuteMedia_w();
+ void SocketWritable_w();
+ void SocketNotWritable_w();
+
+ void OnConnectionMonitorUpdate(SocketMonitor *monitor, const std::vector<ConnectionInfo> &infos);
+ void OnAudioMonitorUpdate(AudioMonitor *monitor, const AudioInfo& info);
+
+ // From MessageHandler
+
+ void OnMessage(Message *pmsg);
+
+ // Setting the send codec based on the remote description.
+ void OnSessionState(Session* session, Session::State state);
+ void SetSendCodec_w();
+
+ // From P2PSocket
+
+ void OnSocketState(P2PSocket *socket, P2PSocket::State state);
+ void OnSocketRead(P2PSocket *socket, const char *data, size_t len);
+
+
+ bool enabled_;
+ bool paused_;
+ bool socket_writable_;
+ bool muted_;
+ MediaChannel *channel_;
+ Session *session_;
+ P2PSocket *socket_;
+ ChannelManager *channel_manager_;
+ SocketMonitor *socket_monitor_;
+ AudioMonitor *audio_monitor_;
+ uint32 start_time_;
+};
+
+}
+
+#endif // _VOICECHANNEL_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h
new file mode 100644
index 00000000..a5326893
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/receiver.h
@@ -0,0 +1,72 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _RECEIVER_H_
+#define _RECEIVER_H_
+
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmpptask.h"
+#include "talk/p2p/client/sessionclient.h"
+
+namespace cricket {
+
+class Receiver : public buzz::XmppTask {
+public:
+ Receiver(Task *parent, SessionClient *session_client)
+ : buzz::XmppTask(parent, buzz::XmppEngine::HL_TYPE) {
+ session_client_ = session_client;
+ }
+
+ virtual int ProcessStart() {
+ const buzz::XmlElement *stanza = NextStanza();
+ if (stanza == NULL)
+ return STATE_BLOCKED;
+ session_client_->OnIncomingStanza(stanza);
+
+ // Respond right away to the sender to let them know that we received
+ // this IQ
+ buzz::XmlElement * result = MakeIqResult(stanza);
+ SendStanza(result);
+
+ return STATE_START;
+ }
+
+protected:
+ virtual bool HandleStanza(const buzz::XmlElement *stanza) {
+ if (!session_client_->IsClientStanza(stanza))
+ return false;
+ QueueStanza(stanza);
+ return true;
+ }
+
+private:
+ SessionClient *session_client_;
+};
+
+}
+
+#endif // _RECEIVER_H_
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h b/kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h
new file mode 100644
index 00000000..9dc5384c
--- /dev/null
+++ b/kopete/protocols/jabber/jingle/libjingle/talk/session/sessionsendtask.h
@@ -0,0 +1,111 @@
+/*
+ * libjingle
+ * Copyright 2004--2005, Google Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CRICKET_PHONE_SESSIONSENDTASK_H_
+#define _CRICKET_PHONE_SESSIONSENDTASK_H_
+
+#include "talk/xmpp/xmppengine.h"
+#include "talk/xmpp/xmpptask.h"
+#include "talk/p2p/client/sessionclient.h"
+
+namespace cricket {
+
+// The job of this task is to send an IQ stanza out (after stamping it with
+// an ID attribute) and then wait for a response. If not response happens
+// within 5 seconds, it will signal failure on a SessionClient. If an error
+// happens it will also signal failure. If, however, the send succeeds this
+// task will quietly go away.
+
+// It is safe for this to hold on to the session client. In the case where
+// the xmpp client goes away, this task will automatically be aborted. The
+// session_client is guaranteed to outlive the xmpp session.
+class SessionSendTask : public buzz::XmppTask {
+public:
+ SessionSendTask(Task *parent, SessionClient *session_client)
+ : buzz::XmppTask(parent, buzz::XmppEngine::HL_SINGLE),
+ session_client_(session_client),
+ timed_out_(false) {
+ }
+
+ void Send(const buzz::XmlElement* stanza) {
+ assert(stanza_.get() == NULL);
+ stanza_.reset(new buzz::XmlElement(*stanza));
+ stanza_->SetAttr(buzz::QN_ID, task_id());
+ }
+
+protected:
+ // This gets called by the task runner every 500 msec
+ virtual void Poll() {
+ if (ElapsedTime() > (15 * 1000 * 10000)) { // 15 secs
+ timed_out_ = true;
+ Wake();
+ }
+ }
+
+ virtual int ProcessStart() {
+ SendStanza(stanza_.get());
+ return STATE_RESPONSE;
+ }
+
+ virtual int ProcessResponse() {
+ if (timed_out_) {
+ session_client_->OnFailedSend(stanza_.get(), NULL);
+ return STATE_DONE;
+ }
+
+ const buzz::XmlElement* next = NextStanza();
+ if (next == NULL)
+ return STATE_BLOCKED;
+
+ if (next->Attr(buzz::QN_TYPE) == "result") {
+ return STATE_DONE;
+ } else {
+ session_client_->OnFailedSend(stanza_.get(), next);
+ return STATE_DONE;
+ }
+ }
+
+ virtual bool HandleStanza(const buzz::XmlElement *stanza) {
+ if (!MatchResponseIq(stanza, buzz::Jid(stanza_->Attr(buzz::QN_TO)), task_id()))
+ return false;
+ if (stanza->Attr(buzz::QN_TYPE) == "result" ||
+ stanza->Attr(buzz::QN_TYPE) == "error") {
+ QueueStanza(stanza);
+ return true;
+ }
+ return false;
+ }
+
+private:
+ SessionClient *session_client_;
+ buzz::scoped_ptr<buzz::XmlElement> stanza_;
+ bool timed_out_;
+};
+
+}
+
+#endif // _CRICKET_PHONE_SESSIONSENDTASK_H_