| /* |
| * libjingle |
| * Copyright 2004--2005, Google Inc. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO |
| * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; |
| * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR |
| * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF |
| * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #ifndef TALK_SESSION_PHONE_GIPSMEDIAENGINE_H_ |
| #define TALK_SESSION_PHONE_GIPSMEDIAENGINE_H_ |
| |
| #include <map> |
| #include <set> |
| #include <string> |
| #include <vector> |
| |
| #include "talk/base/buffer.h" |
| #include "talk/base/byteorder.h" |
| #include "talk/base/logging.h" |
| #include "talk/base/scoped_ptr.h" |
| #include "talk/base/stream.h" |
| #include "talk/session/phone/channel.h" |
| #include "talk/session/phone/mediaengine.h" |
| #include "talk/session/phone/gips.h" |
| #include "talk/session/phone/rtputils.h" |
| |
| namespace cricket { |
| |
| // GipsSoundclipStream is an adapter object that allows a memory stream to be |
| // passed into GIPS, and support looping. |
| class GipsSoundclipStream : public InStream { |
| public: |
| GipsSoundclipStream(const char* buf, size_t len) |
| : mem_(buf, len), loop_(true) { |
| } |
| void set_loop(bool loop) { loop_ = loop; } |
| virtual int Read(void* buf, int len); |
| virtual int Rewind(); |
| |
| private: |
| talk_base::MemoryStream mem_; |
| bool loop_; |
| }; |
| |
| // GipsMonitorStream is used to monitor a stream coming from GIPS. |
| // For now we just dump the data. |
| class GipsMonitorStream : public OutStream { |
| virtual bool Write(const void *buf, int len) { |
| return true; |
| } |
| }; |
| |
| class GipsSoundclipMedia; |
| class GipsVoiceMediaChannel; |
| |
| // GipsVoiceEngine is a class to be used with CompositeMediaEngine. |
| // It uses the GIPS VoiceEngine library for audio handling. |
| class GipsVoiceEngine |
| : public GIPSVoiceEngineObserver, |
| public GIPSTraceCallback { |
| public: |
| GipsVoiceEngine(); // NOLINT |
| // Dependency injection for testing. |
| GipsVoiceEngine(GipsWrapper* gips, |
| GipsWrapper* gips_sc, |
| GipsTraceWrapper* tracing); |
| ~GipsVoiceEngine(); |
| bool Init(); |
| void Terminate(); |
| |
| int GetCapabilities(); |
| VoiceMediaChannel* CreateChannel(); |
| |
| SoundclipMedia *CreateSoundclip(); |
| |
| bool SetOptions(int options); |
| bool SetDevices(const Device* in_device, const Device* out_device); |
| bool GetOutputVolume(int* level); |
| bool SetOutputVolume(int level); |
| int GetInputLevel(); |
| bool SetLocalMonitor(bool enable); |
| |
| const std::vector<AudioCodec>& codecs(); |
| bool FindCodec(const AudioCodec& codec); |
| bool FindGIPSCodec(const AudioCodec& codec, GIPS_CodecInst* gcodec); |
| |
| void SetLogging(int min_sev, const char* filter); |
| |
| // For tracking GIPS channels. Needed because we have to pause them |
| // all when switching devices. |
| // May only be called by GipsVoiceMediaChannel. |
| void RegisterChannel(GipsVoiceMediaChannel *channel); |
| void UnregisterChannel(GipsVoiceMediaChannel *channel); |
| // May only be called by GipsSoundclipMedia. |
| void RegisterSoundclip(GipsSoundclipMedia *channel); |
| void UnregisterSoundclip(GipsSoundclipMedia *channel); |
| |
| // Called by GipsVoiceMediaChannel to set a gain offset from |
| // the default AGC target level. |
| bool AdjustAgcLevel(int delta); |
| |
| // Called by GipsVoiceMediaChannel to configure echo cancellation |
| // and noise suppression modes. |
| bool SetConferenceMode(bool enable); |
| |
| GipsWrapper* gips() { return gips_.get(); } |
| GipsWrapper* gips_sc() { return gips_sc_.get(); } |
| int GetLastGipsError(); |
| |
| private: |
| typedef std::vector<GipsSoundclipMedia *> SoundclipList; |
| typedef std::vector<GipsVoiceMediaChannel *> ChannelList; |
| |
| struct CodecPref { |
| const char* name; |
| int clockrate; |
| }; |
| |
| void Construct(); |
| bool InitInternal(); |
| void ApplyLogging(const std::string& log_filter); |
| virtual void Print(const GIPS::TraceLevel level, |
| const char* traceString, const int length); |
| virtual void CallbackOnError(const int channel, const int errCode); |
| static int GetCodecPreference(const char *name, int clockrate); |
| // Given the device type, name, and id, find GIPS's device id. Return true and |
| // set the output parameter gips_id if successful. |
| bool FindGipsAudioDeviceId( |
| bool is_input, const std::string& dev_name, int dev_id, int* gips_id); |
| bool FindChannelAndSsrc(int channel_num, |
| GipsVoiceMediaChannel** channel, |
| uint32* ssrc) const; |
| bool ChangeLocalMonitor(bool enable); |
| bool PauseLocalMonitor(); |
| bool ResumeLocalMonitor(); |
| |
| static const int kDefaultLogSeverity = talk_base::LS_WARNING; |
| static const CodecPref kCodecPrefs[]; |
| |
| // The primary instance of GIPS VoiceEngine. |
| talk_base::scoped_ptr<GipsWrapper> gips_; |
| // A secondary instance, for playing out soundclips (on the 'ring' device). |
| talk_base::scoped_ptr<GipsWrapper> gips_sc_; |
| talk_base::scoped_ptr<GipsTraceWrapper> tracing_; |
| int log_level_; |
| std::string log_filter_; |
| bool is_dumping_aec_; |
| std::vector<AudioCodec> codecs_; |
| bool desired_local_monitor_enable_; |
| talk_base::scoped_ptr<GipsMonitorStream> monitor_; |
| SoundclipList soundclips_; |
| ChannelList channels_; |
| // channels_ can be read from GIPS callback thread. We need a lock on that |
| // callback as well as the RegisterChannel/UnregisterChannel. |
| talk_base::CriticalSection channels_cs_; |
| GIPS_AGC_config default_agc_config_; |
| bool initialized_; |
| |
| talk_base::CriticalSection signal_media_critical_; |
| }; |
| |
| // GipsMediaChannel is a class that implements the common GIPS channel |
| // functionality. |
| template <class T, class E> |
| class GipsMediaChannel : public T, public GIPS_transport { |
| public: |
| GipsMediaChannel(E *engine, int channel) |
| : engine_(engine), gips_channel_(channel), sequence_number_(-1) {} |
| E *engine() { return engine_; } |
| int gips_channel() const { return gips_channel_; } |
| bool valid() const { return gips_channel_ != -1; } |
| |
| protected: |
| // implements GIPS_transport interface |
| virtual int SendPacket(int channel, const void *data, int len) { |
| if (!T::network_interface_) { |
| return -1; |
| } |
| |
| // We need to store the sequence number to be able to pick up |
| // the same sequence when the device is restarted. |
| // TODO(oja): Remove when GIPS has fixed the problem. |
| int seq_num; |
| if (!GetRtpSeqNum(data, len, &seq_num)) { |
| return -1; |
| } |
| if (sequence_number() == -1) { |
| LOG(LS_INFO) << "GipsVoiceMediaChannel sends first packet seqnum=" |
| << seq_num; |
| } |
| sequence_number_ = seq_num; |
| |
| talk_base::Buffer packet(data, len, kMaxRtpPacketLen); |
| return T::network_interface_->SendPacket(&packet) ? len : -1; |
| } |
| virtual int SendRTCPPacket(int channel, const void *data, int len) { |
| if (!T::network_interface_) { |
| return -1; |
| } |
| |
| talk_base::Buffer packet(data, len, kMaxRtpPacketLen); |
| return T::network_interface_->SendRtcp(&packet) ? len : -1; |
| } |
| int sequence_number() const { |
| return sequence_number_; |
| } |
| |
| private: |
| E *engine_; |
| int gips_channel_; |
| int sequence_number_; |
| }; |
| |
| // GipsVoiceMediaChannel is an implementation of VoiceMediaChannel that uses |
| // GIPS Voice Engine. |
| class GipsVoiceMediaChannel |
| : public GipsMediaChannel<VoiceMediaChannel, GipsVoiceEngine> { |
| public: |
| explicit GipsVoiceMediaChannel(GipsVoiceEngine *engine); |
| virtual ~GipsVoiceMediaChannel(); |
| virtual bool SetOptions(int options); |
| virtual bool SetRecvCodecs(const std::vector<AudioCodec> &codecs); |
| virtual bool SetSendCodecs(const std::vector<AudioCodec> &codecs); |
| virtual bool SetRecvRtpHeaderExtensions( |
| const std::vector<RtpHeaderExtension> &extensions); |
| virtual bool SetSendRtpHeaderExtensions( |
| const std::vector<RtpHeaderExtension> &extensions); |
| virtual bool SetPlayout(bool playout); |
| bool PausePlayout(); |
| bool ResumePlayout(); |
| virtual bool SetSend(SendFlags send); |
| bool PauseSend(); |
| bool ResumeSend(); |
| |
| virtual bool AddStream(uint32 ssrc); |
| virtual bool RemoveStream(uint32 ssrc); |
| virtual bool GetActiveStreams(AudioInfo::StreamList* actives); |
| virtual int GetOutputLevel(); |
| virtual bool SetOutputScaling(uint32 ssrc, double left, double right); |
| virtual bool GetOutputScaling(uint32 ssrc, double* left, double* right); |
| |
| virtual bool SetRingbackTone(const char *buf, int len); |
| virtual bool PlayRingbackTone(uint32 ssrc, bool play, bool loop); |
| virtual bool PressDTMF(int event, bool playout); |
| |
| virtual void OnPacketReceived(talk_base::Buffer* packet); |
| virtual void OnRtcpReceived(talk_base::Buffer* packet); |
| virtual void SetSendSsrc(uint32 id); |
| virtual bool SetRtcpCName(const std::string& cname); |
| virtual bool Mute(bool mute); |
| virtual bool SetSendBandwidth(bool autobw, int bps) { return false; } |
| virtual bool GetStats(VoiceMediaInfo* info); |
| // Gets last reported error from GIPS voice engine. This should be only |
| // called in response a failure. |
| virtual void GetLastMediaError(uint32* ssrc, |
| VoiceMediaChannel::Error* error); |
| bool FindSsrc(int gips_channel, uint32* ssrc); |
| void OnError(uint32 ssrc, int error); |
| |
| protected: |
| int GetLastGipsError() { return engine()->GetLastGipsError(); } |
| int GetChannel(uint32 ssrc); |
| int GetOutputLevel(int channel); |
| bool GetRedSendCodec(const AudioCodec& red_codec, |
| const std::vector<AudioCodec>& all_codecs, |
| GIPS_CodecInst* send_codec); |
| bool EnableRtcp(int channel); |
| bool SetPlayout(int channel, bool playout); |
| static uint32 ParseSsrc(const void* data, size_t len, bool rtcp); |
| static Error GipsErrorToChannelError(int err_code); |
| |
| private: |
| // Tandberg-bridged conferences require a -10dB gain adjustment, |
| // which is actually +10 in GIPS_AGC_config.targetLeveldBOv |
| static const int kTandbergDbAdjustment = 10; |
| |
| bool ChangePlayout(bool playout); |
| bool ChangeSend(SendFlags send); |
| |
| typedef std::map<uint32, int> ChannelMap; |
| talk_base::scoped_ptr<GipsSoundclipStream> ringback_tone_; |
| std::set<int> ringback_channels_; // channels playing ringback |
| int channel_options_; |
| bool agc_adjusted_; |
| bool dtmf_allowed_; |
| bool desired_playout_; |
| bool playout_; |
| SendFlags desired_send_; |
| SendFlags send_; |
| ChannelMap mux_channels_; // for multiple sources |
| // mux_channels_ can be read from GIPS callback thread. Accesses off the |
| // GIPS thread must be synchronized with edits on the worker thread. Reads |
| // on the worker thread are ok. |
| mutable talk_base::CriticalSection mux_channels_cs_; |
| }; |
| |
| } // namespace cricket |
| |
| #endif // TALK_SESSION_PHONE_GIPSMEDIAENGINE_H_ |