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/audiodevices.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

View File

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

View File

@ -18,7 +18,13 @@
#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 <stdlib.h>
@ -40,7 +46,7 @@
necessary symbols we need.
*/
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_hw_params_malloc)(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()
{
WHY("Trying to load ALSA library");
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;
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_any);
GETSYM(snd_pcm_hw_params_set_access);
@ -81,7 +89,8 @@ int alsa_load()
GETSYM(snd_pcm_poll_descriptors);
alsa=a;
dlclose(h);
WHY("Loaded ALSA library");
return 0;
}
@ -120,8 +129,8 @@ int audio_alsa_start_play()
record_params=NULL; play_params=NULL;
/* Open playback device */
r = alsa->snd_pcm_open (&play_handle,"default",SND_PCM_STREAM_PLAYBACK,
SND_PCM_NONBLOCK);
r = alsa->snd_pcm_open_preferred (&play_handle,NULL,NULL,
SND_PCM_STREAM_PLAYBACK|SND_PCM_NONBLOCK);
if (r) { WHYF("ALSA pcm_open() failed"); goto error; }
/* Configure playback device for 8000Hz, 16 bit, mono */
@ -157,8 +166,8 @@ int audio_alsa_start_play()
int audio_alsa_start_record()
{
/* Open recording device non-blocking */
int r = alsa->snd_pcm_open (&record_handle,"default",SND_PCM_STREAM_CAPTURE,
SND_PCM_NONBLOCK);
int r = alsa->snd_pcm_open_preferred(&record_handle,NULL,NULL,
SND_PCM_STREAM_CAPTURE|SND_PCM_NONBLOCK);
if (r) { WHYF("ALSA pcm_open() failed"); goto error; }
/* Configure playback device for 8000Hz, 16 bit, mono */
@ -243,25 +252,23 @@ int audio_alsa_write(unsigned char *buffer,int bytes)
else return 0;
}
#endif // HAVE_ALSA_ASOUNDLIB_H
monitor_audio *audio_alsa_detect()
{
#ifdef HAVE_ALSA_ASOUNDLIB_H
if (!alsa) alsa_load();
if (!alsa) return NULL;
snd_pcm_t *handle;
if (alsa->snd_pcm_open (&handle, "default", SND_PCM_STREAM_PLAYBACK, 0) != -1) {
alsa->snd_pcm_close(handle);
monitor_audio *au=calloc(sizeof(monitor_audio),1);
strcpy(au->name,"ALSA compatible");
au->start=audio_alsa_start;
au->stop=audio_alsa_stop;
au->poll_fds=audio_alsa_pollfds;
au->read=audio_alsa_read;
au->write=audio_alsa_write;
return au;
}
#endif // HAVE_ALSA_ASOUNDLIB_H
return NULL;
if (alsa->snd_pcm_open_preferred(&handle,NULL,NULL,SND_PCM_STREAM_PLAYBACK) < 0)
return NULL;
alsa->snd_pcm_close(handle);
monitor_audio *au=calloc(sizeof(monitor_audio),1);
strcpy(au->name,"ALSA compatible");
au->start=audio_alsa_start;
au->stop=audio_alsa_stop;
au->poll_fds=audio_alsa_pollfds;
au->read=audio_alsa_read;
au->write=audio_alsa_write;
return au;
}
#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;
}
/* 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()
{
if (audev&&audev->stop) return audev->stop();

View File

@ -40,3 +40,14 @@ int encodeAndDispatchRecordedAudio(int fd,int callSessionToken,
write(fd,msg,len);
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 pipeAudio=1;
int reflectAudio=0;
int syntheticAudio=0;
int showReceived=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, "");
struct sockaddr_un addr;
if (!strcasecmp(sid,"reflect")) {
pipeAudio=1; reflectAudio=1;
sid="";
}
if ( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket");
exit(-1);
@ -81,7 +87,10 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
}
if (pipeAudio) {
detectAudioDevice();
if (reflectAudio)
audev=audio_reflector_detect();
else
detectAudioDevice();
char *name=audev?audev->name:NULL;
if (!name) {
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
read. */
int audioRecordBufferBytes=0;
int audioRecordBufferSize=8000*2;
unsigned char audioRecordBuffer[8000*2];
int base_fd_count=fdcount;
while(1) {
fdcount=base_fd_count;
int audio_fd = getAudioRecordFd();
if (audio_fd>-1) {
fds[fdcount].fd=STDIN_FILENO;
fds[fdcount].events=POLLIN;
fdcount++;
}
fdcount+=audev->poll_fds(&fds[fdcount],128-fdcount);
poll(fds,fdcount,1000);
fcntl(fd,F_SETFL,
@ -136,9 +141,6 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
if (interactiveP)
fcntl(STDIN_FILENO,F_SETFL,
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 i;
@ -153,12 +155,14 @@ int app_monitor_cli(int argc, const char *const *argv, struct command_line_optio
printf("< %s",line);
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
to be read at a time. */
audioRecordBufferBytes
=getAudioBytes(audioRecordBuffer,audioRecordBufferBytes,sizeof(audioRecordBuffer));
}
if (audev&&audev->read)
{
int bytesRead=audev->read(&audioRecordBuffer[audioRecordBufferBytes],
audioRecordBufferSize-audioRecordBufferBytes);
if (bytesRead>0) audioRecordBufferBytes+=bytesRead;
/* 8KHz 16 bit samples = 16000 bytes per second.
Thus one 1ms of audio = 16 bytes. */
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;
}
}
fcntl(fd,F_SETFL,
fcntl(fd, F_GETFL, NULL)&~O_NONBLOCK);
fcntl(STDIN_FILENO,F_SETFL,
fcntl(STDIN_FILENO, F_GETFL, NULL)&~O_NONBLOCK);
fcntl(fd,F_SETFL,
fcntl(fd, F_GETFL, NULL)&~O_NONBLOCK);
fcntl(STDIN_FILENO,F_SETFL,
fcntl(STDIN_FILENO, F_GETFL, NULL)&~O_NONBLOCK);
}
return 0;
@ -220,8 +222,8 @@ int processLine(char *cmd,unsigned char *data,int dataLen)
&l_id,&r_id,&l_state,&r_state,
&codec,&start_time,&end_time)==7)
{
if (pipeAudio) {
playAudio(data,dataLen);
if (pipeAudio&&audev) {
bufferAudioForPlayback(codec,start_time,end_time,data,dataLen);
}
}
if (sscanf(cmd,"CALLSTATUS:%x:%x:%d:%d",
@ -268,6 +270,7 @@ int processLine(char *cmd,unsigned char *data,int dataLen)
state=STATE_CMD;
return 0;
}
int processChar(int c)
{
switch(state) {

View File

@ -361,6 +361,7 @@ int monitor_process_command(int index,char *cmd)
}
char msg[1024];
int flag;
if (cmd[0]=='*') {
/* command with content */
@ -391,6 +392,17 @@ int monitor_process_command(int index,char *cmd)
c->flags|=MONITOR_RHIZOME;
else if (!strcasecmp(cmd,"ignore 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) {
if (sid[0]=='*') {
/* 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;
if (show) {
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.state,call->remote.state,
call->fast_audio,
overlay_render_sid(call->local.sid),
overlay_render_sid(call->remote.sid),
call->local.did,call->remote.did);

View File

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