Remove unused audio code

This commit is contained in:
Jeremy Lakeman 2013-07-04 09:42:42 +09:30
parent 53f3920b90
commit 749080cbfb
6 changed files with 1 additions and 1200 deletions

View File

@ -1,238 +0,0 @@
/*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/*! \file
*
* \brief Connect with Serval Distributed Numbering Architecture for Mesh Calling
*
* Paul Gardner-Stephen (paul@servalproject.org)
*
* \ingroup applications
*/
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision: Serval $")
#include <sys/types.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <pthread.h>
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/callerid.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/features.h"
#include "asterisk/options.h"
#include "asterisk/cli.h"
#include "asterisk/config.h"
#include "asterisk/say.h"
#include "asterisk/localtime.h"
#include "asterisk/cdr.h"
#include "asterisk/options.h"
#include "serval.c"
#undef inet_ntoa
#define inet_ntoa ast_inet_ntoa
static char *sdnalookup_descrip =
" SDNALookup(): Resolves a telephone number into SIP address via Serval Distributed Numbering Architecture\n";
static char *sdnalookup_app = "SDNALookup";
static char *sdnalookup_synopsis = "Resolve DID into SIP address via Serval DNA";
static char *handle_cli_sdnalookup(int fd, int argc, char *argv[])
{
char *did=NULL;
char *sid=NULL;
unsigned char buffer[65535];
int len=0;
int instance=0;
if (argc != 4) {
ast_cli(fd, "You did not provide an argument to serval dna lookup\n\n");
return RESULT_FAILURE;
}
did=argv[3];
ast_cli(fd,"Serval DNA Lookup: NOT IMPLEMENTED\n\n",len);
return RESULT_FAILURE;
buffer[len]=0;
ast_cli(fd,"%s resolves to %s (len=%d)\n",did,buffer,len);
return RESULT_SUCCESS;
}
static char *handle_cli_sdnapeers(int fd, int argc, char *argv[])
{
int i;
if (argc != 3) {
ast_cli(fd, "serval dna peers does not argue about arguments.\n\n");
return RESULT_FAILURE;
}
getPeerList();
ast_cli(fd,"%d peers reachable:\n",peer_count);
for(i=0;i<peer_count;i++)
{
unsigned char *c=(unsigned char *)&peers[i];
ast_cli(fd," %d.%d.%d.%d\n",c[0],c[1],c[2],c[3]);
}
return RESULT_SUCCESS;
}
static char *handle_cli_sdnagate(int fd, int argc, char *argv[])
{
unsigned char buffer[65535];
int len=0;
int instance=0;
if (gatewayspec) free(gatewayspec);
gatewayspec=NULL;
if (argc == 3 ) {
ast_cli(fd,"Serval DNA Gateway Function OFF.\n\n",len);
return RESULT_SUCCESS;
}
if (argc != 4) {
ast_cli(fd, "You did not provide an argument to serval dna gateway\n\n");
return RESULT_FAILURE;
}
gatewayspec=strdup(argv[3]);
ast_cli(fd,"Serval DNA Gateway Function ON (trunk spec is %s).\n\n",gatewayspec);
return RESULT_SUCCESS;
}
static char *handle_cli_sdnadebug(int fd, int argc, char *argv[])
{
if (argc != 3) {
ast_cli(fd, "You did not provide an argument to serval debug\n\n");
return RESULT_FAILURE;
}
debug=atoi(argv[2]);
ast_cli(fd,"Serval debug level set to %d\n",debug);
return RESULT_SUCCESS;
}
static char sdnalookup_usage[]=
"Usage: serval dna lookup <did>\n"
" Attempt to resolve a DID into a SIP address via Serval DNA.\n"
"Examples:\n"
" serval dna lookup 0427679796\n";
static char sdnapeers_usage[]=
"Usage: serval dna peers\n"
" Ask DNA to list the peers currently reachable on the mesh.\n"
"Examples:\n"
" serval dna peers\n";
static char sdnadebug_usage[]=
"Usage: serval debug <debug level>\n"
" Set Serval debug level (0-3 are useful values).\n"
"Examples:\n"
" serval debug 3\n";
static char sdnagate_usage[]=
"Usage: serval dna gateway [gateway uri]\n"
" Offer Serval DNA gateway services to allow other BatPhones to use our SIP trunk.\n"
"Examples:\n"
" serval dna gateway 4000@10.130.1.101\n";
static struct ast_cli_entry cli_sdnalookup[] = {
{ { "serval","dna","lookup" }, handle_cli_sdnalookup,
"Resolve a telephone number via Serval DNA", sdnalookup_usage },
{ { "serval","dna","peers" }, handle_cli_sdnapeers,
"Ask DNA to list peers reachable on the mesh", sdnapeers_usage },
{ { "serval","debug" }, handle_cli_sdnadebug,
"Set Serval debug level", sdnadebug_usage },
{ { "serval","dna","gateway" }, handle_cli_sdnagate,
"Enable DNA Gateway ", sdnagate_usage },
};
static int sdnalookup_exec(struct ast_channel *chan, void *data)
{
char *did=data;
char *sid=NULL;
unsigned char buffer[65535];
int len=0;
int instance=0;
char status[256] = "INVALIDARGS";
/* Clear Serval DNA set variables */
pbx_builtin_setvar_helper(chan, "SDNADID", "");
pbx_builtin_setvar_helper(chan, "SDNASID", "");
pbx_builtin_setvar_helper(chan, "SDNALOCATION", "");
pbx_builtin_setvar_helper(chan, "SDNASIG", "");
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "SDNALookup requires an argument (number)\n");
pbx_builtin_setvar_helper(chan, "SDNASTATUS", status);
if (debug) fprintf(stderr,"SDNASTATUS=%s (a)\n",status);
return -1;
}
/* XXX - Simple version for now. Should really use a derivation of the core code from the function below to:
(a) provide more meaningful errors;
(b) retrieve the SID for the DID for further use
(c) fetch the voicesig as well if requested
*/
// NOT IMPLEMENTED
pbx_builtin_setvar_helper(chan,"SNASTATUS","FAILED");
if (debug) fprintf(stderr,"SDNASTATUS=FAILED\n");
return -1;
/* It worked, so set appropriate variables and return happily */
pbx_builtin_setvar_helper(chan,"SNADID",did);
if (debug) fprintf(stderr,"SNADID=%s\n",did);
if (sid) {
pbx_builtin_setvar_helper(chan,"SNASID",sid);
if (debug) fprintf(stderr,"SNASID=%s\n",sid);
}
if (len) {
buffer[len]=0;
pbx_builtin_setvar_helper(chan,"SDNALOCATION",(char*)buffer);
if (debug) fprintf(stderr,"SNALOCATION=%s\n",buffer);
}
return 0;
}
static int unload_module(void)
{
int res;
ast_cli_unregister_multiple(cli_sdnalookup, ARRAY_LEN(cli_sdnalookup));
res = ast_unregister_application(sdnalookup_app);
return res;
}
static int load_module(void)
{
batman_peerfile=NULL;
ast_cli_register_multiple(cli_sdnalookup, ARRAY_LEN(cli_sdnalookup));
return ast_register_application(sdnalookup_app, sdnalookup_exec, sdnalookup_synopsis, sdnalookup_descrip);
}
#define AST_MODULE "app_serval"
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Serval Mesh Telephony Adapter and Serval DNA Resolver");

View File

@ -1,274 +0,0 @@
/*
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"
#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>
#include <dlfcn.h>
#include <alsa/asoundlib.h>
#ifndef ANDROID
#define ALSA_LIB_PATH "/lib/libasound.so.2"
#else
// XXX Verify on a SGS2 ?
#define ALSA_LIB_PATH "/system/lib/libasound.so.2"
#endif
/*
For Android systems we have the fun that this binary (not just the source code)
needs to be able to run on systems that lack the alsa library.
This means it is time for some more dlopen() and dlsym() fun to get the
necessary symbols we need.
*/
typedef struct alsa_functions {
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 *);
int (*snd_pcm_hw_params_set_access)(snd_pcm_t *,snd_pcm_hw_params_t *,int);
int (*snd_pcm_hw_params_set_format)(snd_pcm_t *,snd_pcm_hw_params_t *,int);
int (*snd_pcm_hw_params_set_rate_near)(snd_pcm_t *,snd_pcm_hw_params_t *,int,int);
int (*snd_pcm_hw_params_set_channels)(snd_pcm_t *,snd_pcm_hw_params_t *,int);
int (*snd_pcm_hw_params)(snd_pcm_t *,snd_pcm_hw_params_t *);
void (*snd_pcm_hw_params_free)(snd_pcm_hw_params_t *);
int (*snd_pcm_prepare)(snd_pcm_t *);
int (*snd_pcm_writei)(snd_pcm_t *,short *,int);
int (*snd_pcm_readi)(snd_pcm_t *,short *,int);
int (*snd_pcm_poll_descriptors)(snd_pcm_t *,struct pollfd *,unsigned int);
} alsa_functions;
#define S(X) #X
#define GETSYM(X) {a->X = dlsym(h,S(X)); if (!a->X) { dlclose(h); free(a); return -1; }}
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_preferred);
GETSYM(snd_pcm_hw_params_malloc);
GETSYM(snd_pcm_hw_params_any);
GETSYM(snd_pcm_hw_params_set_access);
GETSYM(snd_pcm_hw_params_set_format);
GETSYM(snd_pcm_hw_params_set_rate_near);
GETSYM(snd_pcm_hw_params_set_channels);
GETSYM(snd_pcm_hw_params);
GETSYM(snd_pcm_hw_params_free);
GETSYM(snd_pcm_writei);
GETSYM(snd_pcm_readi);
GETSYM(snd_pcm_close);
GETSYM(snd_pcm_poll_descriptors);
alsa=a;
dlclose(h);
WHY("Loaded ALSA library");
return 0;
}
int alsa_handles_initialised=0;
snd_pcm_t *play_handle;
snd_pcm_t *record_handle;
snd_pcm_hw_params_t *play_params;
snd_pcm_hw_params_t *record_params;
int audio_alsa_stop_play()
{
if (!alsa) return 0;
alsa->snd_pcm_hw_params_free(play_params); play_params=NULL;
alsa->snd_pcm_close(play_handle);
return 0;
}
int audio_alsa_stop_record()
{
if (!alsa) return 0;
alsa->snd_pcm_hw_params_free(record_params); record_params=NULL;
alsa->snd_pcm_close(record_handle);
return 0;
}
int audio_alsa_start_play()
{
int r;
/* if already playing, then return. */
if (alsa_handles_initialised) return 0;
if (!alsa) return -1;
record_handle=NULL; play_handle=NULL;
record_params=NULL; play_params=NULL;
/* Open playback device */
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 */
r=alsa->snd_pcm_hw_params_malloc(&play_params);
if (r) { WHYF("ALSA hw_params_malloc() failed"); goto error; }
r=alsa->snd_pcm_hw_params_any(play_handle,play_params);
if (r) { WHYF("ALSA hw_params_any() failed"); goto error; }
r=alsa->snd_pcm_hw_params_set_access(play_handle,play_params,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (r) { WHYF("ALSA hw_params_set_access() failed"); goto error; }
r=alsa->snd_pcm_hw_params_set_format(play_handle,play_params,
SND_PCM_FORMAT_S16_LE);
if (r) { WHYF("ALSA hw_params_set_format() failed"); goto error; }
r=alsa->snd_pcm_hw_params_set_rate_near(play_handle,play_params,8000,0);
if (r) { WHYF("ALSA hw_params_set_rate_near() failed"); goto error; }
r=alsa->snd_pcm_hw_params_set_channels(play_handle,play_params,1);
if (r) { WHYF("ALSA hw_params_set_channels() failed"); goto error; }
r=alsa->snd_pcm_hw_params(play_handle,play_params);
if (r) { WHYF("ALSA snd_pcm_hw_params() failed"); goto error; }
alsa->snd_pcm_hw_params_free(play_params); play_params=NULL;
r=alsa->snd_pcm_prepare(play_handle);
if (r) { WHYF("ALSA snd_pcm_prepare() failed"); goto error; }
WHY("Playback device configured");
error:
/* close handles and generally cleanup after ourselves */
audio_alsa_stop_play();
return -1;
}
int audio_alsa_start_record()
{
/* Open recording device non-blocking */
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 */
r=alsa->snd_pcm_hw_params_malloc(&record_params);
if (r) { WHYF("ALSA hw_params_malloc() failed"); goto error; }
r=alsa->snd_pcm_hw_params_any(record_handle,record_params);
if (r) { WHYF("ALSA hw_params_any() failed"); goto error; }
r=alsa->snd_pcm_hw_params_set_access(record_handle,record_params,
SND_PCM_ACCESS_RW_INTERLEAVED);
if (r) { WHYF("ALSA hw_params_set_access() failed"); goto error; }
r=alsa->snd_pcm_hw_params_set_format(record_handle,record_params,
SND_PCM_FORMAT_S16_LE);
if (r) { WHYF("ALSA hw_params_set_format() failed"); goto error; }
r=alsa->snd_pcm_hw_params_set_rate_near(record_handle,record_params,8000,0);
if (r) { WHYF("ALSA hw_params_set_rate_near() failed"); goto error; }
r=alsa->snd_pcm_hw_params_set_channels(record_handle,record_params,1);
if (r) { WHYF("ALSA hw_params_set_channels() failed"); goto error; }
r=alsa->snd_pcm_hw_params(record_handle,record_params);
if (r) { WHYF("ALSA snd_pcm_hw_params() failed"); goto error; }
alsa->snd_pcm_hw_params_free(record_params); record_params=NULL;
r=alsa->snd_pcm_prepare(record_handle);
if (r) { WHYF("ALSA snd_pcm_prepare() failed"); goto error; }
WHY("Record device configured");
return 0;
error:
/* close handles and generally cleanup after ourselves */
audio_alsa_stop_record();
return -1;
}
int audio_alsa_stop()
{
audio_alsa_stop_play();
audio_alsa_stop_record();
return 0;
}
int audio_alsa_start()
{
if (audio_alsa_start_play()) return -1;
if (audio_alsa_start_record()) {
audio_alsa_stop();
return -1;
}
return 0;
}
int audio_alsa_pollfds(struct pollfd *fds,int slots)
{
int used_play
=alsa->snd_pcm_poll_descriptors(play_handle,fds,slots);
int used_record
=alsa->snd_pcm_poll_descriptors(record_handle,&fds[used_play],slots);
return used_play+used_record;
}
int audio_alsa_read(unsigned char *buffer,int maximum_bytes)
{
int frames_read=0;
if ((frames_read=
alsa->snd_pcm_readi(record_handle, (short *)buffer, maximum_bytes/2))<0)
{
alsa->snd_pcm_prepare(record_handle);
frames_read
=alsa->snd_pcm_readi(play_handle, (short *)buffer, maximum_bytes/2);
}
return frames_read*2;
}
int audio_alsa_write(unsigned char *buffer,int bytes)
{
/* 16 bits per sample, so frames = bytes/2 */
int frames_written=0;
if ((frames_written=alsa->snd_pcm_writei(play_handle, (short *)buffer, bytes/2))<0)
{
alsa->snd_pcm_prepare(play_handle);
return alsa->snd_pcm_writei(play_handle, (short *)buffer, bytes/2)*2;
}
else return 0;
}
monitor_audio *audio_alsa_detect()
{
if (!alsa) alsa_load();
if (!alsa) return NULL;
snd_pcm_t *handle;
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

View File

@ -1,551 +0,0 @@
/*
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.
Contains code derived from playwav2.c, which has the following notice:
Copyright (C) 2008 The Android Open Source Project
*/
/*
We ask the driver to reduce it's buffer size, but it doesn't listen.
This is very strange, as looking in pcm_out.c of kernel source it appears
that it should work just fine.
What does work, however, is increasing the sample rate, so that the buffers
empty sooner. So we use 32000Hz instead of 8000Hz so that the 2KB record buffer
holds only 1/32nd of a second instead of 1/8th of a second.
We may need to introduce a low-pass filter to prevent aliasing, assuming that
the microphone and ACD in these phones responds to requencies above 4KHz.
Added fun with this device is that we must read/write exactly one buffer full
at a time.
*/
#define DESIRED_BUFFER_SIZE 256
#define DESIRED_SAMPLE_RATE 32000
#define RESAMPLE_FACTOR (DESIRED_SAMPLE_RATE/8000)
int resamplingBufferSize=0;
unsigned char *playMarshallBuffer=0;
unsigned char *recordMarshallBuffer=0;
extern int playFd;
extern int recordFd;
extern int playBufferSize;
extern int recordBufferSize;
#include "serval.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <errno.h>
#if HAVE_LINUX_IOCTL_H
#include <linux/ioctl.h>
#endif
#if 0
#include <linux/msm_audio.h>
#else
/* ---------- linux/msm_audio.h -------- */
#define AUDIO_IOCTL_MAGIC 'a'
#define AUDIO_START _IOW(AUDIO_IOCTL_MAGIC, 0, unsigned)
#define AUDIO_STOP _IOW(AUDIO_IOCTL_MAGIC, 1, unsigned)
#define AUDIO_FLUSH _IOW(AUDIO_IOCTL_MAGIC, 2, unsigned)
#define AUDIO_GET_CONFIG _IOR(AUDIO_IOCTL_MAGIC, 3, unsigned)
#define AUDIO_SET_CONFIG _IOW(AUDIO_IOCTL_MAGIC, 4, unsigned)
#define AUDIO_GET_STATS _IOR(AUDIO_IOCTL_MAGIC, 5, unsigned)
#define AUDIO_ENABLE_AUDPP _IOW(AUDIO_IOCTL_MAGIC, 6, unsigned)
#define AUDIO_SET_ADRC _IOW(AUDIO_IOCTL_MAGIC, 7, unsigned)
#define AUDIO_SET_EQ _IOW(AUDIO_IOCTL_MAGIC, 8, unsigned)
#define AUDIO_SET_RX_IIR _IOW(AUDIO_IOCTL_MAGIC, 9, unsigned)
#define EQ_MAX_BAND_NUM 12
#define ADRC_ENABLE 0x0001
#define ADRC_DISABLE 0x0000
#define EQ_ENABLE 0x0002
#define EQ_DISABLE 0x0000
#define IIR_ENABLE 0x0004
#define IIR_DISABLE 0x0000
struct eq_filter_type
{
int16_t gain;
uint16_t freq;
uint16_t type;
uint16_t qf;
};
struct eqalizer
{
uint16_t bands;
uint16_t params[132];
};
struct rx_iir_filter
{
uint16_t num_bands;
uint16_t iir_params[48];
};
struct msm_audio_config
{
uint32_t buffer_size;
uint32_t buffer_count;
uint32_t channel_count;
uint32_t sample_rate;
uint32_t codec_type;
uint32_t unused[3];
};
struct msm_audio_stats
{
uint32_t out_bytes;
uint32_t unused[3];
};
/* Audio routing */
#define SND_IOCTL_MAGIC 's'
#define SND_MUTE_UNMUTED 0
#define SND_MUTE_MUTED 1
struct msm_snd_device_config
{
uint32_t device;
uint32_t ear_mute;
uint32_t mic_mute;
};
#define SND_SET_DEVICE _IOW(SND_IOCTL_MAGIC, 2, struct msm_device_config *)
#define SND_METHOD_VOICE 0
#define SND_METHOD_VOICE_1 1
struct msm_snd_volume_config
{
uint32_t device;
uint32_t method;
uint32_t volume;
};
#define SND_SET_VOLUME _IOW(SND_IOCTL_MAGIC, 3, struct msm_snd_volume_config *)
/* Returns the number of SND endpoints supported. */
#define SND_GET_NUM_ENDPOINTS _IOR(SND_IOCTL_MAGIC, 4, unsigned *)
struct msm_snd_endpoint
{
int id; /* input and output */
char name[64]; /* output only */
};
/* Takes an index between 0 and one less than the number returned by
* SND_GET_NUM_ENDPOINTS, and returns the SND index and name of a
* SND endpoint. On input, the .id field contains the number of the
* endpoint, and on exit it contains the SND index, while .name contains
* the description of the endpoint.
*/
#define SND_GET_ENDPOINT _IOWR(SND_IOCTL_MAGIC, 5, struct msm_snd_endpoint *)
#endif
static int
do_route_audio_rpc (uint32_t device, int ear_mute, int mic_mute)
{
if (device == -1UL)
return 0;
int fd;
printf ("rpc_snd_set_device(%d, %d, %d)\n", device, ear_mute, mic_mute);
fd = open ("/dev/msm_snd", O_RDWR);
if (fd < 0)
{
perror ("Can not open snd device");
return -1;
}
// RPC call to switch audio path
/* rpc_snd_set_device(
* device, # Hardware device enum to use
* ear_mute, # Set mute for outgoing voice audio
* # this should only be unmuted when in-call
* mic_mute, # Set mute for incoming voice audio
* # this should only be unmuted when in-call or
* # recording.
* )
*/
struct msm_snd_device_config args;
args.device = device;
args.ear_mute = ear_mute ? SND_MUTE_MUTED : SND_MUTE_UNMUTED;
args.mic_mute = mic_mute ? SND_MUTE_MUTED : SND_MUTE_UNMUTED;
if (ioctl (fd, SND_SET_DEVICE, &args) < 0)
{
perror ("snd_set_device error.");
close (fd);
return -1;
}
close (fd);
return 0;
}
static int
set_volume_rpc (uint32_t device, uint32_t method, uint32_t volume)
{
int fd;
printf ("rpc_snd_set_volume(%d, %d, %d)\n", device, method, volume);
if (device == -1UL)
return 0;
fd = open ("/dev/msm_snd", O_RDWR);
if (fd < 0)
{
perror ("Can not open snd device");
return -1;
}
/* rpc_snd_set_volume(
* device, # Any hardware device enum, including
* # SND_DEVICE_CURRENT
* method, # must be SND_METHOD_VOICE to do anything useful
* volume, # integer volume level, in range [0,5].
* # note that 0 is audible (not quite muted)
* )
* rpc_snd_set_volume only works for in-call sound volume.
*/
struct msm_snd_volume_config args;
args.device = device;
args.method = method;
args.volume = volume;
if (ioctl (fd, SND_SET_VOLUME, &args) < 0)
{
perror ("snd_set_volume error.");
close (fd);
return -1;
}
close (fd);
return 0;
}
/* Prepare audio path, volume etc, and then open play and
record file descriptors.
*/
int audio_msm_g1_start_play()
{
if (playFd>-1) return 0;
/* Get audio control device */
int fd = open ("/dev/msm_snd", O_RDWR);
if (fd<0) return -1;
/* Look through endpoints for the regular in-call endpoint */
int endpoints=0;
ioctl(fd,SND_GET_NUM_ENDPOINTS,&endpoints);
int endpoint=-1;
int i;
for(i=0;i<endpoints;i++) {
struct msm_snd_endpoint ep;
ep.id=i;
ep.name[0]=0;
ioctl(fd,SND_GET_ENDPOINT,&ep);
if (!strcasecmp(ep.name,"HANDSET"))
/* should this be i, or ep.id ? */
endpoint=i;
}
close(fd);
/* Set the specified endpoint and unmute microphone and speaker */
do_route_audio_rpc(endpoint,SND_MUTE_UNMUTED,SND_MUTE_UNMUTED);
/* Set the volume (somewhat arbitrarily for now) */
int vol=5;
int dev=0xd; /* no one seems to know what this magic value means */
set_volume_rpc(dev,SND_METHOD_VOICE_1, vol);
playFd=open("/dev/msm_pcm_out",O_RDWR);
struct msm_audio_config config;
if (ioctl(playFd, AUDIO_GET_CONFIG,&config))
{
close(playFd);
playFd=-1;
return WHY("Could not read audio device configuration");
}
config.channel_count=1;
config.sample_rate=DESIRED_SAMPLE_RATE;
config.buffer_size=DESIRED_BUFFER_SIZE;
if (ioctl(playFd, AUDIO_SET_CONFIG,&config))
{
close(playFd);
playFd=-1;
return WHY("Could not set audio device configuration");
}
fcntl(playFd,F_SETFL,
fcntl(playFd, F_GETFL, NULL)|O_NONBLOCK);
/*
If playBufferSize equates to too long an interval,
then try to reduce it in various ways.
*/
ioctl(playFd, AUDIO_GET_CONFIG,&config);
playBufferSize=config.buffer_size;
float bufferTime=playBufferSize/2*1.0/config.sample_rate;
WHYF("PLAY buf=%.3fsecs.",bufferTime);
playMarshallBuffer=malloc(playBufferSize);
/* tell hardware to start playing */
ioctl(playFd,AUDIO_START,0);
WHYF("G1/IDEOS style MSM audio device initialised and ready to play");
WHYF("Play buffer size = %d bytes",playBufferSize);
return 0;
}
int audio_msm_g1_stop_play()
{
WHY("stopping audio play");
if (playFd>-1) close(playFd);
if (playMarshallBuffer) free(playMarshallBuffer);
playFd=-1; playMarshallBuffer=NULL;
return 0;
}
int audio_msm_g1_start_record()
{
if (recordFd>-1) return 0;
recordFd=open("/dev/msm_pcm_in",O_RDWR);
struct msm_audio_config config;
if (ioctl(recordFd, AUDIO_GET_CONFIG,&config))
{
close(recordFd);
recordFd=-1;
return WHY("Could not read audio device configuration");
}
config.channel_count=1;
config.sample_rate=DESIRED_SAMPLE_RATE;
config.buffer_size=DESIRED_BUFFER_SIZE;
if (ioctl(recordFd, AUDIO_SET_CONFIG,&config))
{
close(recordFd);
recordFd=-1;
return WHY("Could not set audio device configuration");
}
/*
If recordBufferSize equates to too long an interval,
then try to reduce it in various ways.
*/
ioctl(recordFd, AUDIO_GET_CONFIG,&config);
recordBufferSize=config.buffer_size;
float bufferTime=recordBufferSize/2*1.0/config.sample_rate;
WHYF("REC buf=%.3fsecs.",bufferTime);
if (!recordMarshallBuffer)
recordMarshallBuffer=malloc(recordBufferSize);
fcntl(recordFd,F_SETFL,
fcntl(recordFd, F_GETFL, NULL)|O_NONBLOCK);
/* tell hardware to start playing */
ioctl(recordFd,AUDIO_START,0);
WHY("G1/IDEOS style MSM audio device initialised and ready to record");
return 0;
}
int audio_msm_g1_stop_record()
{
WHY("stopping recording");
if (recordFd>-1) close(recordFd);
if (recordMarshallBuffer) free(recordMarshallBuffer);
recordMarshallBuffer=NULL;
recordFd=-1;
return 0;
}
int audio_msm_g1_stop()
{
audio_msm_g1_stop_play();
audio_msm_g1_stop_record();
return 0;
}
int audio_msm_g1_start()
{
if (audio_msm_g1_start_play()) return -1;
if (audio_msm_g1_start_record()) {
audio_msm_g1_stop_play();
return -1;
}
return 0;
}
int audio_msm_g1_poll_fds(struct pollfd *fds,int slots)
{
int count=0;
if (playFd>-1&&slots>0) {
fds[count].fd=playFd;
fds[count].events=POLLIN;
count++; slots--;
}
return count;
}
int recordMarshallBufferOffset=0;
int audio_msm_g1_read(unsigned char *buffer,int maximum_count)
{
if (recordFd==-1) return 0;
if (!recordMarshallBuffer) return 0;
int supplied=0;
/* read new samples if we don't have any lingering around */
if (!recordMarshallBufferOffset) {
fcntl(recordFd,F_SETFL,fcntl(recordFd, F_GETFL, NULL)|O_NONBLOCK);
ioctl(recordFd,AUDIO_START,0);
WHY("calling read()");
int b=read(recordFd,&recordMarshallBuffer[0],recordBufferSize);
if (b<1)
WHYF("read failed: b=%d, err=%s",b,strerror(errno));
if (errno==EBADF) recordFd=-1;
WHYF("read %d raw (upsampled) bytes",b);
recordMarshallBufferOffset=b;
}
/* supply audio from marshalling buffer if it has anything.
Don't forget to downsample first. */
int marshall_offset=0;
while(marshall_offset<recordMarshallBufferOffset
&&supplied<maximum_count) {
buffer[supplied+0]=recordMarshallBuffer[marshall_offset];
buffer[supplied+1]=recordMarshallBuffer[marshall_offset+1];
supplied+=2;
marshall_offset+=2*RESAMPLE_FACTOR;
}
bcopy(&recordMarshallBuffer[marshall_offset],
&recordMarshallBuffer[0],
recordMarshallBufferOffset-marshall_offset);
recordMarshallBufferOffset-=marshall_offset;
/* Else we read exactly one buffer full into the marshalling buffer */
WHYF("Read %d samples.",supplied/2);
return supplied;
}
int playMarshallBufferOffset=0;
int audio_msm_g1_write(unsigned char *data,int bytes)
{
if (playFd==-1) return 0;
fcntl(playFd,F_SETFL,fcntl(playFd, F_GETFL, NULL)|O_NONBLOCK);
WHYF("Writing %d bytes of 8KHz audio",bytes);
int i,played=0;
while(played<bytes)
{
if (playMarshallBufferOffset==playBufferSize) {
/* we have a buffer full of samples, so play it */
struct msm_audio_stats stats;
if (ioctl (playFd, AUDIO_GET_STATS, &stats) == 0)
WHYF("stats.out_bytes = %10d", stats.out_bytes);
/* even if set non-blocking the following write can block
if we don't call this ioctl first */
ioctl(playFd,AUDIO_START,0);
int w=write(playFd,&playMarshallBuffer[0],playBufferSize);
if (w<1)
{
WHYF("Failed to write, returned %d (errno=%s)",
w,strerror(errno));
if (errno==EBADF) playFd=-1;
} else {
if (w<=playBufferSize) {
/* short write, so update buffer status and inform caller */
bcopy(&playMarshallBuffer[w],&playMarshallBuffer[0],
playBufferSize-w);
playMarshallBufferOffset-=w;
WHYF("short write: %d of %d raw bytes written",
w,playBufferSize);
return w/RESAMPLE_FACTOR;
}
}
playMarshallBufferOffset=0;
}
/* upsample for playing back */
for(i=0;i<RESAMPLE_FACTOR;i++) {
playMarshallBuffer[playMarshallBufferOffset++]
=data[played];
playMarshallBuffer[playMarshallBufferOffset++]
=data[played+1];
}
played+=2;
}
WHYF("done writing %d audio bytes",played);
return played;
}
/* See if we can query end-points for this device.
If so, assume we have detected it.
*/
monitor_audio *audio_msm_g1_detect()
{
int fd = open ("/dev/msm_snd", O_RDWR);
if (fd<0) {
WHYF("Could not open /dev/msm_snd (err=%s)",strerror(errno));
return NULL;
}
int endpoints=0;
ioctl(fd,SND_GET_NUM_ENDPOINTS,&endpoints);
close(fd);
if (endpoints>0) {
monitor_audio *au=calloc(sizeof(monitor_audio),1);
strcpy(au->name,"G1/IDEOS style MSM audio");
au->start=audio_msm_g1_start;
au->stop=audio_msm_g1_stop;
au->poll_fds=audio_msm_g1_poll_fds;
au->read=audio_msm_g1_read;
au->write=audio_msm_g1_write;
return au;
} else {
WHY("zero end points, so assuming not compatibile audio device");
return NULL;
}
}

View File

@ -1,57 +0,0 @@
/*
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

@ -1,78 +0,0 @@
/*
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"
#define AUDIO_MSM_G1_ETC 1
#define AUDIO_MSM_N1_ETC 2
monitor_audio *audev=NULL;
int playFd=-1;
int recordFd=-1;
int playBufferSize=0;
int recordBufferSize=0;
int detectAudioDevice()
{
#ifdef ANDROID
if (!audev) audev=audio_msm_g1_detect();
#endif
#ifdef HAVE_SYS_ALSA_ASOUNDLIB_H
if (!audev) audev=audio_alsa_detect();
#endif
if (audev) {
WHYF("Detected audio device '%s'",audev->name);
return 0;
}
return -1;
}
int getAudioPlayFd()
{
return playFd;
}
int getAudioRecordFd()
{
return recordFd;
}
/* read some audio, but not more than bufferSize-offset bytes.
*/
int getAudioBytes(unsigned char *buffer,
int offset,
int bufferSize)
{
if (audev&&audev->write) {
return audev->write(&buffer[offset],bufferSize-offset);
}
return -1;
}
int stopAudio()
{
if (audev&&audev->stop) return audev->stop();
return -1;
}
int startAudio()
{
if (audev&&audev->start) return audev->start();
return -1;
}

View File

@ -1,5 +1,4 @@
SERVAL_SOURCES = $(SERVAL_BASE)audiodevices.c \
$(SERVAL_BASE)audio_reflector.c \
SERVAL_SOURCES = \
$(SERVAL_BASE)cli.c \
$(SERVAL_BASE)commandline.c \
$(SERVAL_BASE)conf.c \