├── LICENSE.md ├── README.md └── code ├── Makefile ├── detectorData.txt ├── include ├── my_channel.h ├── my_common_types.h ├── my_error.h ├── my_macro.h ├── my_voe_ap.h ├── my_voe_base.h ├── my_voe_call_report.h ├── my_voe_codec.h ├── my_voe_dtmf.h ├── my_voe_encryption.h ├── my_voe_external_media.h └── my_voice_engine.h ├── main.cpp ├── python-i386 ├── rat.py ├── recording.log ├── setup.py ├── src ├── my_channel.cpp ├── my_common_types.cpp ├── my_error.cpp ├── my_voe_ap.cpp ├── my_voe_base.cpp ├── my_voe_call_report.cpp ├── my_voe_codec.cpp ├── my_voe_dtmf.cpp ├── my_voe_encryption.cpp ├── my_voe_external_media.cpp └── my_voice_engine.cpp ├── test.py ├── webrtc.log └── webrtc.so /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2015 kundan10@gmail.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Python Wrapper to WebRTC project # 2 | 3 | > This project was migrated from on May 17, 2015 4 | > Keywords: *WebRTC*, *Python* 5 | > Members: *kundan10*, *theintencity*, *voipresearcher* 6 | > License: [MIT License](http://www.opensource.org/licenses/mit-license.php) 7 | > Others: starred by 8 users 8 | 9 | Goal: build python wrapper to Google's WebRTC code so that all the audio/video engine, codecs, devices and peer connection are available from within a Python program. 10 | -------------------------------------------------------------------------------- /code/Makefile: -------------------------------------------------------------------------------- 1 | all : module 2 | 3 | module: $(LIBRARIES) main.cpp Makefile 4 | rm -f build/lib.*/*.so 5 | ARCHFLAGS="-arch i386" python setup.py -v build 6 | cp build/lib.*/webrtc.so . 7 | 8 | clean: 9 | rm -rf build 10 | -------------------------------------------------------------------------------- /code/detectorData.txt: -------------------------------------------------------------------------------- 1 | data = [ 2 | ]; 3 | -------------------------------------------------------------------------------- /code/include/my_channel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_CHANNEL_H 7 | #define MY_CHANNEL_H 1 8 | 9 | #include 10 | #include 11 | 12 | #include "common_types.h" 13 | #include "my_voice_engine.h"; 14 | 15 | using namespace webrtc; 16 | 17 | class RxVadCallback; 18 | class TelephoneEventCallback; 19 | class EncryptionCallback; 20 | class MediaProcessCallback; 21 | 22 | typedef struct { 23 | PyObject_HEAD 24 | /* Type-specific fields go here. */ 25 | int ch; 26 | WebRtcVoiceEngine *voe; 27 | RxVadCallback *rx_vad_callback; 28 | TelephoneEventCallback *telephone_event_callback; 29 | EncryptionCallback *encryption_callback; 30 | MediaProcessCallback *media_process_callback; 31 | } WebRtcChannel; 32 | 33 | 34 | extern int my_channel_preinit(); 35 | extern void my_channel_addobjects(PyObject* m); 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /code/include/my_common_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_COMMON_TYPES_H 7 | #define MY_COMMON_TYPES_H 1 8 | 9 | extern const char* Error2String(int err); 10 | extern const char* attr2string(int attr, const int attrs[], const char* strings[]); 11 | extern int string2attr(const char* str, const int attrs[], const char* strings[]); 12 | 13 | #define My_ATTR2STRING(value, type) \ 14 | attr2string(value, type##_Enum, type##_Str) 15 | 16 | #define My_STRING2ATTR(value, type) \ 17 | string2attr(value, type##_Enum, type##_Str) 18 | 19 | #define My_PROTO_CONVERT(attr) \ 20 | extern const int attr##_Enum[]; \ 21 | extern const char* attr##_Str[]; 22 | 23 | My_PROTO_CONVERT(OnHoldModes) 24 | My_PROTO_CONVERT(NetEqModes) 25 | My_PROTO_CONVERT(NetEqBgnModes) 26 | My_PROTO_CONVERT(NsModes) 27 | My_PROTO_CONVERT(AgcModes) 28 | My_PROTO_CONVERT(AgcConfig) 29 | My_PROTO_CONVERT(EcModes) 30 | My_PROTO_CONVERT(AecmModes) 31 | My_PROTO_CONVERT(VadModes) 32 | My_PROTO_CONVERT(AmrMode) 33 | My_PROTO_CONVERT(TelephoneEventDetectionMethods) 34 | My_PROTO_CONVERT(ProcessingTypes) 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /code/include/my_error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_ERROR_H 7 | #define MY_ERROR_H 1 8 | 9 | #include 10 | 11 | extern PyObject *WebRtcError; 12 | extern const char* Error2String(int err); 13 | extern void my_error_addobjects(PyObject* m); 14 | 15 | #endif 16 | 17 | -------------------------------------------------------------------------------- /code/include/my_macro.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_MACRO_H 7 | #define MY_MACRO_H 1 8 | 9 | #define My_PROPERTY_READONLY(type, attr, name, desc) \ 10 | {name, (getter)type##_Get##attr, NULL, desc, NULL} 11 | 12 | #define My_PROPERTY_WRITEONLY(type, attr, name, desc) \ 13 | {name, NULL, (setter)type##_Set##attr, desc, NULL} 14 | 15 | #define My_PROPERTY_READWRITE(type, attr, name, desc) \ 16 | {name, (getter)type##_Get##attr, (setter)type##_Set##attr, desc, NULL} 17 | 18 | #define My_PROTO_WRITEONLY(type, attr) \ 19 | int type##_Set##attr(type *self, PyObject *value, PyObject *kwargs); 20 | 21 | #define My_PROTO_READONLY(type, attr) \ 22 | PyObject * type##_Get##attr(type *self, void *closure); 23 | 24 | #define My_PROTO_READWRITE(type, attr) \ 25 | PyObject * type##_Get##attr(type *self, void *closure); \ 26 | int type##_Set##attr(type *self, PyObject *value, PyObject *kwargs); 27 | 28 | #define My_METHOD_DECL(type, attr, flags, name, desc) \ 29 | {name, (PyCFunction)type##_##attr, flags, PyDoc_STR(desc)} 30 | 31 | #define My_PROPERTY_SETTER(type, attr) \ 32 | int type##_Set##attr(type *self, PyObject *value, PyObject *kwargs) 33 | 34 | #define My_PROPERTY_GETTER(type, attr) \ 35 | PyObject * type##_Get##attr(type *self, void *closure) 36 | 37 | #define My_METHOD_ARGS_KWARGS(type, name) \ 38 | PyObject * type##_##name(type *self, PyObject *args, PyObject *kwargs) 39 | 40 | #define My_METHOD_ARGS(type, name) \ 41 | PyObject * type##_##name(type *self, PyObject *args) 42 | 43 | #define My_METHOD(type, name) \ 44 | PyObject * type##_##name(type *self, PyObject *unused) 45 | 46 | 47 | #define My_ERROR_IF_NULL(value, type) \ 48 | if (value == NULL) { \ 49 | PyErr_SetString(WebRtcError, "Internal Error: invalid " #value " (" #type ")"); \ 50 | return -1; \ 51 | } 52 | 53 | #define My_NULL_IF_NULL(value, type) \ 54 | if (value == NULL) { \ 55 | PyErr_SetString(WebRtcError, "Internal Error: invalid " #value " (" #type ")"); \ 56 | return NULL; \ 57 | } 58 | 59 | 60 | #define My_ERROR_IF_NEG(value, base) \ 61 | if (value < 0) { \ 62 | PyErr_Format(WebRtcError, "%d %s", base->LastError(), Error2String(base->LastError())); \ 63 | return -1; \ 64 | } 65 | 66 | #define My_NULL_IF_NEG(value, base) \ 67 | if (value < 0) { \ 68 | PyErr_Format(WebRtcError, "%d %s", base->LastError(), Error2String(base->LastError())); \ 69 | return NULL; \ 70 | } 71 | 72 | 73 | #define My_ERROR_IF_NEG2(value) \ 74 | if (value < 0) { \ 75 | PyErr_Format(WebRtcError, "Invalid " #value " (%d)", value); \ 76 | return -1; \ 77 | } 78 | 79 | #define My_NULL_IF_NEG2(value) \ 80 | if (value < 0) { \ 81 | PyErr_Format(WebRtcError, "Invalid " #value " (%d)", value); \ 82 | return NULL; \ 83 | } 84 | 85 | #define My_NULL_IF_NEG3(value, valuestr) \ 86 | if (value< 0) { \ 87 | PyErr_Format(WebRtcError, "Invalid " #value " (\"%s\")", valuestr); \ 88 | return NULL; \ 89 | } 90 | 91 | #define My_ERROR_IF_NEG3(value, valuestr) \ 92 | if (value< 0) { \ 93 | PyErr_Format(WebRtcError, "Invalid " #value " (\"%s\")", valuestr); \ 94 | return -1; \ 95 | } 96 | 97 | 98 | #define My_STRING_OR_NONE(value, valuestr) \ 99 | char *valuestr = NULL; \ 100 | if (value != Py_None) { \ 101 | if (!PyString_Check(value)) { \ 102 | PyErr_SetString(WebRtcError, "must be a string"); \ 103 | return -1; \ 104 | } \ 105 | valuestr = PyString_AsString(value); \ 106 | if (valuestr != NULL && strlen(valuestr) == 0) {\ 107 | valuestr = NULL; \ 108 | } \ 109 | } 110 | 111 | #define My_STRING(value, valuestr) \ 112 | char *valuestr = NULL; \ 113 | if (!PyString_Check(value)) { \ 114 | PyErr_SetString(WebRtcError, "must be a string"); \ 115 | return -1; \ 116 | } \ 117 | valuestr = PyString_AsString(value); \ 118 | 119 | #define My_INT(value, valueint) \ 120 | if (!PyInt_Check(value)) { \ 121 | PyErr_SetString(WebRtcError, "must be a integer"); \ 122 | return -1; \ 123 | } \ 124 | int valueint = PyInt_AsLong(value); \ 125 | 126 | #endif /* My_MACRO_H */ 127 | -------------------------------------------------------------------------------- /code/include/my_voe_ap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef My_VOE_AP_H 7 | #define My_VOE_AP_H 1 8 | 9 | #include "my_macro.h" 10 | #include "my_channel.h" 11 | 12 | extern My_METHOD_ARGS_KWARGS(WebRtcChannel, SetRxVadObserver); 13 | 14 | extern My_PROTO_READWRITE(WebRtcVoiceEngine, NsStatus); 15 | extern My_PROTO_READWRITE(WebRtcVoiceEngine, AgcStatus); 16 | extern My_PROTO_READWRITE(WebRtcVoiceEngine, AgcConfig); 17 | extern My_PROTO_READWRITE(WebRtcVoiceEngine, EcStatus); 18 | extern My_PROTO_READWRITE(WebRtcVoiceEngine, AecmMode); 19 | extern My_PROTO_READWRITE(WebRtcVoiceEngine, MetricsStatus); 20 | extern My_PROTO_READONLY(WebRtcVoiceEngine, SpeechMetrics); 21 | extern My_PROTO_READONLY(WebRtcVoiceEngine, NoiseMetrics); 22 | extern My_PROTO_READONLY(WebRtcVoiceEngine, EchoMetrics); 23 | extern My_PROTO_WRITEONLY(WebRtcVoiceEngine, DebugRecording); 24 | extern My_PROTO_READWRITE(WebRtcVoiceEngine, TypingDetectionStatus); 25 | 26 | extern My_PROTO_READWRITE(WebRtcChannel, RxNsStatus); 27 | extern My_PROTO_READWRITE(WebRtcChannel, RxAgcStatus); 28 | extern My_PROTO_READWRITE(WebRtcChannel, RxAgcConfig); 29 | extern My_PROTO_READONLY(WebRtcChannel, VoiceActivityIndicator); 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /code/include/my_voe_base.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef My_VOE_BASE_H 7 | #define My_VOE_BASE_H 1 8 | 9 | #include "my_channel.h" 10 | 11 | extern My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, RegisterVoiceEngineObserver); 12 | 13 | extern My_METHOD_ARGS_KWARGS(WebRtcChannel, SetLocalReceiver); 14 | extern My_METHOD_ARGS_KWARGS(WebRtcChannel, SetSendDestination); 15 | extern My_METHOD(WebRtcChannel, StartReceive); 16 | extern My_METHOD(WebRtcChannel, StopReceive); 17 | extern My_METHOD(WebRtcChannel, StartPlayout); 18 | extern My_METHOD(WebRtcChannel, StopPlayout); 19 | extern My_METHOD(WebRtcChannel, StartSend); 20 | extern My_METHOD(WebRtcChannel, StopSend); 21 | 22 | extern My_PROTO_READONLY(WebRtcVoiceEngine, Version); 23 | extern My_PROTO_WRITEONLY(WebRtcVoiceEngine, TraceFile); 24 | extern My_PROTO_READONLY(WebRtcVoiceEngine, LastError); 25 | extern My_PROTO_READONLY(WebRtcVoiceEngine, MaxNumOfChannels); 26 | 27 | extern My_PROTO_READONLY(WebRtcChannel, ID); 28 | extern My_PROTO_READONLY(WebRtcChannel, LocalReceiver); 29 | extern My_PROTO_READONLY(WebRtcChannel, SendDestination); 30 | extern My_PROTO_READWRITE(WebRtcChannel, OnHoldStatus); 31 | extern My_PROTO_READWRITE(WebRtcChannel, NetEQPlayoutMode); 32 | extern My_PROTO_READWRITE(WebRtcChannel, NetEQBGNMode); 33 | 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /code/include/my_voe_call_report.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_VOE_CALL_REPORT_H 7 | #define MY_VOE_CALL_REPORT_H 1 8 | 9 | #include 10 | #include "common_types.h" 11 | 12 | #include "my_macro.h" 13 | #include "my_channel.h" 14 | 15 | extern My_METHOD_ARGS(WebRtcVoiceEngine, WriteReportToFile); 16 | 17 | extern My_PROTO_READONLY(WebRtcVoiceEngine, SpeechAndNoiseSummary); 18 | extern My_PROTO_READONLY(WebRtcVoiceEngine, EchoMetricSummary); 19 | 20 | extern My_METHOD(WebRtcChannel, ResetCallReportStatistics); 21 | 22 | extern My_PROTO_READONLY(WebRtcChannel, RoundTripTimeSummary); 23 | extern My_PROTO_READONLY(WebRtcChannel, DeadOrAliveSummary); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /code/include/my_voe_codec.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_VOE_CODEC_H 7 | #define MY_VOE_CODEC_H 1 8 | 9 | #include 10 | #include "common_types.h" 11 | #include "voe_codec.h" 12 | 13 | #include "my_macro.h" 14 | 15 | extern PyObject* codec2object(webrtc::CodecInst& data); 16 | extern int object2codec(PyObject* object, webrtc::CodecInst&data); 17 | 18 | extern My_PROTO_READONLY(WebRtcVoiceEngine, NumOfCodecs); 19 | extern My_PROTO_READONLY(WebRtcVoiceEngine, Codecs); 20 | 21 | extern My_PROTO_READWRITE(WebRtcChannel, SendCodec); 22 | extern My_PROTO_READONLY(WebRtcChannel, RecCodec); 23 | extern My_PROTO_WRITEONLY(WebRtcChannel, ISACInitTargetRate); 24 | extern My_PROTO_WRITEONLY(WebRtcChannel, ISACMaxRate); 25 | extern My_PROTO_WRITEONLY(WebRtcChannel, ISACMaxPayloadSize); 26 | extern My_PROTO_READWRITE(WebRtcChannel, RecPayloadType); 27 | extern My_PROTO_WRITEONLY(WebRtcChannel, SendCNPayloadType); 28 | extern My_PROTO_READWRITE(WebRtcChannel, VADStatus); 29 | //extern My_PROTO_WRITEONLY(WebRtcChannel, AMREncFormat); 30 | //extern My_PROTO_WRITEONLY(WebRtcChannel, AMRDecFormat); 31 | //extern My_PROTO_WRITEONLY(WebRtcChannel, AMRWbEncFormat); 32 | //extern My_PROTO_WRITEONLY(WebRtcChannel, AMRWbDecFormat); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /code/include/my_voe_dtmf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_VOE_DTMF_H 7 | #define MY_VOE_DTMF_H 1 8 | 9 | #include 10 | #include "common_types.h" 11 | 12 | #include "my_macro.h" 13 | #include "my_channel.h" 14 | 15 | 16 | extern My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, PlayDtmfTone); 17 | extern My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, StartPlayingDtmfTone); 18 | extern My_METHOD(WebRtcVoiceEngine, StopPlayingDtmfTone); 19 | 20 | extern My_PROTO_READWRITE(WebRtcVoiceEngine, DtmfFeedbackStatus); 21 | 22 | extern My_METHOD_ARGS_KWARGS(WebRtcChannel, SendTelephoneEvent); 23 | extern My_METHOD_ARGS_KWARGS(WebRtcChannel, RegisterTelephoneEventDetection); 24 | 25 | extern My_PROTO_READWRITE(WebRtcChannel, SendTelephoneEventPayloadType); 26 | extern My_PROTO_READWRITE(WebRtcChannel, DtmfPlayoutStatus); 27 | extern My_PROTO_READONLY(WebRtcChannel, TelephoneEventDetectionStatus); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /code/include/my_voe_encryption.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_VOE_ENCRYPTION_H 7 | #define MY_VOE_ENCRYPTION_H 1 8 | 9 | #include 10 | #include "common_types.h" 11 | 12 | #include "my_macro.h" 13 | #include "my_channel.h" 14 | 15 | extern My_METHOD_ARGS_KWARGS(WebRtcChannel, RegisterExternalEncryption); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /code/include/my_voe_external_media.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_VOE_EXTERNAL_MEDIA_H 7 | #define MY_VOE_EXTERNAL_MEDIA_H 1 8 | 9 | #include 10 | #include "common_types.h" 11 | 12 | #include "my_macro.h" 13 | #include "my_channel.h" 14 | 15 | extern My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, ExternalRecordingInsertData); 16 | extern My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, ExternalPlayoutGetData); 17 | 18 | extern My_PROTO_WRITEONLY(WebRtcVoiceEngine, ExternalRecordingStatus); 19 | extern My_PROTO_WRITEONLY(WebRtcVoiceEngine, ExternalPlayoutStatus); 20 | 21 | 22 | extern My_METHOD_ARGS_KWARGS(WebRtcChannel, RegisterExternalMediaProcessing); 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /code/include/my_voice_engine.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #ifndef MY_VOICE_ENGINE_H 7 | #define MY_VOICE_ENGINE_H 1 8 | 9 | #include 10 | #include 11 | 12 | #include "voe_base.h" 13 | #include "voe_audio_processing.h" 14 | #include "voe_codec.h" 15 | #include "voe_call_report.h" 16 | #include "voe_dtmf.h" 17 | #include "voe_encryption.h" 18 | #include "voe_external_media.h" 19 | 20 | using namespace webrtc; 21 | 22 | class VoiceEngineCallback; 23 | 24 | typedef struct { 25 | PyObject_HEAD 26 | /* Type-specific fields go here. */ 27 | VoiceEngine *voe; 28 | 29 | VoEBase *base; 30 | VoEAudioProcessing *ap; 31 | VoECodec *codec; 32 | VoECallReport *call_report; 33 | VoEDtmf *dtmf; 34 | VoEEncryption *encryption; 35 | VoEExternalMedia *external_media; 36 | 37 | VoiceEngineCallback *callback; 38 | } WebRtcVoiceEngine; 39 | 40 | 41 | extern int my_voice_engine_preinit(); 42 | extern void my_voice_engine_addobjects(PyObject* m); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /code/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "my_error.h" 5 | #include "my_voice_engine.h" 6 | #include "my_channel.h" 7 | 8 | using namespace webrtc; 9 | 10 | extern "C" { 11 | PyMODINIT_FUNC initwebrtc(void); 12 | } 13 | 14 | static PyMethodDef WebRtcMethods[] = { 15 | 16 | {NULL, NULL, 0, NULL} /* Sentinel */ 17 | }; 18 | 19 | PyMODINIT_FUNC 20 | initwebrtc(void) 21 | { 22 | PyObject *m; 23 | 24 | PyEval_InitThreads(); 25 | 26 | if (my_voice_engine_preinit() < 0) 27 | return; 28 | 29 | if (my_channel_preinit() < 0) 30 | return; 31 | 32 | m = Py_InitModule("webrtc", WebRtcMethods); 33 | if (m == NULL) 34 | return; 35 | 36 | my_error_addobjects(m); 37 | my_voice_engine_addobjects(m); 38 | my_channel_addobjects(m); 39 | } 40 | 41 | -------------------------------------------------------------------------------- /code/python-i386: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theintencity/py-webrtc/00283d0383b51e79629faee4d6ddaa8171b4e269/code/python-i386 -------------------------------------------------------------------------------- /code/rat.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | # Copyright (c) 2014, Intencity Cloud Technologies . 4 | # 5 | 6 | 7 | import time, sys, os, traceback 8 | try: 9 | from webrtc import VoiceEngine, Channel 10 | except: 11 | traceback.print_exc() 12 | 13 | def audio_tool(ip, dest_port, receive_port, source_port, codec_name, rate, channels): 14 | try: 15 | #print '%s/%d/%d/%d %s/%d/%d'%(ip, dest_port, receive_port, source_port, codec_name, rate, channels) 16 | 17 | voe = VoiceEngine() 18 | voe.ns_status = "default" 19 | voe.agc_status = "default" 20 | voe.ec_status = "default" 21 | # voe.typing_detection_status = True 22 | 23 | ch = Channel(voe) 24 | if ip.startswith('224.'): 25 | ch.set_local_receiver(port=receive_port, multicast=ip) 26 | else: 27 | ch.set_local_receiver(port=receive_port) 28 | ch.set_send_destination(port=dest_port, ip=ip, source_port=source_port) 29 | # ch.vad_status = True 30 | 31 | 32 | codecs = voe.codecs 33 | found = False 34 | for codec in codecs: 35 | if codec['name'].lower() == codec_name.lower() and codec['channels'] == channels and codec['frequency'] == rate: 36 | ch.send_codec = codec 37 | found = True 38 | break 39 | if not found: 40 | raise ValueError, 'not found %s/%d/%d'%(codec_name, rate, channels) 41 | 42 | ch.start_playout() 43 | ch.start_receive() 44 | ch.start_send() 45 | 46 | while True: 47 | time.sleep(1) 48 | 49 | except KeyboardInterrupt: 50 | ch.stop_send() 51 | ch.stop_receive() 52 | ch.stop_playout() 53 | 54 | del ch 55 | except: 56 | traceback.print_exc() 57 | 58 | if __name__ == '__main__': 59 | try: 60 | if len(sys.argv) < 3: raise ValueError, 'need at least 2 arguments' 61 | ip, dest_port, receive_port, source_port = sys.argv[-2].split("/") 62 | codec_name, rate, channels = sys.argv[-1].split("/") 63 | except: 64 | print 'usage: python %s ip/dest-port/receive-port/source-port codec-name/rate/channels'%(sys.argv[0],) 65 | sys.exit(-1) 66 | 67 | dest_port, receive_port, source_port, rate, channels = map(int, [dest_port, receive_port, source_port, rate, channels]) 68 | 69 | audio_tool(ip, dest_port, receive_port, source_port, codec_name, rate, channels) 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /code/recording.log: -------------------------------------------------------------------------------- 1 | #!vqetrace1.2 2 | @ -------------------------------------------------------------------------------- /code/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup, Extension 2 | 3 | module1 = Extension('webrtc', 4 | sources = ['main.cpp', 'src/my_voice_engine.cpp', 'src/my_channel.cpp', 'src/my_error.cpp', 'src/my_common_types.cpp', 5 | 'src/my_voe_base.cpp', 'src/my_voe_ap.cpp', 'src/my_voe_codec.cpp', 'src/my_voe_call_report.cpp', 6 | 'src/my_voe_dtmf.cpp', 'src/my_voe_encryption.cpp', 'src/my_voe_external_media.cpp', 7 | ], 8 | include_dirs = ['include', '../xcodebuild/Debug/include', '../trunk', '../trunk/voice_engine/main/interface', 9 | '../trunk/system_wrappers/interface', '/usr/include', 10 | '/Developer/SDKs/MacOSX10.5.sdk/usr/include', 11 | '/Developer/SDKs/MacOSX10.5.sdk/usr/lib/gcc/i686-apple-darwin10/4.2.1/include/', 12 | ], 13 | extra_compile_args = [ '-Wno-write-strings', 14 | '-fmessage-length=0', '-Wno-trigraphs','-fno-exceptions', '-fno-rtti', '-O0', '-Wnewline-eof', 15 | '-DWEBRTC_TARGET_MAC_INTEL', '-DWEBRTC_MAC_INTEL', '-DWEBRTC_MAC', '-DWEBRTC_THREAD_RR', 16 | '-DWEBRTC_CLOCK_TYPE_REALTIME', '-DDYNAMIC_ANNOTATIONS_ENABLED=1', '-DWTF_USE_DYNAMIC_ANNOTATIONS=1', 17 | '-isysroot /Developer/SDKs/MacOSX10.5.sdk', 18 | '-fno-threadsafe-statics', '-mmacosx-version-min=10.5', '-gdwarf-2', '-Wendif-labels', 19 | '-Wno-unused-parameter', '-Wno-missing-field-initializers'], 20 | # '-fvisibility=hidden', '-fvisibility-inlines-hidden', 21 | library_dirs = ['../xcodebuild/Debug'], 22 | libraries = ['CNG', 'G711', 'G722', 'NetEq', 'PCM16B', 'aec', 23 | 'aecm', 'agc', 'apm_util', 'audio_coding_module', 'audio_conference_mixer', 24 | 'audio_device', 'audio_processing', 'genperf_libs', 'iLBC', 'iSAC', 25 | 'iSACFix', 'jpeg_turbo', 'media_file', 'ns', 'resampler', 'rtp_rtcp', 26 | 'spl', 'system_wrappers', 'udp_transport', 'vad', 'video_capture_module', 27 | 'video_engine_core', 'video_processing', 'video_render_module', 28 | 'voice_engine_core', 'vpx', 'webrtc_i420', 'webrtc_jpeg', 'webrtc_utility', 29 | 'webrtc_video_coding', 'webrtc_vp8', 'webrtc_vplib'], 30 | extra_link_args = ['-framework', 'Carbon', '-framework', 'AudioToolbox'], 31 | ) 32 | 33 | setup (name = 'PackageName', 34 | version = '1.0', 35 | description = 'Python Wrapper to Google WebRTC module', 36 | ext_modules = [module1]) 37 | 38 | -------------------------------------------------------------------------------- /code/src/my_channel.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "common_types.h" 10 | #include "voe_base.h" 11 | #include "voe_audio_processing.h" 12 | #include "voe_codec.h" 13 | 14 | #include "my_macro.h" 15 | #include "my_error.h" 16 | #include "my_common_types.h" 17 | #include "my_voice_engine.h" 18 | #include "my_channel.h" 19 | 20 | #include "my_voe_base.h" 21 | #include "my_voe_codec.h" 22 | #include "my_voe_ap.h" 23 | #include "my_voe_call_report.h" 24 | #include "my_voe_dtmf.h" 25 | #include "my_voe_encryption.h" 26 | #include "my_voe_external_media.h" 27 | 28 | 29 | using namespace webrtc; 30 | 31 | 32 | static void 33 | WebRtcChannel_dealloc(WebRtcChannel* self) 34 | { 35 | if (self->ch >= 0 && self->voe != NULL) { 36 | self->voe->base->DeleteChannel(self->ch); 37 | Py_DECREF(self->voe); 38 | } 39 | 40 | self->ob_type->tp_free((PyObject*) self); 41 | } 42 | 43 | static int 44 | WebRtcChannel_init(WebRtcChannel *self, PyObject *args, PyObject *kwds) 45 | { 46 | WebRtcVoiceEngine *voe = NULL; 47 | if (!PyArg_ParseTuple(args, "O", &voe)) { 48 | return NULL; 49 | } 50 | 51 | int ch = voe->base->CreateChannel(); 52 | My_ERROR_IF_NEG(ch, voe->base) 53 | 54 | Py_INCREF(voe); 55 | self->voe = voe; 56 | self->ch = ch; 57 | 58 | return 0; 59 | } 60 | 61 | My_PROPERTY_GETTER(WebRtcChannel, ID) 62 | { 63 | My_NULL_IF_NEG2(self->ch) 64 | 65 | if (self->ch < 0) { 66 | Py_INCREF(Py_None); 67 | return Py_None; 68 | } 69 | 70 | return Py_BuildValue("i", self->ch); 71 | } 72 | 73 | static PyMethodDef WebRtcChannel_methods[] = { 74 | 75 | // voe_base.h 76 | 77 | My_METHOD_DECL(WebRtcChannel, SetLocalReceiver, METH_VARARGS | METH_KEYWORDS, "set_local_receiver", 78 | PyDoc_STR("Sets the local receiver port and address for a specified channel number")), 79 | My_METHOD_DECL(WebRtcChannel, SetSendDestination, METH_VARARGS | METH_KEYWORDS, "set_send_destination", 80 | PyDoc_STR("Sets the destination port and address for a specified channel number")), 81 | My_METHOD_DECL(WebRtcChannel, StartReceive, METH_NOARGS, "start_receive", 82 | PyDoc_STR("Prepares and initiates the VoiceEngine for reception of incoming RTP/RTCP packets on the specified channel")), 83 | My_METHOD_DECL(WebRtcChannel, StopReceive, METH_NOARGS, "stop_receive", 84 | PyDoc_STR("Stops receiving incoming RTP/RTCP packets on the specified channel")), 85 | My_METHOD_DECL(WebRtcChannel, StartPlayout, METH_NOARGS, "start_playout", 86 | PyDoc_STR("Starts forwarding the packets to the mixer/soundcard for a specified channel")), 87 | My_METHOD_DECL(WebRtcChannel, StopPlayout, METH_NOARGS, "stop_playout", 88 | PyDoc_STR("Stops forwarding the packets to the mixer/soundcard for a specified channel")), 89 | My_METHOD_DECL(WebRtcChannel, StartSend, METH_NOARGS, "start_send", 90 | PyDoc_STR("Starts sending packets to an already specified IP address and port number for a specified channel")), 91 | My_METHOD_DECL(WebRtcChannel, StopSend, METH_NOARGS, "stop_send", 92 | PyDoc_STR("Stops sending packets from a specified channel")), 93 | 94 | // voe_audio_processing.h 95 | 96 | My_METHOD_DECL(WebRtcChannel, SetRxVadObserver, METH_VARARGS | METH_KEYWORDS, "set_rx_vad_observer", 97 | PyDoc_STR("The voice activity detection observer callback(userdata:object, channel:int, vadDecision:int)) to enable rx VAD notification")), 98 | 99 | // voe_call_report.h 100 | 101 | My_METHOD_DECL(WebRtcChannel, ResetCallReportStatistics, METH_VARARGS, "reset_call_report_statistics", 102 | PyDoc_STR("Performs a combined reset of all components involved in generating the call report for a specified channel")), 103 | 104 | // voe_dtmf.h 105 | 106 | My_METHOD_DECL(WebRtcChannel, SendTelephoneEvent, METH_VARARGS | METH_KEYWORDS, "send_telephone_event", 107 | PyDoc_STR("Sends telephone events either in-band or out-of-band")), 108 | My_METHOD_DECL(WebRtcChannel, RegisterTelephoneEventDetection, METH_VARARGS | METH_KEYWORDS, "set_telephone_event_observer", 109 | PyDoc_STR("Installs or uninstalls a callback and activates/deactivates detection of telephone events")), 110 | 111 | // voe_encryption.h 112 | 113 | My_METHOD_DECL(WebRtcChannel, RegisterExternalEncryption, METH_VARARGS | METH_KEYWORDS, "set_external_encryption", 114 | PyDoc_STR("Set encryption functions (encrypt, decrypt, encrypt_rtcp, decrypt_rtcp) to enable external encryption")), 115 | //My_METHOD_DECL(WebRtcChannel, EnableSRTPSend, "enable_srtp_send", METH_VARARGS | METH_KEYWORDS, 116 | // PyDoc_STR("Not supported")), 117 | //My_METHOD_DECL(WebRtcChannel, EnableSRTPReceive, "enable_srtp_recv", METH_VARARGS | METH_KEYWORDS, 118 | // PyDoc_STR("Not supported")), 119 | 120 | 121 | My_METHOD_DECL(WebRtcChannel, RegisterExternalMediaProcessing, METH_VARARGS | METH_KEYWORDS, "set_external_media_processing", 122 | PyDoc_STR("set_external_media_processing(type, callback, userdata)\n\n" 123 | "Installs an external media process and activates external media for this channel and type")), 124 | 125 | // My_METHOD_DECL(WebRtcChannel, , METH_VARARGS, "", 126 | // PyDoc_STR("")), 127 | {NULL, NULL}, 128 | }; 129 | 130 | static PyGetSetDef WebRtcChannel_getseters[] = { 131 | 132 | // voe_base.h 133 | 134 | My_PROPERTY_READONLY(WebRtcChannel, ID, "id", 135 | PyDoc_STR("(read-only) The underlying channel id for this channel")), 136 | My_PROPERTY_READONLY(WebRtcChannel, LocalReceiver, "local_receiver", 137 | PyDoc_STR("(read-only) Get the local receiver port and address for a specified channel number")), 138 | My_PROPERTY_READONLY(WebRtcChannel, SendDestination, "send_destination", 139 | PyDoc_STR("(read-only) The destination port and address for a specified channel number")), 140 | My_PROPERTY_READWRITE(WebRtcChannel, OnHoldStatus, "on_hold_status", 141 | PyDoc_STR("The current playout and transmission status for this channel")), 142 | My_PROPERTY_READWRITE(WebRtcChannel, NetEQPlayoutMode, "neteq_playout_mode", 143 | PyDoc_STR("The NetEQ playout mode for this channel")), 144 | My_PROPERTY_READWRITE(WebRtcChannel, NetEQBGNMode, "neteq_background_mode", 145 | PyDoc_STR("The NetEQ background noise mode for this channel")), 146 | 147 | // voe_audio_processing.h 148 | 149 | My_PROPERTY_READWRITE(WebRtcChannel, RxNsStatus, "rx_ns_status", 150 | PyDoc_STR("The noise suppression mode of receiving signal intended for advanced use only")), 151 | My_PROPERTY_READWRITE(WebRtcChannel, RxAgcStatus, "rx_agc_status", 152 | PyDoc_STR("The automatic gain control mode to adjust the received signal intended for advanced use only")), 153 | My_PROPERTY_READWRITE(WebRtcChannel, RxAgcConfig, "rx_agc_config", 154 | PyDoc_STR("The automatic gain control configuration of receiving signal intended for advanced use only")), 155 | My_PROPERTY_READONLY(WebRtcChannel, VoiceActivityIndicator, "voice_activity", 156 | PyDoc_STR("(read-only) The voice activity is True if audio frames contain speech else False. Always True if VAD is disabled")), 157 | 158 | // voe_codec.h 159 | 160 | My_PROPERTY_READWRITE(WebRtcChannel, SendCodec, "send_codec", 161 | PyDoc_STR("The codec parameters for the sending codec on this channel")), 162 | My_PROPERTY_READONLY(WebRtcChannel, RecCodec, "recv_codec", 163 | PyDoc_STR("(read-only) The currently received codec for this channel")), 164 | My_PROPERTY_WRITEONLY(WebRtcChannel, ISACInitTargetRate, "isac_init_target_rate", 165 | PyDoc_STR("(write-only) The initial values of target rate and frame size for iSAC for this channel. This API is only valid if iSAC is setup to run in channel-adaptive mode")), 166 | My_PROPERTY_WRITEONLY(WebRtcChannel, ISACMaxRate, "isac_max_rate", 167 | PyDoc_STR("(write-only) The maximum allowed iSAC rate which the codec may not exceed for a single packet for the specified channel. The maximum rate is defined as payload size per frame size in bits per second.")), 168 | My_PROPERTY_WRITEONLY(WebRtcChannel, ISACMaxPayloadSize, "isac_max_payload_size", 169 | PyDoc_STR("(write-only) The maximum allowed iSAC payload size for this channel. The maximum value is set independently of the frame size, i.e. 30 ms and 60 ms packets have the same limit")), 170 | My_PROPERTY_READWRITE(WebRtcChannel, RecPayloadType, "recv_payload_type", 171 | PyDoc_STR("The dynamic payload type number for a particular codec or disables (ignores)) a codec for receiving. For instance, when receiving an invite from a SIP-based client, this function can be used to change the dynamic payload type number to match that in the INVITE SDP-message.")), 172 | My_PROPERTY_WRITEONLY(WebRtcChannel, SendCNPayloadType, "send_cn_payload_type", 173 | PyDoc_STR("(write-only) The payload type for the sending of SID-frames with background noise estimation during silence periods detected by the VAD")), 174 | My_PROPERTY_READWRITE(WebRtcChannel, VADStatus, "vad_status", 175 | PyDoc_STR("the VAD/DTX (silence suppression)) status for this channel")), 176 | //My_PROPERTY_WRITEONLY(WebRtcChannel, AMREncFormat, "amr_end_format", PyDoc_STR("Not supported")), 177 | //My_PROPERTY_WRITEONLY(WebRtcChannel, AMRDecFormat, "amr_dec_format", PyDoc_STR("Not supported")), 178 | //My_PROPERTY_WRITEONLY(WebRtcChannel, AMRWbEncFormat, "amrwb_enc_format", PyDoc_STR("Not supported")), 179 | //My_PROPERTY_WRITEONLY(WebRtcChannel, AMRWbDecFormat, "amrwb_dec_format", PyDoc_STR("Not supported")), 180 | 181 | // voe_call_report.h 182 | 183 | My_PROPERTY_READONLY(WebRtcChannel, RoundTripTimeSummary, "round_trip_time_summary", 184 | PyDoc_STR("(read-only) The minimum, maximum and average levels for Round Trip Time (RTT)) measurements")), 185 | My_PROPERTY_READONLY(WebRtcChannel, DeadOrAliveSummary, "dead_or_alive_summary", 186 | PyDoc_STR("(read-only) The total amount of dead and alive connection detections during a VoIP session")), 187 | 188 | 189 | // voe_dtmf.h 190 | 191 | My_PROPERTY_READWRITE(WebRtcChannel, SendTelephoneEventPayloadType, "send_telephone_event_payload_type", 192 | PyDoc_STR("the currently set dynamic payload type for telephone events")), 193 | My_PROPERTY_READWRITE(WebRtcChannel, DtmfPlayoutStatus, "dtmf_playout_status", 194 | PyDoc_STR("Gets the DTMF playout status")), 195 | My_PROPERTY_READONLY(WebRtcChannel, TelephoneEventDetectionStatus, "telephone_event_detection_status", 196 | PyDoc_STR("(read-only) Gets the current telephone-event detection status for a specified channel")), 197 | 198 | // My_PROPERTY_READWRITE(WebRtcChannel, , "", 199 | // PyDoc_STR("")), 200 | {NULL} /* Sentinel */ 201 | }; 202 | 203 | 204 | static PyTypeObject WebRtcChannelType = { 205 | PyObject_HEAD_INIT(NULL) 206 | 0, /*ob_size*/ 207 | "webrtc.Channel", /*tp_name*/ 208 | sizeof(WebRtcChannel), /*tp_basicsize*/ 209 | 0, /*tp_itemsize*/ 210 | (destructor)WebRtcChannel_dealloc, /*tp_dealloc*/ 211 | 0, /*tp_print*/ 212 | 0, /*tp_getattr*/ 213 | 0, /*tp_setattr*/ 214 | 0, /*tp_compare*/ 215 | 0, /*tp_repr*/ 216 | 0, /*tp_as_number*/ 217 | 0, /*tp_as_sequence*/ 218 | 0, /*tp_as_mapping*/ 219 | 0, /*tp_hash */ 220 | 0, /*tp_call*/ 221 | 0, /*tp_str*/ 222 | 0, /*tp_getattro*/ 223 | 0, /*tp_setattro*/ 224 | 0, /*tp_as_buffer*/ 225 | Py_TPFLAGS_DEFAULT, /*tp_flags*/ 226 | "Channel object", /* tp_doc */ 227 | 0, /* tp_traverse */ 228 | 0, /* tp_clear */ 229 | 0, /* tp_richcompare */ 230 | 0, /* tp_weaklistoffset */ 231 | 0, /* tp_iter */ 232 | 0, /* tp_iternext */ 233 | WebRtcChannel_methods, /* tp_methods */ 234 | 0, /* tp_members */ 235 | WebRtcChannel_getseters, /* tp_getset */ 236 | 0, /* tp_base */ 237 | 0, /* tp_dict */ 238 | 0, /* tp_descr_get */ 239 | 0, /* tp_descr_set */ 240 | 0, /* tp_dictoffset */ 241 | (initproc)WebRtcChannel_init, /* tp_init */ 242 | 0, /* tp_alloc */ 243 | 0, /* tp_new */ 244 | }; 245 | 246 | int my_channel_preinit() { 247 | WebRtcChannelType.tp_new = PyType_GenericNew; 248 | if (PyType_Ready(&WebRtcChannelType) < 0) 249 | return -1; 250 | return 0; 251 | } 252 | 253 | void my_channel_addobjects(PyObject* m) { 254 | Py_INCREF(&WebRtcChannelType); 255 | PyModule_AddObject(m, "Channel", (PyObject *)&WebRtcChannelType); 256 | } 257 | -------------------------------------------------------------------------------- /code/src/my_common_types.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | 8 | #include "common_types.h" 9 | 10 | using namespace webrtc; 11 | 12 | #include "my_common_types.h" 13 | 14 | 15 | const int OnHoldModes_Enum[] = {kHoldSendAndPlay, kHoldSendOnly, kHoldPlayOnly, -1}; 16 | const char* OnHoldModes_Str[] = {"send-play", "send-only", "play-only"}; 17 | const int NetEqModes_Enum[] = {kNetEqDefault, kNetEqStreaming, kNetEqFax, -1}; 18 | const char* NetEqModes_Str[] = {"default", "streaming", "fax"}; 19 | const int NetEqBgnModes_Enum[]= {kBgnOn, kBgnFade, kBgnOff, -1}; 20 | const char* NetEqBgnModes_Str[] = {"on", "fade", "off"}; 21 | const int NsModes_Enum[] = {kNsUnchanged, kNsDefault, kNsConference, kNsLowSuppression, kNsModerateSuppression, kNsHighSuppression, kNsVeryHighSuppression, -1}; 22 | const char* NsModes_Str[] = {"unchanged", "default", "conference", "low", "moderate", "high", "very-high"}; 23 | const int AgcModes_Enum[] = {kAgcUnchanged, kAgcDefault, kAgcAdaptiveAnalog, kAgcAdaptiveDigital, kAgcFixedDigital, -1}; 24 | const char* AgcModes_Str[] = {"unchanged", "default", "adaptive-analog", "adaptive-digital", "fixed-digital"}; 25 | const int EcModes_Enum[] = {kEcUnchanged, kEcDefault, kEcConference, kEcAec, kEcAecm, -1}; 26 | const char* EcModes_Str[] = {"unchanged", "default", "conference", "aec", "aecm"}; 27 | const int AecmModes_Enum[] = {kAecmQuietEarpieceOrHeadset, kAecmEarpiece, kAecmLoudEarpiece, kAecmSpeakerphone, kAecmLoudSpeakerphone, -1}; 28 | const char* AecmModes_Str[] = {"quiet-earpiece", "earpiece", "loud-earpiece", "speakerphone", "loud-speakerphone"}; 29 | const int VadModes_Enum[] = {kVadConventional, kVadAggressiveLow, kVadAggressiveMid, kVadAggressiveHigh, -1}; 30 | const char* VadModes_Str[] = {"conventional", "low", "mid", "high"}; 31 | const int AmrMode_Enum[] = {kRfc3267BwEfficient, kRfc3267OctetAligned, kRfc3267FileStorage, -1}; 32 | const char* AmrMode_Str[] = {"bw-efficient", "octet-aligned", "file-storage"}; 33 | const int TelephoneEventDetectionMethods_Enum[] = {kInBand, kOutOfBand, kInAndOutOfBand, -1}; 34 | const char* TelephoneEventDetectionMethods_Str[] = {"in-band", "out-of-band", "in-and-out-of-band"}; 35 | const int ProcessingTypes_Enum[] = {kPlaybackPerChannel, kPlaybackAllChannelsMixed, kRecordingPerChannel, kRecordingAllChannelsMixed, -1}; 36 | const char* ProcessingTypes_Str[] = {"playback-per-channel", "playback-all-mixed", "recording-per-channel", "recording-all-mixed"}; 37 | 38 | 39 | const char* attr2string(int attr, const int attrs[], const char* strings[]) 40 | { 41 | for (int i=0; attrs[i] >= 0; ++i) { 42 | if (attr == attrs[i]) 43 | return strings[i]; 44 | } 45 | return NULL; 46 | } 47 | 48 | int string2attr(const char* str, const int attrs[], const char* strings[]) 49 | { 50 | for (int i=0; attrs[i] >= 0; ++i) { 51 | if (strcmp(str, strings[i]) == 0) 52 | return attrs[i]; 53 | } 54 | return -1; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /code/src/my_error.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include "Python.h" 7 | 8 | #include "stdio.h" 9 | #include "string.h" 10 | #include "voe_errors.h" 11 | #include "common_types.h" 12 | 13 | using namespace webrtc; 14 | 15 | PyObject *WebRtcError; 16 | 17 | // generated using this command: 18 | // for x in `cat ../trunk//voice_engine/main/interface/voe_errors.h | grep "\#define VE_" |cut -f2 -d" "` 19 | // do echo "case $x: return \"$x\";" 20 | // done 21 | 22 | const char* Error2String(int err) 23 | { 24 | switch (err) { 25 | case VE_PORT_NOT_DEFINED: return "VE_PORT_NOT_DEFINED"; 26 | case VE_CHANNEL_NOT_VALID: return "VE_CHANNEL_NOT_VALID"; 27 | case VE_FUNC_NOT_SUPPORTED: return "VE_FUNC_NOT_SUPPORTED"; 28 | case VE_INVALID_LISTNR: return "VE_INVALID_LISTNR"; 29 | case VE_INVALID_ARGUMENT: return "VE_INVALID_ARGUMENT"; 30 | case VE_INVALID_PORT_NMBR: return "VE_INVALID_PORT_NMBR"; 31 | case VE_INVALID_PLNAME: return "VE_INVALID_PLNAME"; 32 | case VE_INVALID_PLFREQ: return "VE_INVALID_PLFREQ"; 33 | case VE_INVALID_PLTYPE: return "VE_INVALID_PLTYPE"; 34 | case VE_INVALID_PACSIZE: return "VE_INVALID_PACSIZE"; 35 | case VE_NOT_SUPPORTED: return "VE_NOT_SUPPORTED"; 36 | case VE_ALREADY_LISTENING: return "VE_ALREADY_LISTENING"; 37 | case VE_CHANNEL_NOT_CREATED: return "VE_CHANNEL_NOT_CREATED"; 38 | case VE_MAX_ACTIVE_CHANNELS_REACHED: return "VE_MAX_ACTIVE_CHANNELS_REACHED"; 39 | case VE_REC_CANNOT_PREPARE_HEADER: return "VE_REC_CANNOT_PREPARE_HEADER"; 40 | case VE_REC_CANNOT_ADD_BUFFER: return "VE_REC_CANNOT_ADD_BUFFER"; 41 | case VE_PLAY_CANNOT_PREPARE_HEADER: return "VE_PLAY_CANNOT_PREPARE_HEADER"; 42 | case VE_ALREADY_SENDING: return "VE_ALREADY_SENDING"; 43 | case VE_INVALID_IP_ADDRESS: return "VE_INVALID_IP_ADDRESS"; 44 | case VE_ALREADY_PLAYING: return "VE_ALREADY_PLAYING"; 45 | case VE_NOT_ALL_VERSION_INFO: return "VE_NOT_ALL_VERSION_INFO"; 46 | case VE_DTMF_OUTOF_RANGE: return "VE_DTMF_OUTOF_RANGE"; 47 | case VE_INVALID_CHANNELS: return "VE_INVALID_CHANNELS"; 48 | case VE_SET_PLTYPE_FAILED: return "VE_SET_PLTYPE_FAILED"; 49 | case VE_ENCRYPT_NOT_INITED: return "VE_ENCRYPT_NOT_INITED"; 50 | case VE_NOT_INITED: return "VE_NOT_INITED"; 51 | case VE_NOT_SENDING: return "VE_NOT_SENDING"; 52 | case VE_EXT_TRANSPORT_NOT_SUPPORTED: return "VE_EXT_TRANSPORT_NOT_SUPPORTED"; 53 | case VE_EXTERNAL_TRANSPORT_ENABLED: return "VE_EXTERNAL_TRANSPORT_ENABLED"; 54 | case VE_STOP_RECORDING_FAILED: return "VE_STOP_RECORDING_FAILED"; 55 | case VE_INVALID_RATE: return "VE_INVALID_RATE"; 56 | case VE_INVALID_PACKET: return "VE_INVALID_PACKET"; 57 | case VE_NO_GQOS: return "VE_NO_GQOS"; 58 | case VE_INVALID_TIMESTAMP: return "VE_INVALID_TIMESTAMP"; 59 | case VE_RECEIVE_PACKET_TIMEOUT: return "VE_RECEIVE_PACKET_TIMEOUT"; 60 | case VE_STILL_PLAYING_PREV_DTMF: return "VE_STILL_PLAYING_PREV_DTMF"; 61 | case VE_INIT_FAILED_WRONG_EXPIRY: return "VE_INIT_FAILED_WRONG_EXPIRY"; 62 | case VE_SENDING: return "VE_SENDING"; 63 | case VE_ENABLE_IPV6_FAILED: return "VE_ENABLE_IPV6_FAILED"; 64 | case VE_FUNC_NO_STEREO: return "VE_FUNC_NO_STEREO"; 65 | case VE_FW_TRAVERSAL_ALREADY_INITIALIZED: return "VE_FW_TRAVERSAL_ALREADY_INITIALIZED"; 66 | case VE_PACKET_RECEIPT_RESTARTED: return "VE_PACKET_RECEIPT_RESTARTED"; 67 | case VE_NOT_ALL_INFO: return "VE_NOT_ALL_INFO"; 68 | case VE_CANNOT_SET_SEND_CODEC: return "VE_CANNOT_SET_SEND_CODEC"; 69 | case VE_CODEC_ERROR: return "VE_CODEC_ERROR"; 70 | case VE_NETEQ_ERROR: return "VE_NETEQ_ERROR"; 71 | case VE_RTCP_ERROR: return "VE_RTCP_ERROR"; 72 | case VE_INVALID_OPERATION: return "VE_INVALID_OPERATION"; 73 | case VE_CPU_INFO_ERROR: return "VE_CPU_INFO_ERROR"; 74 | case VE_SOUNDCARD_ERROR: return "VE_SOUNDCARD_ERROR"; 75 | case VE_SPEECH_LEVEL_ERROR: return "VE_SPEECH_LEVEL_ERROR"; 76 | case VE_SEND_ERROR: return "VE_SEND_ERROR"; 77 | case VE_CANNOT_REMOVE_CONF_CHANNEL: return "VE_CANNOT_REMOVE_CONF_CHANNEL"; 78 | case VE_PLTYPE_ERROR: return "VE_PLTYPE_ERROR"; 79 | case VE_SET_FEC_FAILED: return "VE_SET_FEC_FAILED"; 80 | case VE_CANNOT_GET_PLAY_DATA: return "VE_CANNOT_GET_PLAY_DATA"; 81 | case VE_APM_ERROR: return "VE_APM_ERROR"; 82 | case VE_RUNTIME_PLAY_WARNING: return "VE_RUNTIME_PLAY_WARNING"; 83 | case VE_RUNTIME_REC_WARNING: return "VE_RUNTIME_REC_WARNING"; 84 | case VE_NOT_PLAYING: return "VE_NOT_PLAYING"; 85 | case VE_SOCKETS_NOT_INITED: return "VE_SOCKETS_NOT_INITED"; 86 | case VE_CANNOT_GET_SOCKET_INFO: return "VE_CANNOT_GET_SOCKET_INFO"; 87 | case VE_INVALID_MULTICAST_ADDRESS: return "VE_INVALID_MULTICAST_ADDRESS"; 88 | case VE_DESTINATION_NOT_INITED: return "VE_DESTINATION_NOT_INITED"; 89 | case VE_RECEIVE_SOCKETS_CONFLICT: return "VE_RECEIVE_SOCKETS_CONFLICT"; 90 | case VE_SEND_SOCKETS_CONFLICT: return "VE_SEND_SOCKETS_CONFLICT"; 91 | case VE_TYPING_NOISE_WARNING: return "VE_TYPING_NOISE_WARNING"; 92 | case VE_SATURATION_WARNING: return "VE_SATURATION_WARNING"; 93 | case VE_NOISE_WARNING: return "VE_NOISE_WARNING"; 94 | case VE_CANNOT_GET_SEND_CODEC: return "VE_CANNOT_GET_SEND_CODEC"; 95 | case VE_CANNOT_GET_REC_CODEC: return "VE_CANNOT_GET_REC_CODEC"; 96 | case VE_ALREADY_INITED: return "VE_ALREADY_INITED"; 97 | case VE_RTCP_SOCKET_ERROR: return "VE_RTCP_SOCKET_ERROR"; 98 | case VE_MIC_VOL_ERROR: return "VE_MIC_VOL_ERROR"; 99 | case VE_SPEAKER_VOL_ERROR: return "VE_SPEAKER_VOL_ERROR"; 100 | case VE_CANNOT_ACCESS_MIC_VOL: return "VE_CANNOT_ACCESS_MIC_VOL"; 101 | case VE_CANNOT_ACCESS_SPEAKER_VOL: return "VE_CANNOT_ACCESS_SPEAKER_VOL"; 102 | case VE_GET_MIC_VOL_ERROR: return "VE_GET_MIC_VOL_ERROR"; 103 | case VE_GET_SPEAKER_VOL_ERROR: return "VE_GET_SPEAKER_VOL_ERROR"; 104 | case VE_THREAD_RTCP_ERROR: return "VE_THREAD_RTCP_ERROR"; 105 | case VE_CANNOT_INIT_APM: return "VE_CANNOT_INIT_APM"; 106 | case VE_SEND_SOCKET_TOS_ERROR: return "VE_SEND_SOCKET_TOS_ERROR"; 107 | case VE_CANNOT_RETRIEVE_DEVICE_NAME: return "VE_CANNOT_RETRIEVE_DEVICE_NAME"; 108 | case VE_SRTP_ERROR: return "VE_SRTP_ERROR"; 109 | case VE_INTERFACE_NOT_FOUND: return "VE_INTERFACE_NOT_FOUND"; 110 | case VE_TOS_GQOS_CONFLICT: return "VE_TOS_GQOS_CONFLICT"; 111 | case VE_CANNOT_ADD_CONF_CHANNEL: return "VE_CANNOT_ADD_CONF_CHANNEL"; 112 | case VE_BUFFER_TOO_SMALL: return "VE_BUFFER_TOO_SMALL"; 113 | case VE_CANNOT_EXECUTE_SETTING: return "VE_CANNOT_EXECUTE_SETTING"; 114 | case VE_CANNOT_RETRIEVE_SETTING: return "VE_CANNOT_RETRIEVE_SETTING"; 115 | case VE_RTP_KEEPALIVE_FAILED: return "VE_RTP_KEEPALIVE_FAILED"; 116 | case VE_SEND_DTMF_FAILED: return "VE_SEND_DTMF_FAILED"; 117 | case VE_CANNOT_RETRIEVE_CNAME: return "VE_CANNOT_RETRIEVE_CNAME"; 118 | case VE_DECRYPTION_FAILED: return "VE_DECRYPTION_FAILED"; 119 | case VE_ENCRYPTION_FAILED: return "VE_ENCRYPTION_FAILED"; 120 | case VE_CANNOT_RETRIEVE_RTP_STAT: return "VE_CANNOT_RETRIEVE_RTP_STAT"; 121 | case VE_GQOS_ERROR: return "VE_GQOS_ERROR"; 122 | case VE_BINDING_SOCKET_TO_LOCAL_ADDRESS_FAILED: return "VE_BINDING_SOCKET_TO_LOCAL_ADDRESS_FAILED"; 123 | case VE_TOS_INVALID: return "VE_TOS_INVALID"; 124 | case VE_TOS_ERROR: return "VE_TOS_ERROR"; 125 | case VE_CANNOT_RETRIEVE_VALUE: return "VE_CANNOT_RETRIEVE_VALUE"; 126 | case VE_PLAY_UNDEFINED_SC_ERR: return "VE_PLAY_UNDEFINED_SC_ERR"; 127 | case VE_REC_CANNOT_OPEN_SC: return "VE_REC_CANNOT_OPEN_SC"; 128 | case VE_SOCKET_ERROR: return "VE_SOCKET_ERROR"; 129 | case VE_MMSYSERR_INVALHANDLE: return "VE_MMSYSERR_INVALHANDLE"; 130 | case VE_MMSYSERR_NODRIVER: return "VE_MMSYSERR_NODRIVER"; 131 | case VE_MMSYSERR_NOMEM: return "VE_MMSYSERR_NOMEM"; 132 | case VE_WAVERR_UNPREPARED: return "VE_WAVERR_UNPREPARED"; 133 | case VE_WAVERR_STILLPLAYING: return "VE_WAVERR_STILLPLAYING"; 134 | case VE_UNDEFINED_SC_ERR: return "VE_UNDEFINED_SC_ERR"; 135 | case VE_UNDEFINED_SC_REC_ERR: return "VE_UNDEFINED_SC_REC_ERR"; 136 | case VE_THREAD_ERROR: return "VE_THREAD_ERROR"; 137 | case VE_CANNOT_START_RECORDING: return "VE_CANNOT_START_RECORDING"; 138 | case VE_PLAY_CANNOT_OPEN_SC: return "VE_PLAY_CANNOT_OPEN_SC"; 139 | case VE_NO_WINSOCK_2: return "VE_NO_WINSOCK_2"; 140 | case VE_SEND_SOCKET_ERROR: return "VE_SEND_SOCKET_ERROR"; 141 | case VE_BAD_FILE: return "VE_BAD_FILE"; 142 | case VE_EXPIRED_COPY: return "VE_EXPIRED_COPY"; 143 | case VE_NOT_AUTHORISED: return "VE_NOT_AUTHORISED"; 144 | case VE_RUNTIME_PLAY_ERROR: return "VE_RUNTIME_PLAY_ERROR"; 145 | case VE_RUNTIME_REC_ERROR: return "VE_RUNTIME_REC_ERROR"; 146 | case VE_BAD_ARGUMENT: return "VE_BAD_ARGUMENT"; 147 | case VE_LINUX_API_ONLY: return "VE_LINUX_API_ONLY"; 148 | case VE_REC_DEVICE_REMOVED: return "VE_REC_DEVICE_REMOVED"; 149 | case VE_NO_MEMORY: return "VE_NO_MEMORY"; 150 | case VE_BAD_HANDLE: return "VE_BAD_HANDLE"; 151 | case VE_RTP_RTCP_MODULE_ERROR: return "VE_RTP_RTCP_MODULE_ERROR"; 152 | case VE_AUDIO_CODING_MODULE_ERROR: return "VE_AUDIO_CODING_MODULE_ERROR"; 153 | case VE_AUDIO_DEVICE_MODULE_ERROR: return "VE_AUDIO_DEVICE_MODULE_ERROR"; 154 | case VE_CANNOT_START_PLAYOUT: return "VE_CANNOT_START_PLAYOUT"; 155 | case VE_CANNOT_STOP_RECORDING: return "VE_CANNOT_STOP_RECORDING"; 156 | case VE_CANNOT_STOP_PLAYOUT: return "VE_CANNOT_STOP_PLAYOUT"; 157 | case VE_CANNOT_INIT_CHANNEL: return "VE_CANNOT_INIT_CHANNEL"; 158 | case VE_RECV_SOCKET_ERROR: return "VE_RECV_SOCKET_ERROR"; 159 | case VE_SOCKET_TRANSPORT_MODULE_ERROR: return "VE_SOCKET_TRANSPORT_MODULE_ERROR"; 160 | case VE_AUDIO_CONF_MIX_MODULE_ERROR: return "VE_AUDIO_CONF_MIX_MODULE_ERROR"; 161 | case VE_IGNORED_FUNCTION: return "VE_IGNORED_FUNCTION"; 162 | default: return ""; 163 | } 164 | } 165 | 166 | void my_error_addobjects(PyObject* m) { 167 | WebRtcError = PyErr_NewException((char*) "webrtc.error", NULL, NULL); 168 | Py_INCREF(WebRtcError); 169 | PyModule_AddObject(m, "error", WebRtcError); 170 | } 171 | -------------------------------------------------------------------------------- /code/src/my_voe_ap.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | 8 | #include "common_types.h" 9 | 10 | #include "my_macro.h" 11 | #include "my_error.h" 12 | #include "my_common_types.h" 13 | #include "my_channel.h" 14 | #include "my_voe_ap.h" 15 | 16 | using namespace webrtc; 17 | 18 | 19 | class RxVadCallback: VoERxVadCallback { 20 | public: 21 | RxVadCallback(PyObject* callback, PyObject* userdata); 22 | ~RxVadCallback(); 23 | void OnRxVad(int channel, int vadDecision); 24 | private: 25 | PyObject *callback; 26 | PyObject *userdata; 27 | }; 28 | 29 | 30 | RxVadCallback::RxVadCallback(PyObject* callback, PyObject* userdata) { 31 | Py_XINCREF(callback); 32 | this->callback = callback; 33 | Py_XINCREF(userdata); 34 | this->userdata = userdata; 35 | } 36 | 37 | RxVadCallback::~RxVadCallback() { 38 | Py_XDECREF(this->callback); 39 | Py_XDECREF(this->userdata); 40 | } 41 | 42 | void RxVadCallback::OnRxVad(int channel, int vadDecision) { 43 | if (this->callback != NULL) { 44 | PyObject* arglist = Py_BuildValue("(Oii)", this->userdata, channel, vadDecision); 45 | PyObject* output = PyObject_CallObject(this->callback, arglist); 46 | Py_DECREF(arglist); 47 | } 48 | } 49 | 50 | 51 | My_PROPERTY_SETTER(WebRtcVoiceEngine, DebugRecording) 52 | { 53 | My_ERROR_IF_NULL(self->base, VoEBase) 54 | My_ERROR_IF_NULL(self->ap, VoEAudioProcessing) 55 | My_STRING_OR_NONE(value, valuestr) 56 | 57 | int er = valuestr != NULL ? self->ap->StartDebugRecording(valuestr) : self->ap->StopDebugRecording(); 58 | My_ERROR_IF_NEG(er, self->base) 59 | 60 | return 0; 61 | } 62 | 63 | My_PROPERTY_GETTER(WebRtcVoiceEngine, TypingDetectionStatus) 64 | { 65 | My_NULL_IF_NULL(self->base, VoEBase) 66 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 67 | 68 | bool status; 69 | int er = self->ap->GetTypingDetectionStatus(status); 70 | My_NULL_IF_NEG(er, self->base); 71 | 72 | return PyBool_FromLong(status); 73 | } 74 | 75 | My_PROPERTY_SETTER(WebRtcVoiceEngine, TypingDetectionStatus) 76 | { 77 | My_ERROR_IF_NULL(self->base, VoEBase) 78 | My_ERROR_IF_NULL(self->ap, VoEAudioProcessing) 79 | 80 | if (!PyBool_Check(value)) { 81 | PyErr_SetString(WebRtcError, "must be a boolean"); 82 | return -1; 83 | } 84 | 85 | bool status = (value == Py_True); 86 | 87 | int er = self->ap->SetTypingDetectionStatus(status); 88 | My_ERROR_IF_NEG(er, self->base) 89 | 90 | return 0; 91 | } 92 | 93 | 94 | My_PROPERTY_GETTER(WebRtcVoiceEngine, NsStatus) 95 | { 96 | My_NULL_IF_NULL(self->base, VoEBase) 97 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 98 | 99 | bool enabled; 100 | NsModes status; 101 | int er = self->ap->GetNsStatus(enabled, status); 102 | My_NULL_IF_NEG(er, self->base); 103 | 104 | if (enabled) { 105 | const char *valuestr = My_ATTR2STRING(status, NsModes); 106 | if (valuestr != NULL) { 107 | return Py_BuildValue("s", valuestr); 108 | } 109 | } 110 | 111 | Py_INCREF(Py_None); 112 | return Py_None; 113 | } 114 | 115 | My_PROPERTY_SETTER(WebRtcVoiceEngine, NsStatus) 116 | { 117 | My_ERROR_IF_NULL(self->base, VoEBase) 118 | My_ERROR_IF_NULL(self->ap, VoEAudioProcessing) 119 | My_STRING_OR_NONE(value, valuestr) 120 | 121 | int er; 122 | if (valuestr == NULL) { 123 | er = self->ap->SetNsStatus(false); 124 | } 125 | else { 126 | int status = My_STRING2ATTR(valuestr, NsModes); 127 | My_ERROR_IF_NEG3(status, valuestr) 128 | er = self->ap->SetNsStatus(true, (NsModes) status); 129 | } 130 | My_ERROR_IF_NEG(er, self->base) 131 | return 0; 132 | } 133 | 134 | My_PROPERTY_GETTER(WebRtcVoiceEngine, AgcStatus) 135 | { 136 | My_NULL_IF_NULL(self->base, VoEBase) 137 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 138 | 139 | bool enabled; 140 | AgcModes status; 141 | int er = self->ap->GetAgcStatus(enabled, status); 142 | My_NULL_IF_NEG(er, self->base); 143 | 144 | if (enabled) { 145 | const char *valuestr = My_ATTR2STRING(status, AgcModes); 146 | if (valuestr != NULL) { 147 | return Py_BuildValue("s", valuestr); 148 | } 149 | } 150 | 151 | Py_INCREF(Py_None); 152 | return Py_None; 153 | } 154 | 155 | My_PROPERTY_SETTER(WebRtcVoiceEngine, AgcStatus) 156 | { 157 | My_ERROR_IF_NULL(self->base, VoEBase) 158 | My_ERROR_IF_NULL(self->ap, VoEAudioProcessing) 159 | My_STRING_OR_NONE(value, valuestr) 160 | 161 | int er; 162 | if (valuestr == NULL) { 163 | er = self->ap->SetAgcStatus(false); 164 | } 165 | else { 166 | int status = My_STRING2ATTR(valuestr, AgcModes); 167 | My_ERROR_IF_NEG3(status, valuestr) 168 | er = self->ap->SetAgcStatus(true, (AgcModes) status); 169 | } 170 | My_ERROR_IF_NEG(er, self->base) 171 | return 0; 172 | } 173 | 174 | My_PROPERTY_GETTER(WebRtcVoiceEngine, AgcConfig) 175 | { 176 | My_NULL_IF_NULL(self->base, VoEBase) 177 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 178 | 179 | AgcConfig status; 180 | int er = self->ap->GetAgcConfig(status); 181 | My_NULL_IF_NEG(er, self->base); 182 | 183 | PyObject *result = PyTuple_New(3); 184 | PyTuple_SetItem(result, 0, PyInt_FromLong(status.targetLeveldBOv)); 185 | PyTuple_SetItem(result, 1, PyInt_FromLong(status.digitalCompressionGaindB)); 186 | PyTuple_SetItem(result, 2, PyBool_FromLong(status.limiterEnable)); 187 | return Py_BuildValue("N", result); 188 | } 189 | 190 | My_PROPERTY_SETTER(WebRtcVoiceEngine, AgcConfig) 191 | { 192 | My_ERROR_IF_NULL(self->base, VoEBase) 193 | My_ERROR_IF_NULL(self->ap, VoEAudioProcessing) 194 | 195 | if (!PyTuple_Check(value) || PyTuple_Size(value) != 3) { 196 | PyErr_SetString(WebRtcError, "must be a tuple (targetLeveldBOv:int, digitalCompressionGaindB:int, limiterEnable:bool)"); 197 | return -1; 198 | } 199 | 200 | PyObject *targetLeveldBOv_o = PyTuple_GetItem(value, 0); 201 | PyObject *digitalCompressionGaindB_o = PyTuple_GetItem(value, 1); 202 | PyObject *limiterEnable_o = PyTuple_GetItem(value, 2); 203 | if (!PyInt_Check(targetLeveldBOv_o) || !PyInt_Check(digitalCompressionGaindB_o) || !PyBool_Check(limiterEnable_o)) { 204 | PyErr_SetString(WebRtcError, "must be a tuple (targetLeveldBOv:int, digitalCompressionGaindB:int, limiterEnable:bool)"); 205 | return -1; 206 | } 207 | 208 | AgcConfig status; 209 | status.targetLeveldBOv = PyInt_AsLong(targetLeveldBOv_o); 210 | status.digitalCompressionGaindB = PyInt_AsLong(digitalCompressionGaindB_o); 211 | status.limiterEnable = PyInt_AsLong(limiterEnable_o); 212 | 213 | int er = self->ap->SetAgcConfig(status); 214 | My_ERROR_IF_NEG(er, self->base) 215 | return 0; 216 | } 217 | 218 | My_PROPERTY_GETTER(WebRtcVoiceEngine, EcStatus) 219 | { 220 | My_NULL_IF_NULL(self->base, VoEBase) 221 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 222 | 223 | bool enabled; 224 | EcModes status; 225 | int er = self->ap->GetEcStatus(enabled, status); 226 | My_NULL_IF_NEG(er, self->base); 227 | 228 | if (enabled) { 229 | const char *valuestr = My_ATTR2STRING(status, EcModes); 230 | if (valuestr != NULL) { 231 | return Py_BuildValue("s", valuestr); 232 | } 233 | } 234 | 235 | Py_INCREF(Py_None); 236 | return Py_None; 237 | } 238 | 239 | My_PROPERTY_SETTER(WebRtcVoiceEngine, EcStatus) 240 | { 241 | My_ERROR_IF_NULL(self->base, VoEBase) 242 | My_ERROR_IF_NULL(self->ap, VoEAudioProcessing) 243 | My_STRING_OR_NONE(value, valuestr) 244 | 245 | int er; 246 | if (valuestr == NULL) { 247 | er = self->ap->SetEcStatus(false); 248 | } 249 | else { 250 | int status = My_STRING2ATTR(valuestr, EcModes); 251 | My_ERROR_IF_NEG3(status, valuestr) 252 | er = self->ap->SetEcStatus(true, (EcModes) status); 253 | } 254 | My_ERROR_IF_NEG(er, self->base) 255 | return 0; 256 | } 257 | 258 | My_PROPERTY_GETTER(WebRtcVoiceEngine, AecmMode) 259 | { 260 | My_NULL_IF_NULL(self->base, VoEBase) 261 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 262 | 263 | bool enabledCNG; 264 | AecmModes status; 265 | int er = self->ap->GetAecmMode(status, enabledCNG); 266 | My_NULL_IF_NEG(er, self->base); 267 | 268 | const char *valuestr = My_ATTR2STRING(status, AecmModes); 269 | if (valuestr != NULL) { 270 | return Py_BuildValue("s", valuestr); 271 | } 272 | // TODO: add CNG to result 273 | 274 | Py_INCREF(Py_None); 275 | return Py_None; 276 | } 277 | 278 | My_PROPERTY_SETTER(WebRtcVoiceEngine, AecmMode) 279 | { 280 | My_ERROR_IF_NULL(self->base, VoEBase) 281 | My_ERROR_IF_NULL(self->ap, VoEAudioProcessing) 282 | My_STRING(value, valuestr) 283 | 284 | int status = My_STRING2ATTR(valuestr, AecmModes); 285 | My_ERROR_IF_NEG3(status, valuestr) 286 | int er = self->ap->SetAecmMode((AecmModes) status); 287 | My_ERROR_IF_NEG(er, self->base) 288 | // TODO: add CNG 289 | 290 | return 0; 291 | } 292 | 293 | My_PROPERTY_GETTER(WebRtcVoiceEngine, MetricsStatus) 294 | { 295 | My_NULL_IF_NULL(self->base, VoEBase) 296 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 297 | 298 | bool status; 299 | int er = self->ap->GetMetricsStatus(status); 300 | My_NULL_IF_NEG(er, self->base); 301 | 302 | return PyBool_FromLong(status); 303 | } 304 | 305 | My_PROPERTY_SETTER(WebRtcVoiceEngine, MetricsStatus) 306 | { 307 | My_ERROR_IF_NULL(self->base, VoEBase) 308 | My_ERROR_IF_NULL(self->ap, VoEAudioProcessing) 309 | 310 | if (!PyBool_Check(value)) { 311 | PyErr_SetString(WebRtcError, "must be bool"); 312 | return -1; 313 | } 314 | 315 | bool status = (value == Py_True); 316 | int er = self->ap->SetMetricsStatus(status); 317 | My_ERROR_IF_NEG(er, self->base) 318 | 319 | return 0; 320 | } 321 | 322 | My_PROPERTY_GETTER(WebRtcVoiceEngine, SpeechMetrics) 323 | { 324 | My_NULL_IF_NULL(self->base, VoEBase) 325 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 326 | 327 | int levelTx, levelRx; 328 | int er = self->ap->GetSpeechMetrics(levelTx, levelRx); 329 | My_NULL_IF_NEG(er, self->base); 330 | 331 | PyObject *result = PyTuple_New(2); 332 | PyTuple_SetItem(result, 0, PyInt_FromLong(levelTx)); 333 | PyTuple_SetItem(result, 1, PyInt_FromLong(levelRx)); 334 | 335 | return Py_BuildValue("N", result); 336 | } 337 | 338 | My_PROPERTY_GETTER(WebRtcVoiceEngine, NoiseMetrics) 339 | { 340 | My_NULL_IF_NULL(self->base, VoEBase) 341 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 342 | 343 | int levelTx, levelRx; 344 | int er = self->ap->GetNoiseMetrics(levelTx, levelRx); 345 | My_NULL_IF_NEG(er, self->base); 346 | 347 | PyObject *result = PyTuple_New(2); 348 | PyTuple_SetItem(result, 0, PyInt_FromLong(levelTx)); 349 | PyTuple_SetItem(result, 1, PyInt_FromLong(levelRx)); 350 | 351 | return Py_BuildValue("N", result); 352 | } 353 | 354 | My_PROPERTY_GETTER(WebRtcVoiceEngine, EchoMetrics) 355 | { 356 | My_NULL_IF_NULL(self->base, VoEBase) 357 | My_NULL_IF_NULL(self->ap, VoEAudioProcessing) 358 | 359 | int ERL, ERLE, RERL, A_NLP; 360 | int er = self->ap->GetEchoMetrics(ERL, ERLE, RERL, A_NLP); 361 | My_NULL_IF_NEG(er, self->base); 362 | 363 | PyObject *result = PyTuple_New(4); 364 | PyTuple_SetItem(result, 0, PyInt_FromLong(ERL)); 365 | PyTuple_SetItem(result, 1, PyInt_FromLong(ERLE)); 366 | PyTuple_SetItem(result, 2, PyInt_FromLong(RERL)); 367 | PyTuple_SetItem(result, 3, PyInt_FromLong(A_NLP)); 368 | 369 | return Py_BuildValue("N", result); 370 | } 371 | 372 | 373 | My_PROPERTY_GETTER(WebRtcChannel, RxNsStatus) 374 | { 375 | My_NULL_IF_NULL(self->voe->base, VoEBase) 376 | My_NULL_IF_NULL(self->voe->ap, VoEAudioProcessing) 377 | My_NULL_IF_NEG2(self->ch) 378 | 379 | bool enabled; 380 | NsModes status; 381 | int er = self->voe->ap->GetRxNsStatus(self->ch, enabled, status); 382 | My_NULL_IF_NEG(er, self->voe->base); 383 | 384 | if (enabled) { 385 | const char *valuestr = My_ATTR2STRING(status, NsModes); 386 | if (valuestr != NULL) { 387 | return Py_BuildValue("s", valuestr); 388 | } 389 | } 390 | 391 | Py_INCREF(Py_None); 392 | return Py_None; 393 | } 394 | 395 | My_PROPERTY_SETTER(WebRtcChannel, RxNsStatus) 396 | { 397 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 398 | My_ERROR_IF_NULL(self->voe->ap, VoEAudioProcessing) 399 | My_ERROR_IF_NEG2(self->ch) 400 | My_STRING_OR_NONE(value, valuestr) 401 | 402 | int er; 403 | if (valuestr == NULL) { 404 | er = self->voe->ap->SetRxNsStatus(self->ch, false); 405 | } 406 | else { 407 | int status = My_STRING2ATTR(valuestr, NsModes); 408 | My_ERROR_IF_NEG3(status, valuestr) 409 | er = self->voe->ap->SetRxNsStatus(self->ch, true, (NsModes) status); 410 | } 411 | My_ERROR_IF_NEG(er, self->voe->base) 412 | return 0; 413 | } 414 | 415 | My_PROPERTY_GETTER(WebRtcChannel, RxAgcStatus) 416 | { 417 | My_NULL_IF_NULL(self->voe->base, VoEBase) 418 | My_NULL_IF_NULL(self->voe->ap, VoEAudioProcessing) 419 | My_NULL_IF_NEG2(self->ch) 420 | 421 | bool enabled; 422 | AgcModes status; 423 | int er = self->voe->ap->GetRxAgcStatus(self->ch, enabled, status); 424 | My_NULL_IF_NEG(er, self->voe->base); 425 | 426 | if (enabled) { 427 | const char *valuestr = My_ATTR2STRING(status, AgcModes); 428 | if (valuestr != NULL) { 429 | return Py_BuildValue("s", valuestr); 430 | } 431 | } 432 | 433 | Py_INCREF(Py_None); 434 | return Py_None; 435 | } 436 | 437 | My_PROPERTY_SETTER(WebRtcChannel, RxAgcStatus) 438 | { 439 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 440 | My_ERROR_IF_NULL(self->voe->ap, VoEAudioProcessing) 441 | My_ERROR_IF_NEG2(self->ch) 442 | My_STRING_OR_NONE(value, valuestr) 443 | 444 | int er; 445 | if (valuestr == NULL) { 446 | er = self->voe->ap->SetRxAgcStatus(self->ch, false); 447 | } 448 | else { 449 | int status = My_STRING2ATTR(valuestr, AgcModes); 450 | My_ERROR_IF_NEG3(status, valuestr) 451 | er = self->voe->ap->SetRxAgcStatus(self->ch, true, (AgcModes) status); 452 | } 453 | My_ERROR_IF_NEG(er, self->voe->base) 454 | return 0; 455 | } 456 | 457 | My_PROPERTY_GETTER(WebRtcChannel, RxAgcConfig) 458 | { 459 | My_NULL_IF_NULL(self->voe->base, VoEBase) 460 | My_NULL_IF_NULL(self->voe->ap, VoEAudioProcessing) 461 | My_NULL_IF_NEG2(self->ch) 462 | 463 | AgcConfig status; 464 | int er = self->voe->ap->GetRxAgcConfig(self->ch, status); 465 | My_NULL_IF_NEG(er, self->voe->base); 466 | 467 | PyObject *result = PyTuple_New(3); 468 | PyTuple_SetItem(result, 0, PyInt_FromLong(status.targetLeveldBOv)); 469 | PyTuple_SetItem(result, 1, PyInt_FromLong(status.digitalCompressionGaindB)); 470 | PyTuple_SetItem(result, 2, PyBool_FromLong(status.limiterEnable)); 471 | return Py_BuildValue("N", result); 472 | } 473 | 474 | My_PROPERTY_SETTER(WebRtcChannel, RxAgcConfig) 475 | { 476 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 477 | My_ERROR_IF_NULL(self->voe->ap, VoEAudioProcessing) 478 | My_ERROR_IF_NEG2(self->ch) 479 | 480 | if (!PyTuple_Check(value) || PyTuple_Size(value) != 3) { 481 | PyErr_SetString(WebRtcError, "must be a tuple (targetLeveldBOv:int, digitalCompressionGaindB:int, limiterEnable:bool)"); 482 | return -1; 483 | } 484 | 485 | PyObject *targetLeveldBOv_o = PyTuple_GetItem(value, 0); 486 | PyObject *digitalCompressionGaindB_o = PyTuple_GetItem(value, 1); 487 | PyObject *limiterEnable_o = PyTuple_GetItem(value, 2); 488 | if (!PyInt_Check(targetLeveldBOv_o) || !PyInt_Check(digitalCompressionGaindB_o) || !PyBool_Check(limiterEnable_o)) { 489 | PyErr_SetString(WebRtcError, "must be a tuple (targetLeveldBOv:int, digitalCompressionGaindB:int, limiterEnable:bool)"); 490 | return -1; 491 | } 492 | 493 | AgcConfig status; 494 | status.targetLeveldBOv = PyInt_AsLong(targetLeveldBOv_o); 495 | status.digitalCompressionGaindB = PyInt_AsLong(digitalCompressionGaindB_o); 496 | status.limiterEnable = PyInt_AsLong(limiterEnable_o); 497 | 498 | int er = self->voe->ap->SetRxAgcConfig(self->ch, status); 499 | My_ERROR_IF_NEG(er, self->voe->base) 500 | return 0; 501 | } 502 | 503 | My_METHOD_ARGS_KWARGS(WebRtcChannel, SetRxVadObserver) 504 | { 505 | My_NULL_IF_NULL(self->voe->base, VoEBase) 506 | My_NULL_IF_NULL(self->voe->ap, VoEAudioProcessing) 507 | My_NULL_IF_NEG2(self->ch) 508 | 509 | PyObject* callback = NULL; 510 | PyObject* userdata = Py_None; 511 | static char *kwlist[] = {"callback", "userdata", NULL}; 512 | 513 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist, &callback, &userdata)) { 514 | return NULL; 515 | } 516 | 517 | if (callback != Py_None && !PyCallable_Check(callback)) { 518 | PyErr_SetString(WebRtcError, "callback must be callable or None"); 519 | return NULL; 520 | } 521 | 522 | if (self->rx_vad_callback != NULL) { 523 | delete self->rx_vad_callback; 524 | self->rx_vad_callback = NULL; 525 | } 526 | 527 | if (callback != Py_None) { 528 | self->rx_vad_callback = new RxVadCallback(callback, userdata); 529 | } 530 | 531 | Py_INCREF(Py_None); 532 | return Py_None; 533 | } 534 | 535 | My_PROPERTY_GETTER(WebRtcChannel, VoiceActivityIndicator) 536 | { 537 | My_NULL_IF_NULL(self->voe->base, VoEBase) 538 | My_NULL_IF_NULL(self->voe->ap, VoEAudioProcessing) 539 | My_NULL_IF_NEG2(self->ch) 540 | 541 | int status = self->voe->ap->VoiceActivityIndicator(self->ch); 542 | return PyBool_FromLong(status); 543 | } 544 | 545 | -------------------------------------------------------------------------------- /code/src/my_voe_base.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | 8 | #include "common_types.h" 9 | 10 | #include "my_macro.h" 11 | #include "my_error.h" 12 | #include "my_common_types.h" 13 | #include "my_channel.h" 14 | #include "my_voe_base.h" 15 | 16 | using namespace webrtc; 17 | 18 | class VoiceEngineCallback: VoiceEngineObserver { 19 | public: 20 | VoiceEngineCallback(PyObject* callback, PyObject* userdata); 21 | ~VoiceEngineCallback(); 22 | void CallbackOnError(const int channel, const int errCode); 23 | private: 24 | PyObject *callback; 25 | PyObject *userdata; 26 | }; 27 | 28 | VoiceEngineCallback::VoiceEngineCallback(PyObject* callback, PyObject* userdata) { 29 | Py_XINCREF(callback); 30 | this->callback = callback; 31 | Py_XINCREF(userdata); 32 | this->userdata = userdata; 33 | } 34 | 35 | VoiceEngineCallback::~VoiceEngineCallback() { 36 | Py_XDECREF(this->callback); 37 | Py_XDECREF(this->userdata); 38 | } 39 | 40 | void VoiceEngineCallback::CallbackOnError(const int channel, const int errCode) { 41 | if (this->callback != NULL) { 42 | PyObject* arglist = Py_BuildValue("(Ois)", this->userdata, channel, Error2String(errCode)); 43 | PyObject* output = PyObject_CallObject(this->callback, arglist); 44 | Py_DECREF(arglist); 45 | } 46 | } 47 | 48 | 49 | My_PROPERTY_SETTER(WebRtcVoiceEngine, TraceFile) 50 | { 51 | My_ERROR_IF_NULL(self->voe, VoEVoiceEngine) 52 | My_ERROR_IF_NULL(self->base, VoEBase) 53 | My_STRING_OR_NONE(value, valuestr) 54 | 55 | int er = self->voe->SetTraceFile(valuestr); 56 | My_ERROR_IF_NEG(er, self->base) 57 | 58 | return 0; 59 | } 60 | 61 | My_PROPERTY_GETTER(WebRtcVoiceEngine, MaxNumOfChannels) 62 | { 63 | My_NULL_IF_NULL(self->base, VoEBase) 64 | int ch = self->base->MaxNumOfChannels(); 65 | return PyInt_FromLong(ch); 66 | } 67 | 68 | My_PROPERTY_GETTER(WebRtcVoiceEngine, Version) 69 | { 70 | My_NULL_IF_NULL(self->base, VoEBase) 71 | char version[1024]; 72 | int er = self->base->GetVersion(version); 73 | My_NULL_IF_NEG(er, self->base) 74 | return PyString_FromString(version); 75 | } 76 | 77 | My_PROPERTY_GETTER(WebRtcVoiceEngine, LastError) 78 | { 79 | My_NULL_IF_NULL(self->base, VoEBase) 80 | int er = self->base->LastError(); 81 | return PyString_FromFormat("%d %s", er, Error2String(er)); 82 | } 83 | 84 | 85 | My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, RegisterVoiceEngineObserver) 86 | { 87 | My_NULL_IF_NULL(self->base, VoEBase) 88 | 89 | PyObject* callback = NULL; 90 | PyObject* userdata = Py_None; 91 | static char *kwlist[] = {"callback", "userdata", NULL}; 92 | 93 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|O", kwlist, &callback, &userdata)) { 94 | return NULL; 95 | } 96 | 97 | if (callback != Py_None && !PyCallable_Check(callback)) { 98 | PyErr_SetString(WebRtcError, "callback must be callable or None"); 99 | return NULL; 100 | } 101 | 102 | if (self->callback != NULL) { 103 | delete self->callback; 104 | self->callback = NULL; 105 | } 106 | 107 | if (callback != Py_None) { 108 | self->callback = new VoiceEngineCallback(callback, userdata); 109 | } 110 | 111 | Py_INCREF(Py_None); 112 | return Py_None; 113 | } 114 | 115 | 116 | 117 | 118 | 119 | My_METHOD_ARGS_KWARGS(WebRtcChannel, SetLocalReceiver) 120 | { 121 | My_NULL_IF_NULL(self->voe->base, VoEBase) 122 | My_NULL_IF_NEG2(self->ch) 123 | 124 | int port = -1; 125 | int rtcp_port = kVoEDefault; 126 | const char* ip = NULL; 127 | const char* multicast = NULL; 128 | static char *kwlist[] = {"port", "rtcp_port", "ip", "multicast", NULL}; 129 | 130 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i|iss", kwlist, &port, &rtcp_port, &ip, &multicast)) { 131 | return NULL; 132 | } 133 | 134 | int er = self->voe->base->SetLocalReceiver(self->ch, port, rtcp_port, ip, multicast); 135 | My_NULL_IF_NEG(er, self->voe->base) 136 | 137 | Py_INCREF(Py_None); 138 | return Py_None; 139 | } 140 | 141 | My_PROPERTY_GETTER(WebRtcChannel, LocalReceiver) 142 | { 143 | My_NULL_IF_NULL(self->voe->base, VoEBase) 144 | My_NULL_IF_NEG2(self->ch) 145 | 146 | int port = -1; 147 | int rtcp_port = -1; 148 | char ip[64]; 149 | int er = self->voe->base->GetLocalReceiver(self->ch, port, rtcp_port, ip); 150 | My_NULL_IF_NEG(er, self->voe->base) 151 | 152 | PyObject* result = PyTuple_New(3); 153 | PyTuple_SetItem(result, 0, PyString_FromString(ip)); 154 | PyTuple_SetItem(result, 1, PyInt_FromLong(port)); 155 | PyTuple_SetItem(result, 2, PyInt_FromLong(rtcp_port)); 156 | 157 | return Py_BuildValue("N", result); 158 | } 159 | 160 | My_METHOD_ARGS_KWARGS(WebRtcChannel, SetSendDestination) 161 | { 162 | My_NULL_IF_NULL(self->voe->base, VoEBase) 163 | My_NULL_IF_NEG2(self->ch) 164 | 165 | int port = -1; 166 | int source_port = kVoEDefault; 167 | int rtcp_port = kVoEDefault; 168 | const char* ip = NULL; 169 | static char *kwlist[] = {"port", "ip", "source_port", "rtcp_port", NULL}; 170 | 171 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "is|ii", kwlist, &port, &ip, &source_port, &rtcp_port)) { 172 | return NULL; 173 | } 174 | 175 | int er = self->voe->base->SetSendDestination(self->ch, port, ip, source_port, rtcp_port); 176 | My_NULL_IF_NEG(er, self->voe->base) 177 | 178 | Py_INCREF(Py_None); 179 | return Py_None; 180 | } 181 | 182 | My_PROPERTY_GETTER(WebRtcChannel, SendDestination) 183 | { 184 | My_NULL_IF_NULL(self->voe->base, VoEBase) 185 | My_NULL_IF_NEG2(self->ch) 186 | 187 | int port = -1; 188 | char ip[64]; 189 | int source_port = -1; 190 | int rtcp_port = -1; 191 | int er = self->voe->base->GetSendDestination(self->ch, port, ip, source_port, rtcp_port); 192 | My_NULL_IF_NEG(er, self->voe->base) 193 | 194 | PyObject* result = PyTuple_New(4); 195 | PyTuple_SetItem(result, 0, PyString_FromString(ip)); 196 | PyTuple_SetItem(result, 1, PyInt_FromLong(port)); 197 | PyTuple_SetItem(result, 2, PyInt_FromLong(rtcp_port)); 198 | PyTuple_SetItem(result, 3, PyInt_FromLong(source_port)); 199 | 200 | return Py_BuildValue("N", result); 201 | } 202 | 203 | My_METHOD(WebRtcChannel, StartReceive) 204 | { 205 | My_NULL_IF_NULL(self->voe->base, VoEBase) 206 | My_NULL_IF_NEG2(self->ch) 207 | 208 | int er = self->voe->base->StartReceive(self->ch); 209 | My_NULL_IF_NEG(er, self->voe->base) 210 | 211 | Py_INCREF(Py_None); 212 | return Py_None; 213 | } 214 | 215 | My_METHOD(WebRtcChannel, StopReceive) 216 | { 217 | My_NULL_IF_NULL(self->voe->base, VoEBase) 218 | My_NULL_IF_NEG2(self->ch) 219 | 220 | int er = self->voe->base->StopReceive(self->ch); 221 | My_NULL_IF_NEG(er, self->voe->base) 222 | 223 | Py_INCREF(Py_None); 224 | return Py_None; 225 | } 226 | 227 | My_METHOD(WebRtcChannel, StartPlayout) 228 | { 229 | My_NULL_IF_NULL(self->voe->base, VoEBase) 230 | My_NULL_IF_NEG2(self->ch) 231 | 232 | int er = self->voe->base->StartPlayout(self->ch); 233 | My_NULL_IF_NEG(er, self->voe->base) 234 | 235 | Py_INCREF(Py_None); 236 | return Py_None; 237 | } 238 | 239 | My_METHOD(WebRtcChannel, StopPlayout) 240 | { 241 | My_NULL_IF_NULL(self->voe->base, VoEBase) 242 | My_NULL_IF_NEG2(self->ch) 243 | 244 | int er = self->voe->base->StopPlayout(self->ch); 245 | My_NULL_IF_NEG(er, self->voe->base) 246 | 247 | Py_INCREF(Py_None); 248 | return Py_None; 249 | } 250 | 251 | My_METHOD(WebRtcChannel, StartSend) 252 | { 253 | My_NULL_IF_NULL(self->voe->base, VoEBase) 254 | My_NULL_IF_NEG2(self->ch) 255 | 256 | int er = self->voe->base->StartSend(self->ch); 257 | My_NULL_IF_NEG(er, self->voe->base) 258 | 259 | Py_INCREF(Py_None); 260 | return Py_None; 261 | } 262 | 263 | My_METHOD(WebRtcChannel, StopSend) 264 | { 265 | My_NULL_IF_NULL(self->voe->base, VoEBase) 266 | My_NULL_IF_NEG2(self->ch) 267 | 268 | int er = self->voe->base->StopSend(self->ch); 269 | My_NULL_IF_NEG(er, self->voe->base) 270 | 271 | Py_INCREF(Py_None); 272 | return Py_None; 273 | } 274 | 275 | My_PROPERTY_GETTER(WebRtcChannel, OnHoldStatus) 276 | { 277 | My_NULL_IF_NULL(self->voe->base, VoEBase) 278 | My_NULL_IF_NEG2(self->ch) 279 | 280 | bool enabled; 281 | OnHoldModes status; 282 | int er = self->voe->base->GetOnHoldStatus(self->ch, enabled, status); 283 | My_NULL_IF_NEG(er, self->voe->base); 284 | 285 | if (enabled) { 286 | const char *valuestr = My_ATTR2STRING(status, OnHoldModes); 287 | if (valuestr != NULL) { 288 | return Py_BuildValue("s", valuestr); 289 | } 290 | } 291 | 292 | Py_INCREF(Py_None); 293 | return Py_None; 294 | } 295 | 296 | My_PROPERTY_SETTER(WebRtcChannel, OnHoldStatus) 297 | { 298 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 299 | My_ERROR_IF_NEG2(self->ch) 300 | My_STRING_OR_NONE(value, valuestr) 301 | 302 | int er; 303 | if (valuestr == NULL) { 304 | er = self->voe->base->SetOnHoldStatus(self->ch, false); 305 | } 306 | else { 307 | int status = My_STRING2ATTR(valuestr, OnHoldModes); 308 | My_ERROR_IF_NEG3(status, valuestr) 309 | er = self->voe->base->SetOnHoldStatus(self->ch, true, (OnHoldModes) status); 310 | } 311 | My_ERROR_IF_NEG(er, self->voe->base) 312 | return 0; 313 | } 314 | 315 | My_PROPERTY_GETTER(WebRtcChannel, NetEQPlayoutMode) 316 | { 317 | My_NULL_IF_NULL(self->voe->base, VoEBase) 318 | My_NULL_IF_NEG2(self->ch) 319 | 320 | NetEqModes status; 321 | int er = self->voe->base->GetNetEQPlayoutMode(self->ch, status); 322 | My_NULL_IF_NEG(er, self->voe->base) 323 | 324 | const char *valuestr = My_ATTR2STRING(status, NetEqModes); 325 | if (valuestr != NULL) { 326 | return Py_BuildValue("s", valuestr); 327 | } 328 | 329 | Py_INCREF(Py_None); 330 | return Py_None; 331 | } 332 | 333 | My_PROPERTY_SETTER(WebRtcChannel, NetEQPlayoutMode) 334 | { 335 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 336 | My_ERROR_IF_NEG2(self->ch) 337 | My_STRING(value, valuestr) 338 | 339 | int status = My_STRING2ATTR(valuestr, NetEqModes); 340 | My_ERROR_IF_NEG3(status, valuestr) 341 | 342 | int er = self->voe->base->SetNetEQPlayoutMode(self->ch, (NetEqModes) status); 343 | My_ERROR_IF_NEG(er, self->voe->base) 344 | 345 | return 0; 346 | } 347 | 348 | My_PROPERTY_GETTER(WebRtcChannel, NetEQBGNMode) 349 | { 350 | My_NULL_IF_NULL(self->voe->base, VoEBase) 351 | My_NULL_IF_NEG2(self->ch) 352 | 353 | NetEqBgnModes status; 354 | int er = self->voe->base->GetNetEQBGNMode(self->ch, status); 355 | My_NULL_IF_NEG(er, self->voe->base) 356 | 357 | const char *valuestr = My_ATTR2STRING(status, NetEqBgnModes); 358 | if (valuestr != NULL) { 359 | return Py_BuildValue("s", valuestr); 360 | } 361 | 362 | Py_INCREF(Py_None); 363 | return Py_None; 364 | } 365 | 366 | My_PROPERTY_SETTER(WebRtcChannel, NetEQBGNMode) 367 | { 368 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 369 | My_ERROR_IF_NEG2(self->ch) 370 | My_STRING(value, valuestr) 371 | 372 | int status = My_STRING2ATTR(valuestr, NetEqBgnModes); 373 | My_ERROR_IF_NEG3(status, valuestr) 374 | 375 | int er = self->voe->base->SetNetEQBGNMode(self->ch, (NetEqBgnModes) status); 376 | My_ERROR_IF_NEG(er, self->voe->base) 377 | 378 | return 0; 379 | } 380 | 381 | -------------------------------------------------------------------------------- /code/src/my_voe_call_report.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | 8 | #include "common_types.h" 9 | 10 | #include "my_macro.h" 11 | #include "my_error.h" 12 | #include "my_common_types.h" 13 | #include "my_voice_engine.h" 14 | #include "my_channel.h" 15 | #include "my_voe_call_report.h" 16 | 17 | using namespace webrtc; 18 | 19 | My_METHOD_ARGS(WebRtcVoiceEngine, WriteReportToFile) 20 | { 21 | My_NULL_IF_NULL(self->base, VoEBase) 22 | My_NULL_IF_NULL(self->call_report, VoECallReport) 23 | 24 | const char* filename = NULL; 25 | if (!PyArg_ParseTuple(args, "s", &filename)) { 26 | return NULL; 27 | } 28 | 29 | int er = self->call_report->WriteReportToFile(filename); 30 | My_NULL_IF_NEG(er, self->base) 31 | 32 | Py_INCREF(Py_None); 33 | return Py_None; 34 | } 35 | 36 | PyObject* stat2object(const StatVal& stat) 37 | { 38 | PyObject* result = PyTuple_New(3); 39 | PyTuple_SetItem(result, 0, PyInt_FromLong(stat.min)); 40 | PyTuple_SetItem(result, 1, PyInt_FromLong(stat.max)); 41 | PyTuple_SetItem(result, 2, PyInt_FromLong(stat.average)); 42 | return result; 43 | } 44 | 45 | My_PROPERTY_GETTER(WebRtcVoiceEngine, SpeechAndNoiseSummary) 46 | { 47 | My_NULL_IF_NULL(self->base, VoEBase) 48 | My_NULL_IF_NULL(self->call_report, VoECallReport) 49 | 50 | LevelStatistics status; 51 | int er = self->call_report->GetSpeechAndNoiseSummary(status); 52 | My_NULL_IF_NEG(er, self->base); 53 | 54 | PyObject* result = PyDict_New(); 55 | PyDict_SetItemString(result, "speech_rx", stat2object(status.speech_rx)); 56 | PyDict_SetItemString(result, "speech_tx", stat2object(status.speech_tx)); 57 | PyDict_SetItemString(result, "noise_rx", stat2object(status.noise_rx)); 58 | PyDict_SetItemString(result, "noise_tx", stat2object(status.noise_tx)); 59 | 60 | return Py_BuildValue("O", result); 61 | } 62 | 63 | My_PROPERTY_GETTER(WebRtcVoiceEngine, EchoMetricSummary) 64 | { 65 | My_NULL_IF_NULL(self->base, VoEBase) 66 | My_NULL_IF_NULL(self->call_report, VoECallReport) 67 | 68 | EchoStatistics status; 69 | int er = self->call_report->GetEchoMetricSummary(status); 70 | My_NULL_IF_NEG(er, self->base); 71 | 72 | 73 | PyObject* result = PyDict_New(); 74 | PyDict_SetItemString(result, "erl", stat2object(status.erl)); 75 | PyDict_SetItemString(result, "erle", stat2object(status.erle)); 76 | PyDict_SetItemString(result, "rerl", stat2object(status.rerl)); 77 | PyDict_SetItemString(result, "a_nlp", stat2object(status.a_nlp)); 78 | 79 | return Py_BuildValue("O", result); 80 | } 81 | 82 | My_METHOD(WebRtcChannel, ResetCallReportStatistics) 83 | { 84 | My_NULL_IF_NULL(self->voe->base, VoEBase) 85 | My_NULL_IF_NULL(self->voe->call_report, VoECallReport) 86 | My_NULL_IF_NEG2(self->ch) 87 | 88 | int er = self->voe->call_report->ResetCallReportStatistics(self->ch); 89 | My_NULL_IF_NEG(er, self->voe->base) 90 | 91 | Py_INCREF(Py_None); 92 | return Py_None; 93 | } 94 | 95 | My_PROPERTY_GETTER(WebRtcChannel, RoundTripTimeSummary) 96 | { 97 | My_NULL_IF_NULL(self->voe->base, VoEBase) 98 | My_NULL_IF_NULL(self->voe->call_report, VoECallReport) 99 | My_NULL_IF_NEG2(self->ch) 100 | 101 | StatVal status; 102 | int er = self->voe->call_report->GetRoundTripTimeSummary(self->ch, status); 103 | My_NULL_IF_NEG(er, self->voe->base) 104 | 105 | return Py_BuildValue("O", stat2object(status)); 106 | } 107 | 108 | My_PROPERTY_GETTER(WebRtcChannel, DeadOrAliveSummary) 109 | { 110 | My_NULL_IF_NULL(self->voe->base, VoEBase) 111 | My_NULL_IF_NULL(self->voe->call_report, VoECallReport) 112 | My_NULL_IF_NEG2(self->ch) 113 | 114 | int numOfDeadDetections, numOfAliveDetections; 115 | int er = self->voe->call_report->GetDeadOrAliveSummary(self->ch, numOfDeadDetections, numOfAliveDetections); 116 | My_NULL_IF_NEG(er, self->voe->base) 117 | 118 | PyObject* result = PyTuple_New(2); 119 | PyTuple_SetItem(result, 0, PyInt_FromLong(numOfDeadDetections)); 120 | PyTuple_SetItem(result, 0, PyInt_FromLong(numOfAliveDetections)); 121 | 122 | return Py_BuildValue("O", result); 123 | } 124 | 125 | 126 | -------------------------------------------------------------------------------- /code/src/my_voe_codec.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | 8 | #include "common_types.h" 9 | 10 | #include "my_macro.h" 11 | #include "my_error.h" 12 | #include "my_common_types.h" 13 | #include "my_channel.h" 14 | #include "my_voe_codec.h" 15 | 16 | using namespace webrtc; 17 | 18 | PyObject* 19 | codec2object(CodecInst& data) 20 | { 21 | PyObject* result = PyDict_New(); 22 | PyDict_SetItemString(result, "type", PyInt_FromLong(data.pltype)); 23 | PyDict_SetItemString(result, "name", PyString_FromString(data.plname)); 24 | PyDict_SetItemString(result, "frequency", PyInt_FromLong(data.plfreq)); 25 | PyDict_SetItemString(result, "size", PyInt_FromLong(data.pacsize)); 26 | PyDict_SetItemString(result, "channels", PyInt_FromLong(data.channels)); 27 | PyDict_SetItemString(result, "rate", PyInt_FromLong(data.rate)); 28 | return result; 29 | } 30 | 31 | int 32 | object2codec(PyObject* object, CodecInst&data) 33 | { 34 | if (!PyDict_Check(object)) { 35 | PyErr_SetString(WebRtcError, "must be dict with keys type:int, name:str, frequency:int, size:int, channels:int, rate:int"); 36 | return -1; 37 | } 38 | PyObject* type_o = PyDict_GetItemString(object, "type"); 39 | PyObject* name_o = PyDict_GetItemString(object, "name"); 40 | PyObject* frequency_o = PyDict_GetItemString(object, "frequency"); 41 | PyObject* size_o = PyDict_GetItemString(object, "size"); 42 | PyObject* channels_o = PyDict_GetItemString(object, "channels"); 43 | PyObject* rate_o = PyDict_GetItemString(object, "rate"); 44 | if (!PyInt_Check(type_o) || !PyString_Check(name_o) || !PyInt_Check(frequency_o) || !PyInt_Check(size_o) || !PyInt_Check(channels_o) || !PyInt_Check(rate_o)) { 45 | PyErr_SetString(WebRtcError, "must be dict with keys type:int, name:str, frequency:int, size:int, channels:int, rate:int"); 46 | return -1; 47 | 48 | } 49 | 50 | data.pltype = PyInt_AsLong(type_o); 51 | const char* name = PyString_AsString(name_o); 52 | strncpy(data.plname, name, sizeof(data.plname)); 53 | data.plfreq = PyInt_AsLong(frequency_o); 54 | data.pacsize = PyInt_AsLong(size_o); 55 | data.channels = PyInt_AsLong(channels_o); 56 | data.rate = PyInt_AsLong(rate_o); 57 | 58 | return 0; 59 | } 60 | 61 | My_PROPERTY_GETTER(WebRtcVoiceEngine, NumOfCodecs) 62 | { 63 | My_NULL_IF_NULL(self->base, VoEBase) 64 | My_NULL_IF_NULL(self->codec, VoECodec) 65 | 66 | int count = self->codec->NumOfCodecs(); 67 | My_NULL_IF_NEG(count, self->base); 68 | 69 | return PyInt_FromLong(count); 70 | } 71 | 72 | My_PROPERTY_GETTER(WebRtcVoiceEngine, Codecs) 73 | { 74 | My_NULL_IF_NULL(self->base, VoEBase) 75 | My_NULL_IF_NULL(self->codec, VoECodec) 76 | 77 | int count = self->codec->NumOfCodecs(); 78 | My_NULL_IF_NEG(count, self->base); 79 | 80 | PyObject *result = PyList_New(count); 81 | for (unsigned i=0; icodec->GetCodec(i, codec); 84 | My_NULL_IF_NEG(er, self->base); 85 | PyObject *codec_o = codec2object(codec); 86 | PyList_SetItem(result, i, codec_o); 87 | } 88 | return Py_BuildValue("N", result); 89 | } 90 | 91 | 92 | My_PROPERTY_GETTER(WebRtcChannel, SendCodec) 93 | { 94 | My_NULL_IF_NULL(self->voe->base, VoEBase) 95 | My_NULL_IF_NULL(self->voe->codec, VoECodec) 96 | My_NULL_IF_NEG2(self->ch) 97 | 98 | CodecInst codec; 99 | int er = self->voe->codec->GetSendCodec(self->ch, codec); 100 | My_NULL_IF_NEG(er, self->voe->base); 101 | 102 | PyObject* result = codec2object(codec); 103 | return result; 104 | } 105 | 106 | My_PROPERTY_SETTER(WebRtcChannel, SendCodec) 107 | { 108 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 109 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 110 | My_ERROR_IF_NEG2(self->ch) 111 | 112 | CodecInst codec; 113 | int er = object2codec(value, codec); 114 | if (er < 0) { 115 | return NULL; 116 | } 117 | 118 | er = self->voe->codec->SetSendCodec(self->ch, codec); 119 | My_ERROR_IF_NEG(er, self->voe->base) 120 | 121 | return 0; 122 | } 123 | 124 | My_PROPERTY_GETTER(WebRtcChannel, RecCodec) 125 | { 126 | My_NULL_IF_NULL(self->voe->base, VoEBase) 127 | My_NULL_IF_NULL(self->voe->codec, VoECodec) 128 | My_NULL_IF_NEG2(self->ch) 129 | 130 | CodecInst codec; 131 | int er = self->voe->codec->GetRecCodec(self->ch, codec); 132 | if (er < 0) { 133 | Py_INCREF(Py_None); 134 | return Py_None; 135 | } 136 | //My_NULL_IF_NEG(er, self->voe->base); 137 | 138 | PyObject* result = codec2object(codec); 139 | return result; 140 | } 141 | 142 | My_PROPERTY_SETTER(WebRtcChannel, ISACInitTargetRate) 143 | { 144 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 145 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 146 | My_ERROR_IF_NEG2(self->ch) 147 | My_INT(value, valueint) 148 | 149 | int er = self->voe->codec->SetISACInitTargetRate(self->ch, valueint); 150 | My_ERROR_IF_NEG(er, self->voe->base) 151 | 152 | return 0; 153 | } 154 | 155 | My_PROPERTY_SETTER(WebRtcChannel, ISACMaxRate) 156 | { 157 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 158 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 159 | My_ERROR_IF_NEG2(self->ch) 160 | My_INT(value, valueint) 161 | 162 | int er = self->voe->codec->SetISACMaxRate(self->ch, valueint); 163 | My_ERROR_IF_NEG(er, self->voe->base) 164 | 165 | return 0; 166 | } 167 | 168 | My_PROPERTY_SETTER(WebRtcChannel, ISACMaxPayloadSize) 169 | { 170 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 171 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 172 | My_ERROR_IF_NEG2(self->ch) 173 | My_INT(value, valueint) 174 | 175 | int er = self->voe->codec->SetISACMaxPayloadSize(self->ch, valueint); 176 | My_ERROR_IF_NEG(er, self->voe->base) 177 | 178 | return 0; 179 | } 180 | 181 | My_PROPERTY_GETTER(WebRtcChannel, RecPayloadType) 182 | { 183 | My_NULL_IF_NULL(self->voe->base, VoEBase) 184 | My_NULL_IF_NULL(self->voe->codec, VoECodec) 185 | My_NULL_IF_NEG2(self->ch) 186 | 187 | CodecInst codec; 188 | int er = self->voe->codec->GetRecPayloadType(self->ch, codec); 189 | My_NULL_IF_NEG(er, self->voe->base); 190 | 191 | PyObject* result = codec2object(codec); 192 | return result; 193 | } 194 | 195 | My_PROPERTY_SETTER(WebRtcChannel, RecPayloadType) 196 | { 197 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 198 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 199 | My_ERROR_IF_NEG2(self->ch) 200 | 201 | CodecInst codec; 202 | int er = object2codec(value, codec); 203 | if (er < 0) { 204 | return NULL; 205 | } 206 | 207 | er = self->voe->codec->SetRecPayloadType(self->ch, codec); 208 | My_ERROR_IF_NEG(er, self->voe->base) 209 | 210 | return 0; 211 | } 212 | 213 | My_PROPERTY_SETTER(WebRtcChannel, SendCNPayloadType) 214 | { 215 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 216 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 217 | My_ERROR_IF_NEG2(self->ch) 218 | 219 | if (!PyTuple_Check(value) || PyTuple_Size(value) != 2) { 220 | PyErr_SetString(WebRtcError, "must be a tuple (type:int, frequency:int)"); 221 | return -1; 222 | } 223 | 224 | PyObject *type_o = PyTuple_GetItem(value, 0); 225 | PyObject *frequency_o = PyTuple_GetItem(value, 1); 226 | if (!PyInt_Check(type_o) || !PyInt_Check(frequency_o)) { 227 | PyErr_SetString(WebRtcError, "must be a tuple (type:int, frequency:int)"); 228 | return -1; 229 | } 230 | 231 | int type = PyInt_AsLong(type_o); 232 | int frequency = PyInt_AsLong(frequency_o); 233 | if (frequency == 0) { 234 | frequency = kFreq16000Hz; 235 | } 236 | 237 | int er = self->voe->codec->SetSendCNPayloadType(self->ch, type, (PayloadFrequencies) frequency); 238 | My_ERROR_IF_NEG(er, self->voe->base) 239 | return 0; 240 | } 241 | 242 | 243 | My_PROPERTY_GETTER(WebRtcChannel, VADStatus) 244 | { 245 | My_NULL_IF_NULL(self->voe->base, VoEBase) 246 | My_NULL_IF_NULL(self->voe->codec, VoECodec) 247 | My_NULL_IF_NEG2(self->ch) 248 | 249 | bool enabled; 250 | VadModes mode; 251 | bool disable_dtx; 252 | int er = self->voe->codec->GetVADStatus(self->ch, enabled, mode, disable_dtx); 253 | My_NULL_IF_NEG(er, self->voe->base); 254 | 255 | if (enabled) { 256 | const char* valuestr = My_ATTR2STRING(mode, VadModes); 257 | if (valuestr != NULL) { 258 | PyObject *result = PyTuple_New(2); 259 | PyTuple_SetItem(result, 0, PyString_FromString(valuestr)); 260 | PyTuple_SetItem(result, 1, PyBool_FromLong(disable_dtx)); 261 | return Py_BuildValue("N", result); 262 | } 263 | } 264 | 265 | Py_INCREF(Py_None); 266 | return Py_None; 267 | } 268 | 269 | My_PROPERTY_SETTER(WebRtcChannel, VADStatus) 270 | { 271 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 272 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 273 | My_ERROR_IF_NEG2(self->ch) 274 | 275 | int er; 276 | if (value == Py_None || value == Py_False) { 277 | er = self->voe->codec->SetVADStatus(self->ch, false); 278 | } 279 | else if (value == Py_True) { 280 | er = self->voe->codec->SetVADStatus(self->ch, true); 281 | } 282 | else if (PyTuple_Check(value) && PyTuple_Size(value) == 2) { 283 | PyObject *mode_o = PyTuple_GetItem(value, 0); 284 | PyObject *disable_dtx_o = PyTuple_GetItem(value, 1); 285 | if (!PyString_Check(mode_o) || !PyBool_Check(disable_dtx_o)) { 286 | PyErr_SetString(WebRtcError, "must be None or tuple (mode:str, disable_dtx:bool)"); 287 | return -1; 288 | } 289 | 290 | const char* modestr = PyString_AsString(mode_o); 291 | int mode = My_STRING2ATTR(modestr, VadModes); 292 | My_ERROR_IF_NEG3(mode, modestr) 293 | bool disable_dtx = (disable_dtx_o == Py_True); 294 | er = self->voe->codec->SetVADStatus(self->ch, true, (VadModes) mode, disable_dtx); 295 | } 296 | else { 297 | PyErr_SetString(WebRtcError, "must be None or tuple (mode:str, disable_dtx:bool)"); 298 | return -1; 299 | } 300 | 301 | My_ERROR_IF_NEG(er, self->voe->base) 302 | return 0; 303 | } 304 | 305 | My_PROPERTY_SETTER(WebRtcChannel, AMREncFormat) 306 | { 307 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 308 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 309 | My_ERROR_IF_NEG2(self->ch) 310 | My_STRING(value, valuestr) 311 | 312 | int valueint = My_STRING2ATTR(valuestr, AmrMode); 313 | My_ERROR_IF_NEG3(valueint, valuestr); 314 | 315 | int er = self->voe->codec->SetAMREncFormat(self->ch, (AmrMode) valueint); 316 | My_ERROR_IF_NEG(er, self->voe->base) 317 | 318 | return 0; 319 | } 320 | 321 | My_PROPERTY_SETTER(WebRtcChannel, AMRDecFormat) 322 | { 323 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 324 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 325 | My_ERROR_IF_NEG2(self->ch) 326 | My_STRING(value, valuestr) 327 | 328 | int valueint = My_STRING2ATTR(valuestr, AmrMode); 329 | My_ERROR_IF_NEG3(valueint, valuestr); 330 | 331 | int er = self->voe->codec->SetAMRDecFormat(self->ch, (AmrMode) valueint); 332 | My_ERROR_IF_NEG(er, self->voe->base) 333 | 334 | return 0; 335 | } 336 | 337 | My_PROPERTY_SETTER(WebRtcChannel, AMRWbEncFormat) 338 | { 339 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 340 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 341 | My_ERROR_IF_NEG2(self->ch) 342 | My_STRING(value, valuestr) 343 | 344 | int valueint = My_STRING2ATTR(valuestr, AmrMode); 345 | My_ERROR_IF_NEG3(valueint, valuestr); 346 | 347 | int er = self->voe->codec->SetAMRWbEncFormat(self->ch, (AmrMode) valueint); 348 | My_ERROR_IF_NEG(er, self->voe->base) 349 | 350 | return 0; 351 | } 352 | 353 | My_PROPERTY_SETTER(WebRtcChannel, AMRWbDecFormat) 354 | { 355 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 356 | My_ERROR_IF_NULL(self->voe->codec, VoECodec) 357 | My_ERROR_IF_NEG2(self->ch) 358 | My_STRING(value, valuestr) 359 | 360 | int valueint = My_STRING2ATTR(valuestr, AmrMode); 361 | My_ERROR_IF_NEG3(valueint, valuestr); 362 | 363 | int er = self->voe->codec->SetAMRWbDecFormat(self->ch, (AmrMode) valueint); 364 | My_ERROR_IF_NEG(er, self->voe->base) 365 | 366 | return 0; 367 | } 368 | 369 | -------------------------------------------------------------------------------- /code/src/my_voe_dtmf.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | 8 | #include "common_types.h" 9 | 10 | #include "my_macro.h" 11 | #include "my_error.h" 12 | #include "my_common_types.h" 13 | #include "my_voice_engine.h" 14 | #include "my_channel.h" 15 | #include "my_voe_dtmf.h" 16 | 17 | using namespace webrtc; 18 | 19 | 20 | class TelephoneEventCallback: public VoETelephoneEventObserver { 21 | public: 22 | TelephoneEventCallback(PyObject* callback, PyObject* userdata); 23 | ~TelephoneEventCallback(); 24 | void OnReceivedTelephoneEventInband(const int channel, const unsigned char eventCode, const bool endOfEvent); 25 | void OnReceivedTelephoneEventOutOfBand(const int channel, const unsigned char eventCode, const bool endOfEvent); 26 | 27 | private: 28 | PyObject *callback; 29 | PyObject *userdata; 30 | }; 31 | 32 | TelephoneEventCallback::TelephoneEventCallback(PyObject* callback, PyObject* userdata) { 33 | Py_XINCREF(callback); 34 | this->callback = callback; 35 | Py_XINCREF(userdata); 36 | this->userdata = userdata; 37 | } 38 | 39 | TelephoneEventCallback::~TelephoneEventCallback() { 40 | Py_XDECREF(this->callback); 41 | Py_XDECREF(this->userdata); 42 | } 43 | 44 | void TelephoneEventCallback::OnReceivedTelephoneEventInband(const int channel, const unsigned char eventCode, const bool endOfEvent) 45 | { 46 | if (this->callback != NULL) { 47 | PyObject* arglist = Py_BuildValue("(OicOO)", this->userdata, channel, eventCode, PyBool_FromLong(endOfEvent), PyBool_FromLong(true)); 48 | PyObject* output = PyObject_CallObject(this->callback, arglist); 49 | Py_DECREF(arglist); 50 | } 51 | } 52 | 53 | void TelephoneEventCallback::OnReceivedTelephoneEventOutOfBand(const int channel, const unsigned char eventCode, const bool endOfEvent) 54 | { 55 | if (this->callback != NULL) { 56 | PyObject* arglist = Py_BuildValue("(OicOO)", this->userdata, channel, eventCode, PyBool_FromLong(endOfEvent), PyBool_FromLong(false)); 57 | PyObject* output = PyObject_CallObject(this->callback, arglist); 58 | Py_DECREF(arglist); 59 | } 60 | } 61 | 62 | 63 | 64 | My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, PlayDtmfTone) 65 | { 66 | My_NULL_IF_NULL(self->base, VoEBase) 67 | My_NULL_IF_NULL(self->dtmf, VoEDtmf) 68 | 69 | unsigned char eventCode; 70 | int lengthMs = 200; 71 | int attenuationDb = 10; 72 | static char *kwlist[] = {"event_code", "length_ms", "attenuation_db", NULL}; 73 | 74 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "c|ii", kwlist, &eventCode, &lengthMs, &attenuationDb)) { 75 | return NULL; 76 | } 77 | 78 | int er = self->dtmf->PlayDtmfTone(eventCode, lengthMs, attenuationDb); 79 | My_NULL_IF_NEG(er, self->base) 80 | 81 | Py_INCREF(Py_None); 82 | return Py_None; 83 | } 84 | 85 | My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, StartPlayingDtmfTone) 86 | { 87 | My_NULL_IF_NULL(self->base, VoEBase) 88 | My_NULL_IF_NULL(self->dtmf, VoEDtmf) 89 | 90 | unsigned char eventCode; 91 | int attenuationDb = 10; 92 | static char *kwlist[] = {"event_code", "attenuation_db", NULL}; 93 | 94 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "c|i", kwlist, &eventCode, &attenuationDb)) { 95 | return NULL; 96 | } 97 | 98 | int er = self->dtmf->StartPlayingDtmfTone(eventCode, attenuationDb); 99 | My_NULL_IF_NEG(er, self->base) 100 | 101 | Py_INCREF(Py_None); 102 | return Py_None; 103 | } 104 | 105 | My_METHOD(WebRtcVoiceEngine, StopPlayingDtmfTone) 106 | { 107 | My_NULL_IF_NULL(self->base, VoEBase) 108 | My_NULL_IF_NULL(self->dtmf, VoEDtmf) 109 | 110 | int er = self->dtmf->StopPlayingDtmfTone(); 111 | My_NULL_IF_NEG(er, self->base) 112 | 113 | Py_INCREF(Py_None); 114 | return Py_None; 115 | } 116 | 117 | My_PROPERTY_GETTER(WebRtcVoiceEngine, DtmfFeedbackStatus) 118 | { 119 | My_NULL_IF_NULL(self->base, VoEBase) 120 | My_NULL_IF_NULL(self->dtmf, VoEDtmf) 121 | 122 | bool enable, directFeedback; 123 | int er = self->dtmf->GetDtmfFeedbackStatus(enable, directFeedback); 124 | My_NULL_IF_NEG(er, self->base) 125 | 126 | return Py_BuildValue("O", PyBool_FromLong(enable)); 127 | } 128 | 129 | My_PROPERTY_SETTER(WebRtcVoiceEngine, DtmfFeedbackStatus) 130 | { 131 | My_ERROR_IF_NULL(self->base, VoEBase) 132 | My_ERROR_IF_NULL(self->dtmf, VoEDtmf) 133 | 134 | if (!PyBool_Check(value)) { 135 | PyErr_SetString(WebRtcError, "must be a bool"); 136 | return -1; 137 | } 138 | 139 | bool enable = (value == Py_True); 140 | int er = self->dtmf->SetDtmfFeedbackStatus(enable); 141 | My_ERROR_IF_NEG(er, self->base) 142 | 143 | return 0; 144 | } 145 | 146 | My_METHOD_ARGS_KWARGS(WebRtcChannel, SendTelephoneEvent) 147 | { 148 | My_NULL_IF_NULL(self->voe->base, VoEBase) 149 | My_NULL_IF_NULL(self->voe->dtmf, VoEDtmf) 150 | My_NULL_IF_NEG2(self->ch) 151 | 152 | unsigned char eventCode; 153 | bool outOfBand = true; 154 | int lengthMs = 160; 155 | int attenuationDb = 10; 156 | static char *kwlist[] = {"event_code", "out_of_band", "length_ms", "attenuation_db", NULL}; 157 | 158 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "c|iii", kwlist, &eventCode, &outOfBand, &lengthMs, &attenuationDb)) { 159 | return NULL; 160 | } 161 | 162 | int er = self->voe->dtmf->SendTelephoneEvent(self->ch, eventCode, outOfBand, lengthMs, attenuationDb); 163 | My_NULL_IF_NEG(er, self->voe->base) 164 | 165 | Py_INCREF(Py_None); 166 | return Py_None; 167 | } 168 | 169 | My_METHOD_ARGS_KWARGS(WebRtcChannel, RegisterTelephoneEventDetection) 170 | { 171 | My_NULL_IF_NULL(self->voe->base, VoEBase) 172 | My_NULL_IF_NULL(self->voe->dtmf, VoEDtmf) 173 | My_NULL_IF_NEG2(self->ch) 174 | 175 | PyObject* callback = NULL; 176 | PyObject* userdata = Py_None; 177 | const char* detection_method_str = NULL; 178 | static char *kwlist[] = {"callback", "detection_method", "userdata", NULL}; 179 | 180 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|O", kwlist, &callback, &detection_method_str, &userdata)) { 181 | return NULL; 182 | } 183 | 184 | if (callback != Py_None && !PyCallable_Check(callback)) { 185 | PyErr_SetString(WebRtcError, "callback must be callable or None"); 186 | return NULL; 187 | } 188 | 189 | int detection_method = My_STRING2ATTR(detection_method_str, TelephoneEventDetectionMethods); 190 | My_NULL_IF_NEG3(detection_method, detection_method_str) 191 | 192 | if (self->telephone_event_callback != NULL) { 193 | delete self->telephone_event_callback; 194 | self->telephone_event_callback = NULL; 195 | } 196 | 197 | if (callback != Py_None) { 198 | self->telephone_event_callback = new TelephoneEventCallback(callback, userdata); 199 | self->voe->dtmf->RegisterTelephoneEventDetection(self->ch, 200 | (TelephoneEventDetectionMethods) detection_method, *self->telephone_event_callback); 201 | } 202 | else { 203 | self->voe->dtmf->DeRegisterTelephoneEventDetection(self->ch); 204 | } 205 | 206 | 207 | Py_INCREF(Py_None); 208 | return Py_None; 209 | } 210 | 211 | My_PROPERTY_GETTER(WebRtcChannel, SendTelephoneEventPayloadType) 212 | { 213 | My_NULL_IF_NULL(self->voe->base, VoEBase) 214 | My_NULL_IF_NULL(self->voe->dtmf, VoEDtmf) 215 | My_NULL_IF_NEG2(self->ch) 216 | 217 | unsigned char status; 218 | int er = self->voe->dtmf->GetSendTelephoneEventPayloadType(self->ch, status); 219 | My_NULL_IF_NEG(er, self->voe->base) 220 | 221 | return Py_BuildValue("i", (int) status); 222 | } 223 | 224 | My_PROPERTY_SETTER(WebRtcChannel, SendTelephoneEventPayloadType) 225 | { 226 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 227 | My_ERROR_IF_NULL(self->voe->dtmf, VoEDtmf) 228 | My_ERROR_IF_NEG2(self->ch) 229 | My_INT(value, valueint) 230 | 231 | int er = self->voe->dtmf->SetSendTelephoneEventPayloadType(self->ch, (unsigned char) valueint); 232 | My_ERROR_IF_NEG(er, self->voe->base) 233 | 234 | return 0; 235 | } 236 | 237 | My_PROPERTY_GETTER(WebRtcChannel, DtmfPlayoutStatus) 238 | { 239 | My_NULL_IF_NULL(self->voe->base, VoEBase) 240 | My_NULL_IF_NULL(self->voe->dtmf, VoEDtmf) 241 | My_NULL_IF_NEG2(self->ch) 242 | 243 | bool status; 244 | int er = self->voe->dtmf->GetDtmfPlayoutStatus(self->ch, status); 245 | My_NULL_IF_NEG(er, self->voe->base) 246 | 247 | return PyBool_FromLong(status); 248 | } 249 | 250 | My_PROPERTY_SETTER(WebRtcChannel, DtmfPlayoutStatus) 251 | { 252 | My_ERROR_IF_NULL(self->voe->base, VoEBase) 253 | My_ERROR_IF_NULL(self->voe->dtmf, VoEDtmf) 254 | My_ERROR_IF_NEG2(self->ch) 255 | 256 | if (!PyBool_Check(value)) { 257 | PyErr_SetString(WebRtcError, "must be a bool"); 258 | return -1; 259 | } 260 | 261 | bool valuebool = (value == Py_True); 262 | int er = self->voe->dtmf->SetDtmfPlayoutStatus(self->ch, valuebool); 263 | My_ERROR_IF_NEG(er, self->voe->base) 264 | 265 | return 0; 266 | } 267 | 268 | My_PROPERTY_GETTER(WebRtcChannel, TelephoneEventDetectionStatus) 269 | { 270 | My_NULL_IF_NULL(self->voe->base, VoEBase) 271 | My_NULL_IF_NULL(self->voe->dtmf, VoEDtmf) 272 | My_NULL_IF_NEG2(self->ch) 273 | 274 | bool enabled; 275 | TelephoneEventDetectionMethods detectionMethod; 276 | int er = self->voe->dtmf->GetTelephoneEventDetectionStatus(self->ch, enabled, detectionMethod); 277 | My_NULL_IF_NEG(er, self->voe->base) 278 | 279 | if (enabled) { 280 | const char* valuestr = My_ATTR2STRING(detectionMethod, TelephoneEventDetectionMethods); 281 | return Py_BuildValue("s", valuestr); 282 | } 283 | 284 | Py_INCREF(Py_None); 285 | return Py_None; 286 | } 287 | -------------------------------------------------------------------------------- /code/src/my_voe_encryption.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | 8 | #include "common_types.h" 9 | 10 | #include "my_macro.h" 11 | #include "my_error.h" 12 | #include "my_common_types.h" 13 | #include "my_voice_engine.h" 14 | #include "my_channel.h" 15 | #include "my_voe_encryption.h" 16 | 17 | using namespace webrtc; 18 | 19 | 20 | class EncryptionCallback: public Encryption { 21 | public: 22 | EncryptionCallback(PyObject* encrypt_o, PyObject* decrypt_o, PyObject* encrypt_rtcp_o, PyObject* decrypt_rtcp_o, PyObject* userdata); 23 | ~EncryptionCallback(); 24 | void encrypt(int channel_no, unsigned char* in_data, unsigned char* out_data, int bytes_in, int* bytes_out); 25 | void decrypt(int channel_no, unsigned char* in_data, unsigned char* out_data, int bytes_in, int* bytes_out); 26 | void encrypt_rtcp(int channel_no, unsigned char* in_data, unsigned char* out_data, int bytes_in, int* bytes_out); 27 | void decrypt_rtcp(int channel_no, unsigned char* in_data, unsigned char* out_data, int bytes_in, int* bytes_out); 28 | 29 | private: 30 | PyObject *encrypt_o; 31 | PyObject *decrypt_o; 32 | PyObject *encrypt_rtcp_o; 33 | PyObject *decrypt_rtcp_o; 34 | PyObject *userdata; 35 | }; 36 | 37 | EncryptionCallback::EncryptionCallback(PyObject* encrypt_o, PyObject* decrypt_o, PyObject* encrypt_rtcp_o, PyObject* decrypt_rtcp_o, PyObject* userdata) 38 | { 39 | Py_XINCREF(encrypt_o); 40 | this->encrypt_o = encrypt_o; 41 | Py_XINCREF(decrypt_o); 42 | this->decrypt_o = decrypt_o; 43 | Py_XINCREF(encrypt_rtcp_o); 44 | this->encrypt_rtcp_o = encrypt_rtcp_o; 45 | Py_XINCREF(decrypt_rtcp_o); 46 | this->decrypt_rtcp_o = decrypt_rtcp_o; 47 | Py_XINCREF(userdata); 48 | this->userdata = userdata; 49 | } 50 | 51 | EncryptionCallback::~EncryptionCallback() { 52 | Py_XDECREF(this->encrypt_o); 53 | Py_XDECREF(this->decrypt_o); 54 | Py_XDECREF(this->encrypt_rtcp_o); 55 | Py_XDECREF(this->decrypt_rtcp_o); 56 | Py_XDECREF(this->userdata); 57 | } 58 | 59 | #define DEFINE_ENCRYPTION_METHOD(name) \ 60 | void EncryptionCallback::name(int channel, unsigned char* in_data, unsigned char* out_data, int bytes_in, int* bytes_out) \ 61 | { \ 62 | if (this->name##_o != NULL) { \ 63 | PyObject* input = PyString_FromStringAndSize((const char*) in_data, bytes_in); \ 64 | PyObject* arglist = Py_BuildValue("(OiO)", this->userdata, channel, input); \ 65 | PyObject* output = PyObject_CallObject(this->name##_o, arglist); \ 66 | Py_DECREF(arglist); \ 67 | if (PyString_Check(output)) { \ 68 | *bytes_out = PyString_Size(output); \ 69 | memcpy(out_data, PyString_AsString(output), *bytes_out); \ 70 | } \ 71 | } \ 72 | } 73 | 74 | DEFINE_ENCRYPTION_METHOD(encrypt) 75 | DEFINE_ENCRYPTION_METHOD(decrypt) 76 | DEFINE_ENCRYPTION_METHOD(encrypt_rtcp) 77 | DEFINE_ENCRYPTION_METHOD(decrypt_rtcp) 78 | 79 | 80 | 81 | My_METHOD_ARGS_KWARGS(WebRtcChannel, RegisterExternalEncryption) 82 | { 83 | My_NULL_IF_NULL(self->voe->base, VoEBase) 84 | My_NULL_IF_NULL(self->voe->encryption, VoEEncryption) 85 | My_NULL_IF_NEG2(self->ch) 86 | 87 | PyObject* encrypt_o = NULL; 88 | PyObject* decrypt_o = NULL; 89 | PyObject* encrypt_rtcp_o = NULL; 90 | PyObject* decrypt_rtcp_o = NULL; 91 | PyObject* userdata = Py_None; 92 | static char *kwlist[] = {"encrypt", "decrypt", "encrypt_rtcp", "decrypt_rtcp", "userdata", NULL}; 93 | 94 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OOOO|O", kwlist, &encrypt_o, &decrypt_o, &encrypt_rtcp_o, &decrypt_rtcp_o, &userdata)) { 95 | return NULL; 96 | } 97 | 98 | if (encrypt_o != Py_None && !PyCallable_Check(encrypt_o)) { 99 | PyErr_SetString(WebRtcError, "encrypt must be callable or None"); 100 | return NULL; 101 | } 102 | if (decrypt_o != Py_None && !PyCallable_Check(decrypt_o)) { 103 | PyErr_SetString(WebRtcError, "decrypt must be callable or None"); 104 | return NULL; 105 | } 106 | if (encrypt_rtcp_o != Py_None && !PyCallable_Check(encrypt_rtcp_o)) { 107 | PyErr_SetString(WebRtcError, "encrypt_rtcp must be callable or None"); 108 | return NULL; 109 | } 110 | if (decrypt_rtcp_o != Py_None && !PyCallable_Check(decrypt_rtcp_o)) { 111 | PyErr_SetString(WebRtcError, "decrypt_rtcp must be callable or None"); 112 | return NULL; 113 | } 114 | 115 | if (self->encryption_callback != NULL) { 116 | delete self->encryption_callback; 117 | self->encryption_callback = NULL; 118 | } 119 | 120 | if (encrypt_o != Py_None && decrypt_o != Py_None && encrypt_rtcp_o != Py_None && decrypt_rtcp_o != Py_None) { 121 | self->encryption_callback = new EncryptionCallback(encrypt_o, decrypt_o, encrypt_rtcp_o, decrypt_rtcp_o, userdata); 122 | self->voe->encryption->RegisterExternalEncryption(self->ch, *self->encryption_callback); 123 | } 124 | else { 125 | self->voe->encryption->DeRegisterExternalEncryption(self->ch); 126 | } 127 | 128 | Py_INCREF(Py_None); 129 | return Py_None; 130 | } 131 | 132 | -------------------------------------------------------------------------------- /code/src/my_voe_external_media.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | 8 | #include "common_types.h" 9 | 10 | #include "my_macro.h" 11 | #include "my_error.h" 12 | #include "my_common_types.h" 13 | #include "my_voice_engine.h" 14 | #include "my_channel.h" 15 | #include "my_voe_external_media.h" 16 | 17 | using namespace webrtc; 18 | 19 | 20 | class MediaProcessCallback: public VoEMediaProcess { 21 | public: 22 | MediaProcessCallback(PyObject* callback, PyObject* userdata); 23 | ~MediaProcessCallback(); 24 | void Process(const int channel, const ProcessingTypes type, WebRtc_Word16 audio10ms[], const int length, const int samplingFreq, const bool isStereo); 25 | 26 | private: 27 | PyObject *callback; 28 | PyObject *userdata; 29 | }; 30 | 31 | MediaProcessCallback::MediaProcessCallback(PyObject* callback, PyObject* userdata) 32 | { 33 | Py_XINCREF(callback); 34 | this->callback = callback; 35 | Py_XINCREF(userdata); 36 | this->userdata = userdata; 37 | } 38 | 39 | MediaProcessCallback::~MediaProcessCallback() { 40 | Py_XDECREF(this->callback); 41 | Py_XDECREF(this->userdata); 42 | } 43 | 44 | void MediaProcessCallback::Process(const int channel, const ProcessingTypes type, WebRtc_Word16 audio10ms[], const int length, const int samplingFreq, const bool isStereo) 45 | { 46 | if (this->callback != NULL) { 47 | PyObject* input = PyString_FromStringAndSize((const char*) audio10ms, length*2); 48 | PyObject* arglist = Py_BuildValue("(OiOiO)", this->userdata, channel, input, samplingFreq, PyBool_FromLong(isStereo)); 49 | PyObject* output = PyObject_CallObject(this->callback, arglist); 50 | Py_DECREF(arglist); 51 | if (PyString_Check(output)) { 52 | memcpy(audio10ms, PyString_AsString(output), length*2); 53 | } 54 | Py_DECREF(output); 55 | } 56 | } 57 | 58 | 59 | My_METHOD_ARGS_KWARGS(WebRtcChannel, RegisterExternalMediaProcessing) 60 | { 61 | My_NULL_IF_NULL(self->voe->base, VoEBase) 62 | My_NULL_IF_NULL(self->voe->encryption, VoEEncryption) 63 | My_NULL_IF_NEG2(self->ch) 64 | 65 | PyObject* callback = NULL; 66 | const char* typestr = NULL; 67 | PyObject* userdata = Py_None; 68 | static char *kwlist[] = {"type", "callback", "userdata", NULL}; 69 | 70 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O", kwlist, &typestr, &callback, &userdata)) { 71 | return NULL; 72 | } 73 | 74 | if (callback != Py_None && !PyCallable_Check(callback)) { 75 | PyErr_SetString(WebRtcError, "callback must be callable or None"); 76 | return NULL; 77 | } 78 | 79 | int type = My_STRING2ATTR(typestr, ProcessingTypes); 80 | My_NULL_IF_NEG3(type, typestr) 81 | 82 | if (self->media_process_callback != NULL) { 83 | delete self->media_process_callback; 84 | self->media_process_callback = NULL; 85 | } 86 | 87 | if (callback != Py_None) { 88 | self->media_process_callback = new MediaProcessCallback(callback, userdata); 89 | self->voe->external_media->RegisterExternalMediaProcessing(self->ch, (ProcessingTypes) type, *self->media_process_callback); 90 | } 91 | else { 92 | self->voe->external_media->DeRegisterExternalMediaProcessing(self->ch, (ProcessingTypes) type); 93 | } 94 | 95 | Py_INCREF(Py_None); 96 | return Py_None; 97 | } 98 | 99 | 100 | 101 | My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, ExternalRecordingInsertData) 102 | { 103 | My_NULL_IF_NULL(self->base, VoEBase) 104 | My_NULL_IF_NULL(self->external_media, VoEExternalMedia) 105 | 106 | PyObject* speech_data_o = NULL; 107 | int sampling_frequency = -1; 108 | int current_delay_ms = -1; 109 | static char *kwlist[] = {"speech_data_10ms", "sampling_frequency", "current_delay_ms", NULL}; 110 | 111 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oii", kwlist, &speech_data_o, &sampling_frequency, ¤t_delay_ms)) { 112 | return NULL; 113 | } 114 | if (!PyString_Check(speech_data_o)) { 115 | PyErr_SetString(WebRtcError, "speech_data_10ms must be a string"); 116 | return NULL; 117 | } 118 | 119 | const char* speech_data = PyString_AsString(speech_data_o); 120 | int length_samples = PyString_Size(speech_data_o) / 2; // assuming 16 bit samples 121 | 122 | int er = self->external_media->ExternalRecordingInsertData((const WebRtc_Word16*) speech_data, length_samples, sampling_frequency, current_delay_ms); 123 | My_NULL_IF_NEG(er, self->base) 124 | 125 | Py_INCREF(Py_None); 126 | return Py_None; 127 | } 128 | 129 | My_METHOD_ARGS_KWARGS(WebRtcVoiceEngine, ExternalPlayoutGetData) 130 | { 131 | My_NULL_IF_NULL(self->base, VoEBase) 132 | My_NULL_IF_NULL(self->external_media, VoEExternalMedia) 133 | 134 | int sampling_frequency = -1; 135 | int current_delay_ms = -1; 136 | static char *kwlist[] = {"sampling_frequency", "current_delay_ms", NULL}; 137 | 138 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii", kwlist, &sampling_frequency, ¤t_delay_ms)) { 139 | return NULL; 140 | } 141 | 142 | WebRtc_Word16 speech_data[480]; 143 | int length_samples = 0; 144 | 145 | int er = self->external_media->ExternalRecordingInsertData((const WebRtc_Word16*) speech_data, sampling_frequency, current_delay_ms, length_samples); 146 | My_NULL_IF_NEG(er, self->base) 147 | 148 | if (length_samples > 0) { 149 | PyObject* speech_data_o = PyString_FromStringAndSize((const char*) speech_data, length_samples*2); 150 | return speech_data_o; 151 | } 152 | 153 | Py_INCREF(Py_None); 154 | return Py_None; 155 | } 156 | 157 | 158 | My_PROPERTY_SETTER(WebRtcVoiceEngine, ExternalRecordingStatus) 159 | { 160 | My_ERROR_IF_NULL(self->base, VoEBase) 161 | My_ERROR_IF_NULL(self->external_media, VoEExternalMedia) 162 | 163 | if (!PyBool_Check(value)) { 164 | PyErr_SetString(WebRtcError, "must be a bool"); 165 | return -1; 166 | } 167 | 168 | bool enable = (value == Py_True); 169 | int er = self->external_media->SetExternalRecordingStatus(enable); 170 | My_ERROR_IF_NEG(er, self->base) 171 | 172 | return 0; 173 | } 174 | 175 | 176 | My_PROPERTY_SETTER(WebRtcVoiceEngine, ExternalPlayoutStatus) 177 | { 178 | My_ERROR_IF_NULL(self->base, VoEBase) 179 | My_ERROR_IF_NULL(self->external_media, VoEExternalMedia) 180 | 181 | if (!PyBool_Check(value)) { 182 | PyErr_SetString(WebRtcError, "must be a bool"); 183 | return -1; 184 | } 185 | 186 | bool enable = (value == Py_True); 187 | int er = self->external_media->SetExternalPlayoutStatus(enable); 188 | My_ERROR_IF_NEG(er, self->base) 189 | 190 | return 0; 191 | } 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /code/src/my_voice_engine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | * Copyright (c) 2014, Intencity Cloud Technologies . 4 | */ 5 | 6 | #include 7 | #include 8 | 9 | #include "common_types.h" 10 | #include "voe_base.h" 11 | #include "voe_audio_processing.h" 12 | #include "voe_codec.h" 13 | 14 | #include "my_macro.h" 15 | #include "my_error.h" 16 | #include "my_common_types.h" 17 | #include "my_voice_engine.h" 18 | 19 | #include "my_voe_base.h" 20 | #include "my_voe_ap.h" 21 | #include "my_voe_codec.h" 22 | #include "my_voe_call_report.h" 23 | #include "my_voe_dtmf.h" 24 | #include "my_voe_encryption.h" 25 | #include "my_voe_external_media.h" 26 | 27 | using namespace webrtc; 28 | 29 | 30 | #define MODULE_RELEASE(name) if (self->name != NULL) { self->name->Release(); self->name = NULL; } 31 | #define MODULE_GET(name,type) type *name = type::GetInterface(voe); 32 | #define MODULE_ASSIGN(name) self->name = name; 33 | 34 | 35 | static void 36 | WebRtcVoiceEngine_dealloc(WebRtcVoiceEngine* self) 37 | { 38 | if (self->base != NULL) { 39 | self->base->Terminate(); 40 | } 41 | 42 | MODULE_RELEASE(base) 43 | MODULE_RELEASE(ap) 44 | MODULE_RELEASE(codec) 45 | MODULE_RELEASE(call_report) 46 | MODULE_RELEASE(dtmf) 47 | MODULE_RELEASE(encryption) 48 | MODULE_RELEASE(external_media) 49 | 50 | if (self->voe != NULL) { 51 | VoiceEngine::Delete(self->voe); 52 | self->voe = NULL; 53 | } 54 | 55 | self->ob_type->tp_free((PyObject*) self); 56 | } 57 | 58 | static int 59 | WebRtcVoiceEngine_init(WebRtcVoiceEngine *self, PyObject *args, PyObject *kwargs) 60 | { 61 | VoiceEngine *voe = NULL; 62 | 63 | voe = VoiceEngine::Create(); 64 | if (voe == NULL) { 65 | return NULL; 66 | } 67 | 68 | MODULE_GET(base, VoEBase) 69 | if (base == NULL) { 70 | VoiceEngine::Delete(voe); 71 | return NULL; 72 | } 73 | 74 | MODULE_GET(ap, VoEAudioProcessing) 75 | MODULE_GET(codec, VoECodec) 76 | MODULE_GET(call_report, VoECallReport) 77 | MODULE_GET(dtmf, VoEDtmf) 78 | MODULE_GET(encryption, VoEEncryption) 79 | MODULE_GET(external_media, VoEExternalMedia) 80 | 81 | if (base->Init() < 0) { 82 | PyErr_Format(WebRtcError, "%d %s", base->LastError(), Error2String(base->LastError())); 83 | base->Release(); 84 | if (ap != NULL) 85 | ap->Release(); 86 | VoiceEngine::Delete(voe); 87 | return NULL; 88 | } 89 | 90 | self->voe = voe; 91 | MODULE_ASSIGN(base) 92 | MODULE_ASSIGN(ap) 93 | MODULE_ASSIGN(codec) 94 | MODULE_ASSIGN(call_report) 95 | MODULE_ASSIGN(dtmf) 96 | MODULE_ASSIGN(encryption) 97 | MODULE_ASSIGN(external_media) 98 | 99 | return 0; 100 | } 101 | 102 | 103 | static PyMethodDef WebRtcVoiceEngine_methods[] = { 104 | // voe_base.h 105 | My_METHOD_DECL(WebRtcVoiceEngine, RegisterVoiceEngineObserver, METH_VARARGS | METH_KEYWORDS, "set_observer", 106 | PyDoc_STR("set_observer(callback)\n\n" 107 | "Sets the callback(ch:int, err:str, data:object) function to enable runtime error control and warning notifications")), 108 | 109 | // voe_call_report.h 110 | My_METHOD_DECL(WebRtcVoiceEngine, WriteReportToFile, METH_VARARGS, "write_report_to_file", 111 | PyDoc_STR("write_report_to_file(filename)\n\n" 112 | "Creates a text file in ASCII format, which contains a summary of all the statistics that can be obtained by the call report sub-API")), 113 | 114 | // voe_dtmf.h 115 | My_METHOD_DECL(WebRtcVoiceEngine, PlayDtmfTone, METH_VARARGS | METH_KEYWORDS, "play_dtmf_tone", 116 | PyDoc_STR("play_dtmf_tone(event_code, length_ms=200, attenuation_db=10)\n\n" 117 | "Plays a DTMF feedback tone for single digit event_code locally, e.g., event_code='0' to play tone for digit 0.")), 118 | My_METHOD_DECL(WebRtcVoiceEngine, StartPlayingDtmfTone, METH_VARARGS | METH_KEYWORDS, "start_playing_dtmf_tone", 119 | PyDoc_STR("start_playing_dtmf_tone(event_code, attenuation_db=10)\n\n" 120 | "Starts playing out a DTMF feedback tone for single digit event_code locally. The tone will be played out until the corresponding stop function is called")), 121 | My_METHOD_DECL(WebRtcVoiceEngine, StopPlayingDtmfTone, METH_NOARGS, "stop_playing_dtmf_tone", 122 | PyDoc_STR("stop_playing_dtmf_tone()\n\n" 123 | "Stops playing out a DTMF feedback tone locally")), 124 | 125 | // voe_external_media.h 126 | My_METHOD_DECL(WebRtcVoiceEngine, ExternalRecordingInsertData, METH_VARARGS | METH_KEYWORDS, "external_recording_insert_data", 127 | PyDoc_STR("external_recording_insert_data(speech_data_10ms, sampling_frequency, current_delay_ms)\n\n" 128 | "This function accepts externally recorded audio. During transmission, this method should be called at as regular an interval as possible with frames of corresponding size")), 129 | My_METHOD_DECL(WebRtcVoiceEngine, ExternalPlayoutGetData, METH_VARARGS | METH_KEYWORDS, "external_playout_get_data", 130 | PyDoc_STR("external_playout_get_data(sampling_freqency, current_delay_ms) -> speech_data_10ms" 131 | "This function gets audio for an external playout sink. During transmission, this function should be called every ~10 ms to obtain a new 10 ms frame of audio. The length of the block will be 160, 320, 440 or 480 samples (for 16, 32, 44 or 48 kHz sampling rates respectively)")), 132 | 133 | 134 | {NULL, NULL}, 135 | }; 136 | 137 | 138 | static PyGetSetDef WebRtcVoiceEngine_getseters[] = { 139 | // voe_base.h 140 | My_PROPERTY_READONLY(WebRtcVoiceEngine, Version, "version", 141 | PyDoc_STR("(read-only) The version information for VoiceEngine and its components")), 142 | My_PROPERTY_WRITEONLY(WebRtcVoiceEngine, TraceFile, "trace_filename", 143 | PyDoc_STR("(write-only) The name of the trace file and enables non-encrypted trace messages")), 144 | My_PROPERTY_READONLY(WebRtcVoiceEngine, LastError, "last_error", 145 | PyDoc_STR("(read-only) The last VoiceEngine error code as a string")), 146 | My_PROPERTY_READONLY(WebRtcVoiceEngine, MaxNumOfChannels, "max_channels", 147 | PyDoc_STR("(read-only) The maximum number of channels that can be created")), 148 | 149 | // voe_audio_processing.h 150 | My_PROPERTY_READWRITE(WebRtcVoiceEngine, NsStatus, "ns_status", 151 | PyDoc_STR("The noise suppression mode to reduce the noise in the microphone signal")), 152 | My_PROPERTY_READWRITE(WebRtcVoiceEngine, AgcStatus, "agc_status", 153 | PyDoc_STR("The automatic gain control mode to adjust the microphone signal to an appropriate level")), 154 | My_PROPERTY_READWRITE(WebRtcVoiceEngine, AgcConfig, "agc_config", 155 | PyDoc_STR("The automatic gain control configuration should be used where the working environment is well known")), 156 | My_PROPERTY_READWRITE(WebRtcVoiceEngine, EcStatus, "ec_status", 157 | PyDoc_STR("The echo control mode mitigates acoustic echo where a user can hear their own speech repeated back due to an acoustic coupling between the speaker and the microphone at the remote end")), 158 | My_PROPERTY_READWRITE(WebRtcVoiceEngine, AecmMode, "aecm_mode", 159 | PyDoc_STR("The settings for the echo cancellation designed for mobile devices")), 160 | My_PROPERTY_READWRITE(WebRtcVoiceEngine, MetricsStatus, "metrics_status", 161 | PyDoc_STR("The ability to retrieve instantaneous speech, noise and echo metrics during an active call")), 162 | My_PROPERTY_READONLY(WebRtcVoiceEngine, SpeechMetrics, "speech_metrics", 163 | PyDoc_STR("(read-only) The instantaneous speech level metrics for the transmitted and received signals")), 164 | My_PROPERTY_READONLY(WebRtcVoiceEngine, NoiseMetrics, "noise_metrics", 165 | PyDoc_STR("(read-only) The instantaneous noise level metrics for the transmitted and received signals")), 166 | My_PROPERTY_READONLY(WebRtcVoiceEngine, EchoMetrics, "echo_metrics", 167 | PyDoc_STR("(read-only) The instantaneous echo level metrics for the near-end and far-end signals")), 168 | My_PROPERTY_WRITEONLY(WebRtcVoiceEngine, DebugRecording, "debug_recording_filename", 169 | PyDoc_STR("(write-only) The file name for recording of Audio Processing (AP) debugging information that can later be used for off-line analysis of the AP performance")), 170 | My_PROPERTY_READWRITE(WebRtcVoiceEngine, TypingDetectionStatus, "typing_detection_status", 171 | PyDoc_STR("The detection of disturbing keyboard typing causes an error notification as a callback upon detection")), 172 | 173 | // voe_codec.h 174 | My_PROPERTY_READONLY(WebRtcVoiceEngine, NumOfCodecs, "num_codecs", 175 | PyDoc_STR("(read-only) The number of supported codecs")), 176 | My_PROPERTY_READONLY(WebRtcVoiceEngine, Codecs, "codecs", 177 | PyDoc_STR("(read-only) The list of supported codecs information")), 178 | 179 | // voe_call_report.h 180 | My_PROPERTY_READONLY(WebRtcVoiceEngine, SpeechAndNoiseSummary, "speech_and_noise_summary", 181 | PyDoc_STR("(read-only) The minimum, maximum and average levels for long-term speech and noise metrics")), 182 | My_PROPERTY_READONLY(WebRtcVoiceEngine, EchoMetricSummary, "echo_metrics_summary", 183 | PyDoc_STR("(read-only) The minimum, maximum and average levels for long-term echo metrics")), 184 | 185 | // voe_dtmf.h 186 | My_PROPERTY_READWRITE(WebRtcVoiceEngine, DtmfFeedbackStatus, "dtmf_feedback_status", 187 | PyDoc_STR("The DTMF feedback state: when a DTMF tone is sent, the same tone is played out on the speaker")), 188 | 189 | // voe_external_media.h 190 | My_PROPERTY_WRITEONLY(WebRtcVoiceEngine, ExternalRecordingStatus, "external_recording_status", 191 | PyDoc_STR("(write-only) The state of external recording")), 192 | My_PROPERTY_WRITEONLY(WebRtcVoiceEngine, ExternalPlayoutStatus, "external_playout_status", 193 | PyDoc_STR("(write-only) The state of external playout")), 194 | 195 | 196 | // My_PROPERTY_READWRITE(WebRtcVoiceEngine, , "", 197 | // PyDoc_STR("")), 198 | 199 | {NULL} /* Sentinel */ 200 | }; 201 | 202 | static PyTypeObject WebRtcVoiceEngineType = { 203 | PyObject_HEAD_INIT(NULL) 204 | 0, /*ob_size*/ 205 | "webrtc.VoiceEngine", /*tp_name*/ 206 | sizeof(WebRtcVoiceEngine), /*tp_basicsize*/ 207 | 0, /*tp_itemsize*/ 208 | (destructor)WebRtcVoiceEngine_dealloc, /*tp_dealloc*/ 209 | 0, /*tp_print*/ 210 | 0, /*tp_getattr*/ 211 | 0, /*tp_setattr*/ 212 | 0, /*tp_compare*/ 213 | 0, /*tp_repr*/ 214 | 0, /*tp_as_number*/ 215 | 0, /*tp_as_sequence*/ 216 | 0, /*tp_as_mapping*/ 217 | 0, /*tp_hash */ 218 | 0, /*tp_call*/ 219 | 0, /*tp_str*/ 220 | 0, /*tp_getattro*/ 221 | 0, /*tp_setattro*/ 222 | 0, /*tp_as_buffer*/ 223 | Py_TPFLAGS_DEFAULT, /*tp_flags*/ 224 | "VoiceEngine object", /* tp_doc */ 225 | 0, /* tp_traverse */ 226 | 0, /* tp_clear */ 227 | 0, /* tp_richcompare */ 228 | 0, /* tp_weaklistoffset */ 229 | 0, /* tp_iter */ 230 | 0, /* tp_iternext */ 231 | WebRtcVoiceEngine_methods, /* tp_methods */ 232 | 0, /* tp_members */ 233 | WebRtcVoiceEngine_getseters,/* tp_getset */ 234 | 0, /* tp_base */ 235 | 0, /* tp_dict */ 236 | 0, /* tp_descr_get */ 237 | 0, /* tp_descr_set */ 238 | 0, /* tp_dictoffset */ 239 | (initproc) WebRtcVoiceEngine_init, /* tp_init */ 240 | 0, /* tp_alloc */ 241 | 0, /* tp_new */ 242 | }; 243 | 244 | int my_voice_engine_preinit() { 245 | WebRtcVoiceEngineType.tp_new = PyType_GenericNew; 246 | if (PyType_Ready(&WebRtcVoiceEngineType) < 0) 247 | return -1; 248 | return 0; 249 | } 250 | 251 | void my_voice_engine_addobjects(PyObject* m) { 252 | Py_INCREF(&WebRtcVoiceEngineType); 253 | PyModule_AddObject(m, "VoiceEngine", (PyObject *)&WebRtcVoiceEngineType); 254 | } 255 | -------------------------------------------------------------------------------- /code/test.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2011, Kundan Singh. All Rights Reserved. 3 | # Copyright (c) 2014, Intencity Cloud Technologies . 4 | # 5 | 6 | import time, sys, os, traceback 7 | 8 | try: 9 | import webrtc 10 | except: 11 | traceback.print_exc() 12 | sys.exit(-1) 13 | 14 | # run using 15 | # export VERSIONER_PYTHON_PREFER_32_BIT=yes 16 | # arch -i386 /usr/bin/python2.6 test.py 17 | 18 | def main(): 19 | ''' 20 | Create the voice engine, and check its version. 21 | 22 | >>> voe = webrtc.VoiceEngine() 23 | >>> print voe.version.split('\\n')[0] 24 | VoiceEngine 4.1.0 25 | 26 | List of all the methods and attributes of a channel. 27 | 28 | print '\\n'.join([x for x in sorted(dir(voe)) if not x.startswith('_')]) 29 | 30 | Get The maximum number of channels supported in the voice engine. 31 | 32 | >>> print voe.max_channels 33 | 32 34 | 35 | Set and reset the trace file name if needed. 36 | 37 | >>> voe.trace_filename = 'webrtc.log' 38 | >>> voe.trace_filename = None 39 | 40 | Set or reset the error callback handler on the voice engine. 41 | 42 | >>> def voe_callback(ch_id, error, data): 43 | ... print "voe_callback(%r, %r, %r)"%(ch_id, error, data) 44 | >>> voe.set_observer(voe_callback, voe) 45 | >>> voe.set_observer(None) 46 | 47 | Create a new voice channel and print its ID. 48 | 49 | >>> ch = webrtc.Channel(voe) 50 | >>> print ch.id 51 | 0 52 | 53 | List of all the methods and attributes of a channel. 54 | 55 | print '\\n'.join([x for x in sorted(dir(ch)) if not x.startswith('_')]) 56 | 57 | Manipulate the local receiver and send destination properties. 58 | 59 | >>> print ch.local_receiver, ch.send_destination 60 | ('', 0, 0) ('', 0, 0, 0) 61 | >>> ch.set_local_receiver(10000) 62 | >>> ch.set_send_destination(port=10000, ip="127.0.0.1") 63 | >>> print ch.local_receiver, ch.send_destination 64 | ('0.0.0.0', 10000, 10001) ('127.0.0.1', 10000, 10001, 10000) 65 | >>> ch.set_local_receiver(ip='127.0.0.1', port=10000, rtcp_port=20000) 66 | >>> ch.set_send_destination(ip='127.0.0.1', port=30000, rtcp_port=30003, source_port=30004) 67 | >>> print ch.local_receiver, ch.send_destination 68 | ('127.0.0.1', 10000, 20000) ('127.0.0.1', 30000, 30003, 30004) 69 | 70 | Manipulate the other channel properties. 71 | 72 | >>> print ch.on_hold_status 73 | None 74 | >>> ch.on_hold_status = "play-only" # values: "send-play", "send-only", "play-only", None 75 | >>> print ch.on_hold_status 76 | play-only 77 | >>> ch.on_hold_status = None 78 | >>> print ch.on_hold_status 79 | None 80 | 81 | >>> print ch.neteq_playout_mode 82 | default 83 | >>> ch.neteq_playout_mode = "streaming" # values: "default", "streaming", "fax" 84 | >>> print ch.neteq_playout_mode 85 | streaming 86 | >>> try: ch.neteq_playout_mode = None # cannot assign to None 87 | ... except: print 'exception' 88 | exception 89 | >>> ch.neteq_playout_mode = "default" 90 | 91 | >>> print ch.neteq_background_mode 92 | on 93 | >>> ch.neteq_background_mode = "fade" # value: "on", "fade", "off" 94 | >>> print ch.neteq_background_mode 95 | fade 96 | >>> ch.neteq_background_mode = "on" 97 | 98 | Start and stop various streams for playout, send and receive. 99 | 100 | >>> ch.start_playout() 101 | >>> ch.start_receive() 102 | >>> ch.start_send() 103 | >>> ch.stop_send() 104 | >>> ch.stop_receive() 105 | >>> ch.stop_playout() 106 | 107 | The audio processing properties are critical in tuning the audio quality. 108 | Some of these properties take None to disable, while others don't. 109 | Some of these properties have abstract values such as "unchanged" and "default" which when set 110 | will pick up the preconfigured value for that meta value. Hence reading the property after setting 111 | it to "unchanged" or "default" will give a different value then what was set. 112 | 113 | >>> print voe.ns_status, voe.agc_status, voe.ec_status, voe.aecm_mode 114 | None adaptive-analog None speakerphone 115 | >>> voe.ns_status = "default" # values: "unchanged", "default", "conference", "low", "moderate", "high", "very-high", None 116 | >>> voe.agc_status = "default" # values: "unchanged", "default", "adaptive-analog", "adaptive-digital", "fixed-digital", None 117 | >>> voe.ec_status = "default" # values: "unchanged", "default", "conference", "aec", "aecm", None 118 | >>> voe.aecm_mode = "loud-speakerphone" # values: "quiet-earpiece", "earpiece", "loud-earpiece", "speakerphone", "loud-speakerphone" 119 | >>> print voe.ns_status, voe.agc_status, voe.ec_status, voe.aecm_mode 120 | moderate adaptive-analog aec loud-speakerphone 121 | >>> print voe.agc_config 122 | (3, 9, True) 123 | >>> voe.agc_config = (3, 9, True) # (targetLeveldBOv:int, digitalCompressionGaindB:int, limiterEnable:bool) 124 | 125 | >>> print ch.rx_ns_status, ch.rx_agc_status, ch.rx_agc_config 126 | None None (3, 9, True) 127 | >>> ch.rx_ns_status = "default" # same as voe.ns_status but for received signal 128 | >>> ch.rx_agc_status = "default" # same as voe.agc_status but for received signal 129 | >>> ch.rx_agc_config = (3, 9, True) # same as voe.agc_config but for received signal 130 | >>> print ch.rx_ns_status, ch.rx_agc_status, ch.rx_agc_config 131 | moderate adaptive-digital (3, 9, True) 132 | 133 | Set or reset the rx_vad_observer for receive signals voice activity detection 134 | 135 | >>> def vad_callback(ch_id, vad_decision, data): print ch_id, vad_decision, data 136 | >>> ch.set_rx_vad_observer(vad_callback, ch) 137 | >>> ch.set_rx_vad_observer(None) 138 | >>> ch.voice_activity 139 | False 140 | 141 | Some metrics related properties such as metrics_status, speech_metrics, noise_metrics and echo_metrics 142 | give error when setting metrics_status. 143 | 144 | Start and stop bebug recording for audio processing data for future analysis. 145 | 146 | >>> voe.debug_recording_filename = "recording.log" 147 | >>> voe.debug_recording_filename = None # to stop recording 148 | >>> try: voe.debug_recording_filename 149 | ... except AttributeError: print 'not readable' 150 | not readable 151 | 152 | The typing detection status 153 | 154 | >>> print voe.typing_detection_status 155 | False 156 | >>> voe.typing_detection_status = True 157 | >>> print voe.typing_detection_status 158 | True 159 | 160 | Get the codecs count and list. 161 | >>> print voe.num_codecs 162 | 14 163 | >>> print voe.codecs 164 | [{'name': 'ISAC', 'channels': 1, 'rate': 32000, 'frequency': 16000, 'type': 103, 'size': 480}, {'name': 'ISAC', 'channels': 1, 'rate': 56000, 'frequency': 32000, 'type': 104, 'size': 960}, {'name': 'L16', 'channels': 1, 'rate': 128000, 'frequency': 8000, 'type': 105, 'size': 80}, {'name': 'L16', 'channels': 1, 'rate': 256000, 'frequency': 16000, 'type': 107, 'size': 160}, {'name': 'L16', 'channels': 1, 'rate': 512000, 'frequency': 32000, 'type': 108, 'size': 320}, {'name': 'PCMU', 'channels': 1, 'rate': 64000, 'frequency': 8000, 'type': 0, 'size': 160}, {'name': 'PCMA', 'channels': 1, 'rate': 64000, 'frequency': 8000, 'type': 8, 'size': 160}, {'name': 'iLBC', 'channels': 1, 'rate': 13300, 'frequency': 8000, 'type': 102, 'size': 240}, {'name': 'G722', 'channels': 1, 'rate': 64000, 'frequency': 16000, 'type': 9, 'size': 320}, {'name': 'CN', 'channels': 1, 'rate': 0, 'frequency': 8000, 'type': 13, 'size': 240}, {'name': 'CN', 'channels': 1, 'rate': 0, 'frequency': 16000, 'type': 98, 'size': 480}, {'name': 'CN', 'channels': 1, 'rate': 0, 'frequency': 32000, 'type': 99, 'size': 960}, {'name': 'telephone-event', 'channels': 1, 'rate': 0, 'frequency': 8000, 'type': 106, 'size': 240}, {'name': 'red', 'channels': 1, 'rate': 0, 'frequency': 8000, 'type': 127, 'size': 0}] 165 | 166 | >>> print ch.send_codec 167 | {'name': 'PCMU', 'channels': 1, 'rate': 64000, 'frequency': 8000, 'type': 0, 'size': 160} 168 | 169 | >>> ch.send_codec = {'name': 'ISAC', 'channels': 1, 'rate': 32000, 'frequency': 16000, 'type': 103, 'size': 480} 170 | >>> print ch.send_codec 171 | {'name': 'ISAC', 'channels': 1, 'rate': 32000, 'frequency': 16000, 'type': 103, 'size': 480} 172 | 173 | >>> print ch.recv_codec # will be None if not receiving 174 | None 175 | 176 | TODO What are the allowed values for these? 177 | ch.isac_init_target_rate = 6400 178 | ch.isac_max_rate = 6400 179 | ch.isac_max_payload_size = 480 180 | ch.recv_payload_type 181 | 182 | >>> ch.send_cn_payload_type = (96, 16000) 183 | 184 | Manipulate voice activity detection related properties. 185 | 186 | >>> print ch.vad_status 187 | None 188 | >>> ch.vad_status = True 189 | >>> print ch.vad_status 190 | ('conventional', False) 191 | >>> ch.vad_status = ('high', True) 192 | >>> print ch.vad_status 193 | ('high', True) 194 | >>> ch.vad_status = None 195 | >>> print ch.vad_status 196 | None 197 | 198 | External media process. 199 | 200 | Close the channel by removing all references. 201 | >>> del ch 202 | ''' 203 | 204 | 205 | 206 | #print audio.Device(type="input") 207 | 208 | #print audio.get_codecs() 209 | # 210 | ## audio capture in speex/8000 211 | #audio.connect(audio.input("l16/16000"), 212 | # audio.pipe("l16/16000", "l16/8000"), 213 | # audio.pipe("l16/8000", "speex/8000"), 214 | # audio.port("speex/8000", on_data)) 215 | # 216 | ## audio playback in pcmu/16000 217 | #p2 = audio.port("pcmu/16000") 218 | #audio.connect(p2, 219 | # audio.pipe("pcmu/16000", "l16/16000"), 220 | # audio.pipe("l16/16000", "l16/44100"), 221 | # audio.output("l16/44100", device="default")) 222 | # 223 | #while True: 224 | # p2.put('some audio data') 225 | # 226 | ## audio mixer from multiple sources 227 | #s = audio.mixer("l16/8000") 228 | #p1 = audio.port("pcmu/8000") 229 | #p2 = audio.port("speex/16000") 230 | #p3 = audio.port("gsm/8000") 231 | #audio.connect(p1, audio.pipe("pcmu/8000", "l16/8000"), s) 232 | #audio.connect(p2, audio.pipe("speex/16000", "l16/16000"), audio.pipe("l16/16000", "l16/8000"), s) 233 | #audio.connect(p3, audio.pipe("gsm/8000", "l16/8000"), s) 234 | #audio.connect(s, audio.subtract(p1), audio.pipe("l16/8000", "pcmu/8000"), p1) 235 | #audio.connect(s, audio.subtract(p2), audio.pipe("l16/8000", "l16/16000"), audio.pipe("l16/16000", "speex/16000"), p2) 236 | #audio.connect(s, audio.subtract(p3), audio.pipe("l16/8000", "gsm/8000"), p3) 237 | # 238 | #sys.exit() 239 | # 240 | #print 'current-api=', rtaudio.get_current_api() 241 | #print 'device_count=', rtaudio.get_device_count() 242 | #for i in range(rtaudio.get_device_count()): 243 | # print 'device', i, rtaudio.get_device_info(i) 244 | #print 'default-output=', rtaudio.get_default_output_device() 245 | #print 'default-input=', rtaudio.get_default_input_device() 246 | # 247 | ##sys.exit() 248 | # 249 | #queue = [] 250 | # 251 | ##def callback(in_buf, frames_count, streamTime, status, userdata): 252 | #def callback(input, buffer_frames, stream_time, status, userdata): 253 | # # print 'callback', len(input), buffer_frames, stream_time, status, userdata 254 | # queue.append(input) 255 | # if len(queue) > 100: 256 | # input = queue.pop(0) 257 | # return input + input 258 | # else: 259 | # return "" 260 | # 261 | ## start 262 | #try: 263 | # print 'open_stream' 264 | # rtaudio.open_stream(output_device=rtaudio.get_default_output_device(), output_channels=2, 265 | # input_device=rtaudio.get_default_input_device(), input_channels=1, 266 | # format='s16', callback=callback, flags=1) 267 | # print 'start_stream' 268 | # rtaudio.start_stream() 269 | #except rtaudio.error, e: 270 | # print e 271 | # 272 | #try: 273 | # while True: 274 | # time.sleep(10) 275 | #except KeyboardInterrupt: 276 | # if rtaudio.is_stream_running: 277 | # print 'stop_stream' 278 | # rtaudio.stop_stream() 279 | # if rtaudio.is_stream_open: 280 | # print 'close_stream' 281 | # rtaudio.close_stream() 282 | # 283 | 284 | if __name__ == "__main__": 285 | import doctest 286 | doctest.testmod() 287 | 288 | -------------------------------------------------------------------------------- /code/webrtc.log: -------------------------------------------------------------------------------- 1 | Local Date: Mon Jun 13 18:27:56 2011 2 | Build info: Jun 7 2011 11:30:07 ? 3 | 4 | STATEINFO ; ( 1:27:55: 0 | 0) UTILITY: -1;2953842688; Thread with name:Trace started 5 | APICALL ; ( 1:27:56: 0 | 1) VOICE: 1 99;2686211296; Init() 6 | STATEINFO ; ( 1:27:56: 0 | 1) UTILITY: -1;2954899456; Thread with name:ProcessThread started 7 | WARNING ; ( 1:27:56: 0 | 0) VOICE: 1 99;2686211296; Init() failed to set Level Estimator state for APmodule (error=8097) 8 | STATEINFO ; ( 1:27:56: 0 | 0) AUDIO DEVICE: 1 99;2686211296; output: kPlatformDefaultAudio 9 | STATEINFO ; ( 1:27:56: 0 | 0) AUDIO DEVICE: 1 99;2686211296; OS info: OS X 10 | STATEINFO ; ( 1:27:56: 0 | 0) AUDIO DEVICE: 1 99;2686211296; output: available=-1073749553 11 | STATEINFO ; ( 1:27:56: 0 | 0) AUDIO DEVICE: 1 99;2686211296; output: available=1 12 | STATEINFO ; ( 1:27:56: 0 | 0) AUDIO DEVICE: 1 99;2686211296; output: available=1 13 | STATEINFO ; ( 1:27:56: 0 | 0) AUDIO DEVICE: 1 99;2686211296; output: available=1 14 | APICALL ; ( 1:27:56: 0 | 0) VOICE: 1 99;2686211296; GetVersion(version=?) 15 | STATEINFO ; ( 1:27:56: 0 | 0) AUDIO DEVICE: -1;2686211296; version: AudioDevice 1.1.0 16 | STATEINFO ; ( 1:27:56: 0 | 0) TRANSPORT: -1;2686211296; Start UdpSocketManagerLinux 17 | STATEINFO ; ( 1:27:56: 0 | 0) UTILITY: -1;2957553664; Thread with name:UdpSocketManagerLinuxImplThread started 18 | STATEINFO ; ( 1:27:56: 0 | 0) TRANSPORT: -1;2686211296; Stop UdpSocketManagerLinux 19 | STATEINFO ; ( 1:27:56: 0 | 0) UTILITY: -1;2957553664; Thread with name:UdpSocketManagerLinuxImplThread stopped 20 | STATEINFO ; ( 1:27:56: 0 | 0) VOICE: 1 99;2686211296; GetVersion() => 21 | STATEINFO ; ( 1:27:56: 0 | 0) VOICE: 1 99;2686211296; VoiceEngine 4.1.0 22 | Build: Jun 7 2011 11:29:14 ? 23 | External recording and playout build 24 | AudioDevice 1.1.0 25 | UdpTransport 1.1.0 26 | Module RTP RTCP 1.3.0 27 | Audio Conference Mixer Module 1.1.0 28 | STATEINFO ; ( 1:27:56: 0 | 0) VOICE: 1 99;2686211296; 29 | AudioProcessing 1.0.0 30 | AEC 2.5.0 31 | AECM 1.2.0 32 | AGC 1.7.0 33 | NS 2.2.0 34 | VAD 1.2.0 35 | AudioCodingModule 1.3.0 36 | NetEq 3.3.0 37 | ISAC 4.3.0 38 | L16 1.0.0 39 | G.711 2.0.0 40 | ILBC 1.1.0 41 | G.722 2.0.0 42 | STATEINFO ; ( 1:27:56: 0 | 0) VOICE: 1 99;2686211296; 43 | CNG 1.2.0 44 | Tone Generation 1.0.0 45 | 46 | SPLIB 1.2.0 47 | 48 | APICALL ; ( 1:27:56: 0 | 0) VOICE: 1 99;2686211296; MaxNumOfChannels() 49 | STATEINFO ; ( 1:27:56: 0 | 0) VOICE: 1 99;2686211296; MaxNumOfChannels() => 32 50 | APICALL ; ( 1:27:56: 0 | 0) VOICE: 1 99;2686211296; SetTraceFile(fileNameUTF8=webrtc.log, addFileCounter=0) 51 | -------------------------------------------------------------------------------- /code/webrtc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theintencity/py-webrtc/00283d0383b51e79629faee4d6ddaa8171b4e269/code/webrtc.so --------------------------------------------------------------------------------