I'm trying to write some BlueZ code using the Management API but I can't seem to get BlueZ to advertise arbitrary data on the advertisement system
I have 2 tests one in C++ and one using the btmgmt tool that BlueZ has released
When I run this command it fails this way
btmgmt add-adv -d 8C33 1
Add Advertising failed with status 0x0d (Invalid Parameters)
The equivalent C++ code also fails identically
#include <iostream>
extern "C" {
#include "external/bluetooth/lib/bluetooth.h"
#include "external/bluetooth/lib/mgmt.h"
#include "external/bluetooth/lib/hci.h"
#include "external/bluetooth/lib/hci_lib.h"
#include "external/bluetooth/src/shared/mgmt.h"
}
static void setup_dv(uint8_t status, uint16_t length,
const void *param, void *user_data)
{
std::cout << "good" << std::endl;
}
struct CPadvertising {
uint8_t instance;
uint32_t flags;
uint16_t duration;
uint16_t timeout;
uint8_t adv_data_len;
uint8_t scan_rsp_len;
uint8_t data[4];
} __packed;
int main()
{
mgmt* sock = mgmt_new_default();
CPadvertising* data = new CPadvertising();
data->instance = 1;
data->duration = 2;
data->timeout = 100;
data->adv_data_len = 4;
data->scan_rsp_len = 0;
data->flags = 0;
data->data[0] = 8;
data->data[1] = 12;
data->data[2] = 3;
data->data[3] = 3;
mgmt_send(sock, MGMT_OP_ADD_ADVERTISING, index,
sizeof(CPadvertising), data, setup_dv, nullptr, nullptr);
auto loop = g_main_loop_new(nullptr, FALSE);
g_main_loop_run(loop);
}
has this output in btmon
# MGMT Command: Add Advertising (0x003e) plen 13 {0x0003} [hci0] 98.205359
Instance: 1
Flags: 0x00000000
Duration: 2
Timeout: 100
Advertising data length: 4
8 c 3 3 .3
Scan response length: 0
# MGMT Event: Command Status (0x0002) plen 3 {0x0003} [hci0] 98.205376
Add Advertising (0x003e)
Status: Invalid Parameters (0x0d)
Referring to these docs, I should not get invalid parameter for any of this but I do
https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/doc/mgmt-api.txt
However, I know certain types of data does indeed work
btmgmt add-adv -d 080954657374204C45
works even in an even weirder way prompting this output on btmon
# MGMT Command: Add Advertising (0x003e) plen 20 {0x0002} [hci0] 143.671485
Instance: 1
Flags: 0x00000000
Duration: 0
Timeout: 0
Advertising data length: 9
Name (complete): Test LL <--- What is this
Scan response length: 0
Looking at the source for btmgmt, these are the options available:
static void add_adv_usage(void)
{
bt_shell_usage();
print("Options:\n"
"\t -u, --uuid <uuid> Service UUID\n"
"\t -d, --adv-data <data> Advertising Data bytes\n"
"\t -s, --scan-rsp <data> Scan Response Data bytes\n"
"\t -t, --timeout <timeout> Timeout in seconds\n"
"\t -D, --duration <duration> Duration in seconds\n"
"\t -P, --phy <phy> Phy type, Specify 1M/2M/CODED\n"
"\t -c, --connectable \"connectable\" flag\n"
"\t -g, --general-discov \"general-discoverable\" flag\n"
"\t -l, --limited-discov \"limited-discoverable\" flag\n"
"\t -n, --scan-rsp-local-name \"local-name\" flag\n"
"\t -a, --scan-rsp-appearance \"appearance\" flag\n"
"\t -m, --managed-flags \"managed-flags\" flag\n"
"\t -p, --tx-power \"tx-power\" flag\n"
"e.g.:\n"
"\tadd-adv -u 180d -u 180f -d 080954657374204C45 1");
}
Looking at the advert that worked, the first number is the length of the data, the second is the data_type, and the rest is the local name string. So:
0x08 = Length of datatype is 8
0x09 = Data type is <Complete Local Name>
0x54 = T
0x65 = e
0x73 = s
0x74 = t
0x20 = ' '
0x4C = L
0x45 = E
Not sure why that has turned up as Test LL in the btmon output. I'll
assume it was a slightly different run that you recorded.
Looking at your data of 8c33; the 8c does not represent the length and 33 is not a valid data type.
I suspect what you want to do is send manufacturer data. Assuming you don't have a company identifier, then you can use 0xffff for testing purposes.
This would be a command of:
btmgmt add-adv -d 05ffffff8C33 -g 1
Which gave the following in btmon
# MGMT Command: Add Adver.. (0x003e) plen 17 {0x0002} [hci0] 341.378134
Instance: 1
Flags: 0x00000002
Advertise as Discoverable
Duration: 0
Timeout: 0
Advertising data length: 6
Company: internal use (65535)
Data: 8c33
Scan response length: 0
Related
I'm using espeak-ng to turn German-language traffic messages into speech. See this example text:
B6 Weserstraße B71 Seeborg vorübergehende Begrenzung der Breite.
B213 Wildeshauser Landstraße Delmenhorst-Deichhorst wegen Baustelle gesperrt.
The espeak method call looks like this:
unsigned int spoken_message_uuid = 0;
espeak_ERROR Speak (wstring text)
{
espeak_ERROR error = EE_OK;
unsigned int *uuid = &spoken_message_uuid;
const wchar_t *input = text.c_str ();
wcout << L"Speaking text:" << endl << input << endl;
error = espeak_Synth (input, text.length (), 0, POS_CHARACTER, 0, espeakCHARS_WCHAR | espeakENDPAUSE | espeakSSML, uuid, NULL);
return error;
}
My issue is now the following: All the German special characters (ä, ö, ü, ß) are not being spoken correctly! Instead, something like A Tilde ein Viertel appears in the spoken text, as if UTF-8 text had been treated erroneously as ASCII.
Here are the respective versions of espeak-ng and g++:
pi#autoradio:/import/valen/autoradio $ espeak-ng --version
eSpeak NG text-to-speech: 1.50 Data at: /usr/lib/arm-linux-gnueabihf/espeak-ng-data
pi#autoradio:/import/valen/autoradio $ g++ --version
g++ (Raspbian 6.5.0-1+rpi1+b1) 6.5.0 20181026
pi#autoradio:/import/valen/autoradio $ apt-cache policy espeak-ng
espeak-ng:
Installiert: 1.50+dfsg-7~bpo10+1
Installationskandidat: 1.50+dfsg-7~bpo10+1
Versionstabelle:
*** 1.50+dfsg-7~bpo10+1 100
100 http://deb.debian.org/debian buster-backports/main armhf Packages
100 /var/lib/dpkg/status
1.49.2+dfsg-8 500
500 http://raspbian.raspberrypi.org/raspbian buster/main armhf Packages
espeak has been installed from Debian's buster-backports repo to replace version 1.49, which didn't work either. The voice I'm using is mb-de5.
OK, this is not exactly a solution, yet a mere workaround, but at least it works: I hand over a string instead of a wstring. The original string turned out to be UTF-8-encoded, so that all the special characters fit into a string resp. char* variable. Here is the adapted code:
unsigned int spoken_message_uuid = 0;
espeak_ERROR Speak (string text)
{
espeak_ERROR error = EE_OK;
unsigned int *uuid = &spoken_message_uuid;
const char *input = text.c_str ();
cout << "Speaking text:" << endl << input << endl;
error = espeak_Synth (input, text.length (), 0, POS_CHARACTER, 0, espeakCHARS_UTF8 | espeakENDPAUSE | espeakSSML, uuid, NULL);
return error;
}
I am using NS3.20 to find the time stamps of packet being sent from a node to another node in a FAT-TREE topology using the command
NS_LOG= "*=level_info|prefix_func|prefix_time|prefix_node" ./waf --run scratch/fat-tree &> save-log.txt
After grepping few selected lines containing info about pkt 196.The output is of the form
Timestamp, Nodeid, Functioncalled, DevNo, pktid
Example lines are as follows
1.74547s 34 CsmaChannel:TransmitStart(): UID is 196)
1.74548s 34 CsmaChannel:TransmitEnd(): UID is 196)
1.74548s 23 Node:ReceiveFromDevice(): Node 23 ReceiveFromDevice: dev 2 (type=ns3::CsmaNetDevice) Packet UID 196
1.74548s 23 BridgeNetDevice:ReceiveFromDevice(): UID is 196
1.74548s 23 CsmaChannel:TransmitStart(): UID is 196)
1.74548s 34 CsmaChannel:PropagationCompleteEvent(): UID is 196)
.
.
.
For my research I need the time stamps to be in nanoseconds. Is there a way to configure this?
NB : I tried cout, and fout within the functions but it just prints time without the node_id which is useless for me.
Please help
First, I will suggest using the latest version of ns-3, ns-3.30.1. Generally, it is a good idea to stay up-to-date. That being said my solution was tested using ns-3.30.1, so it is quite possible it doesn't work with ns-3.20. If it doesn't work, refer to the comments in sample-log-time-format.cc.
I referenced §11.3 of the ns-3 manual, which pointed me to the example, ./src/core/examples/sample-log-time-format.cc. Based off of that example, here is a minimal reproducible example of your desired output.
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
// set the time format and precision of LOG macros
// https://stackoverflow.com/questions/60148908
// this example is adapted from ./src/core/examples/sample-log-time-format.cc
#include "ns3/simulator.h"
#include "ns3/log.h"
#include "ns3/random-variable-stream.h"
using namespace ns3;
void
ReplacementTimePrinter (std::ostream &os)
{
os << Simulator::Now ().GetNanoSeconds () << " ns";
}
void
ReplaceTimePrinter (void)
{
std::cout << "Replacing time printer function after Simulator::Run ()" << std::endl;
LogSetTimePrinter (&ReplacementTimePrinter);
}
int
main (int argc, char *argv[])
{
LogComponentEnable ("RandomVariableStream", LOG_LEVEL_ALL);
LogComponentEnableAll (LOG_PREFIX_TIME);
Ptr<UniformRandomVariable> uniformRv = CreateObject<UniformRandomVariable> ();
Simulator::Schedule (Seconds (0), &ReplaceTimePrinter);
// schedule some bogus events to demonstrate the new TimePrinter
Simulator::Schedule (NanoSeconds (1), &UniformRandomVariable::SetAntithetic, uniformRv, false);
Simulator::Schedule (NanoSeconds (123), &UniformRandomVariable::SetAntithetic, uniformRv, false);
Simulator::Schedule (NanoSeconds (123456), &UniformRandomVariable::SetAntithetic, uniformRv, false);
Simulator::Schedule (NanoSeconds (123456789), &UniformRandomVariable::SetAntithetic, uniformRv, false);
Simulator::Run ();
Simulator::Destroy ();
}
Use
./waf --run <program-name>
to run your program, and output should be
RandomVariableStream:RandomVariableStream(0x7fc0aee287d0)
RandomVariableStream:UniformRandomVariable(0x7fc0aee287d0)
RandomVariableStream:SetStream(0x7fc0aee287d0, -1)
RandomVariableStream:SetAntithetic(0x7fc0aee287d0, 0)
Replacing time printer function after Simulator::Run ()
1 ns RandomVariableStream:SetAntithetic(0x7fc0aee287d0, 0)
123 ns RandomVariableStream:SetAntithetic(0x7fc0aee287d0, 0)
123456 ns RandomVariableStream:SetAntithetic(0x7fc0aee287d0, 0)
123456789 ns RandomVariableStream:SetAntithetic(0x7fc0aee287d0, 0)
RandomVariableStream:~RandomVariableStream(0x7fc0aee287d0)
Notice that rather than directly calling LogSetTimePrinter in our simulator code, we schedule an Event that will call LogSetTimePrinter instead with
Simulator::Schedule (Seconds (0), &ReplaceTimePrinter);
I wasn't sure why this is the case, but on further inspection of it's documentation, it appears that GetImpl() calls LogSetTimePrinter. GetImpl() is called by Simulator::Run() which means that Simulator::Run() will "override" any calls to LogSetTimePrinter before Simulator::Run() is called. Thus, we need to create an Event that sets the TimePrinter after the SimulatorImpl has been created.
I am asking this question again as the mods decided to close my question here as a duplicate, within minutes of it being asked (and also down-voted!!). Now I have gone through all 33 answers of what was thought to be an answer to my solution, but it didn't help. So I am asking again.
I am trying to build a FreeSWITCH module to add text-to-speech functionality using AWS Polly & the AWS C++ SDK.
Dev environment is Debian 8, g++ 4.9.2. AWS C++ SDK is built using instructions here except that I turned off shared libs (produces .a lib files).
The AWS C++ SDK was built as recommended here (basically C++ code with C++ linkage). mod_polly.cpp is built with C++ linkage as well to produce mod_polly.so. It does refer to some C headers & functions. This was built as -
g++ -shared -o mod_polly.so -L/usr/local/lib/ -laws-cpp-sdk-polly -laws-cpp-sdk-core -fPIC -g -ggdb -std=c++11 -Wall -Werror -I/usr/src/freeswitch/src/include/ -I/usr/src/freeswitch/libs/libteletone/src/ mod_polly.cpp
Source below -
extern "C" {
#include <switch.h>
}
#include <fstream>
#define BIG_ENDIAN_SYSTEM (*(uint16_t *)"\0\xff" < 0x100)
#define REVERSE_BYTES(...) do for(size_t REVERSE_BYTES=0; REVERSE_BYTES<sizeof(__VA_ARGS__)>>1; ++REVERSE_BYTES)\
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES],\
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES],\
((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES];\
while(0)
#include <aws/core/Aws.h>
#include <aws/core/auth/AWSCredentials.h>
#include <aws/core/client/ClientConfiguration.h>
#include <aws/core/utils/Outcome.h>
#include <aws/polly/PollyClient.h>
#include <aws/polly/model/SynthesizeSpeechRequest.h>
#include <aws/polly/model/SynthesizeSpeechResult.h>
#include <aws/polly/model/TextType.h>
#include <aws/polly/model/LanguageCode.h>
#include <aws/polly/model/OutputFormat.h>
#include <aws/polly/model/VoiceId.h>
typedef unsigned long DWORD; // 32-bit unsigned integer
typedef unsigned short WORD; // 16-bit unsigned integer
struct riff // Data Bytes Total
{
char chunkID[4]; // "RIFF" 4 4
DWORD riffSize; // file size - 8 4 8
char typeID[4]; // "WAVE" 4 12
char formatChunkID[4]; // "fmt " 4 16
DWORD formatChunkSize; // 16 bytes 4 20
WORD formatTag; // 2 22
WORD noOfChannels; // 2 24
DWORD samplesPerSec; // 4 28
DWORD bytesPerSec; // 4 32
WORD blockAlign; // 2 34
WORD bitsPerSample; // 2 36
char dataChunkID[4]; // "data" 4 40
DWORD dataChunkSize; // not fixed 4 44
};
static struct {
switch_mutex_t *mutex;
switch_thread_rwlock_t *running_rwlock;
switch_memory_pool_t *pool;
int running;
} process;
static struct {
Aws::Auth::AWSCredentials *credentials;
Aws::Client::ClientConfiguration *config;
Aws::SDKOptions *options;
} globals;
switch_loadable_module_interface_t *MODULE_INTERFACE;
static char *supported_formats[SWITCH_MAX_CODECS] = { 0 };
/* Prototypes */
SWITCH_MODULE_LOAD_FUNCTION(mod_polly_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_polly_shutdown);
SWITCH_MODULE_DEFINITION(mod_polly, mod_polly_load, mod_polly_shutdown, NULL);
// ------------------------------------------------------------------------------------------------------------------
/* Implementation */
std::ostream& operator<<(std::ostream& out, const riff& h)
{
if BIG_ENDIAN_SYSTEM {
struct riff hdr = std::move(h);
REVERSE_BYTES(hdr.riffSize);
REVERSE_BYTES(hdr.formatChunkSize);
REVERSE_BYTES(hdr.formatTag);
REVERSE_BYTES(hdr.noOfChannels);
REVERSE_BYTES(hdr.samplesPerSec);
REVERSE_BYTES(hdr.bytesPerSec);
REVERSE_BYTES(hdr.blockAlign);
REVERSE_BYTES(hdr.bitsPerSample);
REVERSE_BYTES(hdr.dataChunkSize);
return out
.write(hdr.chunkID, 4)
.write((const char *)&hdr.riffSize, 4)
.write(hdr.typeID, 4)
.write(hdr.formatChunkID, 4)
.write((const char *)&hdr.formatChunkSize, 4)
.write((const char *)&hdr.formatTag, 2)
.write((const char *)&hdr.noOfChannels, 2)
.write((const char *)&hdr.samplesPerSec, 4)
.write((const char *)&hdr.bytesPerSec, 4)
.write((const char *)&hdr.blockAlign, 2)
.write((const char *)&hdr.bitsPerSample, 2)
.write(hdr.dataChunkID, 4)
.write((const char *)&hdr.dataChunkSize, 4);
} else {
return out
.write(h.chunkID, 4)
.write((const char *)&h.riffSize, 4)
.write(h.typeID, 4)
.write(h.formatChunkID, 4)
.write((const char *)&h.formatChunkSize, 4)
.write((const char *)&h.formatTag, 2)
.write((const char *)&h.noOfChannels, 2)
.write((const char *)&h.samplesPerSec, 4)
.write((const char *)&h.bytesPerSec, 4)
.write((const char *)&h.blockAlign, 2)
.write((const char *)&h.bitsPerSample, 2)
.write(h.dataChunkID, 4)
.write((const char *)&h.dataChunkSize, 4);
}
}
riff init_pcm_header(std::ostream& in)
{
// get length of file
in.seekp(0, in.end);
DWORD sz = in.tellp();
in.seekp(0, in.beg);
struct riff result = {
{'R','I','F','F'}, // chunkID
sz + 0x24, // riffSize (size of stream + 0x24) or (file size - 8)
{'W','A','V','E'}, // typeID
{'f','m','t',' '}, // formatChunkID
16, // formatChunkSize
1, // formatTag (PCM)
1, // noOfChannels (mono)
8000, // samplesPerSec (8KHz)
16000, // bytesPerSec ((Sample Rate * BitsPerSample * Channels) / 8)
2, // blockAlign ((bits per sample * channels) / 8)
16, // bitsPerSample (multiples of 8)
{'d','a','t','a'}, // dataChunkID
sz // dataChunkSize (sample size)
};
return result;
}
struct voice_sync {
char* session_uuid;
Aws::IOStream *audio_stream;
switch_size_t blockAlign;
};
typedef struct voice_sync voice_sync_t;
static switch_status_t polly_file_open(switch_file_handle_t *handle, const char *path)
{
voice_sync_t *sync_info = (voice_sync_t*)malloc(sizeof(voice_sync_t));
sync_info->audio_stream = new Aws::StringStream(std::ios::in | std::ios::out | std::ios::binary);
handle->private_info = sync_info;
handle->samplerate = 8000;
handle->channels = 1;
handle->pos = 0;
handle->format = 0;
handle->sections = 0;
handle->seekable = 0;
handle->speed = 0.5;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "submitting text [%s] to polly", path);
Aws::Polly::PollyClient polly_client(*globals.credentials, *globals.config);
Aws::Polly::Model::SynthesizeSpeechRequest request;
request.SetLanguageCode(Aws::Polly::Model::LanguageCode::en_US);
request.SetOutputFormat(Aws::Polly::Model::OutputFormat::pcm);
request.SetSampleRate("8000");
request.SetTextType(Aws::Polly::Model::TextType::text); // or ssml
request.SetVoiceId(Aws::Polly::Model::VoiceId::Matthew);
request.SetText(path);
if (handle->params) {
// get the session UUID for this channel
// note: this doesnt fire for a standard call session in the audio context; is there a way to make sure it is there?
const char *uuid = switch_event_get_header(handle->params, "session");
if (!zstr(uuid)) {
sync_info->session_uuid = switch_core_strdup(handle->memory_pool, uuid);
switch_log_printf(SWITCH_CHANNEL_UUID_LOG(sync_info->session_uuid), SWITCH_LOG_DEBUG, "Polly linked to session %s\n", sync_info->session_uuid);
}
}
sync_info->audio_stream->clear();
// sync_info->audio_stream.open(filename.c_str(), std::ios::out | std::ios::binary);
auto outcome = polly_client.SynthesizeSpeech(request);
// Output operation status
if (outcome.IsSuccess()) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "received audio response for %s", request.GetServiceRequestName());
Aws::Polly::Model::SynthesizeSpeechResult& result = ((Aws::Polly::Model::SynthesizeSpeechResult&)(outcome));
Aws::IOStream* audio_stream = &result.GetAudioStream();
// this is raw PCM so we need to add a wav header!
riff header = init_pcm_header(*audio_stream);
*sync_info->audio_stream << header;
// tansfer audio data into stream
*sync_info->audio_stream << audio_stream->rdbuf();
sync_info->audio_stream->seekp(0, sync_info->audio_stream->beg);
// update handle information about audio stream
handle->samplerate = header.samplesPerSec;
handle->channels = header.noOfChannels;
handle->format = header.formatTag;
handle->duration = header.dataChunkSize / header.bytesPerSec +1;
handle->samples_in = header.dataChunkSize / header.blockAlign +1;
sync_info->blockAlign = header.blockAlign;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "polly audio stream ready; duration: %ld secs", handle->duration);
return SWITCH_STATUS_SUCCESS;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "something went wrong retrieving audio from polly");
return SWITCH_STATUS_FALSE;
}
static switch_status_t polly_file_close(switch_file_handle_t *handle)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "closiing polly audio stream");
voice_sync_t *sync_info = (voice_sync_t*)handle->private_info;
//sync_info->audio_stream->close(); -- doesnt exist on stringstream
delete sync_info->audio_stream;
if (sync_info->session_uuid) {
switch_safe_free(sync_info->session_uuid);
}
switch_safe_free(sync_info);
handle->private_info = NULL;
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t polly_file_read(switch_file_handle_t *handle, void *data, size_t *len)
{
voice_sync_t *sync_info = (voice_sync_t*)handle->private_info;
switch_size_t bytes;
sync_info->audio_stream->read((char *)data, *len * sync_info->blockAlign);
if ((bytes = sync_info->audio_stream->gcount()) <= 0) {
return SWITCH_STATUS_FALSE;
}
*len = bytes / sync_info->blockAlign;
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_LOAD_FUNCTION(mod_polly_load)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Initializing polly audio interface");
supported_formats[0] = (char*)"polly";
/*
switch_application_interface_t *app_interface;
switch_api_interface_t *api_interface;
*/
switch_file_interface_t *file_interface;
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
file_interface = (switch_file_interface_t*)switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE);
file_interface->interface_name = modname;
file_interface->extens = supported_formats;
file_interface->file_open = polly_file_open;
file_interface->file_close = polly_file_close;
file_interface->file_read = polly_file_read;
MODULE_INTERFACE = *module_interface;
memset(&process, 0, sizeof(process));
memset(&globals, 0, sizeof(globals));
process.pool = pool;
switch_thread_rwlock_create(&process.running_rwlock, pool);
switch_mutex_init(&process.mutex, SWITCH_MUTEX_NESTED, pool);
globals.options = new Aws::SDKOptions();
globals.options->loggingOptions.logLevel = Aws::Utils::Logging::LogLevel::Debug;
globals.credentials = new Aws::Auth::AWSCredentials();
globals.credentials->SetAWSAccessKeyId("your aws key");
globals.credentials->SetAWSSecretKey("your aws secret");
globals.config = new Aws::Client::ClientConfiguration();
globals.config->region = "eu-west-1"; // Ireland
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Initializing aws api");
Aws::InitAPI(*globals.options);
switch_thread_rwlock_wrlock(process.running_rwlock);
process.running = 1;
switch_thread_rwlock_unlock(process.running_rwlock);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ready to rock!");
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_polly_shutdown)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Shutting down polly polly audio interface");
switch_thread_rwlock_wrlock(process.running_rwlock);
process.running = 0;
switch_thread_rwlock_unlock(process.running_rwlock);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Closing aws api");
Aws::ShutdownAPI(*globals.options);
delete globals.credentials;
delete globals.config;
delete globals.options;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Module shutdown finished");
return SWITCH_STATUS_UNLOAD;
}
Now when i try to load this on Freeswitch , it throws an error
2019-07-31 22:00:51.918181 [CRIT] switch_loadable_module.c:1522 Error Loading module /usr/local/freeswitch/mod/mod_polly.so
/usr/local/freeswitch/mod/mod_polly.so: undefined symbol: _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
Freeswitch is C code with C++ guards in header files (extern "C" declaration).
Looking at symbols in mod_polly.so
readelf -Ws mod_polly.so | grep _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
66: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
590: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
Now my basic understanding of the post here tells me that the symbol is present in the so file but Freeswitch cannot find it or load it.
Now this error has very likely to do with mixing C/C++ code but looking at this and this hasn't helped me figure out how to fix it.
I do not want to build Freeswitch to load my module and I am thinking I shouldn't have to, as that renders this project un-scalable.
What am I missing here?
PS:
readelf -Ws libaws-cpp-sdk-core.a | grep AmazonSerializableWebServiceRequest7GetBodyEv
165: 0000000000000000 716 FUNC GLOBAL DEFAULT 42 _ZNK3Aws35AmazonSerializableWebServiceRequest7GetBodyEv
Symbol is defined in libaws-cpp-sdk-core.a which is part of the compilation command for mod_polly.cpp
#Sam V - turns out it was ordering issue while building. Change in ordering of build command to
g++ -shared -o mod_polly.so -fPIC -g -ggdb -std=c++11 -Wall -Werror -I/usr/src/freeswitch/src/include/ -I/usr/src/freeswitch/libs/libteletone/src/ mod_polly.cpp -L/usr/local/lib/ -laws-cpp-sdk-polly -laws-cpp-sdk-core
fixed the problem. Your 1st comment was the key. Thanks.
I'm trying to find all paths through a given network of activities and thought that I could do so using recursion. It is much like traversing through a network drive with different folders and sub-folders.
I have defined an activity class (for storing each activity's properties) and a network class (for storing the network's activities). I'm passing the network object as a parameter to the recursive function call. The recursive function does not work as expected. It gives a segmentation fault and seems not to be able to access the network object properly.
Can someone point me in the right direction on how to solve this (and how I could also store the found paths in a 2 dimensional array).
Here is the code:
#include <iostream>
using namespace std;
class Activity {
public:
int id;
double duration;
int successors[10];
};
class Network {
public:
Activity activities[];
};
int traverse(int, Network);
int main()
{
// define the set of successors for each activity
// a value of -1 indicates that no more successors are present
const int successorset[][5] = {
{ 1,2,3,-1 },
{ 5,-1 },
{ 4,-1 },
{ 4,-1 },
{ 5,-1 },
{ -1},
};
// two dimensional array where for each path the activity ids are stored
int pathset [10][10];
// declare activities
Activity Activity0, Activity1, Activity2, Activity3, Activity4, Activity5;
// declare network
Network NetworkMain;
// define activity 0
Activity0.id = 0;
Activity0.duration = 0;
Activity0.successors[0] = successorset[0][0];
Activity0.successors[1] = successorset[0][1];
Activity0.successors[2] = successorset[0][2];
Activity0.successors[3] = successorset[0][3];
NetworkMain.activities[0] = Activity0;
// define activity 1
Activity1.id = 1;
Activity1.duration = 3;
Activity1.successors[0] = successorset[1][0];
Activity1.successors[1] = successorset[1][1];
NetworkMain.activities[1] = Activity1;
// define activity 2
Activity2.id = 2;
Activity2.duration = 1;
Activity2.successors[0] = successorset[2][0];
Activity2.successors[1] = successorset[2][1];
NetworkMain.activities[2] = Activity2;
// define activity 3
Activity3.id = 3;
Activity3.duration = 2;
Activity3.successors[0] = successorset[3][0];
Activity3.successors[1] = successorset[3][1];
NetworkMain.activities[3] = Activity3;
// define activity 4
Activity4.id = 4;
Activity4.duration = 4;
Activity4.successors[0] = successorset[4][0];
Activity4.successors[1] = successorset[4][1];
NetworkMain.activities[4] = Activity4;
// define activity 5
Activity5.id = 5;
Activity5.duration = 0;
Activity5.successors[0] = successorset[5][0];
NetworkMain.activities[5] = Activity5;
// print info on all activities to check whether they are defined correctly
for( int a = 0; a < 6; a++ ) {
cout << "id of activity = " << NetworkMain.activities[a].id << endl;
cout << "duration of activity = " << NetworkMain.activities[a].duration << endl;
int s = 0;
while (NetworkMain.activities[a].successors[s]!=-1) {
cout << "successor of activity " << a << " = " << NetworkMain.activities[a].successors[s] << endl;
s++;
}
}
// call recursive function to traverse through all paths of the network
traverse(0, NetworkMain);
return 0;
}
int traverse(int id, Network net)
{
if (net.activities[id].successors[0]==-1) // reached finish activity
{
cout << "reached finish " << endl;
return 1;
}
else
{
cout << "id of activity under investigation " << net.activities[id].id << endl;
int t = 0;
while (net.activities[id].successors[t]!=-1) {
cout << "going to investigate successor " << t << endl;
traverse(net.activities[id].successors[t], net);
t++;
}
}
}
Here is the output:
id of activity = 0
duration of activity = 0
successor of activity 0 = 1
successor of activity 0 = 2
successor of activity 0 = 3
id of activity = 1
duration of activity = 3
successor of activity 1 = 5
id of activity = 2
duration of activity = 1
successor of activity 2 = 4
id of activity = 3
duration of activity = 2
successor of activity 3 = 4
id of activity = 4
duration of activity = 4
successor of activity 4 = 5
id of activity = 5
duration of activity = 0
id of activity under investigation -578861888
going to investigate successor 0
id of activity under investigation 0
going to investigate successor 0
id of activity under investigation -581127744
going to investigate successor 0
Segmentation fault (core dumped)
Process returned 139 (0x8B) execution time : 0.087 s
Press ENTER to continue.
Edit: should have added the newbie alert, below is the debugger output.
Active debugger config: GDB/CDB debugger:Default
Building to ensure sources are up-to-date
Selecting target:
Debug
Adding source dir: /home/home/Desktop/recursion/
Adding source dir: /home/home/Desktop/recursion/
Adding file: /home/home/Desktop/recursion/bin/Debug/recursion
Changing directory to: /home/home/Desktop/recursion/.
Set variable: LD_LIBRARY_PATH=.:
[debug]Command-line: /usr/bin/gdb -nx -fullname -quiet -args /home/home/Desktop/recursion/bin/Debug/recursion
[debug]Working dir : /home/home/Desktop/recursion
Starting debugger: /usr/bin/gdb -nx -fullname -quiet -args /home/home/Desktop/recursion/bin/Debug/recursion
done
[debug]Reading symbols from /home/home/Desktop/recursion/bin/Debug/recursion...done.
[debug](gdb)
[debug]> set prompt >>>>>>cb_gdb:
Registered new type: wxString
Registered new type: STL String
Registered new type: STL Vector
Setting breakpoints
[debug]>>>>>>cb_gdb:
[debug]> show version
[debug]GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
[debug]Copyright (C) 2016 Free Software Foundation, Inc.
[debug]License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
[debug]This is free software: you are free to change and redistribute it.
[debug]There is NO WARRANTY, to the extent permitted by law. Type "show copying"
[debug]and "show warranty" for details.
[debug]This GDB was configured as "x86_64-linux-gnu".
[debug]Type "show configuration" for configuration details.
[debug]For bug reporting instructions, please see:
[debug]<http://www.gnu.org/software/gdb/bugs/>.
[debug]Find the GDB manual and other documentation resources online at:
[debug]<http://www.gnu.org/software/gdb/documentation/>.
[debug]For help, type "help".
[debug]Type "apropos word" to search for commands related to "word".
[debug]>>>>>>cb_gdb:
[debug]> set confirm off
Debugger name and version: GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
[debug]>>>>>>cb_gdb:
[debug]> set width 0
[debug]>>>>>>cb_gdb:
[debug]> set height 0
[debug]>>>>>>cb_gdb:
[debug]> set breakpoint pending on
[debug]>>>>>>cb_gdb:
[debug]> set print asm-demangle on
[debug]>>>>>>cb_gdb:
[debug]> set unwindonsignal on
[debug]>>>>>>cb_gdb:
[debug]> set print elements 0
[debug]>>>>>>cb_gdb:
[debug]> set disassembly-flavor intel
[debug]>>>>>>cb_gdb:
[debug]> catch throw
[debug]Catchpoint 1 (throw)
[debug]>>>>>>cb_gdb:
[debug]> source /usr/share/codeblocks/scripts/stl-views-1.0.3.gdb
[debug]>>>>>>cb_gdb:
[debug]> directory /home/home/Desktop/recursion/
[debug]Source directories searched: /home/home/Desktop/recursion:$cdir:$cwd
[debug]>>>>>>cb_gdb:
[debug]Using terminal's PID as console PID 13148, TTY /dev/pts/1
[debug]> tty /dev/pts/1
[debug]Queued:[tty /dev/pts/1]
[debug]>>>>>>cb_gdb:
[debug]> run
[debug]Starting program: /home/home/Desktop/recursion/bin/Debug/recursion
[debug]Program received signal SIGSEGV, Segmentation fault.
[debug]0x0000000000400ee9 in traverse (id=-140179936, net=...) at /home/home/Desktop/recursion/main.cpp:103
[debug]/home/home/Desktop/recursion/main.cpp:103:2808:beg:0x400ee9
[debug]>>>>>>cb_gdb:
Program received signal SIGSEGV, Segmentation fault.
At /home/home/Desktop/recursion/main.cpp:103
[debug]> bt 30
[debug]#0 0x0000000000400ee9 in traverse (id=-140179936, net=...) at /home/home/Desktop/recursion/main.cpp:103
[debug]#1 0x0000000000400ff1 in traverse (id=0, net=...) at /home/home/Desktop/recursion/main.cpp:114
[debug]#2 0x0000000000400ff1 in traverse (id=6, net=...) at /home/home/Desktop/recursion/main.cpp:114
[debug]#3 0x0000000000400ff1 in traverse (id=0, net=...) at /home/home/Desktop/recursion/main.cpp:114
[debug]#4 0x0000000000400e91 in main () at /home/home/Desktop/recursion/main.cpp:96
[debug]>>>>>>cb_gdb:
Seemingly a newbie mistake, I had to declare the size of the activities array to make room for it in the computer's memory.
Incorrect:
class Network {
public:
Activity activities[];
};
Correct:
class Network {
public:
Activity activities[6]; // given 6 activities
};
Thanks all for your help.
Learning about the /proc/ directory today, in particular I'm interested in the security implications of having all the information about a process semi-publicly available, so I wrote a simple program that does some simple whatnot that allows me to explore some properties of the /proc/ directory:
#include <iostream>
#include <unistd.h>
#include <fcntl.h>
using namespace std;
extern char** environ;
void is_linux() {
#ifdef __linux
cout << "this is running on linux" << endl;
#endif
}
int main(int argc, char* argv[]) {
is_linux();
cout << "hello world" << endl;
int fd = open("afile.txt", O_RDONLY | O_CREAT, 0600);
cout << "afile.txt open on: " << fd << endl;
cout << "current pid: " << getpid() << endl;;
cout << "launch arguments: " << endl;
for (int index = 0; index != argc; ++index) {
cout << argv[index] << endl;
}
cout << "program environment: " << endl;
for (char** entry = environ; *entry; ++entry) {
cout << *entry << endl;
}
pause();
}
Interestingly though (to me anyway), when I check the file-descriptors folder (/pid/<PID#>/fd), I see this:
root#excalibur-VirtualBox:/proc/1546/fd# ls -l
total 0
lrwx------ 1 root root 64 Nov 7 09:12 0 -> /dev/null
lrwx------ 1 root root 64 Nov 7 09:12 1 -> /dev/null
lrwx------ 1 root root 64 Nov 7 09:12 2 -> /dev/null
lrwx------ 1 root root 64 Nov 7 09:12 3 -> socket:[11050]
why do the file descriptors point to /dev/null? Is that to prevent user's from being able to inject content into a file without actually being the process itself, or am I off base on that? And even more curious, why does the file descriptor to an open file point to a socket? That seems really odd. If anyone can shed some light on this for me, I would really appreciate it. Thanks!
You are definitely looking at the wrong /proc directory (for other PID or on another computer). The contents of /proc/<pid>/fd for your program should look like here:
lrwx------ 1 user group 64 Nov 7 22:15 0 -> /dev/pts/4
lrwx------ 1 user group 64 Nov 7 22:15 1 -> /dev/pts/4
lrwx------ 1 user group 64 Nov 7 22:15 2 -> /dev/pts/4
lr-x------ 1 user group 64 Nov 7 22:15 3 -> /tmp/afile.txt
Here we can see that file descriptors 0, 1, and 2 are shown as symbolic links to the pseudo terminal in which the program is running. It could be /dev/null if you started your program with input, output, and error redirection. The file descriptor #3 points to the file afile.txt which is currently opened.