diff --git a/DEPS b/DEPS index 255ce4f09a..a85ed319d0 100644 --- a/DEPS +++ b/DEPS @@ -4,7 +4,7 @@ vars = { "googlecode_url": "http://%s.googlecode.com/svn", "chromium_trunk" : "http://src.chromium.org/svn/trunk", "chromium_revision": "98568", - "libjingle_revision": "85", + "libjingle_revision": "87", } # NOTE: Prefer revision numbers to tags for svn deps. diff --git a/third_party_mods/libjingle/libjingle.gyp b/third_party_mods/libjingle/libjingle.gyp index 92926f530a..e8de7f6fa7 100644 --- a/third_party_mods/libjingle/libjingle.gyp +++ b/third_party_mods/libjingle/libjingle.gyp @@ -112,7 +112,6 @@ ['inside_chromium_build==1', { 'include_dirs': [ '<(overrides)', - '<(libjingle_mods)/source', '<(libjingle_orig)/source', '../..', # the third_party folder for webrtc includes '../../third_party/expat/files', @@ -120,7 +119,6 @@ 'direct_dependent_settings': { 'include_dirs': [ '<(overrides)', - '<(libjingle_mods)/source', '<(libjingle_orig)/source', '../../third_party/expat/files' ], @@ -133,7 +131,6 @@ 'include_dirs': [ # the third_party folder for webrtc/ includes (non-chromium). '../../src', - '<(libjingle_mods)/source', '<(libjingle_orig)/source', '../../third_party/expat/files', ], @@ -522,7 +519,7 @@ '<(libjingle_orig)/source/talk/p2p/client/basicportallocator.h', '<(libjingle_orig)/source/talk/p2p/client/httpportallocator.cc', '<(libjingle_orig)/source/talk/p2p/client/httpportallocator.h', - '<(libjingle_mods)/source/talk/p2p/client/fakeportallocator.h', + '<(libjingle_orig)/source/talk/p2p/client/fakeportallocator.h', '<(libjingle_orig)/source/talk/p2p/client/sessionmanagertask.h', '<(libjingle_orig)/source/talk/p2p/client/sessionsendtask.h', '<(libjingle_orig)/source/talk/p2p/client/socketmonitor.cc', @@ -531,8 +528,8 @@ '<(libjingle_orig)/source/talk/session/phone/audiomonitor.h', '<(libjingle_orig)/source/talk/session/phone/call.cc', '<(libjingle_orig)/source/talk/session/phone/call.h', - '<(libjingle_mods)/source/talk/session/phone/channel.cc', - '<(libjingle_mods)/source/talk/session/phone/channel.h', + '<(libjingle_orig)/source/talk/session/phone/channel.cc', + '<(libjingle_orig)/source/talk/session/phone/channel.h', '<(libjingle_orig)/source/talk/session/phone/channelmanager.cc', '<(libjingle_orig)/source/talk/session/phone/channelmanager.h', '<(libjingle_orig)/source/talk/session/phone/codec.cc', @@ -540,8 +537,8 @@ '<(libjingle_orig)/source/talk/session/phone/cryptoparams.h', '<(libjingle_orig)/source/talk/session/phone/currentspeakermonitor.cc', '<(libjingle_orig)/source/talk/session/phone/currentspeakermonitor.h', - '<(libjingle_mods)/source/talk/session/phone/devicemanager.cc', - '<(libjingle_mods)/source/talk/session/phone/devicemanager.h', + '<(libjingle_orig)/source/talk/session/phone/devicemanager.cc', + '<(libjingle_orig)/source/talk/session/phone/devicemanager.h', '<(libjingle_orig)/source/talk/session/phone/filemediaengine.cc', '<(libjingle_orig)/source/talk/session/phone/filemediaengine.h', '<(libjingle_orig)/source/talk/session/phone/mediachannel.h', @@ -569,13 +566,13 @@ '<(libjingle_orig)/source/talk/session/phone/webrtcpassthroughrender.cc', '<(libjingle_orig)/source/talk/session/phone/voicechannel.h', '<(libjingle_orig)/source/talk/session/phone/webrtccommon.h', - '<(libjingle_mods)/source/talk/session/phone/webrtcvideoengine.cc', + '<(libjingle_orig)/source/talk/session/phone/webrtcvideoengine.cc', '<(libjingle_orig)/source/talk/session/phone/webrtcvideoengine.h', '<(libjingle_orig)/source/talk/session/phone/webrtcvideoframe.cc', '<(libjingle_orig)/source/talk/session/phone/webrtcvideoframe.h', '<(libjingle_orig)/source/talk/session/phone/webrtcvie.h', '<(libjingle_orig)/source/talk/session/phone/webrtcvoe.h', - '<(libjingle_mods)/source/talk/session/phone/webrtcvoiceengine.cc', + '<(libjingle_orig)/source/talk/session/phone/webrtcvoiceengine.cc', '<(libjingle_orig)/source/talk/session/phone/webrtcvoiceengine.h', '<(libjingle_orig)/source/talk/session/tunnel/pseudotcpchannel.cc', '<(libjingle_orig)/source/talk/session/tunnel/pseudotcpchannel.h', diff --git a/third_party_mods/libjingle/source/talk/session/phone/devicemanager.cc b/third_party_mods/libjingle/source/talk/session/phone/devicemanager.cc deleted file mode 100644 index 628f0f7d13..0000000000 --- a/third_party_mods/libjingle/source/talk/session/phone/devicemanager.cc +++ /dev/null @@ -1,1023 +0,0 @@ -/* - * libjingle - * Copyright 2004--2008, 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/devicemanager.h" - -#if WIN32 -#include -#include -#include // must come before ks.h -#include -#include -#define INITGUID // For PKEY_AudioEndpoint_GUID -#include -#include -#include -#include -#include "talk/base/win32.h" // ToUtf8 -#include "talk/base/win32window.h" -#elif OSX -#include -#include -#elif LINUX -#include -#include -#include "talk/base/linux.h" -#include "talk/base/fileutils.h" -#include "talk/base/pathutils.h" -#include "talk/base/physicalsocketserver.h" -#include "talk/base/stream.h" -#include "talk/session/phone/libudevsymboltable.h" -#include "talk/session/phone/v4llookup.h" -#if defined(LINUX_SOUND_USED) -#include "talk/sound/platformsoundsystem.h" -#include "talk/sound/platformsoundsystemfactory.h" -#include "talk/sound/sounddevicelocator.h" -#include "talk/sound/soundsysteminterface.h" -#endif -#endif - -#include "talk/base/logging.h" -#include "talk/base/stringutils.h" -#include "talk/base/thread.h" -#include "talk/session/phone/mediacommon.h" - -namespace cricket { -// Initialize to empty string. -const char DeviceManagerInterface::kDefaultDeviceName[] = ""; - -DeviceManagerInterface* DeviceManagerFactory::Create() { - return new DeviceManager(); -} - -#ifdef WIN32 -class DeviceWatcher : public talk_base::Win32Window { - public: - explicit DeviceWatcher(DeviceManager* dm); - bool Start(); - void Stop(); - - private: - HDEVNOTIFY Register(REFGUID guid); - void Unregister(HDEVNOTIFY notify); - virtual bool OnMessage(UINT msg, WPARAM wp, LPARAM lp, LRESULT& result); - - DeviceManager* manager_; - HDEVNOTIFY audio_notify_; - HDEVNOTIFY video_notify_; -}; -#elif defined(LINUX) -class DeviceWatcher : private talk_base::Dispatcher { - public: - explicit DeviceWatcher(DeviceManager* dm); - bool Start(); - void Stop(); - - private: - virtual uint32 GetRequestedEvents(); - virtual void OnPreEvent(uint32 ff); - virtual void OnEvent(uint32 ff, int err); - virtual int GetDescriptor(); - virtual bool IsDescriptorClosed(); - - DeviceManager* manager_; - LibUDevSymbolTable libudev_; - struct udev* udev_; - struct udev_monitor* udev_monitor_; - bool registered_; -}; -#define LATE(sym) LATESYM_GET(LibUDevSymbolTable, &libudev_, sym) -#elif defined(OSX) -class DeviceWatcher { - public: - explicit DeviceWatcher(DeviceManager* dm); - bool Start(); - void Stop(); - private: - DeviceManager* manager_; - void* impl_; -}; -#endif - -#if defined(CHROMEOS) -static bool ShouldAudioDeviceBeIgnored(const std::string& device_name); -#endif -#if !defined(LINUX) && !defined(IOS) -static bool ShouldVideoDeviceBeIgnored(const std::string& device_name); -#endif -#ifndef OSX -static bool GetVideoDevices(std::vector* out); -#endif -#if WIN32 -static const wchar_t kFriendlyName[] = L"FriendlyName"; -static const wchar_t kDevicePath[] = L"DevicePath"; -static const char kUsbDevicePathPrefix[] = "\\\\?\\usb"; -static bool GetDevices(const CLSID& catid, std::vector* out); -static bool GetCoreAudioDevices(bool input, std::vector* devs); -static bool GetWaveDevices(bool input, std::vector* devs); -#elif OSX -static const int kVideoDeviceOpenAttempts = 3; -static const UInt32 kAudioDeviceNameLength = 64; -// Obj-C functions defined in devicemanager-mac.mm -extern void* CreateDeviceWatcherCallback(DeviceManager* dm); -extern void ReleaseDeviceWatcherCallback(void* impl); -extern bool GetQTKitVideoDevices(std::vector* out); -static bool GetAudioDeviceIDs(bool inputs, std::vector* out); -static bool GetAudioDeviceName(AudioDeviceID id, bool input, std::string* out); -#endif - -DeviceManager::DeviceManager() - : initialized_(false), -#if defined(WIN32) - need_couninitialize_(false), -#endif - watcher_(new DeviceWatcher(this)) -#ifdef LINUX_SOUND_USED - , sound_system_(new PlatformSoundSystemFactory()) -#endif - { -} - -DeviceManager::~DeviceManager() { - if (initialized_) { - Terminate(); - } - delete watcher_; -} - -bool DeviceManager::Init() { - if (!initialized_) { -#if defined(WIN32) - HRESULT hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); - need_couninitialize_ = SUCCEEDED(hr); - if (FAILED(hr)) { - LOG(LS_ERROR) << "CoInitialize failed, hr=" << hr; - if (hr != RPC_E_CHANGED_MODE) { - return false; - } - } -#endif - if (!watcher_->Start()) { - return false; - } - initialized_ = true; - } - return true; -} - -void DeviceManager::Terminate() { - if (initialized_) { - watcher_->Stop(); -#if defined(WIN32) - if (need_couninitialize_) { - CoUninitialize(); - need_couninitialize_ = false; - } -#endif - initialized_ = false; - } -} - -int DeviceManager::GetCapabilities() { - std::vector devices; - int caps = VIDEO_RECV; - if (GetAudioInputDevices(&devices) && !devices.empty()) { - caps |= AUDIO_SEND; - } - if (GetAudioOutputDevices(&devices) && !devices.empty()) { - caps |= AUDIO_RECV; - } - if (GetVideoCaptureDevices(&devices) && !devices.empty()) { - caps |= VIDEO_SEND; - } - return caps; -} - -bool DeviceManager::GetAudioInputDevices(std::vector* devices) { - return GetAudioDevicesByPlatform(true, devices); -} - -bool DeviceManager::GetAudioOutputDevices(std::vector* devices) { - return GetAudioDevicesByPlatform(false, devices); -} - -bool DeviceManager::GetAudioInputDevice(const std::string& name, Device* out) { - return GetAudioDevice(true, name, out); -} - -bool DeviceManager::GetAudioOutputDevice(const std::string& name, Device* out) { - return GetAudioDevice(false, name, out); -} - -#ifdef OSX -static bool FilterDevice(const Device& d) { - return ShouldVideoDeviceBeIgnored(d.name); -} -#endif - -bool DeviceManager::GetVideoCaptureDevices(std::vector* devices) { - devices->clear(); -#ifdef OSX - if (GetQTKitVideoDevices(devices)) { - // Now filter out any known incompatible devices - devices->erase(remove_if(devices->begin(), devices->end(), FilterDevice), - devices->end()); - return true; - } - return false; -#else - return GetVideoDevices(devices); -#endif -} - -bool DeviceManager::GetDefaultVideoCaptureDevice(Device* device) { - bool ret = false; -#if WIN32 - // If there are multiple capture devices, we want the first USB one. - // This avoids issues with defaulting to virtual cameras or grabber cards. - std::vector devices; - ret = (GetVideoDevices(&devices) && !devices.empty()); - if (ret) { - *device = devices[0]; - for (size_t i = 0; i < devices.size(); ++i) { - if (strnicmp(devices[i].id.c_str(), kUsbDevicePathPrefix, - ARRAY_SIZE(kUsbDevicePathPrefix) - 1) == 0) { - *device = devices[i]; - break; - } - } - } -#else - // We just return the first device. - std::vector devices; - ret = (GetVideoCaptureDevices(&devices) && !devices.empty()); - if (ret) { - *device = devices[0]; - } -#endif - return ret; -} - -bool DeviceManager::GetVideoCaptureDevice(const std::string& name, - Device* out) { - // If the name is empty, return the default device. - if (name.empty() || name == kDefaultDeviceName) { - return GetDefaultVideoCaptureDevice(out); - } - - std::vector devices; - if (!GetVideoCaptureDevices(&devices)) { - return false; - } - - for (std::vector::const_iterator it = devices.begin(); - it != devices.end(); ++it) { - if (name == it->name) { - *out = *it; - return true; - } - } - - return false; -} - -bool DeviceManager::GetAudioDevice(bool is_input, const std::string& name, - Device* out) { - // If the name is empty, return the default device id. - if (name.empty() || name == kDefaultDeviceName) { - *out = Device(name, -1); - return true; - } - - std::vector devices; - bool ret = is_input ? GetAudioInputDevices(&devices) : - GetAudioOutputDevices(&devices); - if (ret) { - ret = false; - for (size_t i = 0; i < devices.size(); ++i) { - if (devices[i].name == name) { - *out = devices[i]; - ret = true; - break; - } - } - } - return ret; -} - -bool DeviceManager::GetAudioDevicesByPlatform(bool input, - std::vector* devs) { - devs->clear(); - -#if defined(LINUX_SOUND_USED) - if (!sound_system_.get()) { - return false; - } - SoundSystemInterface::SoundDeviceLocatorList list; - bool success; - if (input) { - success = sound_system_->EnumerateCaptureDevices(&list); - } else { - success = sound_system_->EnumeratePlaybackDevices(&list); - } - if (!success) { - LOG(LS_ERROR) << "Can't enumerate devices"; - sound_system_.release(); - return false; - } - // We have to start the index at 1 because GIPS VoiceEngine puts the default - // device at index 0, but Enumerate(Capture|Playback)Devices does not include - // a locator for the default device. - int index = 1; - for (SoundSystemInterface::SoundDeviceLocatorList::iterator i = list.begin(); - i != list.end(); - ++i, ++index) { -#if defined(CHROMEOS) - // On ChromeOS, we ignore ALSA surround and S/PDIF devices. - if (!ShouldAudioDeviceBeIgnored((*i)->device_name())) { -#endif - devs->push_back(Device((*i)->name(), index)); -#if defined(CHROMEOS) - } -#endif - } - SoundSystemInterface::ClearSoundDeviceLocatorList(&list); - sound_system_.release(); - return true; - -#elif defined(WIN32) - if (talk_base::IsWindowsVistaOrLater()) { - return GetCoreAudioDevices(input, devs); - } else { - return GetWaveDevices(input, devs); - } - -#elif defined(OSX) - std::vector dev_ids; - bool ret = GetAudioDeviceIDs(input, &dev_ids); - if (ret) { - for (size_t i = 0; i < dev_ids.size(); ++i) { - std::string name; - if (GetAudioDeviceName(dev_ids[i], input, &name)) { - devs->push_back(Device(name, dev_ids[i])); - } - } - } - return ret; - -#else - return false; -#endif -} - -#if defined(WIN32) -bool GetVideoDevices(std::vector* devices) { - return GetDevices(CLSID_VideoInputDeviceCategory, devices); -} - -bool GetDevices(const CLSID& catid, std::vector* devices) { - HRESULT hr; - - // CComPtr is a scoped pointer that will be auto released when going - // out of scope. CoUninitialize must not be called before the - // release. - CComPtr sys_dev_enum; - CComPtr cam_enum; - if (FAILED(hr = sys_dev_enum.CoCreateInstance(CLSID_SystemDeviceEnum)) || - FAILED(hr = sys_dev_enum->CreateClassEnumerator(catid, &cam_enum, 0))) { - LOG(LS_ERROR) << "Failed to create device enumerator, hr=" << hr; - return false; - } - - // Only enum devices if CreateClassEnumerator returns S_OK. If there are no - // devices available, S_FALSE will be returned, but enumMk will be NULL. - if (hr == S_OK) { - CComPtr mk; - while (cam_enum->Next(1, &mk, NULL) == S_OK) { - CComPtr bag; - if (SUCCEEDED(mk->BindToStorage(NULL, NULL, - __uuidof(bag), reinterpret_cast(&bag)))) { - CComVariant name, path; - std::string name_str, path_str; - if (SUCCEEDED(bag->Read(kFriendlyName, &name, 0)) && - name.vt == VT_BSTR) { - name_str = talk_base::ToUtf8(name.bstrVal); - if (!ShouldVideoDeviceBeIgnored(name_str)) { - // Get the device id if one exists. - if (SUCCEEDED(bag->Read(kDevicePath, &path, 0)) && - path.vt == VT_BSTR) { - path_str = talk_base::ToUtf8(path.bstrVal); - } - - devices->push_back(Device(name_str, path_str)); - } - } - } - mk = NULL; - } - } - - return true; -} - -HRESULT GetStringProp(IPropertyStore* bag, PROPERTYKEY key, std::string* out) { - out->clear(); - PROPVARIANT var; - PropVariantInit(&var); - - HRESULT hr = bag->GetValue(key, &var); - if (SUCCEEDED(hr)) { - if (var.pwszVal) - *out = talk_base::ToUtf8(var.pwszVal); - else - hr = E_FAIL; - } - - PropVariantClear(&var); - return hr; -} - -// Adapted from http://msdn.microsoft.com/en-us/library/dd370812(v=VS.85).aspx -HRESULT CricketDeviceFromImmDevice(IMMDevice* device, Device* out) { - CComPtr props; - - HRESULT hr = device->OpenPropertyStore(STGM_READ, &props); - if (FAILED(hr)) { - return hr; - } - - // Get the endpoint's name and id. - std::string name, guid; - hr = GetStringProp(props, PKEY_Device_FriendlyName, &name); - if (SUCCEEDED(hr)) { - hr = GetStringProp(props, PKEY_AudioEndpoint_GUID, &guid); - - if (SUCCEEDED(hr)) { - out->name = name; - out->id = guid; - } - } - return hr; -} - -bool GetCoreAudioDevices(bool input, std::vector* devs) { - HRESULT hr = S_OK; - CComPtr enumerator; - - hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, - __uuidof(IMMDeviceEnumerator), reinterpret_cast(&enumerator)); - if (SUCCEEDED(hr)) { - CComPtr devices; - hr = enumerator->EnumAudioEndpoints((input ? eCapture : eRender), - DEVICE_STATE_ACTIVE, &devices); - if (SUCCEEDED(hr)) { - unsigned int count; - hr = devices->GetCount(&count); - - if (SUCCEEDED(hr)) { - for (unsigned int i = 0; i < count; i++) { - CComPtr device; - - // Get pointer to endpoint number i. - hr = devices->Item(i, &device); - if (FAILED(hr)) { - break; - } - - Device dev; - hr = CricketDeviceFromImmDevice(device, &dev); - if (SUCCEEDED(hr)) { - devs->push_back(dev); - } else { - LOG(LS_WARNING) << "Unable to query IMM Device, skipping. HR=" - << hr; - hr = S_FALSE; - } - } - } - } - } - - if (!SUCCEEDED(hr)) { - LOG(LS_WARNING) << "GetCoreAudioDevices failed with hr " << hr; - return false; - } - return true; -} - -bool GetWaveDevices(bool input, std::vector* devs) { - // Note, we don't use the System Device Enumerator interface here since it - // adds lots of pseudo-devices to the list, such as DirectSound and Wave - // variants of the same device. - if (input) { - int num_devs = waveInGetNumDevs(); - for (int i = 0; i < num_devs; ++i) { - WAVEINCAPS caps; - if (waveInGetDevCaps(i, &caps, sizeof(caps)) == MMSYSERR_NOERROR && - caps.wChannels > 0) { - devs->push_back(Device(talk_base::ToUtf8(caps.szPname), - talk_base::ToString(i))); - } - } - } else { - int num_devs = waveOutGetNumDevs(); - for (int i = 0; i < num_devs; ++i) { - WAVEOUTCAPS caps; - if (waveOutGetDevCaps(i, &caps, sizeof(caps)) == MMSYSERR_NOERROR && - caps.wChannels > 0) { - devs->push_back(Device(talk_base::ToUtf8(caps.szPname), i)); - } - } - } - return true; -} - -DeviceWatcher::DeviceWatcher(DeviceManager* manager) - : manager_(manager), audio_notify_(NULL), video_notify_(NULL) { -} - -bool DeviceWatcher::Start() { - if (!Create(NULL, _T("libjingle DeviceWatcher Window"), - 0, 0, 0, 0, 0, 0)) { - return false; - } - - audio_notify_ = Register(KSCATEGORY_AUDIO); - if (!audio_notify_) { - Stop(); - return false; - } - - video_notify_ = Register(KSCATEGORY_VIDEO); - if (!video_notify_) { - Stop(); - return false; - } - - return true; -} - -void DeviceWatcher::Stop() { - UnregisterDeviceNotification(video_notify_); - video_notify_ = NULL; - UnregisterDeviceNotification(audio_notify_); - audio_notify_ = NULL; - Destroy(); -} - -HDEVNOTIFY DeviceWatcher::Register(REFGUID guid) { - DEV_BROADCAST_DEVICEINTERFACE dbdi; - dbdi.dbcc_size = sizeof(dbdi); - dbdi.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; - dbdi.dbcc_classguid = guid; - dbdi.dbcc_name[0] = '\0'; - return RegisterDeviceNotification(handle(), &dbdi, - DEVICE_NOTIFY_WINDOW_HANDLE); -} - -void DeviceWatcher::Unregister(HDEVNOTIFY handle) { - UnregisterDeviceNotification(handle); -} - -bool DeviceWatcher::OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, - LRESULT& result) { - if (uMsg == WM_DEVICECHANGE) { - if (wParam == DBT_DEVICEARRIVAL || - wParam == DBT_DEVICEREMOVECOMPLETE) { - DEV_BROADCAST_DEVICEINTERFACE* dbdi = - reinterpret_cast(lParam); - if (dbdi->dbcc_classguid == KSCATEGORY_AUDIO || - dbdi->dbcc_classguid == KSCATEGORY_VIDEO) { - manager_->OnDevicesChange(); - } - } - result = 0; - return true; - } - - return false; -} -#elif defined(OSX) -static bool GetAudioDeviceIDs(bool input, - std::vector* out_dev_ids) { - UInt32 propsize; - OSErr err = AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, - &propsize, NULL); - if (0 != err) { - LOG(LS_ERROR) << "Couldn't get information about property, " - << "so no device list acquired."; - return false; - } - - size_t num_devices = propsize / sizeof(AudioDeviceID); - talk_base::scoped_array device_ids( - new AudioDeviceID[num_devices]); - - err = AudioHardwareGetProperty(kAudioHardwarePropertyDevices, - &propsize, device_ids.get()); - if (0 != err) { - LOG(LS_ERROR) << "Failed to get device ids, " - << "so no device listing acquired."; - return false; - } - - for (size_t i = 0; i < num_devices; ++i) { - AudioDeviceID an_id = device_ids[i]; - // find out the number of channels for this direction - // (input/output) on this device - - // we'll ignore anything with no channels. - err = AudioDeviceGetPropertyInfo(an_id, 0, input, - kAudioDevicePropertyStreams, - &propsize, NULL); - if (0 == err) { - unsigned num_channels = propsize / sizeof(AudioStreamID); - if (0 < num_channels) { - out_dev_ids->push_back(an_id); - } - } else { - LOG(LS_ERROR) << "No property info for stream property for device id " - << an_id << "(is_input == " << input - << "), so not including it in the list."; - } - } - - return true; -} - -static bool GetAudioDeviceName(AudioDeviceID id, - bool input, - std::string* out_name) { - UInt32 nameLength = kAudioDeviceNameLength; - char name[kAudioDeviceNameLength + 1]; - OSErr err = AudioDeviceGetProperty(id, 0, input, - kAudioDevicePropertyDeviceName, - &nameLength, name); - if (0 != err) { - LOG(LS_ERROR) << "No name acquired for device id " << id; - return false; - } - - *out_name = name; - return true; -} - -DeviceWatcher::DeviceWatcher(DeviceManager* manager) - : manager_(manager), impl_(NULL) { -} - -bool DeviceWatcher::Start() { - if (!impl_) { - impl_ = CreateDeviceWatcherCallback(manager_); - } - return impl_ != NULL; -} - -void DeviceWatcher::Stop() { - if (impl_) { - ReleaseDeviceWatcherCallback(impl_); - impl_ = NULL; - } -} - -#elif defined(LINUX) -static const std::string kVideoMetaPathK2_4("/proc/video/dev/"); -static const std::string kVideoMetaPathK2_6("/sys/class/video4linux/"); - -enum MetaType { M2_4, M2_6, NONE }; - -static void ScanDeviceDirectory(const std::string& devdir, - std::vector* devices) { - talk_base::scoped_ptr directoryIterator( - talk_base::Filesystem::IterateDirectory()); - - if (directoryIterator->Iterate(talk_base::Pathname(devdir))) { - do { - std::string filename = directoryIterator->Name(); - std::string device_name = devdir + filename; - if (!directoryIterator->IsDots()) { - if (filename.find("video") == 0 && - V4LLookup::IsV4L2Device(device_name)) { - devices->push_back(Device(device_name, device_name)); - } - } - } while (directoryIterator->Next()); - } -} - -static std::string GetVideoDeviceNameK2_6(const std::string& device_meta_path) { - std::string device_name; - - talk_base::scoped_ptr device_meta_stream( - talk_base::Filesystem::OpenFile(device_meta_path, "r")); - - if (device_meta_stream.get() != NULL) { - if (device_meta_stream->ReadLine(&device_name) != talk_base::SR_SUCCESS) { - LOG(LS_ERROR) << "Failed to read V4L2 device meta " << device_meta_path; - } - device_meta_stream->Close(); - } - - return device_name; -} - -static std::string Trim(const std::string& s, const std::string& drop = " \t") { - std::string::size_type first = s.find_first_not_of(drop); - std::string::size_type last = s.find_last_not_of(drop); - - if (first == std::string::npos || last == std::string::npos) - return std::string(""); - - return s.substr(first, last - first + 1); -} - -static std::string GetVideoDeviceNameK2_4(const std::string& device_meta_path) { - talk_base::ConfigParser::MapVector all_values; - - talk_base::ConfigParser config_parser; - talk_base::FileStream* file_stream = - talk_base::Filesystem::OpenFile(device_meta_path, "r"); - - if (file_stream == NULL) return ""; - - config_parser.Attach(file_stream); - config_parser.Parse(&all_values); - - for (talk_base::ConfigParser::MapVector::iterator i = all_values.begin(); - i != all_values.end(); ++i) { - talk_base::ConfigParser::SimpleMap::iterator device_name_i = - i->find("name"); - - if (device_name_i != i->end()) { - return device_name_i->second; - } - } - - return ""; -} - -static std::string GetVideoDeviceName(MetaType meta, - const std::string& device_file_name) { - std::string device_meta_path; - std::string device_name; - std::string meta_file_path; - - if (meta == M2_6) { - meta_file_path = kVideoMetaPathK2_6 + device_file_name + "/name"; - - LOG(LS_INFO) << "Trying " + meta_file_path; - device_name = GetVideoDeviceNameK2_6(meta_file_path); - - if (device_name.empty()) { - meta_file_path = kVideoMetaPathK2_6 + device_file_name + "/model"; - - LOG(LS_INFO) << "Trying " << meta_file_path; - device_name = GetVideoDeviceNameK2_6(meta_file_path); - } - } else { - meta_file_path = kVideoMetaPathK2_4 + device_file_name; - LOG(LS_INFO) << "Trying " << meta_file_path; - device_name = GetVideoDeviceNameK2_4(meta_file_path); - } - - if (device_name.empty()) { - device_name = "/dev/" + device_file_name; - LOG(LS_ERROR) - << "Device name not found, defaulting to device path " << device_name; - } - - LOG(LS_INFO) << "Name for " << device_file_name << " is " << device_name; - - return Trim(device_name); -} - -static void ScanV4L2Devices(std::vector* devices) { - LOG(LS_INFO) << ("Enumerating V4L2 devices"); - - MetaType meta; - std::string metadata_dir; - - talk_base::scoped_ptr directoryIterator( - talk_base::Filesystem::IterateDirectory()); - - // Try and guess kernel version - if (directoryIterator->Iterate(kVideoMetaPathK2_6)) { - meta = M2_6; - metadata_dir = kVideoMetaPathK2_6; - } else if (directoryIterator->Iterate(kVideoMetaPathK2_4)) { - meta = M2_4; - metadata_dir = kVideoMetaPathK2_4; - } else { - meta = NONE; - } - - if (meta != NONE) { - LOG(LS_INFO) << "V4L2 device metadata found at " << metadata_dir; - - do { - std::string filename = directoryIterator->Name(); - - if (filename.find("video") == 0) { - std::string device_path = "/dev/" + filename; - - if (V4LLookup::IsV4L2Device(device_path)) { - devices->push_back( - Device(GetVideoDeviceName(meta, filename), device_path)); - } - } - } while (directoryIterator->Next()); - } else { - LOG(LS_ERROR) << "Unable to detect v4l2 metadata directory"; - } - - if (devices->size() == 0) { - LOG(LS_INFO) << "Plan B. Scanning all video devices in /dev directory"; - ScanDeviceDirectory("/dev/", devices); - } - - LOG(LS_INFO) << "Total V4L2 devices found : " << devices->size(); -} - -static bool GetVideoDevices(std::vector* devices) { - ScanV4L2Devices(devices); - return true; -} - -DeviceWatcher::DeviceWatcher(DeviceManager* dm) - : manager_(dm), udev_(NULL), udev_monitor_(NULL), registered_(false) {} - -bool DeviceWatcher::Start() { - // We deliberately return true in the failure paths here because libudev is - // not a critical component of a Linux system so it may not be present/usable, - // and we don't want to halt DeviceManager initialization in such a case. - if (!libudev_.Load()) { - LOG(LS_WARNING) << "libudev not present/usable; DeviceWatcher disabled"; - return true; - } - udev_ = LATE(udev_new)(); - if (!udev_) { - LOG_ERR(LS_ERROR) << "udev_new()"; - return true; - } - // The second argument here is the event source. It can be either "kernel" or - // "udev", but "udev" is the only correct choice. Apps listen on udev and the - // udev daemon in turn listens on the kernel. - udev_monitor_ = LATE(udev_monitor_new_from_netlink)(udev_, "udev"); - if (!udev_monitor_) { - LOG_ERR(LS_ERROR) << "udev_monitor_new_from_netlink()"; - return true; - } - // We only listen for changes in the video devices. Audio devices are more or - // less unimportant because receiving device change notifications really only - // matters for broadcasting updated send/recv capabilities based on whether - // there is at least one device available, and almost all computers have at - // least one audio device. Also, PulseAudio device notifications don't come - // from the udev daemon, they come from the PulseAudio daemon, so we'd only - // want to listen for audio device changes from udev if using ALSA. For - // simplicity, we don't bother with any audio stuff at all. - if (LATE(udev_monitor_filter_add_match_subsystem_devtype)(udev_monitor_, - "video4linux", - NULL) < 0) { - LOG_ERR(LS_ERROR) << "udev_monitor_filter_add_match_subsystem_devtype()"; - return true; - } - if (LATE(udev_monitor_enable_receiving)(udev_monitor_) < 0) { - LOG_ERR(LS_ERROR) << "udev_monitor_enable_receiving()"; - return true; - } - static_cast( - talk_base::Thread::Current()->socketserver())->Add(this); - registered_ = true; - return true; -} - -void DeviceWatcher::Stop() { - if (registered_) { - static_cast( - talk_base::Thread::Current()->socketserver())->Remove(this); - registered_ = false; - } - if (udev_monitor_) { - LATE(udev_monitor_unref)(udev_monitor_); - udev_monitor_ = NULL; - } - if (udev_) { - LATE(udev_unref)(udev_); - udev_ = NULL; - } - libudev_.Unload(); -} - -uint32 DeviceWatcher::GetRequestedEvents() { - return talk_base::DE_READ; -} - -void DeviceWatcher::OnPreEvent(uint32 ff) { - // Nothing to do. -} - -void DeviceWatcher::OnEvent(uint32 ff, int err) { - udev_device* device = LATE(udev_monitor_receive_device)(udev_monitor_); - if (!device) { - // Probably the socket connection to the udev daemon was terminated (perhaps - // the daemon crashed or is being restarted?). - LOG_ERR(LS_WARNING) << "udev_monitor_receive_device()"; - // Stop listening to avoid potential livelock (an fd with EOF in it is - // always considered readable). - static_cast( - talk_base::Thread::Current()->socketserver())->Remove(this); - registered_ = false; - return; - } - // Else we read the device successfully. - - // Since we already have our own filesystem-based device enumeration code, we - // simply re-enumerate rather than inspecting the device event. - LATE(udev_device_unref)(device); - manager_->OnDevicesChange(); -} - -int DeviceWatcher::GetDescriptor() { - return LATE(udev_monitor_get_fd)(udev_monitor_); -} - -bool DeviceWatcher::IsDescriptorClosed() { - // If it is closed then we will just get an error in - // udev_monitor_receive_device and unregister, so we don't need to check for - // it separately. - return false; -} - -#endif - -#if defined(CHROMEOS) -// Checks if we want to ignore this audio device. -static bool ShouldAudioDeviceBeIgnored(const std::string& device_name) { - static const char* const kFilteredAudioDevicesName[] = { - "surround40:", - "surround41:", - "surround50:", - "surround51:", - "surround71:", - "iec958:" // S/PDIF - }; - for (int i = 0; i < ARRAY_SIZE(kFilteredAudioDevicesName); ++i) { - if (0 == device_name.find(kFilteredAudioDevicesName[i])) { - LOG(LS_INFO) << "Ignoring device " << device_name; - return true; - } - } - return false; -} -#endif - -// TODO: Try to get hold of a copy of Final Cut to understand why we -// crash while scanning their components on OS X. -#if !defined(LINUX) && !defined(IOS) -static bool ShouldVideoDeviceBeIgnored(const std::string& device_name) { - static const char* const kFilteredVideoDevicesName[] = { - "Google Camera Adapter", // Our own magiccams -#ifdef WIN32 - "Asus virtual Camera", // Bad Asus desktop virtual cam - "Bluetooth Video", // Bad Sony viao bluetooth sharing driver -#elif OSX - "DVCPRO HD", // Final cut - "Sonix SN9C201p", // Crashes in OpenAComponent and CloseComponent -#endif - }; - - for (int i = 0; i < ARRAY_SIZE(kFilteredVideoDevicesName); ++i) { - if (strnicmp(device_name.c_str(), kFilteredVideoDevicesName[i], - strlen(kFilteredVideoDevicesName[i])) == 0) { - LOG(LS_INFO) << "Ignoring device " << device_name; - return true; - } - } - return false; -} -#endif - -}; // namespace cricket diff --git a/third_party_mods/libjingle/source/talk/session/phone/devicemanager.h b/third_party_mods/libjingle/source/talk/session/phone/devicemanager.h deleted file mode 100644 index d2d7db91f1..0000000000 --- a/third_party_mods/libjingle/source/talk/session/phone/devicemanager.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * libjingle - * Copyright 2004--2008, 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_DEVICEMANAGER_H_ -#define TALK_SESSION_PHONE_DEVICEMANAGER_H_ - -#include -#include - -#include "talk/base/sigslot.h" -#include "talk/base/stringencode.h" -#ifdef LINUX_SOUND_USED -#include "talk/sound/soundsystemfactory.h" -#endif - -namespace cricket { - -class DeviceWatcher; - -// Used to represent an audio or video capture or render device. -struct Device { - Device() {} - Device(const std::string& first, int second) - : name(first), - id(talk_base::ToString(second)) { - } - Device(const std::string& first, const std::string& second) - : name(first), id(second) {} - - std::string name; - std::string id; -}; - -// DeviceManagerInterface - interface to manage the audio and -// video devices on the system. -class DeviceManagerInterface { - public: - virtual ~DeviceManagerInterface() { } - - // Initialization - virtual bool Init() = 0; - virtual void Terminate() = 0; - - // Capabilities - virtual int GetCapabilities() = 0; - - // Device enumeration - virtual bool GetAudioInputDevices(std::vector* devices) = 0; - virtual bool GetAudioOutputDevices(std::vector* devices) = 0; - - virtual bool GetAudioInputDevice(const std::string& name, Device* out) = 0; - virtual bool GetAudioOutputDevice(const std::string& name, Device* out) = 0; - - virtual bool GetVideoCaptureDevices(std::vector* devs) = 0; - virtual bool GetVideoCaptureDevice(const std::string& name, Device* out) = 0; - - sigslot::signal0<> SignalDevicesChange; - - static const char kDefaultDeviceName[]; -}; - -class DeviceManagerFactory { - public: - static DeviceManagerInterface* Create(); - private: - DeviceManagerFactory(); -}; - -class DeviceManager : public DeviceManagerInterface { - public: - DeviceManager(); - virtual ~DeviceManager(); - - // Initialization - virtual bool Init(); - virtual void Terminate(); - - // Capabilities - virtual int GetCapabilities(); - - // Device enumeration - virtual bool GetAudioInputDevices(std::vector* devices); - virtual bool GetAudioOutputDevices(std::vector* devices); - - virtual bool GetAudioInputDevice(const std::string& name, Device* out); - virtual bool GetAudioOutputDevice(const std::string& name, Device* out); - - virtual bool GetVideoCaptureDevices(std::vector* devs); - virtual bool GetVideoCaptureDevice(const std::string& name, Device* out); - - bool initialized() const { return initialized_; } - void OnDevicesChange() { SignalDevicesChange(); } - - protected: - virtual bool GetAudioDevice(bool is_input, const std::string& name, - Device* out); - virtual bool GetDefaultVideoCaptureDevice(Device* device); - - private: - bool GetAudioDevicesByPlatform(bool input, std::vector* devs); - - bool initialized_; -#ifdef WIN32 - bool need_couninitialize_; -#endif - DeviceWatcher* watcher_; -#ifdef LINUX_SOUND_USED - SoundSystemHandle sound_system_; -#endif -}; - -} // namespace cricket - -#endif // TALK_SESSION_PHONE_DEVICEMANAGER_H_ diff --git a/third_party_mods/libjingle/source/talk/session/phone/webrtcvideoengine.cc b/third_party_mods/libjingle/source/talk/session/phone/webrtcvideoengine.cc deleted file mode 100644 index 0452813221..0000000000 --- a/third_party_mods/libjingle/source/talk/session/phone/webrtcvideoengine.cc +++ /dev/null @@ -1,1031 +0,0 @@ -/* - * libjingle - * Copyright 2004--2011, 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_WEBRTC_VIDEO - -#include "talk/session/phone/webrtcvideoengine.h" - -#include "talk/base/common.h" -#include "talk/base/buffer.h" -#include "talk/base/byteorder.h" -#include "talk/base/logging.h" -#include "talk/base/stringutils.h" -#include "talk/session/phone/videorenderer.h" -#include "talk/session/phone/webrtcpassthroughrender.h" -#include "talk/session/phone/webrtcvoiceengine.h" -#include "talk/session/phone/webrtcvideoframe.h" -#include "talk/session/phone/webrtcvie.h" -#include "talk/session/phone/webrtcvoe.h" - -namespace cricket { - -static const int kDefaultLogSeverity = talk_base::LS_WARNING; -static const int kStartVideoBitrate = 300; -static const int kMaxVideoBitrate = 1000; -static const int kMaxVideoRtpBufferSize = 0xFFFF; - -class WebRtcRenderAdapter : public webrtc::ExternalRenderer { - public: - explicit WebRtcRenderAdapter(VideoRenderer* renderer) - : renderer_(renderer) { - } - - virtual int FrameSizeChange(unsigned int width, unsigned int height, - unsigned int /*number_of_streams*/) { - if (renderer_ == NULL) - return 0; - width_ = width; - height_ = height; - return renderer_->SetSize(width_, height_, 0) ? 0 : -1; - } - - virtual int DeliverFrame(unsigned char* buffer, int buffer_size, - unsigned int time_stamp) { - if (renderer_ == NULL) - return 0; - WebRtcVideoFrame video_frame; - video_frame.Attach(buffer, buffer_size, width_, height_, 0, time_stamp); - int ret = renderer_->RenderFrame(&video_frame) ? 0 : -1; - uint8* buffer_temp; - size_t buffer_size_temp; - video_frame.Detach(&buffer_temp, &buffer_size_temp); - return ret; - } - - virtual ~WebRtcRenderAdapter() {} - - private: - VideoRenderer* renderer_; - unsigned int width_; - unsigned int height_; -}; - -const WebRtcVideoEngine::VideoCodecPref - WebRtcVideoEngine::kVideoCodecPrefs[] = { - {"VP8", 120, 0}, -}; - -// The formats are sorted by the descending order of width. We use the order to -// find the next format for CPU and bandwidth adaptation. -const VideoFormat WebRtcVideoEngine::kVideoFormats[] = { - // TODO: Understand why we have problem with 16:9 formats. - VideoFormat(1280, 800, VideoFormat::FpsToInterval(30), FOURCC_ANY), -//VideoFormat(1280, 720, VideoFormat::FpsToInterval(30), FOURCC_ANY), - VideoFormat(960, 600, VideoFormat::FpsToInterval(30), FOURCC_ANY), -//VideoFormat(960, 540, VideoFormat::FpsToInterval(30), FOURCC_ANY), - VideoFormat(640, 400, VideoFormat::FpsToInterval(30), FOURCC_ANY), -//VideoFormat(640, 360, VideoFormat::FpsToInterval(30), FOURCC_ANY), - VideoFormat(480, 300, VideoFormat::FpsToInterval(30), FOURCC_ANY), -//VideoFormat(480, 270, VideoFormat::FpsToInterval(30), FOURCC_ANY), - VideoFormat(320, 200, VideoFormat::FpsToInterval(30), FOURCC_ANY), -//VideoFormat(320, 180, VideoFormat::FpsToInterval(30), FOURCC_ANY), - VideoFormat(240, 150, VideoFormat::FpsToInterval(30), FOURCC_ANY), -//VideoFormat(240, 135, VideoFormat::FpsToInterval(30), FOURCC_ANY), - VideoFormat(160, 100, VideoFormat::FpsToInterval(30), FOURCC_ANY), -//VideoFormat(160, 90, VideoFormat::FpsToInterval(30), FOURCC_ANY), -}; - -// TODO: Understand why 640x400 is not working. -const VideoFormat WebRtcVideoEngine::kDefaultVideoFormat = - VideoFormat(320, 200, VideoFormat::FpsToInterval(30), FOURCC_ANY); - -WebRtcVideoEngine::WebRtcVideoEngine() - : vie_wrapper_(new ViEWrapper()), - voice_engine_(NULL) { - Construct(); -} - -WebRtcVideoEngine::WebRtcVideoEngine(WebRtcVoiceEngine* voice_engine, - ViEWrapper* vie_wrapper) - : vie_wrapper_(vie_wrapper), - voice_engine_(voice_engine) { - Construct(); -} - -void WebRtcVideoEngine::Construct() { - initialized_ = false; - capture_id_ = -1; - capture_module_ = NULL; - external_capture_ = false; - log_level_ = kDefaultLogSeverity; - capture_started_ = false; - render_module_.reset(new WebRtcPassthroughRender()); - - ApplyLogging(); - if (vie_wrapper_->engine()->SetTraceCallback(this) != 0) { - LOG_RTCERR1(SetTraceCallback, this); - } - - // Set default quality levels for our supported codecs. We override them here - // if we know your cpu performance is low, and they can be updated explicitly - // by calling SetDefaultCodec. For example by a flute preference setting, or - // by the server with a jec in response to our reported system info. - VideoCodec max_codec(kVideoCodecPrefs[0].payload_type, - kVideoCodecPrefs[0].name, - kDefaultVideoFormat.width, - kDefaultVideoFormat.height, - kDefaultVideoFormat.framerate(), 0); - if (!SetDefaultCodec(max_codec)) { - LOG(LS_ERROR) << "Failed to initialize list of supported codec types"; - } -} - -WebRtcVideoEngine::~WebRtcVideoEngine() { - LOG(LS_INFO) << " WebRtcVideoEngine::~WebRtcVideoEngine"; - vie_wrapper_->engine()->SetTraceCallback(NULL); - Terminate(); - vie_wrapper_.reset(); - if (capture_module_) { - capture_module_->Release(); - } -} - -bool WebRtcVideoEngine::Init() { - LOG(LS_INFO) << "WebRtcVideoEngine::Init"; - bool result = InitVideoEngine(); - if (result) { - LOG(LS_INFO) << "VideoEngine Init done"; - } else { - LOG(LS_ERROR) << "VideoEngine Init failed, releasing"; - Terminate(); - } - return result; -} - -bool WebRtcVideoEngine::InitVideoEngine() { - LOG(LS_INFO) << "WebRtcVideoEngine::InitVideoEngine"; - - if (vie_wrapper_->base()->Init() != 0) { - LOG_RTCERR0(Init); - return false; - } - - if (!voice_engine_) { - LOG(LS_WARNING) << "NULL voice engine"; - } else if ((vie_wrapper_->base()->SetVoiceEngine( - voice_engine_->voe()->engine())) != 0) { - LOG_RTCERR0(SetVoiceEngine); - return false; - } - - if ((vie_wrapper_->base()->RegisterObserver(*this)) != 0) { - LOG_RTCERR0(RegisterObserver); - return false; - } - - if (vie_wrapper_->render()->RegisterVideoRenderModule( - *render_module_.get()) != 0) { - LOG_RTCERR0(RegisterVideoRenderModule); - return false; - } - - std::sort(video_codecs_.begin(), video_codecs_.end(), - &VideoCodec::Preferable); - - initialized_ = true; - return true; -} - -void WebRtcVideoEngine::PerformanceAlarm(const unsigned int cpu_load) { - LOG(LS_INFO) << "WebRtcVideoEngine::PerformanceAlarm"; -} - -// Ignore spammy trace messages, mostly from the stats API when we haven't -// gotten RTCP info yet from the remote side. -static bool ShouldIgnoreTrace(const std::string& trace) { - static const char* kTracesToIgnore[] = { - "\tfailed to GetReportBlockInformation", - NULL - }; - for (const char* const* p = kTracesToIgnore; *p; ++p) { - if (trace.find(*p) == 0) { - return true; - } - } - return false; -} - -void WebRtcVideoEngine::Print(const webrtc::TraceLevel level, - const char* trace, const int length) { - talk_base::LoggingSeverity sev = talk_base::LS_VERBOSE; - if (level == webrtc::kTraceError || level == webrtc::kTraceCritical) - sev = talk_base::LS_ERROR; - else if (level == webrtc::kTraceWarning) - sev = talk_base::LS_WARNING; - else if (level == webrtc::kTraceStateInfo || level == webrtc::kTraceInfo) - sev = talk_base::LS_INFO; - - if (sev >= log_level_) { - // Skip past boilerplate prefix text - if (length < 72) { - std::string msg(trace, length); - LOG(LS_ERROR) << "Malformed webrtc log message: "; - LOG_V(sev) << msg; - } else { - std::string msg(trace + 71, length - 72); - if (!ShouldIgnoreTrace(msg)) { - LOG_V(sev) << "WebRtc ViE:" << msg; - } - } - } -} - -void WebRtcVideoEngine::ApplyLogging() { - int filter = 0; - switch (log_level_) { - case talk_base::LS_VERBOSE: filter |= webrtc::kTraceAll; - case talk_base::LS_INFO: filter |= webrtc::kTraceStateInfo; - case talk_base::LS_WARNING: filter |= webrtc::kTraceWarning; - case talk_base::LS_ERROR: filter |= - webrtc::kTraceError | webrtc::kTraceCritical; - } -} - -// Rebuilds the codec list to be only those that are less intensive -// than the specified codec. -bool WebRtcVideoEngine::RebuildCodecList(const VideoCodec& in_codec) { - if (!FindCodec(in_codec)) - return false; - - video_codecs_.clear(); - - bool found = false; - for (size_t i = 0; i < ARRAY_SIZE(kVideoCodecPrefs); ++i) { - const VideoCodecPref& pref(kVideoCodecPrefs[i]); - if (!found) - found = (in_codec.name == pref.name); - if (found) { - VideoCodec codec(pref.payload_type, pref.name, - in_codec.width, in_codec.height, in_codec.framerate, - ARRAY_SIZE(kVideoCodecPrefs) - i); - video_codecs_.push_back(codec); - } - } - ASSERT(found); - return true; -} - -void WebRtcVideoEngine::Terminate() { - LOG(LS_INFO) << "WebRtcVideoEngine::Terminate"; - initialized_ = false; - SetCapture(false); - if (local_renderer_.get()) { - // If the renderer already set, stop it first - if (vie_wrapper_->render()->StopRender(capture_id_) != 0) - LOG_RTCERR1(StopRender, capture_id_); - } - - if (vie_wrapper_->render()->DeRegisterVideoRenderModule( - *render_module_.get()) != 0) - LOG_RTCERR0(DeRegisterVideoRenderModule); - - if ((vie_wrapper_->base()->DeregisterObserver()) != 0) - LOG_RTCERR0(DeregisterObserver); - - if ((vie_wrapper_->base()->SetVoiceEngine(NULL)) != 0) - LOG_RTCERR0(SetVoiceEngine); - - if (vie_wrapper_->engine()->SetTraceCallback(NULL) != 0) - LOG_RTCERR0(SetTraceCallback); -} - -int WebRtcVideoEngine::GetCapabilities() { - return VIDEO_RECV | VIDEO_SEND; -} - -bool WebRtcVideoEngine::SetOptions(int options) { - return true; -} - -bool WebRtcVideoEngine::ReleaseCaptureDevice() { - if (capture_id_ != -1) { - // Stop capture - SetCapture(false); - // DisconnectCaptureDevice - WebRtcVideoMediaChannel* channel; - for (VideoChannels::const_iterator it = channels_.begin(); - it != channels_.end(); ++it) { - ASSERT(*it != NULL); - channel = *it; - // Ignore the return value here as the channel may not have connected to - // the capturer yet. - vie_wrapper_->capture()->DisconnectCaptureDevice( - channel->video_channel()); - channel->set_connected(false); - } - // ReleaseCaptureDevice - vie_wrapper_->capture()->ReleaseCaptureDevice(capture_id_); - capture_id_ = -1; - } - - return true; -} - -bool WebRtcVideoEngine::SetCaptureDevice(const Device* cam) { - ASSERT(cam != NULL); - - ReleaseCaptureDevice(); - - webrtc::ViECapture* vie_capture = vie_wrapper_->capture(); - - // There's an external VCM - if (capture_module_) { - if (vie_capture->AllocateCaptureDevice(*capture_module_, capture_id_) != 0) - ASSERT(capture_id_ == -1); - } else if (!external_capture_) { - char device_name[256], device_id[256]; - bool found = false; - for (int i = 0; i < vie_capture->NumberOfCaptureDevices(); ++i) { - if (vie_capture->GetCaptureDevice(i, device_name, - ARRAY_SIZE(device_name), - device_id, - ARRAY_SIZE(device_id)) == 0) { - // TODO: We should only compare the device_id here, - // however the devicemanager and webrtc use different format for th v4l2 - // device id. So here we also compare the device_name for now. - // For example "usb-0000:00:1d.7-6" vs "/dev/video0". - if (cam->name.compare(device_name) == 0 || - cam->id.compare(device_id) == 0) { - LOG(INFO) << "Found video capture device: " << device_name; - found = true; - break; - } - } - } - if (!found) { - return false; - } - if (vie_capture->AllocateCaptureDevice(device_id, strlen(device_id), - capture_id_) != 0) { - ASSERT(capture_id_ == -1); - } - } - - if (capture_id_ != -1) { - // Connect to all the channels if there is any. - WebRtcVideoMediaChannel* channel; - for (VideoChannels::const_iterator it = channels_.begin(); - it != channels_.end(); ++it) { - ASSERT(*it != NULL); - channel = *it; - - // No channel should have been connected yet. - // In case of switching device, all channel connections should have been - // disconnected in ReleaseCaptureDevice() first. - ASSERT(!channel->connected()); - - if (vie_capture->ConnectCaptureDevice(capture_id_, - channel->video_channel()) == 0) { - channel->set_connected(true); - } else { - LOG(LS_WARNING) << "SetCaptureDevice failed to ConnectCaptureDevice."; - } - } - SetCapture(true); - } - - return (capture_id_ != -1); -} - -bool WebRtcVideoEngine::SetCaptureModule(webrtc::VideoCaptureModule* vcm) { - ReleaseCaptureDevice(); - if (capture_module_) { - capture_module_->Release(); - capture_module_ = NULL; - } - - if (vcm) { - capture_module_ = vcm; - capture_module_->AddRef(); - external_capture_ = true; - } else { - external_capture_ = false; - } - - return true; -} - -bool WebRtcVideoEngine::SetLocalRenderer(VideoRenderer* renderer) { - if (local_renderer_.get()) { - // If the renderer already set, stop and remove it first - if (vie_wrapper_->render()->StopRender(capture_id_) != 0) { - LOG_RTCERR1(StopRender, capture_id_); - } - if (vie_wrapper_->render()->RemoveRenderer(capture_id_) != 0) { - LOG_RTCERR1(RemoveRenderer, capture_id_); - } - } - local_renderer_.reset(new WebRtcRenderAdapter(renderer)); - - int ret; - ret = vie_wrapper_->render()->AddRenderer(capture_id_, - webrtc::kVideoI420, - local_renderer_.get()); - if (ret != 0) - return false; - ret = vie_wrapper_->render()->StartRender(capture_id_); - return (ret == 0); -} - -CaptureResult WebRtcVideoEngine::SetCapture(bool capture) { - if ((capture_started_ != capture) && (capture_id_ != -1)) { - int ret; - if (capture) - ret = vie_wrapper_->capture()->StartCapture(capture_id_); - else - ret = vie_wrapper_->capture()->StopCapture(capture_id_); - if (ret != 0) - return CR_NO_DEVICE; - capture_started_ = capture; - } - return CR_SUCCESS; -} - -const std::vector& WebRtcVideoEngine::codecs() const { - return video_codecs_; -} - -void WebRtcVideoEngine::SetLogging(int min_sev, const char* filter) { - log_level_ = min_sev; - ApplyLogging(); -} - -int WebRtcVideoEngine::GetLastEngineError() { - return vie_wrapper_->error(); -} - -bool WebRtcVideoEngine::SetDefaultEncoderConfig( - const VideoEncoderConfig& config) { - default_encoder_config_ = config; - return true; -} - -WebRtcVideoMediaChannel* WebRtcVideoEngine::CreateChannel( - VoiceMediaChannel* voice_channel) { - WebRtcVideoMediaChannel* channel = - new WebRtcVideoMediaChannel(this, voice_channel); - if (channel) { - if (!channel->Init()) { - delete channel; - channel = NULL; - } - } - return channel; -} - -// Checks to see whether we comprehend and could receive a particular codec -bool WebRtcVideoEngine::FindCodec(const VideoCodec& in) { - for (int i = 0; i < ARRAY_SIZE(kVideoFormats); ++i) { - const VideoFormat& fmt = kVideoFormats[i]; - if ((in.width == 0 && in.height == 0) || - (fmt.width == in.width && fmt.height == in.height)) { - for (int j = 0; j < ARRAY_SIZE(kVideoCodecPrefs); ++j) { - VideoCodec codec(kVideoCodecPrefs[j].payload_type, - kVideoCodecPrefs[j].name, 0, 0, 0, 0); - if (codec.Matches(in)) { - return true; - } - } - } - } - return false; -} - -// SetDefaultCodec may be called while the capturer is running. For example, a -// test call is started in a page with QVGA default codec, and then a real call -// is started in another page with VGA default codec. This is the corner case -// and happens only when a session is started. We ignore this case currently. -bool WebRtcVideoEngine::SetDefaultCodec(const VideoCodec& codec) { - if (!RebuildCodecList(codec)) { - LOG(LS_WARNING) << "Failed to RebuildCodecList"; - return false; - } - return true; -} - -void WebRtcVideoEngine::ConvertToCricketVideoCodec( - const webrtc::VideoCodec& in_codec, VideoCodec& out_codec) { - out_codec.id = in_codec.plType; - out_codec.name = in_codec.plName; - out_codec.width = in_codec.width; - out_codec.height = in_codec.height; - out_codec.framerate = in_codec.maxFramerate; -} - -bool WebRtcVideoEngine::ConvertFromCricketVideoCodec( - const VideoCodec& in_codec, webrtc::VideoCodec& out_codec) { - bool found = false; - int ncodecs = vie_wrapper_->codec()->NumberOfCodecs(); - for (int i = 0; i < ncodecs; ++i) { - if ((vie_wrapper_->codec()->GetCodec(i, out_codec) == 0) && - (strncmp(out_codec.plName, - in_codec.name.c_str(), - webrtc::kPayloadNameSize - 1) == 0)) { - found = true; - break; - } - } - - if (!found) { - LOG(LS_ERROR) << "invalid codec type"; - return false; - } - - if (in_codec.id != 0) - out_codec.plType = in_codec.id; - - if (in_codec.width != 0) - out_codec.width = in_codec.width; - - if (in_codec.height != 0) - out_codec.height = in_codec.height; - - if (in_codec.framerate != 0) - out_codec.maxFramerate = in_codec.framerate; - - out_codec.maxBitrate = kMaxVideoBitrate; - out_codec.startBitrate = kStartVideoBitrate; - out_codec.minBitrate = kStartVideoBitrate; - - return true; -} - -int WebRtcVideoEngine::GetLastVideoEngineError() { - return vie_wrapper_->base()->LastError(); -} - -void WebRtcVideoEngine::RegisterChannel(WebRtcVideoMediaChannel *channel) { - channels_.push_back(channel); -} - -void WebRtcVideoEngine::UnregisterChannel(WebRtcVideoMediaChannel *channel) { - VideoChannels::iterator i = std::find(channels_.begin(), - channels_.end(), - channel); - if (i != channels_.end()) { - channels_.erase(i); - } -} - -bool WebRtcVideoEngine::SetVoiceEngine(WebRtcVoiceEngine* voice_engine) { - if (initialized_) { - LOG(LS_WARNING) << "SetVoiceEngine can not be called after Init."; - return false; - } - voice_engine_ = voice_engine; - return true; -} - -bool WebRtcVideoEngine::EnableTimedRender() { - if (initialized_) { - LOG(LS_WARNING) << "EnableTimedRender can not be called after Init."; - return false; - } - render_module_.reset(webrtc::VideoRender::CreateVideoRender(0, NULL, - false, webrtc::kRenderExternal)); - return true; -} - -// WebRtcVideoMediaChannel - -WebRtcVideoMediaChannel::WebRtcVideoMediaChannel( - WebRtcVideoEngine* engine, VoiceMediaChannel* channel) - : engine_(engine), - voice_channel_(channel), - vie_channel_(-1), - sending_(false), - connected_(false), - render_started_(false), - send_codec_(NULL) { - engine->RegisterChannel(this); -} - -bool WebRtcVideoMediaChannel::Init() { - bool ret = true; - if (engine_->video_engine()->base()->CreateChannel(vie_channel_) != 0) { - LOG_RTCERR1(CreateChannel, vie_channel_); - return false; - } - - LOG(LS_INFO) << "WebRtcVideoMediaChannel::Init " - << "video_channel " << vie_channel_ << " created"; - - // connect audio channel - if (voice_channel_) { - WebRtcVoiceMediaChannel* channel = - static_cast (voice_channel_); - if (engine_->video_engine()->base()->ConnectAudioChannel( - vie_channel_, channel->voe_channel()) != 0) { - LOG(LS_WARNING) << "ViE ConnectAudioChannel failed" - << "A/V not synchronized"; - // Don't set ret to false; - } - } - - // Register external transport - if (engine_->video_engine()->network()->RegisterSendTransport( - vie_channel_, *this) != 0) { - ret = false; - } else { - EnableRtcp(); - EnablePLI(); - } - return ret; -} - -WebRtcVideoMediaChannel::~WebRtcVideoMediaChannel() { - // Stop and remote renderer - SetRender(false); - if (engine()->video_engine()->render()->RemoveRenderer(vie_channel_) - == -1) { - LOG_RTCERR1(RemoveRenderer, vie_channel_); - } - - // DeRegister external transport - if (engine()->video_engine()->network()->DeregisterSendTransport( - vie_channel_) == -1) { - LOG_RTCERR1(DeregisterSendTransport, vie_channel_); - } - - // Unregister RtcChannel with the engine. - engine()->UnregisterChannel(this); - - // Delete VideoChannel - if (engine()->video_engine()->base()->DeleteChannel(vie_channel_) == -1) { - LOG_RTCERR1(DeleteChannel, vie_channel_); - } -} - -bool WebRtcVideoMediaChannel::SetRecvCodecs( - const std::vector& codecs) { - bool ret = true; - for (std::vector::const_iterator iter = codecs.begin(); - iter != codecs.end(); ++iter) { - if (engine()->FindCodec(*iter)) { - webrtc::VideoCodec wcodec; - if (engine()->ConvertFromCricketVideoCodec(*iter, wcodec)) { - if (engine()->video_engine()->codec()->SetReceiveCodec( - vie_channel_, wcodec) != 0) { - LOG_RTCERR2(SetReceiveCodec, vie_channel_, wcodec.plName); - ret = false; - } - } - } else { - LOG(LS_INFO) << "Unknown codec" << iter->name; - ret = false; - } - } - - // make channel ready to receive packets - if (ret) { - if (engine()->video_engine()->base()->StartReceive(vie_channel_) != 0) { - LOG_RTCERR1(StartReceive, vie_channel_); - ret = false; - } - } - if (ret && network_interface_) { - network_interface_->SetOption(NetworkInterface::ST_RTP, - talk_base::Socket::OPT_RCVBUF, - kMaxVideoRtpBufferSize); - network_interface_->SetOption(NetworkInterface::ST_RTP, - talk_base::Socket::OPT_SNDBUF, - kMaxVideoRtpBufferSize); - } - return ret; -} - -bool WebRtcVideoMediaChannel::SetSendCodecs( - const std::vector& codecs) { - if (sending_) { - LOG(LS_ERROR) << "channel is alredy sending"; - return false; - } - - // match with local video codec list - std::vector send_codecs; - for (std::vector::const_iterator iter = codecs.begin(); - iter != codecs.end(); ++iter) { - if (engine()->FindCodec(*iter)) { - webrtc::VideoCodec wcodec; - if (engine()->ConvertFromCricketVideoCodec(*iter, wcodec)) - send_codecs.push_back(wcodec); - } - } - - // if none matches, return with set - if (send_codecs.empty()) { - LOG(LS_ERROR) << "No matching codecs avilable"; - return false; - } - - // select the first matched codec - const webrtc::VideoCodec& codec(send_codecs[0]); - send_codec_.reset(new webrtc::VideoCodec(codec)); - if (engine()->video_engine()->codec()->SetSendCodec( - vie_channel_, codec) != 0) { - LOG_RTCERR2(SetSendCodec, vie_channel_, codec.plName); - return false; - } - return true; -} - -bool WebRtcVideoMediaChannel::SetRender(bool render) { - if (render != render_started_) { - int ret; - if (render) { - ret = engine()->video_engine()->render()->StartRender(vie_channel_); - } else { - ret = engine()->video_engine()->render()->StopRender(vie_channel_); - } - if (ret != 0) { - return false; - } - render_started_ = render; - } - return true; -} - -bool WebRtcVideoMediaChannel::SetSend(bool send) { - if (send == sending()) { - return true; // no action required - } - - bool ret = true; - if (send) { // enable - if (engine()->video_engine()->base()->StartSend(vie_channel_) != 0) { - LOG_RTCERR1(StartSend, vie_channel_); - ret = false; - } - - // If the channel has not been connected to the capturer yet, - // connect it now. - if (!connected()) { - if (engine()->video_engine()->capture()->ConnectCaptureDevice( - engine()->capture_id(), vie_channel_) != 0) { - LOG_RTCERR2(ConnectCaptureDevice, engine()->capture_id(), vie_channel_); - ret = false; - } else { - set_connected(true); - } - } - } else { // disable - if (engine()->video_engine()->base()->StopSend(vie_channel_) != 0) { - LOG_RTCERR1(StopSend, vie_channel_); - ret = false; - } - } - if (ret) { - sending_ = send; - } - - return ret; -} - -bool WebRtcVideoMediaChannel::AddStream(uint32 ssrc, uint32 voice_ssrc) { - return false; -} - -bool WebRtcVideoMediaChannel::RemoveStream(uint32 ssrc) { - return false; -} - -bool WebRtcVideoMediaChannel::SetRenderer( - uint32 ssrc, VideoRenderer* renderer) { - ASSERT(vie_channel_ != -1); - if (ssrc != 0) - return false; - if (remote_renderer_.get()) { - // If the renderer already set, stop and remove it first - if (engine_->video_engine()->render()->StopRender(vie_channel_) != 0) { - LOG_RTCERR1(StopRender, vie_channel_); - } - if (engine_->video_engine()->render()->RemoveRenderer(vie_channel_) != 0) { - LOG_RTCERR1(RemoveRenderer, vie_channel_); - } - } - remote_renderer_.reset(new WebRtcRenderAdapter(renderer)); - - if (engine_->video_engine()->render()->AddRenderer(vie_channel_, - webrtc::kVideoI420, remote_renderer_.get()) != 0) { - LOG_RTCERR3(AddRenderer, vie_channel_, webrtc::kVideoI420, - remote_renderer_.get()); - remote_renderer_.reset(); - return false; - } - - if (engine_->video_engine()->render()->StartRender(vie_channel_) != 0) { - LOG_RTCERR1(StartRender, vie_channel_); - return false; - } - - return true; -} - -bool WebRtcVideoMediaChannel::GetStats(VideoMediaInfo* info) { - VideoSenderInfo sinfo; - memset(&sinfo, 0, sizeof(sinfo)); - - unsigned int ssrc; - if (engine_->video_engine()->rtp()->GetLocalSSRC(vie_channel_, - ssrc) != 0) { - LOG_RTCERR2(GetLocalSSRC, vie_channel_, ssrc); - return false; - } - sinfo.ssrc = ssrc; - - unsigned int cumulative_lost, extended_max, jitter; - int rtt_ms; - uint16 fraction_lost; - - if (engine_->video_engine()->rtp()->GetReceivedRTCPStatistics(vie_channel_, - fraction_lost, cumulative_lost, extended_max, jitter, rtt_ms) != 0) { - LOG_RTCERR6(GetReceivedRTCPStatistics, vie_channel_, - fraction_lost, cumulative_lost, extended_max, jitter, rtt_ms); - return false; - } - - sinfo.fraction_lost = fraction_lost; - sinfo.packets_lost = cumulative_lost; - sinfo.rtt_ms = rtt_ms; - - unsigned int bytes_sent, packets_sent, bytes_recv, packets_recv; - if (engine_->video_engine()->rtp()->GetRTPStatistics(vie_channel_, - bytes_sent, packets_sent, bytes_recv, packets_recv) != 0) { - LOG_RTCERR5(GetRTPStatistics, vie_channel_, - bytes_sent, packets_sent, bytes_recv, packets_recv); - return false; - } - sinfo.packets_sent = packets_sent; - sinfo.bytes_sent = bytes_sent; - sinfo.packets_lost = -1; - sinfo.packets_cached = -1; - - info->senders.push_back(sinfo); - - // build receiver info. - // reusing the above local variables - VideoReceiverInfo rinfo; - memset(&rinfo, 0, sizeof(rinfo)); - if (engine_->video_engine()->rtp()->GetSentRTCPStatistics(vie_channel_, - fraction_lost, cumulative_lost, extended_max, jitter, rtt_ms) != 0) { - LOG_RTCERR6(GetSentRTCPStatistics, vie_channel_, - fraction_lost, cumulative_lost, extended_max, jitter, rtt_ms); - return false; - } - rinfo.bytes_rcvd = bytes_recv; - rinfo.packets_rcvd = packets_recv; - rinfo.fraction_lost = fraction_lost; - rinfo.packets_lost = cumulative_lost; - - if (engine_->video_engine()->rtp()->GetRemoteSSRC(vie_channel_, - ssrc) != 0) { - return false; - } - rinfo.ssrc = ssrc; - - // Get codec for wxh - info->receivers.push_back(rinfo); - return true; -} - -bool WebRtcVideoMediaChannel::SendIntraFrame() { - bool ret = true; - if (engine()->video_engine()->codec()->SendKeyFrame(vie_channel_) != 0) { - LOG_RTCERR1(SendKeyFrame, vie_channel_); - ret = false; - } - - return ret; -} - -bool WebRtcVideoMediaChannel::RequestIntraFrame() { - // There is no API exposed to application to request a key frame - // ViE does this internally when there are errors from decoder - return false; -} - -void WebRtcVideoMediaChannel::OnPacketReceived(talk_base::Buffer* packet) { - engine()->video_engine()->network()->ReceivedRTPPacket(vie_channel_, - packet->data(), - packet->length()); -} - -void WebRtcVideoMediaChannel::OnRtcpReceived(talk_base::Buffer* packet) { - engine_->video_engine()->network()->ReceivedRTCPPacket(vie_channel_, - packet->data(), - packet->length()); -} - -void WebRtcVideoMediaChannel::SetSendSsrc(uint32 id) { - if (!sending_) { - if (engine()->video_engine()->rtp()->SetLocalSSRC(vie_channel_, - id) != 0) { - LOG_RTCERR1(SetLocalSSRC, vie_channel_); - } - } else { - LOG(LS_ERROR) << "Channel already in send state"; - } -} - -bool WebRtcVideoMediaChannel::SetRtcpCName(const std::string& cname) { - if (engine()->video_engine()->rtp()->SetRTCPCName(vie_channel_, - cname.c_str()) != 0) { - LOG_RTCERR2(SetRTCPCName, vie_channel_, cname.c_str()); - return false; - } - return true; -} - -bool WebRtcVideoMediaChannel::Mute(bool on) { - // stop send?? - return false; -} - -bool WebRtcVideoMediaChannel::SetSendBandwidth(bool autobw, int bps) { - LOG(LS_INFO) << "RtcVideoMediaChanne::SetSendBandwidth"; - - if (!send_codec_.get()) { - LOG(LS_INFO) << "The send codec has not been set up yet."; - return true; - } - - if (!autobw) { - send_codec_->startBitrate = bps; - send_codec_->minBitrate = bps; - } - send_codec_->maxBitrate = bps; - - if (engine()->video_engine()->codec()->SetSendCodec(vie_channel_, - *send_codec_.get()) != 0) { - LOG_RTCERR2(SetSendCodec, vie_channel_, send_codec_->plName); - return false; - } - - return true; -} - -bool WebRtcVideoMediaChannel::SetOptions(int options) { - return true; -} - -void WebRtcVideoMediaChannel::EnableRtcp() { - engine()->video_engine()->rtp()->SetRTCPStatus( - vie_channel_, webrtc::kRtcpCompound_RFC4585); -} - -void WebRtcVideoMediaChannel::EnablePLI() { - engine_->video_engine()->rtp()->SetKeyFrameRequestMethod( - vie_channel_, webrtc::kViEKeyFrameRequestPliRtcp); -} - -void WebRtcVideoMediaChannel::EnableTMMBR() { - engine_->video_engine()->rtp()->SetTMMBRStatus(vie_channel_, true); -} - -int WebRtcVideoMediaChannel::SendPacket(int channel, const void* data, - int len) { - if (!network_interface_) { - return -1; - } - talk_base::Buffer packet(data, len, kMaxRtpPacketLen); - return network_interface_->SendPacket(&packet) ? len : -1; -} - -int WebRtcVideoMediaChannel::SendRTCPPacket(int channel, - const void* data, - int len) { - if (!network_interface_) { - return -1; - } - talk_base::Buffer packet(data, len, kMaxRtpPacketLen); - return network_interface_->SendRtcp(&packet) ? len : -1; -} - -} // namespace cricket - -#endif // HAVE_WEBRTC_VIDEO - diff --git a/third_party_mods/libjingle/source/talk/session/phone/webrtcvoiceengine.cc b/third_party_mods/libjingle/source/talk/session/phone/webrtcvoiceengine.cc deleted file mode 100644 index e6332aed28..0000000000 --- a/third_party_mods/libjingle/source/talk/session/phone/webrtcvoiceengine.cc +++ /dev/null @@ -1,2055 +0,0 @@ -/* - * libjingle - * Copyright 2004--2011, 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_WEBRTC_VOICE - -#include "talk/session/phone/webrtcvoiceengine.h" - -#include -#include -#include -#include - -#include "talk/base/base64.h" -#include "talk/base/byteorder.h" -#include "talk/base/common.h" -#include "talk/base/helpers.h" -#include "talk/base/logging.h" -#include "talk/base/stringencode.h" -#include "talk/base/stringutils.h" -#include "talk/session/phone/webrtcvoe.h" - -#ifdef WIN32 -#include // NOLINT -#endif - -namespace cricket { - -// For Linux/Mac, using the default device is done by specifying index 0 for -// VoE 4.0 and not -1 (which was the case for VoE 3.5). -// -// On Windows Vista and newer, Microsoft introduced the concept of "Default -// Communications Device". This means that there are two types of default -// devices (old Wave Audio style default and Default Communications Device). -// -// On Windows systems which only support Wave Audio style default, uses either -// -1 or 0 to select the default device. -// -// On Windows systems which support both "Default Communication Device" and -// old Wave Audio style default, use -1 for Default Communications Device and -// -2 for Wave Audio style default, which is what we want to use for clips. -// It's not clear yet whether the -2 index is handled properly on other OSes. - -#ifdef WIN32 -static const int kDefaultAudioDeviceId = -1; -static const int kDefaultSoundclipDeviceId = -2; -#else -static const int kDefaultAudioDeviceId = 0; -#endif - -// extension header for audio levels, as defined in -// http://tools.ietf.org/html/draft-ietf-avtext-client-to-mixer-audio-level-03 -static const char kRtpAudioLevelHeaderExtension[] = - "urn:ietf:params:rtp-hdrext:ssrc-audio-level"; - -static const char kIsacCodecName[] = "ISAC"; -static const char kL16CodecName[] = "L16"; - -// Dumps an AudioCodec in RFC 2327-ish format. -static std::string ToString(const AudioCodec& codec) { - std::stringstream ss; - ss << codec.name << "/" << codec.clockrate << "/" << codec.channels - << " (" << codec.id << ")"; - return ss.str(); -} -static std::string ToString(const webrtc::CodecInst& codec) { - std::stringstream ss; - ss << codec.plname << "/" << codec.plfreq << "/" << codec.channels - << " (" << codec.pltype << ")"; - return ss.str(); -} - -static void LogMultiline(talk_base::LoggingSeverity sev, char* text) { - const char* delim = "\r\n"; - for (char* tok = strtok(text, delim); tok; tok = strtok(NULL, delim)) { - LOG_V(sev) << tok; - } -} - -// WebRtcVoiceEngine -const WebRtcVoiceEngine::CodecPref WebRtcVoiceEngine::kCodecPrefs[] = { - { "ISAC", 16000, 103 }, - { "ISAC", 32000, 104 }, - { "speex", 16000, 107 }, - { "G722", 16000, 9 }, - { "ILBC", 8000, 102 }, - { "speex", 8000, 108 }, - { "PCMU", 8000, 0 }, - { "PCMA", 8000, 8 }, - { "CN", 32000, 106 }, - { "CN", 16000, 105 }, - { "CN", 8000, 13 }, - { "red", 8000, 127 }, - { "telephone-event", 8000, 126 }, -}; - -class WebRtcSoundclipMedia : public SoundclipMedia { - public: - explicit WebRtcSoundclipMedia(WebRtcVoiceEngine *engine) - : engine_(engine), webrtc_channel_(-1) { - engine_->RegisterSoundclip(this); - } - - virtual ~WebRtcSoundclipMedia() { - engine_->UnregisterSoundclip(this); - if (webrtc_channel_ != -1) { - if (engine_->voe_sc()->base()->DeleteChannel(webrtc_channel_) - == -1) { - LOG_RTCERR1(DeleteChannel, webrtc_channel_); - } - } - } - - bool Init() { - webrtc_channel_ = engine_->voe_sc()->base()->CreateChannel(); - if (webrtc_channel_ == -1) { - LOG_RTCERR0(CreateChannel); - return false; - } - return true; - } - - bool Enable() { - if (engine_->voe_sc()->base()->StartPlayout(webrtc_channel_) == -1) { - LOG_RTCERR1(StartPlayout, webrtc_channel_); - return false; - } - return true; - } - - bool Disable() { - if (engine_->voe_sc()->base()->StopPlayout(webrtc_channel_) == -1) { - LOG_RTCERR1(StopPlayout, webrtc_channel_); - return false; - } - return true; - } - - virtual bool PlaySound(const char *buf, int len, int flags) { - // Must stop playing the current sound (if any), because we are about to - // modify the stream. - if (engine_->voe_sc()->file()->StopPlayingFileLocally(webrtc_channel_) - == -1) { - LOG_RTCERR1(StopPlayingFileLocally, webrtc_channel_); - return false; - } - - if (buf) { - stream_.reset(new WebRtcSoundclipStream(buf, len)); - stream_->set_loop((flags & SF_LOOP) != 0); - stream_->Rewind(); - - // Play it. - if (engine_->voe_sc()->file()->StartPlayingFileLocally( - webrtc_channel_, stream_.get()) == -1) { - LOG_RTCERR2(StartPlayingFileLocally, webrtc_channel_, stream_.get()); - LOG(LS_ERROR) << "Unable to start soundclip"; - return false; - } - } else { - stream_.reset(); - } - return true; - } - - int GetLastEngineError() const { return engine_->voe_sc()->error(); } - - private: - WebRtcVoiceEngine *engine_; - int webrtc_channel_; - talk_base::scoped_ptr stream_; -}; - -WebRtcVoiceEngine::WebRtcVoiceEngine() - : voe_wrapper_(new VoEWrapper()), - voe_wrapper_sc_(new VoEWrapper()), - tracing_(new VoETraceWrapper()), - adm_(NULL), - adm_sc_(NULL), - log_level_(kDefaultLogSeverity), - is_dumping_aec_(false), - desired_local_monitor_enable_(false) { - Construct(); -} - -WebRtcVoiceEngine::WebRtcVoiceEngine(VoEWrapper* voe_wrapper, - VoEWrapper* voe_wrapper_sc, - VoETraceWrapper* tracing) - : voe_wrapper_(voe_wrapper), - voe_wrapper_sc_(voe_wrapper_sc), - tracing_(tracing), - adm_(NULL), - adm_sc_(NULL), - log_level_(kDefaultLogSeverity), - is_dumping_aec_(false), - desired_local_monitor_enable_(false) { - Construct(); -} - -void WebRtcVoiceEngine::Construct() { - initialized_ = false; - LOG(LS_VERBOSE) << "WebRtcVoiceEngine::WebRtcVoiceEngine"; - ApplyLogging(""); - if (tracing_->SetTraceCallback(this) == -1) { - LOG_RTCERR0(SetTraceCallback); - } - - if (voe_wrapper_->base()->RegisterVoiceEngineObserver(*this) == -1) { - LOG_RTCERR0(RegisterVoiceEngineObserver); - } - // Clear the default agc state. - memset(&default_agc_config_, 0, sizeof(default_agc_config_)); - - // Load our audio codec list. - ConstructCodecs(); -} - -void WebRtcVoiceEngine::ConstructCodecs() { - LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; - int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); - for (int i = 0; i < ncodecs; ++i) { - webrtc::CodecInst voe_codec; - if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) { - // Skip uncompressed formats. - if (_stricmp(voe_codec.plname, kL16CodecName) == 0) { - continue; - } - - const CodecPref* pref = NULL; - for (size_t j = 0; j < ARRAY_SIZE(kCodecPrefs); ++j) { - if (_stricmp(kCodecPrefs[j].name, voe_codec.plname) == 0 && - kCodecPrefs[j].clockrate == voe_codec.plfreq) { - pref = &kCodecPrefs[j]; - break; - } - } - - if (pref) { - // Use the payload type that we've configured in our pref table; - // use the offset in our pref table to determine the sort order. - AudioCodec codec(pref->payload_type, voe_codec.plname, voe_codec.plfreq, - voe_codec.rate, voe_codec.channels, - ARRAY_SIZE(kCodecPrefs) - (pref - kCodecPrefs)); - LOG(LS_INFO) << ToString(codec); - // For ISAC, use 0 to indicate auto bandwidth in our signaling. - if (_stricmp(codec.name.c_str(), kIsacCodecName) == 0) { - codec.bitrate = 0; - } - codecs_.push_back(codec); - } else { - LOG(LS_WARNING) << "Unexpected codec: " << ToString(voe_codec); - } - } - } - // Make sure they are in local preference order. - std::sort(codecs_.begin(), codecs_.end(), &AudioCodec::Preferable); -} - -WebRtcVoiceEngine::~WebRtcVoiceEngine() { - LOG(LS_VERBOSE) << "WebRtcVoiceEngine::~WebRtcVoiceEngine"; - if (voe_wrapper_->base()->DeRegisterVoiceEngineObserver() == -1) { - LOG_RTCERR0(DeRegisterVoiceEngineObserver); - } - if (adm_) { - voe_wrapper_.reset(); - adm_->Release(); - adm_ = NULL; - } - if (adm_sc_) { - voe_wrapper_sc_.reset(); - adm_sc_->Release(); - adm_sc_ = NULL; - } - - tracing_->SetTraceCallback(NULL); -} - -bool WebRtcVoiceEngine::Init() { - LOG(LS_INFO) << "WebRtcVoiceEngine::Init"; - bool res = InitInternal(); - if (res) { - LOG(LS_INFO) << "WebRtcVoiceEngine::Init Done!"; - } else { - LOG(LS_ERROR) << "WebRtcVoiceEngine::Init failed"; - Terminate(); - } - return res; -} - -bool WebRtcVoiceEngine::InitInternal() { - // Temporarily turn logging level up for the Init call - int old_level = log_level_; - log_level_ = talk_base::_min(log_level_, - static_cast(talk_base::LS_INFO)); - ApplyLogging(""); - - // Init WebRtc VoiceEngine, enabling AEC logging if specified in SetLogging. - if (voe_wrapper_->base()->Init(adm_) == -1) { - LOG_RTCERR0_EX(Init, voe_wrapper_->error()); - return false; - } - - // Restore the previous log level and apply the log filter. - log_level_ = old_level; - ApplyLogging(log_filter_); - - // Log the VoiceEngine version info - char buffer[1024] = ""; - voe_wrapper_->base()->GetVersion(buffer); - LOG(LS_INFO) << "WebRtc VoiceEngine Version:"; - LogMultiline(talk_base::LS_INFO, buffer); - - // Turn on AEC and AGC by default. - if (!SetOptions( - MediaEngineInterface::ECHO_CANCELLATION | - MediaEngineInterface::AUTO_GAIN_CONTROL)) { - return false; - } - - // Save the default AGC configuration settings. - if (voe_wrapper_->processing()->SetAgcConfig(default_agc_config_) == -1) { - LOG_RTCERR0(GetAGCConfig); - return false; - } - - // Print our codec list again for the call diagnostic log - LOG(LS_INFO) << "WebRtc VoiceEngine codecs:"; - for (std::vector::const_iterator it = codecs_.begin(); - it != codecs_.end(); ++it) { - LOG(LS_INFO) << ToString(*it); - } - -#if defined(LINUX) && !defined(HAVE_LIBPULSE) - voe_wrapper_sc_->hw()->SetAudioDeviceLayer(webrtc::kAudioLinuxAlsa); -#endif - - // Initialize the VoiceEngine instance that we'll use to play out sound clips. - if (voe_wrapper_sc_->base()->Init(adm_sc_) == -1) { - LOG_RTCERR0_EX(Init, voe_wrapper_sc_->error()); - return false; - } - - // On Windows, tell it to use the default sound (not communication) devices. - // First check whether there is a valid sound device for playback. - // TODO: Clean this up when we support setting the soundclip device. -#ifdef WIN32 - int num_of_devices = 0; - if (voe_wrapper_sc_->hw()->GetNumOfPlayoutDevices(num_of_devices) != -1 && - num_of_devices > 0) { - if (voe_wrapper_sc_->hw()->SetPlayoutDevice(kDefaultSoundclipDeviceId) - == -1) { - LOG_RTCERR1_EX(SetPlayoutDevice, kDefaultSoundclipDeviceId, - voe_wrapper_sc_->error()); - return false; - } - } else { - LOG(LS_WARNING) << "No valid sound playout device found."; - } -#endif - - initialized_ = true; - return true; -} - -void WebRtcVoiceEngine::Terminate() { - LOG(LS_INFO) << "WebRtcVoiceEngine::Terminate"; - initialized_ = false; - - if (is_dumping_aec_) { - if (voe_wrapper_->processing()->StopDebugRecording() == -1) { - LOG_RTCERR0(StopDebugRecording); - } - is_dumping_aec_ = false; - } - - voe_wrapper_sc_->base()->Terminate(); - voe_wrapper_->base()->Terminate(); - desired_local_monitor_enable_ = false; -} - -int WebRtcVoiceEngine::GetCapabilities() { - return AUDIO_SEND | AUDIO_RECV; -} - -VoiceMediaChannel *WebRtcVoiceEngine::CreateChannel() { - WebRtcVoiceMediaChannel* ch = new WebRtcVoiceMediaChannel(this); - if (!ch->valid()) { - delete ch; - ch = NULL; - } - return ch; -} - -SoundclipMedia *WebRtcVoiceEngine::CreateSoundclip() { - WebRtcSoundclipMedia *soundclip = new WebRtcSoundclipMedia(this); - if (!soundclip->Init() || !soundclip->Enable()) { - delete soundclip; - return NULL; - } - return soundclip; -} - -bool WebRtcVoiceEngine::SetOptions(int options) { - // NS and typing detection are always on, if supported. - bool aec = (options & MediaEngineInterface::ECHO_CANCELLATION) ? true : false; - bool agc = (options & MediaEngineInterface::AUTO_GAIN_CONTROL) ? true : false; -#if !defined(IOS) && !defined(ANDROID) - if (voe_wrapper_->processing()->SetEcStatus(aec) == -1) { - LOG_RTCERR1(SetEcStatus, aec); - return false; - } - - if (voe_wrapper_->processing()->SetAgcStatus(agc) == -1) { - LOG_RTCERR1(SetAgcStatus, agc); - return false; - } - - if (voe_wrapper_->processing()->SetNsStatus(true) == -1) { - LOG_RTCERR1(SetNsStatus, true); - return false; - } - - if (voe_wrapper_->processing()->SetTypingDetectionStatus(true) == -1) { - // In case of error, log the info and continue - LOG_RTCERR1(SetTypingDetectionStatus, true); - } -#else - if (voe_wrapper_->processing()->SetEcStatus(aec, kEcAecm) == -1) { - LOG_RTCERR2(SetEcStatus, aec, kEcAecm); - return false; - } - - if (aec) { - // Use speakerphone mode with comfort noise generation for mobile. - if (voe_wrapper_->processing()->SetAecmMode(kAecmSpeakerphone, true) != 0) { - LOG_RTCERR2(SetAecmMode, kAecmSpeakerphone, true); - } - } - - // On mobile, GIPS recommends fixed AGC (not adaptive) - if (voe_wrapper_->processing()->SetAgcStatus(agc, kAgcFixedDigital) == -1) { - LOG_RTCERR2(SetAgcStatus, agc, kAgcFixedDigital); - return false; - } - - // On mobile, GIPS recommends moderate aggressiveness. - if (voe_wrapper_->processing()->SetNsStatus(true, - kNsModerateSuppression) == -1) { - LOG_RTCERR2(SetNsStatus, ns, kNsModerateSuppression); - return false; - } - - // No typing detection support on iOS or Android. -#endif // !IOS && !ANDROID - - return true; -} - -struct ResumeEntry { - ResumeEntry(WebRtcVoiceMediaChannel *c, bool p, SendFlags s) - : channel(c), - playout(p), - send(s) { - } - - WebRtcVoiceMediaChannel *channel; - bool playout; - SendFlags send; -}; - -// TODO: Refactor this so that the core logic can be used to set the -// soundclip device. At that time, reinstate the soundclip pause/resume code. -bool WebRtcVoiceEngine::SetDevices(const Device* in_device, - const Device* out_device) { -#if !defined(IOS) && !defined(ANDROID) - int in_id = in_device ? talk_base::FromString(in_device->id) : - kDefaultAudioDeviceId; - int out_id = out_device ? talk_base::FromString(out_device->id) : - kDefaultAudioDeviceId; - // The device manager uses -1 as the default device, which was the case for - // VoE 3.5. VoE 4.0, however, uses 0 as the default in Linux and Mac. -#ifndef WIN32 - if (-1 == in_id) { - in_id = kDefaultAudioDeviceId; - } - if (-1 == out_id) { - out_id = kDefaultAudioDeviceId; - } -#endif - - std::string in_name = (in_id != kDefaultAudioDeviceId) ? - in_device->name : "Default device"; - std::string out_name = (out_id != kDefaultAudioDeviceId) ? - out_device->name : "Default device"; - LOG(LS_INFO) << "Setting microphone to (id=" << in_id << ", name=" << in_name - << ") and speaker to (id=" << out_id << ", name=" << out_name - << ")"; - - // If we're running the local monitor, we need to stop it first. - bool ret = true; - if (!PauseLocalMonitor()) { - LOG(LS_WARNING) << "Failed to pause local monitor"; - ret = false; - } - - // Must also pause all audio playback and capture. - for (ChannelList::const_iterator i = channels_.begin(); - i != channels_.end(); ++i) { - WebRtcVoiceMediaChannel *channel = *i; - if (!channel->PausePlayout()) { - LOG(LS_WARNING) << "Failed to pause playout"; - ret = false; - } - if (!channel->PauseSend()) { - LOG(LS_WARNING) << "Failed to pause send"; - ret = false; - } - } - - // Find the recording device id in VoiceEngine and set recording device. - if (!FindWebRtcAudioDeviceId(true, in_name, in_id, &in_id)) { - ret = false; - } - if (ret) { - if (voe_wrapper_->hw()->SetRecordingDevice(in_id) == -1) { - LOG_RTCERR2(SetRecordingDevice, in_device->name, in_id); - ret = false; - } - } - - // Find the playout device id in VoiceEngine and set playout device. - if (!FindWebRtcAudioDeviceId(false, out_name, out_id, &out_id)) { - LOG(LS_WARNING) << "Failed to find VoiceEngine device id for " << out_name; - ret = false; - } - if (ret) { - if (voe_wrapper_->hw()->SetPlayoutDevice(out_id) == -1) { - LOG_RTCERR2(SetPlayoutDevice, out_device->name, out_id); - ret = false; - } - } - - // Resume all audio playback and capture. - for (ChannelList::const_iterator i = channels_.begin(); - i != channels_.end(); ++i) { - WebRtcVoiceMediaChannel *channel = *i; - if (!channel->ResumePlayout()) { - LOG(LS_WARNING) << "Failed to resume playout"; - ret = false; - } - if (!channel->ResumeSend()) { - LOG(LS_WARNING) << "Failed to resume send"; - ret = false; - } - } - - // Resume local monitor. - if (!ResumeLocalMonitor()) { - LOG(LS_WARNING) << "Failed to resume local monitor"; - ret = false; - } - - if (ret) { - LOG(LS_INFO) << "Set microphone to (id=" << in_id <<" name=" << in_name - << ") and speaker to (id="<< out_id << " name=" << out_name - << ")"; - } - - return ret; -#else - return true; -#endif // !IOS && !ANDROID -} - -bool WebRtcVoiceEngine::FindWebRtcAudioDeviceId( - bool is_input, const std::string& dev_name, int dev_id, int* rtc_id) { - // In Linux, VoiceEngine uses the same device dev_id as the device manager. -#ifdef LINUX - *rtc_id = dev_id; - return true; -#else - // In Windows and Mac, we need to find the VoiceEngine device id by name - // unless the input dev_id is the default device id. - if (kDefaultAudioDeviceId == dev_id) { - *rtc_id = dev_id; - return true; - } - - // Get the number of VoiceEngine audio devices. - int count = 0; - if (is_input) { - if (-1 == voe_wrapper_->hw()->GetNumOfRecordingDevices(count)) { - LOG_RTCERR0(GetNumOfRecordingDevices); - return false; - } - } else { - if (-1 == voe_wrapper_->hw()->GetNumOfPlayoutDevices(count)) { - LOG_RTCERR0(GetNumOfPlayoutDevices); - return false; - } - } - - for (int i = 0; i < count; ++i) { - char name[128]; - char guid[128]; - if (is_input) { - voe_wrapper_->hw()->GetRecordingDeviceName(i, name, guid); - LOG(LS_VERBOSE) << "VoiceEngine microphone " << i << ": " << name; - } else { - voe_wrapper_->hw()->GetPlayoutDeviceName(i, name, guid); - LOG(LS_VERBOSE) << "VoiceEngine speaker " << i << ": " << name; - } - - std::string webrtc_name(name); - if (dev_name.compare(0, webrtc_name.size(), webrtc_name) == 0) { - *rtc_id = i; - return true; - } - } - LOG(LS_WARNING) << "VoiceEngine cannot find device: " << dev_name; - return false; -#endif -} - -bool WebRtcVoiceEngine::GetOutputVolume(int* level) { - unsigned int ulevel; - if (voe_wrapper_->volume()->GetSpeakerVolume(ulevel) == -1) { - LOG_RTCERR1(GetSpeakerVolume, level); - return false; - } - *level = ulevel; - return true; -} - -bool WebRtcVoiceEngine::SetOutputVolume(int level) { - ASSERT(level >= 0 && level <= 255); - if (voe_wrapper_->volume()->SetSpeakerVolume(level) == -1) { - LOG_RTCERR1(SetSpeakerVolume, level); - return false; - } - return true; -} - -int WebRtcVoiceEngine::GetInputLevel() { - unsigned int ulevel; - return (voe_wrapper_->volume()->GetSpeechInputLevel(ulevel) != -1) ? - static_cast(ulevel) : -1; -} - -bool WebRtcVoiceEngine::SetLocalMonitor(bool enable) { - desired_local_monitor_enable_ = enable; - return ChangeLocalMonitor(desired_local_monitor_enable_); -} - -bool WebRtcVoiceEngine::ChangeLocalMonitor(bool enable) { - if (enable && !monitor_.get()) { - monitor_.reset(new WebRtcMonitorStream); - if (voe_wrapper_->file()->StartRecordingMicrophone(monitor_.get()) == -1) { - LOG_RTCERR1(StartRecordingMicrophone, monitor_.get()); - // Must call Stop() because there are some cases where Start will report - // failure but still change the state, and if we leave VE in the on state - // then it could crash later when trying to invoke methods on our monitor. - voe_wrapper_->file()->StopRecordingMicrophone(); - monitor_.reset(); - return false; - } - } else if (!enable && monitor_.get()) { - voe_wrapper_->file()->StopRecordingMicrophone(); - monitor_.reset(); - } - return true; -} - -bool WebRtcVoiceEngine::PauseLocalMonitor() { - return ChangeLocalMonitor(false); -} - -bool WebRtcVoiceEngine::ResumeLocalMonitor() { - return ChangeLocalMonitor(desired_local_monitor_enable_); -} - -const std::vector& WebRtcVoiceEngine::codecs() { - return codecs_; -} - -bool WebRtcVoiceEngine::FindCodec(const AudioCodec& in) { - return FindWebRtcCodec(in, NULL); -} - -// Get the VoiceEngine codec that matches |in|, with the supplied settings. -bool WebRtcVoiceEngine::FindWebRtcCodec(const AudioCodec& in, - webrtc::CodecInst* out) { - int ncodecs = voe_wrapper_->codec()->NumOfCodecs(); - for (int i = 0; i < ncodecs; ++i) { - webrtc::CodecInst voe_codec; - if (voe_wrapper_->codec()->GetCodec(i, voe_codec) != -1) { - AudioCodec codec(voe_codec.pltype, voe_codec.plname, voe_codec.plfreq, - voe_codec.rate, voe_codec.channels, 0); - // Allow arbitrary rates for ISAC to be specified. - if (_stricmp(codec.name.c_str(), kIsacCodecName) == 0) { - codec.bitrate = 0; - } - if (codec.Matches(in)) { - if (out) { - // Fixup the payload type. - voe_codec.pltype = in.id; - // If ISAC is being used, and an explicit bitrate is not specified, - // enable auto bandwidth adjustment. - if (_stricmp(codec.name.c_str(), kIsacCodecName) == 0) { - voe_codec.rate = (in.bitrate > 0) ? in.bitrate : -1; - } - *out = voe_codec; - } - return true; - } - } - } - return false; -} - -void WebRtcVoiceEngine::SetLogging(int min_sev, const char* filter) { - // if min_sev == -1, we keep the current log level. - if (min_sev >= 0) { - log_level_ = min_sev; - } - log_filter_ = filter; - ApplyLogging(initialized_ ? log_filter_ : ""); -} - -int WebRtcVoiceEngine::GetLastEngineError() { - return voe_wrapper_->error(); -} - -// We suppport three different logging settings for VoiceEngine: -// 1. Observer callback that goes into talk diagnostic logfile. -// Use --logfile and --loglevel -// -// 2. Encrypted VoiceEngine log for debugging VoiceEngine. -// Use --voice_loglevel --voice_logfilter "tracefile file_name" -// -// 3. EC log and dump for debugging QualityEngine. -// Use --voice_loglevel --voice_logfilter "recordEC file_name" -// -// For more details see: "https://sites.google.com/a/google.com/wavelet/Home/ -// Magic-Flute--RTC-Engine-/Magic-Flute-Command-Line-Parameters" -void WebRtcVoiceEngine::ApplyLogging(const std::string& log_filter) { - // Set log level. - int filter = 0; - switch (log_level_) { - case talk_base::LS_VERBOSE: - filter |= webrtc::kTraceAll; // fall through - case talk_base::LS_INFO: - filter |= webrtc::kTraceStateInfo; // fall through - case talk_base::LS_WARNING: - filter |= (webrtc::kTraceInfo | webrtc::kTraceWarning); // fall through - case talk_base::LS_ERROR: - filter |= (webrtc::kTraceError | webrtc::kTraceCritical); - } - tracing_->SetTraceFilter(filter); - - // Set encrypted trace file. - std::vector opts; - talk_base::tokenize(log_filter, ' ', '"', '"', &opts); - std::vector::iterator tracefile = - std::find(opts.begin(), opts.end(), "tracefile"); - if (tracefile != opts.end() && ++tracefile != opts.end()) { - // Write encrypted debug output (at same loglevel) to file - // EncryptedTraceFile no longer supported. - if (tracing_->SetTraceFile(tracefile->c_str()) == -1) { - LOG_RTCERR1(SetTraceFile, *tracefile); - } - } - - // Set AEC dump file - std::vector::iterator recordEC = - std::find(opts.begin(), opts.end(), "recordEC"); - if (recordEC != opts.end()) { - ++recordEC; - if (recordEC != opts.end() && !is_dumping_aec_) { - // Start dumping AEC when we are not dumping and recordEC has a filename. - if (voe_wrapper_->processing()->StartDebugRecording( - recordEC->c_str()) == -1) { - LOG_RTCERR0(StartDebugRecording); - } else { - is_dumping_aec_ = true; - } - } else if (recordEC == opts.end() && is_dumping_aec_) { - // Stop dumping EC when we are dumping and recordEC has no filename. - if (voe_wrapper_->processing()->StopDebugRecording() == -1) { - LOG_RTCERR0(StopDebugRecording); - } - is_dumping_aec_ = false; - } - } -} - -// Ignore spammy trace messages, mostly from the stats API when we haven't -// gotten RTCP info yet from the remote side. -static bool ShouldIgnoreTrace(const std::string& trace) { - static const char* kTracesToIgnore[] = { - "\tfailed to GetReportBlockInformation", - "GetRecCodec() failed to get received codec", - "GetRemoteRTCPData() failed to measure statistics dueto lack of received RTP and/or RTCP packets", // NOLINT - "GetRemoteRTCPData() failed to retrieve sender info for remoteside", - "GetRTPStatistics() failed to measure RTT since noRTP packets have been received yet", // NOLINT - "GetRTPStatistics() failed to read RTP statistics from the RTP/RTCP module", - "GetRTPStatistics() failed to retrieve RTT fromthe RTP/RTCP module", - "webrtc::RTCPReceiver::SenderInfoReceived No received SR", - "StatisticsRTP() no statisitics availble", - NULL - }; - for (const char* const* p = kTracesToIgnore; *p; ++p) { - if (trace.find(*p) == 0) { - return true; - } - } - return false; -} - -void WebRtcVoiceEngine::Print(const webrtc::TraceLevel level, - const char* trace, const int length) { - talk_base::LoggingSeverity sev = talk_base::LS_VERBOSE; - if (level == webrtc::kTraceError || level == webrtc::kTraceCritical) - sev = talk_base::LS_ERROR; - else if (level == webrtc::kTraceWarning) - sev = talk_base::LS_WARNING; - else if (level == webrtc::kTraceStateInfo || level == webrtc::kTraceInfo) - sev = talk_base::LS_INFO; - - if (sev >= log_level_) { - // Skip past boilerplate prefix text - if (length < 72) { - std::string msg(trace, length); - LOG(LS_ERROR) << "Malformed webrtc log message: "; - LOG_V(sev) << msg; - } else { - std::string msg(trace + 71, length - 72); - if (!ShouldIgnoreTrace(msg)) { - LOG_V(sev) << "WebRtc VoE:" << msg; - } - } - } -} - -void WebRtcVoiceEngine::CallbackOnError(const int channel_num, - const int err_code) { - talk_base::CritScope lock(&channels_cs_); - WebRtcVoiceMediaChannel* channel = NULL; - uint32 ssrc = 0; - LOG(LS_WARNING) << "VoiceEngine error " << err_code << " reported on channel " - << channel_num << "."; - if (FindChannelAndSsrc(channel_num, &channel, &ssrc)) { - ASSERT(channel != NULL); - channel->OnError(ssrc, err_code); - } else { - LOG(LS_ERROR) << "VoiceEngine channel " << channel_num - << " could not be found in the channel list when error reported."; - } -} - -bool WebRtcVoiceEngine::FindChannelAndSsrc( - int channel_num, WebRtcVoiceMediaChannel** channel, uint32* ssrc) const { - ASSERT(channel != NULL && ssrc != NULL); - - *channel = NULL; - *ssrc = 0; - // Find corresponding channel and ssrc - for (ChannelList::const_iterator it = channels_.begin(); - it != channels_.end(); ++it) { - ASSERT(*it != NULL); - if ((*it)->FindSsrc(channel_num, ssrc)) { - *channel = *it; - return true; - } - } - - return false; -} - -void WebRtcVoiceEngine::RegisterChannel(WebRtcVoiceMediaChannel *channel) { - talk_base::CritScope lock(&channels_cs_); - channels_.push_back(channel); -} - -void WebRtcVoiceEngine::UnregisterChannel(WebRtcVoiceMediaChannel *channel) { - talk_base::CritScope lock(&channels_cs_); - ChannelList::iterator i = std::find(channels_.begin(), - channels_.end(), - channel); - if (i != channels_.end()) { - channels_.erase(i); - } -} - -void WebRtcVoiceEngine::RegisterSoundclip(WebRtcSoundclipMedia *soundclip) { - soundclips_.push_back(soundclip); -} - -void WebRtcVoiceEngine::UnregisterSoundclip(WebRtcSoundclipMedia *soundclip) { - SoundclipList::iterator i = std::find(soundclips_.begin(), - soundclips_.end(), - soundclip); - if (i != soundclips_.end()) { - soundclips_.erase(i); - } -} - -// Adjusts the default AGC target level by the specified delta. -// NB: If we start messing with other config fields, we'll want -// to save the current webrtc::AgcConfig as well. -bool WebRtcVoiceEngine::AdjustAgcLevel(int delta) { - webrtc::AgcConfig config = default_agc_config_; - config.targetLeveldBOv += delta; - - LOG(LS_INFO) << "Adjusting AGC level from default -" - << default_agc_config_.targetLeveldBOv << "dB to -" - << config.targetLeveldBOv << "dB"; - - if (voe_wrapper_->processing()->SetAgcConfig(config) == -1) { - LOG_RTCERR1(SetAgcConfig, config.targetLeveldBOv); - return false; - } - return true; -} - -// Configures echo cancellation and noise suppression modes according to -// whether or not we are in a multi-point conference. -bool WebRtcVoiceEngine::SetConferenceMode(bool enable) { -// Only use EC_AECM for mobile. -#if defined(IOS) || defined(ANDROID) - return true; -#endif - - LOG(LS_INFO) << (enable ? "Enabling" : "Disabling") - << " Conference Mode noise reduction"; - - // We always configure noise suppression on, so just toggle the mode. - const webrtc::NsModes ns_mode = enable ? webrtc::kNsConference - : webrtc::kNsDefault; - if (voe_wrapper_->processing()->SetNsStatus(true, ns_mode) == -1) { - LOG_RTCERR2(SetNsStatus, true, ns_mode); - return false; - } - - // Echo-cancellation is a user-option, so preserve the enable state and - // just toggle the mode. - bool aec; - webrtc::EcModes ec_mode; - if (voe_wrapper_->processing()->GetEcStatus(aec, ec_mode) == -1) { - LOG_RTCERR0(GetEcStatus); - return false; - } - ec_mode = enable ? webrtc::kEcConference : webrtc::kEcDefault; - if (voe_wrapper_->processing()->SetEcStatus(aec, ec_mode) == -1) { - LOG_RTCERR2(SetEcStatus, aec, ec_mode); - return false; - } - return true; -} - -bool WebRtcVoiceEngine::SetAudioDeviceModule(webrtc::AudioDeviceModule* adm, - webrtc::AudioDeviceModule* adm_sc) { - if (initialized_) { - LOG(LS_WARNING) << "SetAudioDeviceModule can not be called after Init."; - return false; - } - if (adm_) { - adm_->Release(); - adm_ = NULL; - } - if (adm) { - adm_ = adm; - adm_->AddRef(); - } - - if (adm_sc_) { - adm_sc_->Release(); - adm_sc_ = NULL; - } - if (adm_sc) { - adm_sc_ = adm_sc; - adm_sc_->AddRef(); - } - return true; -} - -// WebRtcVoiceMediaChannel -WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel(WebRtcVoiceEngine *engine) - : WebRtcMediaChannel( - engine, - engine->voe()->base()->CreateChannel()), - channel_options_(0), - agc_adjusted_(false), - dtmf_allowed_(false), - desired_playout_(false), - playout_(false), - desired_send_(SEND_NOTHING), - send_(SEND_NOTHING) { - engine->RegisterChannel(this); - LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::WebRtcVoiceMediaChannel " - << voe_channel(); - - // Register external transport - if (engine->voe()->network()->RegisterExternalTransport( - voe_channel(), *static_cast(this)) == -1) { - LOG_RTCERR2(RegisterExternalTransport, voe_channel(), this); - } - - // Enable RTCP (for quality stats and feedback messages) - EnableRtcp(voe_channel()); - - // Create a random but nonzero send SSRC - SetSendSsrc(talk_base::CreateRandomNonZeroId()); - - // Reset all recv codecs; they will be enabled via SetRecvCodecs. - ResetRecvCodecs(voe_channel()); -} - -WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel() { - LOG(LS_VERBOSE) << "WebRtcVoiceMediaChannel::~WebRtcVoiceMediaChannel " - << voe_channel(); - - // DeRegister external transport - if (engine()->voe()->network()->DeRegisterExternalTransport( - voe_channel()) == -1) { - LOG_RTCERR1(DeRegisterExternalTransport, voe_channel()); - } - - // Unregister ourselves from the engine. - engine()->UnregisterChannel(this); - // Remove any remaining streams. - while (!mux_channels_.empty()) { - RemoveStream(mux_channels_.begin()->first); - } - // Delete the primary channel. - if (engine()->voe()->base()->DeleteChannel(voe_channel()) == -1) { - LOG_RTCERR1(DeleteChannel, voe_channel()); - } -} - -bool WebRtcVoiceMediaChannel::SetOptions(int flags) { - // Always accept flags that are unchanged. - if (channel_options_ == flags) { - return true; - } - - // Reject new options if we're already sending. - if (send_ != SEND_NOTHING) { - return false; - } - - // Save the options, to be interpreted where appropriate. - channel_options_ = flags; - return true; -} - -bool WebRtcVoiceMediaChannel::SetRecvCodecs( - const std::vector& codecs) { - // Set the payload types to be used for incoming media. - bool ret = true; - LOG(LS_INFO) << "Setting receive voice codecs:"; - for (std::vector::const_iterator it = codecs.begin(); - it != codecs.end() && ret; ++it) { - webrtc::CodecInst voe_codec; - if (engine()->FindWebRtcCodec(*it, &voe_codec)) { - LOG(LS_INFO) << ToString(*it); - voe_codec.pltype = it->id; - if (engine()->voe()->codec()->SetRecPayloadType( - voe_channel(), voe_codec) == -1) { - LOG_RTCERR2(SetRecPayloadType, voe_channel(), ToString(voe_codec)); - ret = false; - } - } else { - LOG(LS_WARNING) << "Unknown codec " << ToString(*it); - ret = false; - } - } - - return ret; -} - -bool WebRtcVoiceMediaChannel::SetSendCodecs( - const std::vector& codecs) { - // Disable DTMF, VAD, and FEC unless we know the other side wants them. - dtmf_allowed_ = false; - engine()->voe()->codec()->SetVADStatus(voe_channel(), false); - engine()->voe()->rtp()->SetFECStatus(voe_channel(), false); - - // Scan through the list to figure out the codec to use for sending, along - // with the proper configuration for VAD and DTMF. - bool first = true; - webrtc::CodecInst send_codec; - memset(&send_codec, 0, sizeof(send_codec)); - - for (std::vector::const_iterator it = codecs.begin(); - it != codecs.end(); ++it) { - // Ignore codecs we don't know about. The negotiation step should prevent - // this, but double-check to be sure. - webrtc::CodecInst voe_codec; - if (!engine()->FindWebRtcCodec(*it, &voe_codec)) { - LOG(LS_WARNING) << "Unknown codec " << ToString(voe_codec); - continue; - } - - // Find the DTMF telephone event "codec" and tell VoiceEngine about it. - if (_stricmp(it->name.c_str(), "telephone-event") == 0 || - _stricmp(it->name.c_str(), "audio/telephone-event") == 0) { - engine()->voe()->dtmf()->SetSendTelephoneEventPayloadType( - voe_channel(), it->id); - dtmf_allowed_ = true; - } - - // Turn voice activity detection/comfort noise on if supported. - // Set the wideband CN payload type appropriately. - // (narrowband always uses the static payload type 13). - if (_stricmp(it->name.c_str(), "CN") == 0) { - webrtc::PayloadFrequencies cn_freq; - switch (it->clockrate) { - case 8000: - cn_freq = webrtc::kFreq8000Hz; - break; - case 16000: - cn_freq = webrtc::kFreq16000Hz; - break; - case 32000: - cn_freq = webrtc::kFreq32000Hz; - break; - default: - LOG(LS_WARNING) << "CN frequency " << it->clockrate - << " not supported."; - continue; - } - engine()->voe()->codec()->SetVADStatus(voe_channel(), true); - if (cn_freq != webrtc::kFreq8000Hz) { - engine()->voe()->codec()->SetSendCNPayloadType(voe_channel(), - it->id, cn_freq); - } - } - - // We'll use the first codec in the list to actually send audio data. - // Be sure to use the payload type requested by the remote side. - // "red", for FEC audio, is a special case where the actual codec to be - // used is specified in params. - if (first) { - if (_stricmp(it->name.c_str(), "red") == 0) { - // Parse out the RED parameters. If we fail, just ignore RED; - // we don't support all possible params/usage scenarios. - if (!GetRedSendCodec(*it, codecs, &send_codec)) { - continue; - } - - // Enable redundant encoding of the specified codec. Treat any - // failure as a fatal internal error. - LOG(LS_INFO) << "Enabling FEC"; - if (engine()->voe()->rtp()->SetFECStatus(voe_channel(), - true, it->id) == -1) { - LOG_RTCERR3(SetFECStatus, voe_channel(), true, it->id); - return false; - } - } else { - send_codec = voe_codec; - } - first = false; - } - } - - // If we're being asked to set an empty list of codecs, due to a buggy client, - // choose the most common format: PCMU - if (first) { - LOG(LS_WARNING) << "Received empty list of codecs; using PCMU/8000"; - AudioCodec codec(0, "PCMU", 8000, 0, 1, 0); - engine()->FindWebRtcCodec(codec, &send_codec); - } - - // Set the codec. - LOG(LS_INFO) << "Selected voice codec " << ToString(send_codec) - << ", bitrate=" << send_codec.rate; - if (engine()->voe()->codec()->SetSendCodec(voe_channel(), - send_codec) == -1) { - LOG_RTCERR2(SetSendCodec, voe_channel(), ToString(send_codec)); - return false; - } - - return true; -} - -bool WebRtcVoiceMediaChannel::SetRecvRtpHeaderExtensions( - const std::vector& extensions) { - // We don't support any incoming extensions headers right now. - return true; -} - -bool WebRtcVoiceMediaChannel::SetSendRtpHeaderExtensions( - const std::vector& extensions) { - // Enable the audio level extension header if requested. - std::vector::const_iterator it; - for (it = extensions.begin(); it != extensions.end(); ++it) { - if (it->uri == kRtpAudioLevelHeaderExtension) { - break; - } - } - - bool enable = (it != extensions.end()); - int id = 0; - - if (enable) { - id = it->id; - if (id < kMinRtpHeaderExtensionId || - id > kMaxRtpHeaderExtensionId) { - LOG(LS_WARNING) << "Invalid RTP header extension id " << id; - return false; - } - } - -// This api call is not available in iOS version of VoiceEngine currently. -#if !defined(IOS) && !defined(ANDROID) - if (engine()->voe()->rtp()->SetRTPAudioLevelIndicationStatus( - voe_channel(), enable, id) == -1) { - LOG_RTCERR3(SetRTPAudioLevelIndicationStatus, voe_channel(), enable, id); - return false; - } -#endif - - return true; -} - -bool WebRtcVoiceMediaChannel::SetPlayout(bool playout) { - desired_playout_ = playout; - return ChangePlayout(desired_playout_); -} - -bool WebRtcVoiceMediaChannel::PausePlayout() { - return ChangePlayout(false); -} - -bool WebRtcVoiceMediaChannel::ResumePlayout() { - return ChangePlayout(desired_playout_); -} - -bool WebRtcVoiceMediaChannel::ChangePlayout(bool playout) { - if (playout_ == playout) { - return true; - } - - bool result = true; - if (mux_channels_.empty()) { - // Only toggle the default channel if we don't have any other channels. - result = SetPlayout(voe_channel(), playout); - } - for (ChannelMap::iterator it = mux_channels_.begin(); - it != mux_channels_.end() && result; ++it) { - if (!SetPlayout(it->second, playout)) { - LOG(LS_ERROR) << "SetPlayout " << playout << " on channel " << it->second - << " failed"; - result = false; - } - } - - if (result) { - playout_ = playout; - } - return result; -} - -bool WebRtcVoiceMediaChannel::SetSend(SendFlags send) { - desired_send_ = send; - return ChangeSend(desired_send_); -} - -bool WebRtcVoiceMediaChannel::PauseSend() { - return ChangeSend(SEND_NOTHING); -} - -bool WebRtcVoiceMediaChannel::ResumeSend() { - return ChangeSend(desired_send_); -} - -bool WebRtcVoiceMediaChannel::ChangeSend(SendFlags send) { - if (send_ == send) { - return true; - } - - if (send == SEND_MICROPHONE) { -#ifdef CHROMEOS - // Conference mode doesn't work well on ChromeOS. - if (!engine()->SetConferenceMode(false)) { - LOG_RTCERR1(SetConferenceMode, voe_channel()); - return false; - } -#else - // Multi-point conferences use conference-mode noise filtering. - if (!engine()->SetConferenceMode( - 0 != (channel_options_ & OPT_CONFERENCE))) { - LOG_RTCERR1(SetConferenceMode, voe_channel()); - return false; - } -#endif // CHROMEOS - - // Tandberg-bridged conferences have an AGC target that is lower than - // GTV-only levels. - if ((channel_options_ & 0x80000000) && !agc_adjusted_) { - if (engine()->AdjustAgcLevel(kTandbergDbAdjustment)) { - agc_adjusted_ = true; - } - } - - // VoiceEngine resets sequence number when StopSend is called. This - // sometimes causes libSRTP to complain about packets being - // replayed. To get around this we store the last sent sequence - // number and initializes the channel with the next to continue on - // the same sequence. - if (sequence_number() != -1) { - LOG(LS_INFO) << "WebRtcVoiceMediaChannel restores seqnum=" - << sequence_number() + 1; - if (engine()->voe()->sync()->SetInitSequenceNumber( - voe_channel(), sequence_number() + 1) == -1) { - LOG_RTCERR2(SetInitSequenceNumber, voe_channel(), - sequence_number() + 1); - } - } - if (engine()->voe()->base()->StartSend(voe_channel()) == -1) { - LOG_RTCERR1(StartSend, voe_channel()); - return false; - } - if (engine()->voe()->file()->StopPlayingFileAsMicrophone( - voe_channel()) == -1) { - LOG_RTCERR1(StopPlayingFileAsMicrophone, voe_channel()); - return false; - } - } else if (send == SEND_RINGBACKTONE) { - ASSERT(ringback_tone_.get() != NULL); - if (!ringback_tone_.get()) { - return false; - } - if (engine()->voe()->file()->StartPlayingFileAsMicrophone( - voe_channel(), ringback_tone_.get(), false) == -1) { - LOG_RTCERR3(StartPlayingFileAsMicrophone, voe_channel(), - ringback_tone_.get(), false); - return false; - } - // VoiceEngine resets sequence number when StopSend is called. This - // sometimes causes libSRTP to complain about packets being - // replayed. To get around this we store the last sent sequence - // number and initializes the channel with the next to continue on - // the same sequence. - if (sequence_number() != -1) { - LOG(LS_INFO) << "WebRtcVoiceMediaChannel restores seqnum=" - << sequence_number() + 1; - if (engine()->voe()->sync()->SetInitSequenceNumber( - voe_channel(), sequence_number() + 1) == -1) { - LOG_RTCERR2(SetInitSequenceNumber, voe_channel(), - sequence_number() + 1); - } - } - if (engine()->voe()->base()->StartSend(voe_channel()) == -1) { - LOG_RTCERR1(StartSend, voe_channel()); - return false; - } - } else { // SEND_NOTHING - if (engine()->voe()->base()->StopSend(voe_channel()) == -1) { - LOG_RTCERR1(StopSend, voe_channel()); - } - - // Reset the AGC level, if it was set. - if (agc_adjusted_) { - if (engine()->AdjustAgcLevel(0)) { - agc_adjusted_ = false; - } - } - - // Disable conference-mode noise filtering. - if (!engine()->SetConferenceMode(false)) { - LOG_RTCERR1(SetConferenceMode, voe_channel()); - } - } - send_ = send; - return true; -} - -bool WebRtcVoiceMediaChannel::AddStream(uint32 ssrc) { - talk_base::CritScope lock(&mux_channels_cs_); - - if (mux_channels_.find(ssrc) != mux_channels_.end()) { - return false; - } - - // Create a new channel for receiving audio data. - int channel = engine()->voe()->base()->CreateChannel(); - if (channel == -1) { - LOG_RTCERR0(CreateChannel); - return false; - } - - // Configure to use external transport, like our default channel. - if (engine()->voe()->network()->RegisterExternalTransport( - channel, *this) == -1) { - LOG_RTCERR2(SetExternalTransport, channel, this); - return false; - } - - // Use the same SSRC as our default channel (so the RTCP reports are correct). - unsigned int send_ssrc; - webrtc::VoERTP_RTCP* rtp = engine()->voe()->rtp(); - if (rtp->GetLocalSSRC(voe_channel(), send_ssrc) == -1) { - LOG_RTCERR2(GetSendSSRC, channel, send_ssrc); - return false; - } - if (rtp->SetLocalSSRC(channel, send_ssrc) == -1) { - LOG_RTCERR2(SetSendSSRC, channel, send_ssrc); - return false; - } - - // Use the same recv payload types as our default channel. - ResetRecvCodecs(channel); - int ncodecs = engine()->voe()->codec()->NumOfCodecs(); - for (int i = 0; i < ncodecs; ++i) { - webrtc::CodecInst voe_codec; - if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) { - voe_codec.rate = 0; // Needed to make GetRecPayloadType work for ISAC - if (engine()->voe()->codec()->GetRecPayloadType( - voe_channel(), voe_codec) != -1) { - if (engine()->voe()->codec()->SetRecPayloadType( - channel, voe_codec) == -1) { - LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); - return false; - } - } - } - } - - if (mux_channels_.empty() && playout_) { - // This is the first stream in a multi user meeting. We can now - // disable playback of the default stream. This since the default - // stream will probably have received some initial packets before - // the new stream was added. This will mean that the CN state from - // the default channel will be mixed in with the other streams - // throughout the whole meeting, which might be disturbing. - LOG(LS_INFO) << "Disabling playback on the default voice channel"; - SetPlayout(voe_channel(), false); - } - - mux_channels_[ssrc] = channel; - - // TODO: We should rollback the add if SetPlayout fails. - LOG(LS_INFO) << "New audio stream " << ssrc - << " registered to VoiceEngine channel #" - << channel << "."; - return SetPlayout(channel, playout_); -} - -bool WebRtcVoiceMediaChannel::RemoveStream(uint32 ssrc) { - talk_base::CritScope lock(&mux_channels_cs_); - ChannelMap::iterator it = mux_channels_.find(ssrc); - - if (it != mux_channels_.end()) { - if (engine()->voe()->network()->DeRegisterExternalTransport( - it->second) == -1) { - LOG_RTCERR1(DeRegisterExternalTransport, it->second); - } - - LOG(LS_INFO) << "Removing audio stream " << ssrc - << " with VoiceEngine channel #" - << it->second << "."; - if (engine()->voe()->base()->DeleteChannel(it->second) == -1) { - LOG_RTCERR1(DeleteChannel, voe_channel()); - return false; - } - - mux_channels_.erase(it); - if (mux_channels_.empty() && playout_) { - // The last stream was removed. We can now enable the default - // channel for new channels to be played out immediately without - // waiting for AddStream messages. - // TODO: Does the default channel still have it's CN state? - LOG(LS_INFO) << "Enabling playback on the default voice channel"; - SetPlayout(voe_channel(), true); - } - } - return true; -} - -bool WebRtcVoiceMediaChannel::GetActiveStreams( - AudioInfo::StreamList* actives) { - actives->clear(); - for (ChannelMap::iterator it = mux_channels_.begin(); - it != mux_channels_.end(); ++it) { - int level = GetOutputLevel(it->second); - if (level > 0) { - actives->push_back(std::make_pair(it->first, level)); - } - } - return true; -} - -int WebRtcVoiceMediaChannel::GetOutputLevel() { - // return the highest output level of all streams - int highest = GetOutputLevel(voe_channel()); - for (ChannelMap::iterator it = mux_channels_.begin(); - it != mux_channels_.end(); ++it) { - int level = GetOutputLevel(it->second); - highest = talk_base::_max(level, highest); - } - return highest; -} - - -bool WebRtcVoiceMediaChannel::SetOutputScaling( - uint32 ssrc, double left, double right) { - talk_base::CritScope lock(&mux_channels_cs_); - // Collect the channels to scale the output volume. - std::vector channels; - if (0 == ssrc) { // Collect all channels, including the default one. - channels.push_back(voe_channel()); - for (ChannelMap::const_iterator it = mux_channels_.begin(); - it != mux_channels_.end(); ++it) { - channels.push_back(it->second); - } - } else { // Collect only the channel of the specified ssrc. - int channel = GetChannel(ssrc); - if (-1 == channel) { - LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc; - return false; - } - channels.push_back(channel); - } - - // Scale the output volume for the collected channels. We first normalize to - // scale the volume and then set the left and right pan. - float scale = static_cast(talk_base::_max(left, right)); - if (scale > 0.0001f) { - left /= scale; - right /= scale; - } - for (std::vector::const_iterator it = channels.begin(); - it != channels.end(); ++it) { - if (-1 == engine()->voe()->volume()->SetChannelOutputVolumeScaling( - *it, scale)) { - LOG_RTCERR2(SetChannelOutputVolumeScaling, *it, scale); - return false; - } - if (-1 == engine()->voe()->volume()->SetOutputVolumePan( - *it, static_cast(left), static_cast(right))) { - LOG_RTCERR3(SetOutputVolumePan, *it, left, right); - // Do not return if fails. SetOutputVolumePan is not available for all - // pltforms. - } - LOG(LS_INFO) << "SetOutputScaling to left=" << left * scale - << " right=" << right * scale - << " for channel " << *it << " and ssrc " << ssrc; - } - return true; -} - -bool WebRtcVoiceMediaChannel::GetOutputScaling( - uint32 ssrc, double* left, double* right) { - if (!left || !right) return false; - - talk_base::CritScope lock(&mux_channels_cs_); - // Determine which channel based on ssrc. - int channel = (0 == ssrc) ? voe_channel() : GetChannel(ssrc); - if (channel == -1) { - LOG(LS_WARNING) << "Cannot find channel for ssrc:" << ssrc; - return false; - } - - float scaling; - if (-1 == engine()->voe()->volume()->GetChannelOutputVolumeScaling( - channel, scaling)) { - LOG_RTCERR2(GetChannelOutputVolumeScaling, channel, scaling); - return false; - } - - float left_pan; - float right_pan; - if (-1 == engine()->voe()->volume()->GetOutputVolumePan( - channel, left_pan, right_pan)) { - LOG_RTCERR3(GetOutputVolumePan, channel, left_pan, right_pan); - // If GetOutputVolumePan fails, we use the default left and right pan. - left_pan = 1.0f; - right_pan = 1.0f; - } - - *left = scaling * left_pan; - *right = scaling * right_pan; - return true; -} - -bool WebRtcVoiceMediaChannel::SetRingbackTone(const char *buf, int len) { - ringback_tone_.reset(new WebRtcSoundclipStream(buf, len)); - return true; -} - -bool WebRtcVoiceMediaChannel::PlayRingbackTone(uint32 ssrc, - bool play, bool loop) { - if (!ringback_tone_.get()) { - return false; - } - - // Determine which VoiceEngine channel to play on. - int channel = (ssrc == 0) ? voe_channel() : GetChannel(ssrc); - if (channel == -1) { - return false; - } - - // Make sure the ringtone is cued properly, and play it out. - if (play) { - ringback_tone_->set_loop(loop); - ringback_tone_->Rewind(); - if (engine()->voe()->file()->StartPlayingFileLocally(channel, - ringback_tone_.get()) == -1) { - LOG_RTCERR2(StartPlayingFileLocally, channel, ringback_tone_.get()); - LOG(LS_ERROR) << "Unable to start ringback tone"; - return false; - } - ringback_channels_.insert(channel); - LOG(LS_INFO) << "Started ringback on channel " << channel; - } else { - if (engine()->voe()->file()->StopPlayingFileLocally(channel) - == -1) { - LOG_RTCERR1(StopPlayingFileLocally, channel); - return false; - } - LOG(LS_INFO) << "Stopped ringback on channel " << channel; - ringback_channels_.erase(channel); - } - - return true; -} - -bool WebRtcVoiceMediaChannel::PressDTMF(int event, bool playout) { - if (!dtmf_allowed_) { - return false; - } - - // Enable or disable DTMF playout of this tone as requested. This will linger - // until the next call to this method, but that's OK. - if (engine()->voe()->dtmf()->SetDtmfFeedbackStatus(playout) == -1) { - LOG_RTCERR2(SendDTMF, voe_channel(), playout); - return false; - } - - // Send DTMF using out-of-band DTMF. ("true", as 3rd arg) - if (engine()->voe()->dtmf()->SendTelephoneEvent(voe_channel(), event, - true) == -1) { - LOG_RTCERR3(SendDTMF, voe_channel(), event, true); - return false; - } - - return true; -} - -void WebRtcVoiceMediaChannel::OnPacketReceived(talk_base::Buffer* packet) { - // Pick which channel to send this packet to. If this packet doesn't match - // any multiplexed streams, just send it to the default channel. Otherwise, - // send it to the specific decoder instance for that stream. - int which_channel = GetChannel( - ParseSsrc(packet->data(), packet->length(), false)); - if (which_channel == -1) { - which_channel = voe_channel(); - } - - // Stop any ringback that might be playing on the channel. - // It's possible the ringback has already stopped, ih which case we'll just - // use the opportunity to remove the channel from ringback_channels_. - const std::set::iterator it = ringback_channels_.find(which_channel); - if (it != ringback_channels_.end()) { - if (engine()->voe()->file()->IsPlayingFileLocally( - which_channel) == 1) { - engine()->voe()->file()->StopPlayingFileLocally(which_channel); - LOG(LS_INFO) << "Stopped ringback on channel " << which_channel - << " due to incoming media"; - } - ringback_channels_.erase(which_channel); - } - - // Pass it off to the decoder. - engine()->voe()->network()->ReceivedRTPPacket(which_channel, - packet->data(), - packet->length()); -} - -void WebRtcVoiceMediaChannel::OnRtcpReceived(talk_base::Buffer* packet) { - // See above. - int which_channel = GetChannel( - ParseSsrc(packet->data(), packet->length(), true)); - if (which_channel == -1) { - which_channel = voe_channel(); - } - - engine()->voe()->network()->ReceivedRTCPPacket(which_channel, - packet->data(), - packet->length()); -} - -void WebRtcVoiceMediaChannel::SetSendSsrc(uint32 ssrc) { - if (engine()->voe()->rtp()->SetLocalSSRC(voe_channel(), ssrc) - == -1) { - LOG_RTCERR2(SetSendSSRC, voe_channel(), ssrc); - } -} - -bool WebRtcVoiceMediaChannel::SetRtcpCName(const std::string& cname) { - if (engine()->voe()->rtp()->SetRTCP_CNAME(voe_channel(), - cname.c_str()) == -1) { - LOG_RTCERR2(SetRTCP_CNAME, voe_channel(), cname); - return false; - } - return true; -} - -bool WebRtcVoiceMediaChannel::Mute(bool muted) { - if (engine()->voe()->volume()->SetInputMute(voe_channel(), - muted) == -1) { - LOG_RTCERR2(SetInputMute, voe_channel(), muted); - return false; - } - return true; -} - -bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) { - // In VoiceEngine 3.5, GetRTCPStatistics will return 0 even when it fails, - // causing the stats to contain garbage information. To prevent this, we - // zero the stats structure before calling this API. - // TODO: Remove this workaround. - webrtc::CallStatistics cs; - unsigned int ssrc; - webrtc::CodecInst codec; - unsigned int level; - - // Fill in the sender info, based on what we know, and what the - // remote side told us it got from its RTCP report. - VoiceSenderInfo sinfo; - memset(&sinfo, 0, sizeof(sinfo)); - - // Data we obtain locally. - memset(&cs, 0, sizeof(cs)); - if (engine()->voe()->rtp()->GetRTCPStatistics(voe_channel(), cs) == -1 || - engine()->voe()->rtp()->GetLocalSSRC(voe_channel(), ssrc) == -1) { - return false; - } - - sinfo.ssrc = ssrc; - sinfo.bytes_sent = cs.bytesSent; - sinfo.packets_sent = cs.packetsSent; - // RTT isn't known until a RTCP report is received. Until then, VoiceEngine - // returns 0 to indicate an error value. - sinfo.rtt_ms = (cs.rttMs > 0) ? cs.rttMs : -1; - - // Data from the last remote RTCP report. - unsigned int ntp_high, ntp_low, timestamp, ptimestamp, jitter; - unsigned short loss; // NOLINT - if (engine()->voe()->rtp()->GetRemoteRTCPData(voe_channel(), - ntp_high, ntp_low, timestamp, ptimestamp, &jitter, &loss) != -1 && - engine()->voe()->codec()->GetSendCodec(voe_channel(), - codec) != -1) { - // Convert Q8 to floating point. - sinfo.fraction_lost = static_cast(loss) / (1 << 8); - // Convert samples to milliseconds. - if (codec.plfreq / 1000 > 0) { - sinfo.jitter_ms = jitter / (codec.plfreq / 1000); - } - } else { - sinfo.fraction_lost = -1; - sinfo.jitter_ms = -1; - } - // TODO: Figure out how to get remote packets_lost, ext_seqnum - sinfo.packets_lost = -1; - sinfo.ext_seqnum = -1; - - // Local speech level. - sinfo.audio_level = (engine()->voe()->volume()-> - GetSpeechInputLevelFullRange(level) != -1) ? level : -1; - info->senders.push_back(sinfo); - - // Build the list of receivers, one for each mux channel, or 1 in a 1:1 call. - std::vector channels; - for (ChannelMap::const_iterator it = mux_channels_.begin(); - it != mux_channels_.end(); ++it) { - channels.push_back(it->second); - } - if (channels.empty()) { - channels.push_back(voe_channel()); - } - - // Get the SSRC and stats for each receiver, based on our own calculations. - for (std::vector::const_iterator it = channels.begin(); - it != channels.end(); ++it) { - memset(&cs, 0, sizeof(cs)); - if (engine()->voe()->rtp()->GetRemoteSSRC(*it, ssrc) != -1 && - engine()->voe()->rtp()->GetRTCPStatistics(*it, cs) != -1 && - engine()->voe()->codec()->GetRecCodec(*it, codec) != -1) { - VoiceReceiverInfo rinfo; - memset(&rinfo, 0, sizeof(rinfo)); - rinfo.ssrc = ssrc; - rinfo.bytes_rcvd = cs.bytesReceived; - rinfo.packets_rcvd = cs.packetsReceived; - // The next four fields are from the most recently sent RTCP report. - // Convert Q8 to floating point. - rinfo.fraction_lost = static_cast(cs.fractionLost) / (1 << 8); - rinfo.packets_lost = cs.cumulativeLost; - rinfo.ext_seqnum = cs.extendedMax; - // Convert samples to milliseconds. - if (codec.plfreq / 1000 > 0) { - rinfo.jitter_ms = cs.jitterSamples / (codec.plfreq / 1000); - } - - // Get jitter buffer and total delay (alg + jitter + playout) stats. - webrtc::NetworkStatistics ns; - if (engine()->voe()->neteq() && - engine()->voe()->neteq()->GetNetworkStatistics( - *it, ns) != -1) { - rinfo.jitter_buffer_ms = ns.currentBufferSize; - rinfo.jitter_buffer_preferred_ms = ns.preferredBufferSize; - } - if (engine()->voe()->sync()) { - engine()->voe()->sync()->GetDelayEstimate(*it, - rinfo.delay_estimate_ms); - } - - // Get speech level. - rinfo.audio_level = (engine()->voe()->volume()-> - GetSpeechOutputLevelFullRange(*it, level) != -1) ? level : -1; - info->receivers.push_back(rinfo); - } - } - - return true; -} - -void WebRtcVoiceMediaChannel::GetLastMediaError( - uint32* ssrc, VoiceMediaChannel::Error* error) { - ASSERT(ssrc != NULL); - ASSERT(error != NULL); - FindSsrc(voe_channel(), ssrc); - *error = WebRtcErrorToChannelError(GetLastEngineError()); -} - -bool WebRtcVoiceMediaChannel::FindSsrc(int channel_num, uint32* ssrc) { - talk_base::CritScope lock(&mux_channels_cs_); - ASSERT(ssrc != NULL); - if (channel_num == voe_channel()) { - unsigned local_ssrc = 0; - // This is a sending channel. - if (engine()->voe()->rtp()->GetLocalSSRC( - channel_num, local_ssrc) != -1) { - *ssrc = local_ssrc; - } - return true; - } else if (channel_num == -1 && send_ != SEND_NOTHING) { - // Sometimes the VoiceEngine core will throw error with channel_num = -1. - // This means the error is not limited to a specific channel. Signal the - // message using ssrc=0. If the current channel is sending, use this - // channel for sending the message. - *ssrc = 0; - return true; - } else { - // Check whether this is a receiving channel. - for (ChannelMap::const_iterator it = mux_channels_.begin(); - it != mux_channels_.end(); ++it) { - if (it->second == channel_num) { - *ssrc = it->first; - return true; - } - } - } - return false; -} - -void WebRtcVoiceMediaChannel::OnError(uint32 ssrc, int error) { - SignalMediaError(ssrc, WebRtcErrorToChannelError(error)); -} - -int WebRtcVoiceMediaChannel::GetOutputLevel(int channel) { - unsigned int ulevel; - int ret = - engine()->voe()->volume()->GetSpeechOutputLevel(channel, ulevel); - return (ret == 0) ? static_cast(ulevel) : -1; -} - -int WebRtcVoiceMediaChannel::GetChannel(uint32 ssrc) { - ChannelMap::iterator it = mux_channels_.find(ssrc); - return (it != mux_channels_.end()) ? it->second : -1; -} - -bool WebRtcVoiceMediaChannel::GetRedSendCodec(const AudioCodec& red_codec, - const std::vector& all_codecs, webrtc::CodecInst* send_codec) { - // Get the RED encodings from the parameter with no name. This may - // change based on what is discussed on the Jingle list. - // The encoding parameter is of the form "a/b"; we only support where - // a == b. Verify this and parse out the value into red_pt. - // If the parameter value is absent (as it will be until we wire up the - // signaling of this message), use the second codec specified (i.e. the - // one after "red") as the encoding parameter. - int red_pt = -1; - std::string red_params; - CodecParameterMap::const_iterator it = red_codec.params.find(""); - if (it != red_codec.params.end()) { - red_params = it->second; - std::vector red_pts; - if (talk_base::split(red_params, '/', &red_pts) != 2 || - red_pts[0] != red_pts[1] || - !talk_base::FromString(red_pts[0], &red_pt)) { - LOG(LS_WARNING) << "RED params " << red_params << " not supported."; - return false; - } - } else if (red_codec.params.empty()) { - LOG(LS_WARNING) << "RED params not present, using defaults"; - if (all_codecs.size() > 1) { - red_pt = all_codecs[1].id; - } - } - - // Try to find red_pt in |codecs|. - std::vector::const_iterator codec; - for (codec = all_codecs.begin(); codec != all_codecs.end(); ++codec) { - if (codec->id == red_pt) - break; - } - - // If we find the right codec, that will be the codec we pass to - // SetSendCodec, with the desired payload type. - if (codec != all_codecs.end() && - engine()->FindWebRtcCodec(*codec, send_codec)) { - } else { - LOG(LS_WARNING) << "RED params " << red_params << " are invalid."; - return false; - } - - return true; -} - -bool WebRtcVoiceMediaChannel::EnableRtcp(int channel) { - if (engine()->voe()->rtp()->SetRTCPStatus(channel, true) == -1) { - LOG_RTCERR2(SetRTCPStatus, voe_channel(), 1); - return false; - } - // TODO: Enable VQMon and RTCP XR reports, once we know what - // what we want to do with them. - // engine()->voe().EnableVQMon(voe_channel(), true); - // engine()->voe().EnableRTCP_XR(voe_channel(), true); - return true; -} - -bool WebRtcVoiceMediaChannel::ResetRecvCodecs(int channel) { - int ncodecs = engine()->voe()->codec()->NumOfCodecs(); - for (int i = 0; i < ncodecs; ++i) { - webrtc::CodecInst voe_codec; - if (engine()->voe()->codec()->GetCodec(i, voe_codec) != -1) { - voe_codec.pltype = -1; - if (engine()->voe()->codec()->SetRecPayloadType( - channel, voe_codec) == -1) { - LOG_RTCERR2(SetRecPayloadType, channel, ToString(voe_codec)); - return false; - } - } - } - return true; -} - -bool WebRtcVoiceMediaChannel::SetPlayout(int channel, bool playout) { - if (playout) { - LOG(LS_INFO) << "Starting playout for channel #" << channel; - if (engine()->voe()->base()->StartPlayout(channel) == -1) { - LOG_RTCERR1(StartPlayout, channel); - return false; - } - } else { - LOG(LS_INFO) << "Stopping playout for channel #" << channel; - engine()->voe()->base()->StopPlayout(channel); - } - return true; -} - -uint32 WebRtcVoiceMediaChannel::ParseSsrc(const void* data, size_t len, - bool rtcp) { - size_t ssrc_pos = (!rtcp) ? 8 : 4; - uint32 ssrc = 0; - if (len >= (ssrc_pos + sizeof(ssrc))) { - ssrc = talk_base::GetBE32(static_cast(data) + ssrc_pos); - } - return ssrc; -} - -// Convert VoiceEngine error code into VoiceMediaChannel::Error enum. -VoiceMediaChannel::Error - WebRtcVoiceMediaChannel::WebRtcErrorToChannelError(int err_code) { - switch (err_code) { - case 0: - return ERROR_NONE; - case VE_CANNOT_START_RECORDING: - case VE_MIC_VOL_ERROR: - case VE_GET_MIC_VOL_ERROR: - case VE_CANNOT_ACCESS_MIC_VOL: - return ERROR_REC_DEVICE_OPEN_FAILED; - case VE_SATURATION_WARNING: - return ERROR_REC_DEVICE_SATURATION; - case VE_REC_DEVICE_REMOVED: - return ERROR_REC_DEVICE_REMOVED; - case VE_RUNTIME_REC_WARNING: - case VE_RUNTIME_REC_ERROR: - return ERROR_REC_RUNTIME_ERROR; - case VE_CANNOT_START_PLAYOUT: - case VE_SPEAKER_VOL_ERROR: - case VE_GET_SPEAKER_VOL_ERROR: - case VE_CANNOT_ACCESS_SPEAKER_VOL: - return ERROR_PLAY_DEVICE_OPEN_FAILED; - case VE_RUNTIME_PLAY_WARNING: - case VE_RUNTIME_PLAY_ERROR: - return ERROR_PLAY_RUNTIME_ERROR; - case VE_TYPING_NOISE_WARNING: - return ERROR_REC_TYPING_NOISE_DETECTED; - default: - return VoiceMediaChannel::ERROR_OTHER; - } -} - -int WebRtcSoundclipStream::Read(void *buf, int len) { - size_t res = 0; - mem_.Read(buf, len, &res, NULL); - return res; -} - -int WebRtcSoundclipStream::Rewind() { - mem_.Rewind(); - // Return -1 to keep VoiceEngine from looping. - return (loop_) ? 0 : -1; -} - -} // namespace cricket - -#endif // HAVE_WEBRTC_VOICE