work on bypass-audio.

CALLSTATUS monitor message has gained a field, thus changing
API for java side.
This commit is contained in:
gardners 2012-05-11 08:00:09 +09:30
parent c29f210e91
commit 7b82ccbd7b
9 changed files with 151 additions and 64 deletions

View File

@ -71,7 +71,8 @@ LOCAL_SRC_FILES:= \
serval-dna/codecs.c \ serval-dna/codecs.c \
serval-dna/audiodevices.c \ serval-dna/audiodevices.c \
serval-dna/audio_msm_g1.c \ serval-dna/audio_msm_g1.c \
serval-dna/audio_alsa.c serval-dna/audio_alsa.c \
serval-dna/audio_reflector.c
LOCAL_MODULE:= serval LOCAL_MODULE:= serval

View File

@ -44,7 +44,8 @@ SRCS= batman.c \
codecs.c \ codecs.c \
audiodevices.c \ audiodevices.c \
audio_msm_g1.c \ audio_msm_g1.c \
audio_alsa.c audio_alsa.c \
audio_reflector.c
HAVE_VOIPTEST= @HAVE_VOIPTEST@ HAVE_VOIPTEST= @HAVE_VOIPTEST@
ifeq ($(HAVE_VOIPTEST), 1) ifeq ($(HAVE_VOIPTEST), 1)

View File

@ -18,7 +18,13 @@
#include "serval.h" #include "serval.h"
#ifdef HAVE_ALSA_ASOUNDLIB_H #ifndef HAVE_ALSA_ASOUNDLIB_H
/* XXX Android NDK lacks the header files needed to build this.
Will deal with it later */
monitor_audio *audio_alsa_detect() {
return NULL;
}
#else
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -40,7 +46,7 @@
necessary symbols we need. necessary symbols we need.
*/ */
typedef struct alsa_functions { typedef struct alsa_functions {
int (*snd_pcm_open)(snd_pcm_t **,char *,int,int); int (*snd_pcm_open_preferred)(snd_pcm_t **,int *,int *,int);
int (*snd_pcm_close)(snd_pcm_t *); int (*snd_pcm_close)(snd_pcm_t *);
int (*snd_pcm_hw_params_malloc)(snd_pcm_hw_params_t **); int (*snd_pcm_hw_params_malloc)(snd_pcm_hw_params_t **);
int (*snd_pcm_hw_params_any)(snd_pcm_t *,snd_pcm_hw_params_t *); int (*snd_pcm_hw_params_any)(snd_pcm_t *,snd_pcm_hw_params_t *);
@ -63,10 +69,12 @@ alsa_functions *alsa = NULL;
int alsa_load() int alsa_load()
{ {
WHY("Trying to load ALSA library");
void *h = dlopen(ALSA_LIB_PATH,RTLD_LAZY); void *h = dlopen(ALSA_LIB_PATH,RTLD_LAZY);
if (!h) h=dlopen("/usr/lib/i386-linux-gnu/libasound.so.2",RTLD_LAZY);
if (!h) return -1; if (!h) return -1;
alsa_functions *a=calloc(sizeof(alsa_functions),1); alsa_functions *a=calloc(sizeof(alsa_functions),1);
GETSYM(snd_pcm_open); GETSYM(snd_pcm_open_preferred);
GETSYM(snd_pcm_hw_params_malloc); GETSYM(snd_pcm_hw_params_malloc);
GETSYM(snd_pcm_hw_params_any); GETSYM(snd_pcm_hw_params_any);
GETSYM(snd_pcm_hw_params_set_access); GETSYM(snd_pcm_hw_params_set_access);
@ -81,7 +89,8 @@ int alsa_load()
GETSYM(snd_pcm_poll_descriptors); GETSYM(snd_pcm_poll_descriptors);
alsa=a; alsa=a;
dlclose(h); dlclose(h);
WHY("Loaded ALSA library");
return 0; return 0;
} }
@ -120,8 +129,8 @@ int audio_alsa_start_play()
record_params=NULL; play_params=NULL; record_params=NULL; play_params=NULL;
/* Open playback device */ /* Open playback device */
r = alsa->snd_pcm_open (&play_handle,"default",SND_PCM_STREAM_PLAYBACK, r = alsa->snd_pcm_open_preferred (&play_handle,NULL,NULL,
SND_PCM_NONBLOCK); SND_PCM_STREAM_PLAYBACK|SND_PCM_NONBLOCK);
if (r) { WHYF("ALSA pcm_open() failed"); goto error; } if (r) { WHYF("ALSA pcm_open() failed"); goto error; }
/* Configure playback device for 8000Hz, 16 bit, mono */ /* Configure playback device for 8000Hz, 16 bit, mono */
@ -157,8 +166,8 @@ int audio_alsa_start_play()
int audio_alsa_start_record() int audio_alsa_start_record()
{ {
/* Open recording device non-blocking */ /* Open recording device non-blocking */
int r = alsa->snd_pcm_open (&record_handle,"default",SND_PCM_STREAM_CAPTURE, int r = alsa->snd_pcm_open_preferred(&record_handle,NULL,NULL,
SND_PCM_NONBLOCK); SND_PCM_STREAM_CAPTURE|SND_PCM_NONBLOCK);
if (r) { WHYF("ALSA pcm_open() failed"); goto error; } if (r) { WHYF("ALSA pcm_open() failed"); goto error; }
/* Configure playback device for 8000Hz, 16 bit, mono */ /* Configure playback device for 8000Hz, 16 bit, mono */
@ -243,25 +252,23 @@ int audio_alsa_write(unsigned char *buffer,int bytes)
else return 0; else return 0;
} }
#endif // HAVE_ALSA_ASOUNDLIB_H
monitor_audio *audio_alsa_detect() monitor_audio *audio_alsa_detect()
{ {
#ifdef HAVE_ALSA_ASOUNDLIB_H
if (!alsa) alsa_load(); if (!alsa) alsa_load();
if (!alsa) return NULL; if (!alsa) return NULL;
snd_pcm_t *handle; snd_pcm_t *handle;
if (alsa->snd_pcm_open (&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) != -1) { if (alsa->snd_pcm_open_preferred(&handle,NULL,NULL,SND_PCM_STREAM_PLAYBACK) < 0)
alsa->snd_pcm_close(handle); return NULL;
monitor_audio *au=calloc(sizeof(monitor_audio),1); alsa->snd_pcm_close(handle);
strcpy(au->name,"ALSA compatible");
au->start=audio_alsa_start; monitor_audio *au=calloc(sizeof(monitor_audio),1);
au->stop=audio_alsa_stop; strcpy(au->name,"ALSA compatible");
au->poll_fds=audio_alsa_pollfds; au->start=audio_alsa_start;
au->read=audio_alsa_read; au->stop=audio_alsa_stop;
au->write=audio_alsa_write; au->poll_fds=audio_alsa_pollfds;
return au; au->read=audio_alsa_read;
} au->write=audio_alsa_write;
#endif // HAVE_ALSA_ASOUNDLIB_H return au;
return NULL;
} }
#endif

57
audio_reflector.c Normal file
View File

@ -0,0 +1,57 @@
/*
Copyright (C) 2012 Paul Gardner-Stephen
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "serval.h"
int audio_reflector_null() { return 0; }
int audio_reflector_pollfds(struct pollfd *fd,int slots) { return 0; }
unsigned char reflectBuffer[8192];
int reflectBufferLen=0;
int audio_reflector_write(unsigned char *buffer,int len)
{
if (reflectBufferLen+len>=8192)
len=8192-reflectBufferLen;
bcopy(&buffer[0],&reflectBuffer[reflectBufferLen],len);
reflectBufferLen+=len;
return len;
}
int audio_reflector_read(unsigned char *buffer,int maximum_count)
{
int count=reflectBufferLen;
if (count>maximum_count) count=maximum_count;
bcopy(&reflectBuffer[0],&buffer[0],count);
bcopy(&reflectBuffer[count],&reflectBuffer[0],
reflectBufferLen-count);
reflectBufferLen-=count;
return count;
}
monitor_audio *audio_reflector_detect()
{
monitor_audio *au=calloc(sizeof(monitor_audio),1);
strcpy(au->name,"Echo Reflector");
au->start=audio_reflector_null;
au->stop=audio_reflector_null;
au->poll_fds=audio_reflector_pollfds;
au->read=audio_reflector_read;
au->write=audio_reflector_write;
return au;
}

View File

@ -61,15 +61,6 @@ int getAudioBytes(unsigned char *buffer,
return -1; return -1;
} }
/* as with recording, some of the devices have a fixed buffer size that
we must completely fill.
*/
int playAudio(unsigned char *data,int bytes)
{
if (audev&&audev->write) return audev->write(data,bytes);
return -1;
}
int stopAudio() int stopAudio()
{ {
if (audev&&audev->stop) return audev->stop(); if (audev&&audev->stop) return audev->stop();

View File

@ -40,3 +40,14 @@ int encodeAndDispatchRecordedAudio(int fd,int callSessionToken,
write(fd,msg,len); write(fd,msg,len);
return 0; return 0;
} }
int bufferAudioForPlayback(int codec,long long start_time,long long end_time,
unsigned char *data,int dataLen)
{
/* XXX We need to buffer and reorder out-of-order sample blocks and
decode codecs etc here. */
/* send audio to device */
int bytesWritten=audev->write(&data[0],dataLen);
return 0;
}

View File

@ -48,6 +48,7 @@ int processChar(int c);
int autoAnswerP=1; int autoAnswerP=1;
int pipeAudio=1; int pipeAudio=1;
int reflectAudio=0;
int syntheticAudio=0; int syntheticAudio=0;
int showReceived=1; int showReceived=1;
int interactiveP=1; int interactiveP=1;
@ -62,6 +63,11 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
cli_arg(argc, argv, o, "sid", &sid, NULL, ""); cli_arg(argc, argv, o, "sid", &sid, NULL, "");
struct sockaddr_un addr; struct sockaddr_un addr;
if (!strcasecmp(sid,"reflect")) {
pipeAudio=1; reflectAudio=1;
sid="";
}
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket"); perror("socket");
exit(-1); exit(-1);
@ -81,7 +87,10 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
} }
if (pipeAudio) { if (pipeAudio) {
detectAudioDevice(); if (reflectAudio)
audev=audio_reflector_detect();
else
detectAudioDevice();
char *name=audev?audev->name:NULL; char *name=audev?audev->name:NULL;
if (!name) { if (!name) {
WHY("Could not detect any audio device. Will not pipe audio."); WHY("Could not detect any audio device. Will not pipe audio.");
@ -118,17 +127,13 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
we need, so we need to keep any left over ones from the previous we need, so we need to keep any left over ones from the previous
read. */ read. */
int audioRecordBufferBytes=0; int audioRecordBufferBytes=0;
int audioRecordBufferSize=8000*2;
unsigned char audioRecordBuffer[8000*2]; unsigned char audioRecordBuffer[8000*2];
int base_fd_count=fdcount; int base_fd_count=fdcount;
while(1) { while(1) {
fdcount=base_fd_count; fdcount=base_fd_count;
int audio_fd = getAudioRecordFd(); fdcount+=audev->poll_fds(&fds[fdcount],128-fdcount);
if (audio_fd>-1) {
fds[fdcount].fd=STDIN_FILENO;
fds[fdcount].events=POLLIN;
fdcount++;
}
poll(fds,fdcount,1000); poll(fds,fdcount,1000);
fcntl(fd,F_SETFL, fcntl(fd,F_SETFL,
@ -136,9 +141,6 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
if (interactiveP) if (interactiveP)
fcntl(STDIN_FILENO,F_SETFL, fcntl(STDIN_FILENO,F_SETFL,
fcntl(STDIN_FILENO, F_GETFL, NULL)|O_NONBLOCK); fcntl(STDIN_FILENO, F_GETFL, NULL)|O_NONBLOCK);
if (audio_fd>-1)
fcntl(audio_fd,F_SETFL,
fcntl(audio_fd, F_GETFL, NULL)|O_NONBLOCK);
int bytes; int bytes;
int i; int i;
@ -153,12 +155,14 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
printf("< %s",line); printf("< %s",line);
write(fd,line,bytes); write(fd,line,bytes);
} }
if (audio_fd>-1) { }
/* attempt to read next audio buffer.
Some audio devices that we are using require an entire buffer if (audev&&audev->read)
to be read at a time. */ {
audioRecordBufferBytes int bytesRead=audev->read(&audioRecordBuffer[audioRecordBufferBytes],
=getAudioBytes(audioRecordBuffer,audioRecordBufferBytes,sizeof(audioRecordBuffer)); audioRecordBufferSize-audioRecordBufferBytes);
if (bytesRead>0) audioRecordBufferBytes+=bytesRead;
/* 8KHz 16 bit samples = 16000 bytes per second. /* 8KHz 16 bit samples = 16000 bytes per second.
Thus one 1ms of audio = 16 bytes. */ Thus one 1ms of audio = 16 bytes. */
int audioRecordBufferOffset=0; int audioRecordBufferOffset=0;
@ -180,13 +184,11 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
audioRecordBufferBytes-audioRecordBufferOffset); audioRecordBufferBytes-audioRecordBufferOffset);
audioRecordBufferBytes-=audioRecordBufferOffset; audioRecordBufferBytes-=audioRecordBufferOffset;
} }
}
fcntl(fd,F_SETFL,
fcntl(fd,F_SETFL, fcntl(fd, F_GETFL, NULL)&~O_NONBLOCK);
fcntl(fd, F_GETFL, NULL)&~O_NONBLOCK); fcntl(STDIN_FILENO,F_SETFL,
fcntl(STDIN_FILENO,F_SETFL, fcntl(STDIN_FILENO, F_GETFL, NULL)&~O_NONBLOCK);
fcntl(STDIN_FILENO, F_GETFL, NULL)&~O_NONBLOCK);
} }
return 0; return 0;
@ -220,8 +222,8 @@ int processLine(char *cmd,unsigned char *data,int dataLen)
&l_id,&r_id,&l_state,&r_state, &l_id,&r_id,&l_state,&r_state,
&codec,&start_time,&end_time)==7) &codec,&start_time,&end_time)==7)
{ {
if (pipeAudio) { if (pipeAudio&&audev) {
playAudio(data,dataLen); bufferAudioForPlayback(codec,start_time,end_time,data,dataLen);
} }
} }
if (sscanf(cmd,"CALLSTATUS:%x:%x:%d:%d", if (sscanf(cmd,"CALLSTATUS:%x:%x:%d:%d",
@ -268,6 +270,7 @@ int processLine(char *cmd,unsigned char *data,int dataLen)
state=STATE_CMD; state=STATE_CMD;
return 0; return 0;
} }
int processChar(int c) int processChar(int c)
{ {
switch(state) { switch(state) {

View File

@ -361,6 +361,7 @@ int monitor_process_command(int index,char *cmd)
} }
char msg[1024]; char msg[1024];
int flag;
if (cmd[0]=='*') { if (cmd[0]=='*') {
/* command with content */ /* command with content */
@ -391,6 +392,17 @@ int monitor_process_command(int index,char *cmd)
c->flags|=MONITOR_RHIZOME; c->flags|=MONITOR_RHIZOME;
else if (!strcasecmp(cmd,"ignore rhizome")) else if (!strcasecmp(cmd,"ignore rhizome"))
c->flags&=~MONITOR_RHIZOME; c->flags&=~MONITOR_RHIZOME;
else if (sscanf(cmd,"FASTAUDIO:%x:%d",&callSessionToken,&flag)==2)
{
int i;
for(i=0;i<vomp_call_count;i++)
if (vomp_call_states[i].local.session==callSessionToken
||callSessionToken==0) {
vomp_call_states[i].fast_audio=flag;
vomp_call_states[i].local.last_state=-1;
monitor_call_status(&vomp_call_states[i]);
}
}
else if (sscanf(cmd,"call %s %s %s",sid,localDid,remoteDid)==3) { else if (sscanf(cmd,"call %s %s %s",sid,localDid,remoteDid)==3) {
if (sid[0]=='*') { if (sid[0]=='*') {
/* For testing, pick a peer and call them */ /* For testing, pick a peer and call them */
@ -515,9 +527,10 @@ int monitor_call_status(vomp_call_state *call)
call->remote.last_state=call->remote.state; call->remote.last_state=call->remote.state;
if (show) { if (show) {
if (0) WHYF("sending call status to monitor"); if (0) WHYF("sending call status to monitor");
snprintf(msg,1024,"\nCALLSTATUS:%06x:%06x:%d:%d:%s:%s:%s:%s\n", snprintf(msg,1024,"\nCALLSTATUS:%06x:%06x:%d:%d:%d:%s:%s:%s:%s\n",
call->local.session,call->remote.session, call->local.session,call->remote.session,
call->local.state,call->remote.state, call->local.state,call->remote.state,
call->fast_audio,
overlay_render_sid(call->local.sid), overlay_render_sid(call->local.sid),
overlay_render_sid(call->remote.sid), overlay_render_sid(call->remote.sid),
call->local.did,call->remote.did); call->local.did,call->remote.did);

View File

@ -1320,6 +1320,7 @@ typedef struct vomp_call_state {
vomp_call_half local; vomp_call_half local;
vomp_call_half remote; vomp_call_half remote;
int ringing; int ringing;
int fast_audio;
unsigned long long create_time; unsigned long long create_time;
unsigned long long last_activity; unsigned long long last_activity;
unsigned long long audio_clock; unsigned long long audio_clock;
@ -1444,17 +1445,19 @@ extern monitor_audio *audev;
monitor_audio *audio_msm_g1_detect(); monitor_audio *audio_msm_g1_detect();
monitor_audio *audio_alsa_detect(); monitor_audio *audio_alsa_detect();
monitor_audio *audio_reflector_detect();
int detectAudioDevice(); int detectAudioDevice();
int getAudioPlayFd(); int getAudioPlayFd();
int getAudioRecordFd(); int getAudioRecordFd();
int getAudioBytes(unsigned char *buffer, int getAudioBytes(unsigned char *buffer,
int offset, int offset,
int bufferSize); int bufferSize);
int playAudio(unsigned char *data,int bytes);
int startAudio();
int stopAudio();
int encodeAndDispatchRecordedAudio(int fd,int callSessionToken, int encodeAndDispatchRecordedAudio(int fd,int callSessionToken,
int recordCodec, int recordCodec,
unsigned char *sampleData, unsigned char *sampleData,
int sampleBytes); int sampleBytes);
int scrapeProcNetRoute(); int scrapeProcNetRoute();
int bufferAudioForPlayback(int codec,long long start_time,long long end_time,
unsigned char *data,int dataLen);
int startAudio();
int stopAudio();