/* * 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_CONFIG_H #include #endif // GipsLiteMediaEngine is a GIPS Voice Engine Lite implementation of MediaEngine #include "talk/base/logging.h" #include #include #include "gipslitemediaengine.h" using namespace cricket; #if 0 #define TRACK(x) LOG(LS_VERBOSE) << x #else #define TRACK(x) #endif //#define GIPS_TRACING namespace { struct CodecPref { const char* name; int clockrate; int pref; }; const CodecPref kGIPSCodecPrefs[] = { { "ISAC", 1600, 7 }, { "speex", 1600, 6 }, { "IPCMWB", 1600, 6}, { "speex", 8000, 4}, { "iLBC", 8000, 1 }, { "G723", 8000, 4 }, { "EG711U", 8000, 3 }, { "EG711A", 8000, 3 }, { "PCMU", 8000, 2 }, { "PCMA", 8000, 2 }, { "CN", 8000, 2 }, { "red", 8000, -1 }, { "telephone-event", 8000, -1 } }; const size_t kNumGIPSCodecs = sizeof(kGIPSCodecPrefs) / sizeof(CodecPref); } void GipsLiteMediaChannel::SetCodecs(const std::vector &codecs) { GIPS_CodecInst c; std::vector::const_iterator i; bool first = true; for (i = codecs.begin(); i < codecs.end(); i++) { if (engine_->FindGIPSCodec(*i, &c) == false) continue; if (c.pltype != i->id) { c.pltype = i->id; engine_->gips().GIPSVE_SetRecPayloadType(gips_channel_, &c); } if (first) { LOG(LS_INFO) << "Using " << c.plname << "/" << c.plfreq; engine_->gips().GIPSVE_SetSendCodec(gips_channel_, &c); first = false; } } if (first) { // We're being asked to set an empty list of codecs. This will only happen when // dealing with a buggy client. We'll send them the most common format: PCMU Codec codec(0, "PCMU", 8000, 0, 1, 0); LOG(LS_WARNING) << "Received empty list of codces; using PCMU/8000"; engine_->FindGIPSCodec(codec, &c); engine_->gips().GIPSVE_SetSendCodec(gips_channel_, &c); } } void GipsLiteMediaChannel::OnPacketReceived(const void *data, int len) { engine_->gips().GIPSVE_ReceivedRTPPacket(gips_channel_, data, (int)len); } void GipsLiteMediaChannel::SetPlayout(bool playout) { if (playout) engine_->gips().GIPSVE_StartPlayout(gips_channel_); else engine_->gips().GIPSVE_StopPlayout(gips_channel_); } void GipsLiteMediaChannel::SetSend(bool send) { if (send) engine_->gips().GIPSVE_StartSend(gips_channel_); else engine_->gips().GIPSVE_StopSend(gips_channel_); } GipsLiteMediaChannel::GipsLiteMediaChannel(GipsLiteMediaEngine *engine) { network_interface_ = NULL; engine_ = engine; gips_channel_ = engine_->gips().GIPSVE_CreateChannel(); engine_->gips().GIPSVE_SetSendTransport(gips_channel_, *this); } int GipsLiteMediaEngine::GetGIPSCodecPreference(const char *name, int clockrate) { for (size_t i = 0; i < kNumGIPSCodecs; ++i) { if ((strcmp(kGIPSCodecPrefs[i].name, name) == 0) && (kGIPSCodecPrefs[i].clockrate == clockrate)) return kGIPSCodecPrefs[i].pref; } assert(false); return -1; } GipsLiteMediaEngine::GipsLiteMediaEngine() : gips_(GetGipsVoiceEngineLite()) {} bool GipsLiteMediaEngine::Init() { TRACK("GIPSVE_Init"); if (gips_.GIPSVE_Init() == -1) return false; char buffer[1024]; TRACK("GIPSVE_GetVersion"); int r = gips_.GIPSVE_GetVersion(buffer, sizeof(buffer)); LOG(LS_INFO) << "GIPS Version: " << r << ": " << buffer; // Set auto gain control on TRACK("GIPSVE_SetAGCStatus"); if (gips_.GIPSVE_SetAGCStatus(1) == -1) return false; TRACK("GIPSVE_GetNofCodecs"); int ncodecs = gips_.GIPSVE_GetNofCodecs(); for (int i = 0; i < ncodecs; ++i) { GIPS_CodecInst gips_codec; if (gips_.GIPSVE_GetCodec(i, &gips_codec) >= 0) { Codec codec(gips_codec.pltype, gips_codec.plname, gips_codec.plfreq, gips_codec.rate, gips_codec.channels, GetGIPSCodecPreference(gips_codec.plname, gips_codec.plfreq)); LOG(LS_INFO) << gips_codec.plname << "/" << gips_codec.plfreq << "/" << gips_codec.channels << " " << gips_codec.pltype; codecs_.push_back(codec); } } return true; } void GipsLiteMediaEngine::Terminate() { gips_.GIPSVE_Terminate(); } MediaChannel * GipsLiteMediaEngine::CreateChannel() { return new GipsLiteMediaChannel(this); } bool GipsLiteMediaEngine::FindGIPSCodec(Codec codec, GIPS_CodecInst* gips_codec) { int ncodecs = gips_.GIPSVE_GetNofCodecs(); for (int i = 0; i < ncodecs; ++i) { GIPS_CodecInst gc; if (gips_.GIPSVE_GetCodec(i, &gc) >= 0) { if (codec.id < 96) { // Compare by id if (codec.id != gc.pltype) continue; } else { // Compare by name if (strcmp(codec.name.c_str(), gc.plname) != 0) continue; } // If the clockrate is specified, make sure it matches if (codec.clockrate > 0 && codec.clockrate != gc.plfreq) continue; // If the bitrate is specified, make sure it matches if (codec.bitrate > 0 && codec.bitrate != gc.rate) continue; // Make sure the channels match if (codec.channels != gc.channels) continue; // If we got this far, we match. if (gips_codec) *gips_codec = gc; return true; } } return false; } int GipsLiteMediaEngine::SetAudioOptions(int options) { // Set auto gain control on if (gips_.GIPSVE_SetAGCStatus(options & AUTO_GAIN_CONTROL ? 1 : 0) == -1) { return -1; // TODO: We need to log these failures. } return 0; } int GipsLiteMediaEngine::SetSoundDevices(int wave_in_device, int wave_out_device) { if (gips_.GIPSVE_SetSoundDevices(wave_in_device, wave_out_device) == -1) { int error = gips_.GIPSVE_GetLastError(); // TODO: We need to log these failures. return error; } return 0; } bool GipsLiteMediaEngine::FindCodec(const Codec &codec) { return FindGIPSCodec(codec, NULL); } std::vector GipsLiteMediaEngine::codecs() { return codecs_; }