⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcm_a2dpd.c

📁 linux蓝牙剖面实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/***  BlueZ - Bluetooth protocol stack for Linux**  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>***  This library is free software; you can redistribute it and/or*  modify it under the terms of the GNU Lesser General Public*  License as published by the Free Software Foundation; either*  version 2.1 of the License, or (at your option) any later version.**  This library 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*  Lesser General Public License for more details.**  You should have received a copy of the GNU Lesser General Public*  License along with this library; if not, write to the Free Software*  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA**/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <stdio.h>#include <errno.h>#include <malloc.h>#include <signal.h>#include <sys/ioctl.h>#include <sys/socket.h>#include <sys/time.h>#include <syslog.h>#include <alsa/asoundlib.h>#include <alsa/pcm_external.h>#include <alsa/timer.h>#include "../a2dp.h"#include "a2dpd_protocol.h"#include "a2dpd_timer.h"#include "a2dpd_ipc.h"int g_bdebug = 0;typedef struct snd_pcm_a2dp {	snd_pcm_ioplug_t io;	int opened_for;	int streamid;	int rateconstraint;	int rate;	int sk;	int channels;	snd_pcm_sframes_t num;	unsigned int frame_bytes;	TIMERINFO TimerInfos;} snd_pcm_a2dp_t;static int a2dp_disconnect(snd_pcm_a2dp_t * a2dp){	close_socket(&a2dp->sk);	return 0;}static int a2dp_connect(snd_pcm_a2dp_t * a2dp){	if (a2dp->sk <= 0) {		int sockfd = make_client_socket();		a2dp->sk = -1;		if (sockfd > 0) {			int32_t client_type = a2dp->opened_for;			if (send_socket(sockfd, &client_type, sizeof(client_type)) == sizeof(client_type)) {				// Fill stream informations				AUDIOSTREAMINFOS StreamInfos = INVALIDAUDIOSTREAMINFOS;				StreamInfos.rate = a2dp->rate;				StreamInfos.channels = a2dp->channels;				StreamInfos.bitspersample = a2dp->frame_bytes/a2dp->channels;				StreamInfos.streamid = a2dp->streamid;				switch(a2dp->io.format) {				case SND_PCM_FORMAT_S8:     StreamInfos.format = A2DPD_PCM_FORMAT_S8; break;				case SND_PCM_FORMAT_U8:     StreamInfos.format = A2DPD_PCM_FORMAT_U8; break;				case SND_PCM_FORMAT_S16_LE: StreamInfos.format = A2DPD_PCM_FORMAT_S16_LE; break;				default: StreamInfos.format = A2DPD_PCM_FORMAT_UNKNOWN; break;				}				if (send_socket(sockfd, &StreamInfos, sizeof(StreamInfos)) == sizeof(StreamInfos)) {					a2dp->sk = sockfd;					DBG("Connected a2dp %p, sk %d, fps %f", a2dp, a2dp->sk, a2dp->TimerInfos.fps);				} else {					//syslog(LOG_WARNING, "Couldn't send stream informations");					a2dp_disconnect(a2dp);				}			} else {				close_socket(&sockfd);				//syslog(LOG_WARNING, "Connected a2dp %p, sk %d, Authorisation failed", a2dp, a2dp->sk);			}		} else {			//syslog(LOG_ERR, "Socket failed a2dp %p, sk %d", a2dp, a2dp->sk);		}	}	return 0;}static inline snd_pcm_a2dp_t *a2dp_alloc(void){	snd_pcm_a2dp_t *a2dp;	a2dp = malloc(sizeof(*a2dp));	if (a2dp) {		memset(a2dp, 0, sizeof(*a2dp));		a2dp->sk = -1;	}	return a2dp;}static inline void a2dp_free(snd_pcm_a2dp_t * a2dp){	a2dp_disconnect(a2dp);	free(a2dp);}static int a2dp_start(snd_pcm_ioplug_t * io){	//snd_pcm_a2dp_t *a2dp = io->private_data;	//FIXME	return 0;}static int a2dp_stop(snd_pcm_ioplug_t * io){	//snd_pcm_a2dp_t *a2dp = io->private_data;	return 0;}static snd_pcm_sframes_t a2dp_pointer(snd_pcm_ioplug_t * io){	snd_pcm_a2dp_t *a2dp = io->private_data;	//DBG("returning a2dp->num = %lu", a2dp->num);	return a2dp->num;}// This is the main transfer func which does the transfer and sleep jobstatic snd_pcm_sframes_t a2dp_transfer2(snd_pcm_ioplug_t * io, char *buf, int32_t datatoread){	snd_pcm_a2dp_t *a2dp = io->private_data;	int transfer = 0;	int delay = 0;	AUDIOPACKETHEADER hdr;	gettimeofday(&hdr.packet_date, NULL);	hdr.pcm_buffer_size = datatoread;	// Connect if needed and send	a2dp_connect(a2dp);	if (transfer >= 0)		transfer = send_socket(a2dp->sk, &hdr, sizeof(hdr));	if (transfer >= 0)		transfer = send_socket(a2dp->sk, buf, hdr.pcm_buffer_size);	// Disconnect if error detected	if (transfer < 0)		a2dp_disconnect(a2dp);	// The data are sent to the daemon that act as a proxy thus we double transfer delay to compensate latency	a2dp_timer_notifyframe(&a2dp->TimerInfos);	delay = a2dp_timer_sleep(&a2dp->TimerInfos, 4*A2DPTIMERPREDELAY);	//usleep(delay);	// Stats	if (a2dp->TimerInfos.display > 0) {		if (errno != 0 || transfer <= 0) {			//syslog(LOG_INFO, "send_socket(%d bytes)=%d (errno=%d:%s)", datatoread, transfer, errno, strerror(errno));		}	}	// update pointer, tell alsa we're done	a2dp->num += datatoread / a2dp->frame_bytes;	return datatoread / a2dp->frame_bytes;}// also works but sleeps between transfers// This is the main transfer func which does the transfer and sleep jobstatic snd_pcm_sframes_t a2dp_transfer(snd_pcm_ioplug_t * io, const snd_pcm_channel_area_t * areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t nframes){	snd_pcm_a2dp_t *a2dp = io->private_data;	int i = 0;	snd_pcm_sframes_t totaltransfered = 0;	while (i++ < 1 && totaltransfered < nframes) {		char *buf = (char *) areas->addr + (areas->first + areas->step * offset) / 8;		int datatoread = min(A2DPD_BLOCK_SIZE, nframes * a2dp->frame_bytes);		snd_pcm_sframes_t transfered = a2dp_transfer2(io, buf, datatoread);		if (transfered > 0) {			offset += transfered;			totaltransfered += transfered;		} else {			break;		}	}	return totaltransfered;}// This is the main transfer func which does the transfer and sleep jobstatic snd_pcm_sframes_t a2dp_read2(snd_pcm_ioplug_t * io, char *buf, int32_t datatoread){	snd_pcm_a2dp_t *a2dp = io->private_data;	int transfer = 0;	uint32_t pkt_size = 0;	int dummy = 0;	int delay = 0;	// Connect if needed and send	a2dp_connect(a2dp);	DBG("writing 2");	if(transfer>=0)		transfer = send_socket(a2dp->sk, &dummy, sizeof(dummy));	DBG("reading 2 = %d", transfer);	if(transfer>=0)		transfer = recv_socket(a2dp->sk, &pkt_size, sizeof(pkt_size));	DBG("got size %d:%d", transfer, pkt_size);	if(transfer>=0) {		if(pkt_size<datatoread) {			transfer = recv_socket(a2dp->sk, buf, min(datatoread, pkt_size));			DBG("got data %d/%d", transfer, pkt_size);		} else {			DBG("invalid pkt size");		}	}	// update pointer, tell alsa we're done	if(transfer>=0)		a2dp->num += transfer / a2dp->frame_bytes;	// Disconnect if error detected	if (transfer < 0) {		a2dp_disconnect(a2dp);		transfer = 0;	}	a2dp_timer_notifyframe(&a2dp->TimerInfos);	delay = a2dp_timer_sleep(&a2dp->TimerInfos, 0);	//usleep(delay);	return transfer / a2dp->frame_bytes;}static snd_pcm_sframes_t a2dp_read(snd_pcm_ioplug_t *io,				  const snd_pcm_channel_area_t *areas,				  snd_pcm_uframes_t offset,				  snd_pcm_uframes_t nframes){	snd_pcm_a2dp_t *a2dp = io->private_data;	DBG("reading");	char *buf = (char *) areas->addr + (areas->first + areas->step * offset) / 8;	int datatoread = min(A2DPD_BLOCK_SIZE, nframes * a2dp->frame_bytes);	snd_pcm_uframes_t totaltransfered = a2dp_read2(io, buf, datatoread);	return totaltransfered;}/*//	DBG("areas->step=%u, areas->first=%u, offset=%lu, size=%lu, io->nonblock=%u", areas->step, areas->first, offset, size, io->nonblock);	if(bt_headset->sco_data_count == 0) {		int nrecv = recv(scofd, &bt_headset->pkt, sizeof(sco_packet_t),			MSG_WAITALL | (io->nonblock ? MSG_DONTWAIT : 0 ));		if(nrecv == sizeof(sco_packet_t)) {			ret = 0;			// Increment hardware transmition pointer			bt_headset->hw_ptr = (bt_headset->hw_ptr + SCO_PACKET_LEN / 2) % io->buffer_size;		}		else if(nrecv > 0) {			ret = -EIO;			SNDERR(strerror(-ret));		}		else if(nrecv == -1 && errno == EAGAIN) {			ret = -EAGAIN;		}		else { // nrecv < 0			// EPIPE means device underrun in ALSA world. But we mean we lost contact                        //   with server, so we have to find another error cod			ret = (errno == EPIPE ? -EIO : -errno);			SYSERR("Lost contact with headsetd");		}		}	if(ret == 0) { // Still ok, proceed		snd_pcm_uframes_t frames_to_write;		unsigned char *buff;		buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8;				if((bt_headset->sco_data_count + 2 * size) <= SCO_PACKET_LEN) {			frames_to_write = size;		}		else {			frames_to_write = (SCO_PACKET_LEN - bt_headset->sco_data_count) / 2;		}		memcpy(buff, bt_headset->pkt.sco_data + bt_headset->sco_data_count, areas->step / 8 * frames_to_write);			bt_headset->sco_data_count += (areas->step / 8 * frames_to_write);		bt_headset->sco_data_count %= SCO_PACKET_LEN;		// Return written frames count		ret = frames_to_write;	}	return totaltransfered;}*/static int a2dp_close(snd_pcm_ioplug_t * io){	snd_pcm_a2dp_t *a2dp = io->private_data;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -