我尝试在boost容器中保存一个char *,但它失败了。我的char *是2048个内存块的二进制数据。这些二进制数据是用ALSA记录的声音 但是当我将它保存在共享内存字符串的向量中时,它会以某种方式变异,我无法弄清楚如何修复它。
编辑并可能回答:
ALSA发送void * buffers,所以如果我可以创建一个void *的共享内存向量,我可以做到这一点。所以我基本上需要创建一个void *的向量,每个void *必须是大小固定的(在这种情况下:2048)。我认为boost::interprocess::basic_string
是问题
结束修改
这里有完整的解释:
我正在尝试使用ALSA通过程序直接输入声音,然后使用其他程序将其写入文件(或处理任何内容)
我从这个问题开始:Create a shared-memory vector of strings
现在我被困住了,我不知道提升得很好。 我已经用完整的项目创建了一个github(https://github.com/Waxo/nodetest)。使用方法listen使用回调的Alsa控件只需使用(char *,int)原型调用方法。
构建项目后,您可以在./nodetest
说“开始”时启动./nodetest arg
和./nodetest
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <iostream>
#include <atomic>
#include <future>
#include <iostream>
#include <alsa_control.h>
using std::cout;
using std::endl;
typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> MyShmString;
typedef boost::interprocess::allocator<MyShmString, boost::interprocess::managed_shared_memory::segment_manager> StringAllocator;
typedef boost::interprocess::vector<MyShmString, StringAllocator> MyShmStringVector;
class lambda_class {
public:
void lambda_callback(char *c, int rc) {
this->sample_count_ += rc;
this->output_file_.write(c, rc * 2);
}
lambda_class(std::string filename) {
this->filename_ = filename;
this->sample_count_ = 0;
this->output_file_.open(this->filename_, std::ios::binary);
write_header_wav(this->output_file_, 16000, 16, MONO, 10000);
}
~lambda_class() {
this->output_file_.close();
this->output_file_.open(this->filename_,
std::ios::binary | std::ios::in);
write_header_wav(this->output_file_, 16000, 16, MONO, this->sample_count_);
}
private:
std::string filename_;
int sample_count_;
std::ofstream output_file_;
lambda_class(const lambda_class &a) = delete;
};
class input_class {
public:
input_class() {
boost::interprocess::shared_memory_object::remove("MySharedMemory");
this->shm = new boost::interprocess::managed_shared_memory(boost::interprocess::create_only, "MySharedMemory",
1000000);
CharAllocator charallocator(this->shm->get_segment_manager());
StringAllocator stringallocator(this->shm->get_segment_manager());
this->myshmvector = shm->construct<MyShmStringVector>("myshmvector")(stringallocator);
};
~input_class() {
lambda_class *lc = new lambda_class("listener_vector.wav");
char *c = (char *) malloc(2048);
for (MyShmStringVector::iterator it = this->myshmvector->begin(); it != this->myshmvector->end(); it++) {
strcpy(c, it->c_str());
lc->lambda_callback(c, 2048);
}
delete lc;
boost::interprocess::shared_memory_object::remove("MySharedMemory");
this->shm->destroy_ptr(this->myshmvector);
}
void to_node(char *c, int rc) {
CharAllocator charallocator(this->shm->get_segment_manager());
StringAllocator stringallocator(this->shm->get_segment_manager());
MyShmString mystring(charallocator);
mystring = c;
this->myshmvector->insert(this->myshmvector->begin(), mystring);
}
private:
boost::interprocess::managed_shared_memory *shm;
MyShmStringVector *myshmvector;
};
void listener() {
lambda_class *ctc = new lambda_class("writer.wav");
char *c = (char *) malloc(2048);
boost::interprocess::managed_shared_memory segment(boost::interprocess::open_only, "MySharedMemory");
MyShmStringVector *myvector = segment.find<MyShmStringVector>("myshmvector").first;
for (MyShmStringVector::iterator it = myvector->begin(); it != myvector->end(); it++) {
strcpy(c, std::string(it->begin(), it->end()).c_str());
ctc->lambda_callback(c, 2048);
}
delete ctc;
return;
}
int main(int argc, char **argv) {
alsa_control *ac = new alsa_control(16000, 2048, 16, MONO);
if (argc == 1) {
input_class *ic = new input_class();
ac->listen_with_callback(std::bind(&input_class::to_node, ic, std::placeholders::_1, std::placeholders::_2),
"listener");
sleep(5);
ac->stop();
cout << "Go" << endl;
sleep(10);
delete ic;
delete ac;
} else {
auto th = std::async(std::launch::async, listener);
th.get();
}
return 0;
}
我只是想在多个过程中使用我的声音,我可以使用和分享它的结构(我将为我的所有程序创建和组织)。 char *可以有一个固定的大小,如果我可以使用它,这一切都很好。
编辑:
我的问题是录制的声音:
无效,我认为MyShmString将它们变为无效的二进制数据。
答案 0 :(得分:1)
我还没有检查过你的代码墙,但在你的问题中,我注意到你说:
我尝试在提升容器中保存一个char *
然后
我的char *是二进制数据
然后
我认为boost :: interprocess :: basic_string是问题
现在,如果您指定的是确切的类型而不仅仅是说&#34; boost container&#34;那么它会有所帮助。 - 哪个容器,但如果您尝试在字符串类中存储二进制数据 - NOOOOOOO,那不是您使用字符串的方式。您将文本存储在字符串中,而非二进制数据。对于二进制数据,请使用std::vector<char>
。
特别是,如果你在代码中的任何地方使用类似的东西
string s = (char*) binary_data;
字符串将在第一次遇到零时被截断!
答案 1 :(得分:1)
除了其他人一直在说的话,
您的样本中有错误 - &gt;字节数转换。这导致一半的输出是未初始化的数据
void lambda_callback(char *c, int rc) {
this->sample_count_ += rc;
this->output_file_.write(c, rc * 2);
}
变为
void lambda_callback(char *c, int rc) {
this->sample_count_ += rc/2;
this->output_file_.write(c, rc);
}
注意另请参阅下面
rc*2
中的to_node
您将字符串插入前面的 - 这会导致音频块以相反的顺序输出。此外,mystring
的分配忽略了rc
信息
void to_node(char *c, int rc) {
CharAllocator charallocator(this->shm->get_segment_manager());
StringAllocator stringallocator(this->shm->get_segment_manager());
MyShmString mystring(charallocator);
mystring = c; // OOPS! this cuts off at any NUL char
this->myshmvector->insert(this->myshmvector->begin(), mystring);
}
变为
void to_node(char *c, int rc) {
_myshmvector->emplace_back(c, rc*2, shm->get_segment_manager());
}
而不是依赖于固定的缓冲区大小,实际上在迭代共享向量时应该使用字符串大小。除外,不要将strcpy
用于二进制数据:
void listener() {
lambda_class ctc("writer.wav");
char *c = (char *) malloc(2048);
boost::interprocess::managed_shared_memory segment(boost::interprocess::open_only, "MySharedMemory");
MyShmStringVector *myvector = segment.find<MyShmStringVector>("myshmvector").first;
for (MyShmStringVector::iterator it = myvector->begin(); it != myvector->end(); it++) {
//strcpy(c, std::string(it->begin(), it->end()).c_str()); //HUHUH!?!
strcpy(c, it->c_str());
ctc.lambda_callback(c, 2048);
}
}
变为:
void listener() {
lambda_class ctc("writer.wav");
char c[4096];
boost::interprocess::managed_shared_memory segment(boost::interprocess::open_only, "MySharedMemory");
MyShmStringVector *myvector = segment.find<MyShmStringVector>("myshmvector").first;
for (MyShmStringVector::iterator it = myvector->begin(); it != myvector->end(); it++) {
//strcpy(c, std::string(it->begin(), it->end()).c_str()); //HUHUH!?!
assert(it->size()<=sizeof(c));
memcpy(c, it->c_str(), it->size());
ctc.lambda_callback(c, it->size());
}
}
在c ++中不要malloc
。你有那些泄露的
你的测试场景很活泼(但我想你知道这一点,这是为了简单起见吗?)
而不是“魔术”文件重新打开,只需seekp
:
this->output_file_.close();
this->output_file_.open(this->filename_, std::ios::binary | std::ios::in);
成为
output_file_.seekp(0ul);
<强> Pull Request on GitHub 强>
commit 660208ff3fe792112ccae70a61e8a2442a853664
Author: Seth Heeren <sgheeren@gmail.com>
Date: Mon Aug 17 00:13:31 2015 +0200
Fixes, now
./nodetest & sleep 6; ./nodetest 1; fg; md5sum *.wav
results in proper identical files, e.g.
$ ./nodetest & sleep 6; ./nodetest 1; fg; md5sum *.wav
[1] 12350
Go
./nodetest
ff083a6344d7037da9c4f6d730239f30 listener_vector.wav
ff083a6344d7037da9c4f6d730239f30 listener.wav
ff083a6344d7037da9c4f6d730239f30 writer.wav
commit 04a5dec3da322dab196bfe568f52db6d9ed68b43
Author: Seth Heeren <sgheeren@gmail.com>
Date: Sun Aug 16 23:30:40 2015 +0200
we have repro
main.cc
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <iostream>
#include <atomic>
#include <future>
#include <iostream>
#include <alsa_control.h>
using std::cout;
using std::endl;
typedef boost::interprocess::allocator<char, boost::interprocess::managed_shared_memory::segment_manager> CharAllocator;
typedef boost::interprocess::basic_string<char, std::char_traits<char>, CharAllocator> MyShmString;
typedef boost::interprocess::allocator<MyShmString, boost::interprocess::managed_shared_memory::segment_manager> StringAllocator;
typedef boost::interprocess::vector<MyShmString, StringAllocator> MyShmStringVector;
class lambda_class {
public:
void lambda_callback(char *c, int rc) {
this->sample_count_ += rc/2;
this->output_file_.write(c, rc);
}
lambda_class(std::string filename) {
this->filename_ = filename;
this->sample_count_ = 0;
this->output_file_.open(this->filename_, std::ios::binary);
write_header_wav(this->output_file_, 16000, 16, MONO, 10000);
}
~lambda_class() {
/*
*this->output_file_.close();
*this->output_file_.open(this->filename_, std::ios::binary | std::ios::in);
*/
output_file_.seekp(0ul);
write_header_wav(this->output_file_, 16000, 16, MONO, this->sample_count_);
}
private:
std::string filename_;
int sample_count_;
std::ofstream output_file_;
lambda_class(const lambda_class &a) = delete;
};
class input_class {
public:
input_class() {
boost::interprocess::shared_memory_object::remove("MySharedMemory");
this->shm = new boost::interprocess::managed_shared_memory(boost::interprocess::create_only, "MySharedMemory",
1000000);
CharAllocator charallocator(this->shm->get_segment_manager());
StringAllocator stringallocator(this->shm->get_segment_manager());
this->myshmvector = shm->construct<MyShmStringVector>("myshmvector")(stringallocator);
};
~input_class() {
lambda_class lc("listener_vector.wav");
char c[4096];
for (MyShmStringVector::iterator it = this->myshmvector->begin(); it != this->myshmvector->end(); it++) {
assert(it->size()<=sizeof(c));
memcpy(c, it->c_str(), it->size());
lc.lambda_callback(c, it->size());
}
boost::interprocess::shared_memory_object::remove("MySharedMemory");
shm->destroy_ptr(this->myshmvector);
}
void to_node(char *c, int rc) {
this->myshmvector->emplace_back(c, rc*2, shm->get_segment_manager());
}
private:
boost::interprocess::managed_shared_memory *shm;
MyShmStringVector *myshmvector;
};
void listener() {
lambda_class ctc("writer.wav");
char c[4096];
boost::interprocess::managed_shared_memory segment(boost::interprocess::open_only, "MySharedMemory");
MyShmStringVector *myvector = segment.find<MyShmStringVector>("myshmvector").first;
for (MyShmStringVector::iterator it = myvector->begin(); it != myvector->end(); it++) {
//strcpy(c, std::string(it->begin(), it->end()).c_str()); //HUHUH!?!
assert(it->size()<=sizeof(c));
memcpy(c, it->c_str(), it->size());
ctc.lambda_callback(c, it->size());
}
}
int main(int argc, char **argv) {
alsa_control ac(16000, 2048, 16, MONO);
if (argc == 1) {
input_class ic;
ac.listen_with_callback(std::bind(&input_class::to_node, &ic, std::placeholders::_1, std::placeholders::_2), "listener");
sleep(5);
ac.stop();
cout << "Go" << endl;
sleep(10);
} else {
// std::atomic<bool> done(false);
auto th = std::async(std::launch::async, listener);
// done.store(true, std::memory_order_relaxed);
th.get();
}
return 0;
}
答案 2 :(得分:-1)
问题不明确,所以我建议改进问题。
尽管如此,我发现您的代码中存在错误: 您为数组分配了2048个元素
char *c = (char *) malloc(2048);
然后你在lambda_callback()
中写两次 void lambda_callback(char *c, int rc) {
this->sample_count_ += rc;
this->output_file_.write(c, rc * 2);
}
您需要将 rc 而不是 rc * 2 传递给write();