📄 sound.c
字号:
/* Gnome-o-Phone - A program for internet telephony Copyright (C) 1999 Roland Dreier 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., 675 Mass Ave, Cambridge, MA 02139, USA. $Id: sound.c 1.15 Sat, 11 Dec 1999 23:53:26 -0600 dreier $*/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include "sound.h"#ifdef HAVE_LINUX_TELEPHONY_H#include <linux/telephony.h>#endif#ifdef HAVE_LINUX_IXJUSER_H#include <linux/ixjuser.h>#endif#include <linux/soundcard.h>#include <sys/types.h>#include <sys/ioctl.h>#include <unistd.h>#include <sys/stat.h>#include <fcntl.h>#include <glib.h>#if defined (HAVE_GSM_H)#include <gsm.h>#elif defined (HAVE_GSM_GSM_H)#include <gsm/gsm.h>#else#error "GSM header file not found."#endif#include <errno.h>#include <string.h>#include "gphone.h"#include "gphone-lib.h"struct Sound_Handle { int fd;};enum { RAW_FRAME_LENGTH = 160 /* samples in an uncompressed GSM frame */};static int Sound_Use_Count = 0;static Duplex_Type Duplex;static Sound_Device_Type Device;static int Ixj_Port;static int Eight_Bit;static int Sound_FD = -1;static int Sound_Direction;static int Mic_Mute = 0;G_LOCK_DEFINE_STATIC(Sound_Access);voidsound_init(void){#ifdef HAVE_LINUX_TELEPHONY_H#ifdef HAVE_LINUX_IXJUSER_H set_sound_ixj_port(PORT_POTS);#endif#endif}static Sound_Handlesound_handle_new(void){ Sound_Handle handle; handle = g_malloc(sizeof *handle); return handle;}static voidsound_handle_free(Sound_Handle handle){ g_return_if_fail(handle != NULL); g_free(handle);}size_tget_enc_frame_length(void){ return(sizeof(gsm_frame));}size_tget_raw_frame_length(void){ return(RAW_FRAME_LENGTH * sizeof (gsm_signal));}Duplex_Typeget_sound_duplex(void){ Duplex_Type ret; G_LOCK(Sound_Access); ret = Duplex; G_UNLOCK(Sound_Access); return ret;}voidset_sound_duplex(Duplex_Type dup){ if (!sound_in_use()) { G_LOCK(Sound_Access); Duplex = dup; G_UNLOCK(Sound_Access); }}Sound_Device_Typeget_sound_device(void){ Sound_Device_Type ret; G_LOCK(Sound_Access); ret = Device; G_UNLOCK(Sound_Access); return ret;}voidset_sound_device(Sound_Device_Type dev){ if (!sound_in_use()) { G_LOCK(Sound_Access); Device = dev; G_UNLOCK(Sound_Access); }}intget_sound_ixj_port(void){ int ret; G_LOCK(Sound_Access); ret = Ixj_Port; G_UNLOCK(Sound_Access); return ret;}voidset_sound_ixj_port(int port){ if (!sound_in_use()) { G_LOCK(Sound_Access); Ixj_Port = port; G_UNLOCK(Sound_Access); }}voidset_sound_eight_bit(int eight){ if (!sound_in_use()) { G_LOCK(Sound_Access); Eight_Bit = eight; G_UNLOCK(Sound_Access); }}voidsound_mute_mic(int mute){ G_LOCK(Sound_Access); Mic_Mute = mute; G_UNLOCK(Sound_Access);}static intsound_oss_open(int direction){ int soundfd; int format, stereo, speed; soundfd = open("/dev/dsp", direction); if (soundfd == -1) { return soundfd; } if (!Eight_Bit) { format = AFMT_S16_LE; } else { format = AFMT_U8; } if (ioctl(soundfd, SNDCTL_DSP_SETFMT, &format) < 0) { gphone_perror_exit("*** sound_open : SNDCTL_DSP_SETFMT", 2); } if ((Eight_Bit) && (format != AFMT_U8)) { gphone_print_exit("*** sound_open : 8 bit unsigned samples not supported.\n", 2); } if ((!Eight_Bit) && (format != AFMT_S16_LE)) { gphone_print_exit("*** sound_open : 16 bit signed samples not supported..\n", 2); } stereo = 0; /* mono */ if (ioctl(soundfd, SNDCTL_DSP_STEREO, &stereo) < 0) { gphone_perror_exit("*** sound_open : SNDCTL_DSP_STEREO", 2); } if (stereo != 0) { gphone_print_exit("*** sound_open : mono not supported.\n", 2); } speed = 8000; if (ioctl(soundfd, SNDCTL_DSP_SPEED, &speed) < 0) { gphone_perror_exit("*** sound_open : SNDCTL_DSP_SPEED", 2); } if (speed < 7950 || speed > 8050) { gphone_print_exit("*** sound_open : 8khz sampling not supported.\n", 2); } return soundfd;}static intsound_ixj_open(int direction){ int soundfd; int codec; soundfd = open("/dev/phone0", O_RDWR); /* ignore direction param */ if (soundfd == -1) { return soundfd; }#ifdef HAVE_LINUX_TELEPHONY_H#ifdef HAVE_LINUX_IXJUSER_H if (!Eight_Bit) { codec = LINEAR16; } else { codec = LINEAR8; } ioctl(soundfd, IXJCTL_PORT, Ixj_Port); ioctl(soundfd, IXJCTL_AEC_START, AEC_HIGH); ioctl(soundfd, IXJCTL_DAA_AGAIN, AGRR06DB | AGX00DB); ioctl(soundfd, PHONE_REC_CODEC, codec); ioctl(soundfd, PHONE_PLAY_CODEC, codec); if (!ioctl(soundfd, PHONE_RING)) { g_warning("Cannot issue a RING to Quicknet/POTS device"); } ioctl(soundfd, PHONE_REC_START); ioctl(soundfd, PHONE_PLAY_START);#else g_warning("Compiled without Quicknet support and tried to open Quicknet device.");#endif /* HAVE_LINUX_IXJUSER_H */#else g_warning("Compiled without Quicknet support and tried to open Quicknet device.");#endif /* HAVE_LINUX_TELEPHONY_H */ return soundfd;}staticint sound_open_device(int direction){ switch (Device) { case OSS_DEVICE: return sound_oss_open(Sound_Direction); break; case IXJ_DEVICE: return sound_ixj_open(Sound_Direction); break; default: g_warning("Unknown sound device type: %d", Device); return -1; break; }}Sound_Handlesound_open(int direction){ int fd; Sound_Handle hand; G_LOCK(Sound_Access); if (Duplex == FULL_DUPLEX) { if (Sound_Use_Count == 0) { Sound_Direction = O_RDWR; Sound_FD = sound_open_device(Sound_Direction); } fd = Sound_FD; } else { if (Sound_Use_Count == 0) { Sound_Direction = direction; Sound_FD = sound_open_device(Sound_Direction); fd = Sound_FD; } else { if (direction == Sound_Direction) { fd = Sound_FD; } else { g_warning("attempt to open sound device in wrong direction"); fd = -1; } } } if (fd == -1) { hand = NULL; } else { hand = sound_handle_new(); hand -> fd = Sound_FD; } ++Sound_Use_Count; G_UNLOCK(Sound_Access); return hand;}intsound_in_use(void){ int in_use; G_LOCK(Sound_Access); in_use = Sound_Use_Count > 0; G_UNLOCK(Sound_Access); return in_use;}voidsound_close(Sound_Handle hand){ g_return_if_fail(hand != NULL); G_LOCK(Sound_Access); --Sound_Use_Count; if (Sound_Use_Count == 0) { if (ioctl(hand -> fd, SNDCTL_DSP_SYNC, 0) < 0) { gphone_perror_exit("*** sound_close : SNDCTL_DSP_SYNC", 2); } if (close(hand -> fd) < 0) { gphone_perror_exit("*** sound_close : close soundfd", 2); } } sound_handle_free(hand); G_UNLOCK(Sound_Access);}voidread_samples(Sound_Handle hand, void *sample, int bufsize){ int i; int readsize; int tot, bytes; gchar *readbuf; g_return_if_fail(hand != NULL); if (Mic_Mute) { for (i = 0; i < bufsize / 2; i++) { ((gint16 *) sample)[i] = 0; } } else { if (!Eight_Bit) { readsize = bufsize; readbuf = sample; } else { readsize = bufsize / 2; readbuf = g_malloc(readsize); } tot = 0; while (tot < readsize) { bytes = read(hand -> fd, readbuf + tot, readsize - tot); if (bytes < 0) { gphone_perror_exit("*** read_sample : read", 3); } tot += bytes; } if (Eight_Bit) { for (i = 0; i < readsize; i++) { ((char *) sample)[i * 2] = 0; ((char *) sample)[i * 2 + 1] = readbuf[i] - 0x80; } g_free(readbuf); } }}voidwrite_samples(Sound_Handle hand, void *sample, int bufsize){ int i; int writesize; int tot, bytes; gchar *writebuf; g_return_if_fail(hand != NULL); if (!Eight_Bit) { writesize = bufsize; writebuf = (gchar *) sample; } else { writesize = bufsize / 2; writebuf = g_malloc(writesize / 2); for (i = 0; i < writesize; i++) { writebuf[i] = ((char *) sample)[i * 2 + 1] + 0x80; } } tot = 0; while (tot < writesize) { bytes = write(hand -> fd, writebuf + tot, writesize - tot); if (bytes < 0) { gphone_perror_exit("*** write_sample : write", 3); } tot += bytes; } /* Does syncing here reduce latency?? */ if (fsync(hand -> fd) > 0) { g_warning("cannot synch writing sample: %s", strerror(errno)); } if (Eight_Bit) { g_free(writebuf); }}intfind_power_level(void *buf, int buflen){ int i; guint32 level; level = 0; for (i = 0; i < buflen / 2; i++) { if (ABS(GINT16_FROM_LE(((gint16 *) buf)[i])) > level) { level = ABS(GINT16_FROM_LE(((gint16 *) buf)[i])); } } return (int) CLAMP(level, 0, G_MAXSHORT);}/* * Local variables: * compile-command: "make -k libgphone.a" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -