Witam po raz kolejny z nowym wyzwaniem...
Ogolnie mam za zadanie wykonac taka "skrzyneczke" - przerobic w sumie kod podany ponizej - :
<-open,
<-close,
<-record start,
<-record stop,
<-play.
Ogolnie czuje sie zle - zostalem wrzucony na glebokie wody przez ignorancje niektorych... nieistotne, mam nadzieje, ze uronicie conieco ze swej wiedzy...
Trzeba to przerobic "na ALSA-e"... Przynajmniej tak zrozumialem.
Ogolnie mam za zadanie wykonac taka "skrzyneczke" - przerobic w sumie kod podany ponizej - :
<-open,
<-close,
<-record start,
<-record stop,
<-play.
Ogolnie czuje sie zle - zostalem wrzucony na glebokie wody przez ignorancje niektorych... nieistotne, mam nadzieje, ze uronicie conieco ze swej wiedzy...
#include "soundLayer.h"
#include <sys/ioctl.h>
#include <unistd.h>
#include <sys/fcntl.h>
#include <sys/soundcard.h>
#include <string.h>
#include "datapacket.h"
#include "soundDeviceMsg.h"
#include "libs/slog.h"
soundLayer::soundLayer(abstractScheduler* _sched)
: abstractAudioLayer(_sched)
{
name = "soundLayer";
}
soundLayer::~soundLayer()
{
if (audio_fd>0)
close(audio_fd);
}
char soundLayer::openToPlay()
{
if (_record) {
slog(Slog::levelWarning)<<name<<": Device is occupied\n";
return (-1);
}
slog(Slog::levelDebug)<<name<<": opening device to Play\n";
// we should enqueue this ..
int open_mode = O_WRONLY;
// std::cerr<<"opening device\n";
if ((audio_fd = open(devName.c_str(), open_mode, 0)) == -1) {
/* Opening device failed */
perror(devName.c_str());
return(-1);
}
// set audio sampling format: 16 bit signed:
int format = AFMT_S16_LE;
if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1)
perror("can't set soundcard format");
// frequency is 8kHz
// left out - hope sc will take default value
int arg = 0x7fff0009; // 256 Byte packets
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &arg))
perror("setting dsp fragment failed");
// play nothing ...
int size = startBufferSize;
char zero[size];
bzero(zero,size);
// std::cerr <<"write nothing";
if (write(audio_fd, zero , size) == -1) {
perror("audio write");
return(-1);
}
_play = 4;
return(0);
}
char soundLayer::closePlay()
{
_play = 0;
if (audio_fd > 0) {
close(audio_fd);
audio_fd = -1;
return(0);
}
return(-1); // device was not open
}
void soundLayer::initSchedule()
{
Event to1(SignalID::timeout, timerWait+getTics());
setEvent(to1);
}
void soundLayer::timerHandler(Event e)
{
if (_play)
_play--;
if ((!_play) && (!_record) && (audio_fd > 0)) {
slog(Slog::levelDebug)<<name<<": closing audio device (playing)\n";
closePlay();
}
Event to1(SignalID::timeout, timerWait+getTics());
setEvent(to1);
}
void soundLayer::upperQueueHandler(Event e)
{
if (!_play) {
slog(Slog::levelDebug)<<name<<"start playing\n";
if (openToPlay() < 0)
return; // packets will be queued until next call - not nice
}
while(!UpperQueue_empty()){
transferItem tr(getFromUpper());
tr.dec_layer();
datapacket* pack = GETIPACKTYPE(datapacket*,tr);
slog(Slog::levelDebug)<<"p";
if (write(audio_fd, pack->getData(), pack->getBodyLength()) == -1) {
perror("audio write failed");
continue;
}
_play = 2; //pack->getBodyLength()/7650;
}
}
void soundLayer::descHandler(Event e)
{
if (!_record)
return;
audio_buf_info info;
ioctl(audio_fd, SNDCTL_DSP_GETISPACE, &info);
if (info.bytes == 0) {
// slog(Slog::levelWarning)<<"we are called with no data available!?\n";
return;
}
// where will this packet be deleted?
char* sample = new char[info.bytes+2];
int size;
// std::cerr<<"space: "<<info.bytes<<" ";
if ((size = read(audio_fd, sample+2, info.bytes)) <= 0) {
perror("audio read failed");
delete sample;
return;
}
*((unsigned short*)(sample)) = (unsigned short) size;
// adjust record level, if this is a bullshit windows driver only card
if (recordLevel) {
unsigned short* adjustSamples = (unsigned short*) sample+2;
for(unsigned int i=0; i < (unsigned int)(info.bytes/2); ++i)
adjustSamples[i] = adjustSamples[i] << recordLevel; // exponential level
}
transferItem tr;
tr.setdata(new ICI(0,0,size,2,false));
tr.setRaw(sample,size+2);
slog(Slog::levelDebug)<<"r";
Layer* to = UpperLayer.findLayer();
// tr.getItem()->print();
if (to)
to->transferFromLower(tr,0);
}
char soundLayer::openToRecord()
{
if (_play) {
slog(Slog::levelWarning)<<name<<": can't record -> device is occupied\n";
return (-1);
}
slog(Slog::levelDebug)<<name<<": opening device to Record\n";
// just open the device and wait for the samples
int open_mode = O_RDONLY;
if ((audio_fd = open(devName.c_str(), open_mode, 0)) == -1) {
/* Opening device failed */
perror(devName.c_str());
return (-1);
}
// set audio sampling format: 16 bit signed:
int format = AFMT_S16_LE;
if (ioctl(audio_fd, SNDCTL_DSP_SETFMT, &format) == -1)
perror("can't set soundcard format");
int arg = 0x7fff0009;
if (ioctl(audio_fd, SNDCTL_DSP_SETFRAGMENT, &arg)) {
perror("dsp fragment failed");
return (-2);
}
// tell scheduler, that we want to be informed on soundcard events
sched->add_select(this, audio_fd);
_record = 1;
return (0);
}
char soundLayer::closeRecord()
{
if (_record) {
_record = 0;
if (audio_fd > 0) {
slog(Slog::levelDebug)<<name<<": closing audioDevice (recording)\n";
sched->del_select(audio_fd);
close(audio_fd);
audio_fd = -1;
}
else
return(-1);
}
else
return (-1);
return(0);
}
void soundLayer::controlPlaneMsgHandler(controlMsg& msg)
{
/**** start/stop recording *******/
if (msg.getName() == "Record") {
RecordMsg* am = dynamic_cast<RecordMsg*>(&msg);
if (am && (am->status == RecordMsg::start))
openToRecord();
else
if (am && (am->status == RecordMsg::stop))
closeRecord();
else
slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
}
/**** close soundcard for playing *******/
if (msg.getName() == "closePlay") {
closePlayMsg* am = dynamic_cast<closePlayMsg*>(&msg);
if (am)
closePlay();
else
slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
}
/**** set record level ******/
if (msg.getName() == "setRecordLevel") {
recordLevelMsg* am = dynamic_cast<recordLevelMsg*>(&msg);
if (am){
if (am->recordLevel < 5)
recordLevel = am->recordLevel;
}
else
slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
}
/**** set record device ******/
if (msg.getName() == "setDevice") {
setDeviceMsg* am = dynamic_cast<setDeviceMsg*>(&msg);
if (am)
setDeviceName(am->device);
else
slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
}
/**** request availabel byte for output *****/
if (msg.getName() == "getOutBufferSize") {
bufferInfoMsg* bi = dynamic_cast<bufferInfoMsg*>(&msg);
if (bi) {
audio_buf_info info;
if (audio_fd <= 0) {
int open_mode = O_RDONLY;
int afd;
if ((afd = open(devName.c_str(), open_mode, 0)) == -1) {
/* Opening device failed */
//perror(devName.c_str());
bi->size = 0;
return;
}
else {
ioctl(afd, SNDCTL_DSP_GETOSPACE, &info);
close(afd);
}
}
else // audio_fd is set!
ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &info);
bi->size = info.bytes;
slog(Slog::levelDebug)<<"bytes = "<<(int) info.bytes<<oendl;
}
else
slog(Slog::levelWarning)<<name<<": wrong control message type;\n";
}
}
Trzeba to przerobic "na ALSA-e"... Przynajmniej tak zrozumialem.