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

📄 a2dpd.c

📁 linux蓝牙剖面实现
💻 C
📖 第 1 页 / 共 4 页
字号:
			lpClientData->ring[lpClientData->ring_in].hdr = *lpHdr;			lpClientData->ring[lpClientData->ring_in].len = lpConvert->size;			lpClientData->ring_in = next_ring;			// We will not free that buffer, it's the bthandler thread which will do it			lpConvert->lpVoid = NULL;			lpConvert->size = 0;			lpConvert->index_to_construct = 0;			lpConvert->index_0 = 0;		} else {			//DBG("Ring buffer is full");		}		pthread_mutex_unlock(&lpClientData->mutex);	}	// Reintegrate data in pool if not transmitted via bthandler thread	safefree(lpConvert->lpVoid);}// Convert individual samplevoid convert_sample(AUDIOSTREAMINFOS* lpStreamInfos, void* lpSample, void* lpConvertedSample, BTA2DPPERDEVICEDATA* lpDevice){	// Signed 32bits pivot	int32_t channel_1=0;	int32_t channel_2=0;	// Convert to pivot format	if(lpStreamInfos->channels==1) {		if(lpStreamInfos->format==A2DPD_PCM_FORMAT_S8) {			channel_1 = (*(((int8_t*)lpSample)+0))*256;			channel_2 = (*(((int8_t*)lpSample)+0))*256;		} else if(lpStreamInfos->format==A2DPD_PCM_FORMAT_U8) {			channel_1 = ((*(((int8_t*)lpSample)+0))-(int)128)*256;			channel_2 = ((*(((int8_t*)lpSample)+0))-(int)128)*256;		} else if(lpStreamInfos->format==A2DPD_PCM_FORMAT_S16_LE) {			channel_1 = *(((int16_t*)lpSample)+0);			channel_2 = *(((int16_t*)lpSample)+0);		}	} else if(lpStreamInfos->channels==2) {		if(lpStreamInfos->format==A2DPD_PCM_FORMAT_S8) {			channel_1 = (*(((int8_t*)lpSample)+0))*256;			channel_2 = (*(((int8_t*)lpSample)+1))*256;		} else if(lpStreamInfos->format==A2DPD_PCM_FORMAT_U8) {			channel_1 = ((*(((int8_t*)lpSample)+0))-(int)128)*256;			channel_2 = ((*(((int8_t*)lpSample)+1))-(int)128)*256;		} else if(lpStreamInfos->format==A2DPD_PCM_FORMAT_S16_LE) {			channel_1 = *(((int16_t*)lpSample)+0);			channel_2 = *(((int16_t*)lpSample)+1);		}	} else {		if(lpStreamInfos->format==A2DPD_PCM_FORMAT_S8) {			channel_1 = (*(((int8_t*)lpSample)+0))*256;			channel_2 = (*(((int8_t*)lpSample)+1))*256;		} else if(lpStreamInfos->format==A2DPD_PCM_FORMAT_U8) {			channel_1 = ((*(((int8_t*)lpSample)+0))-(int)128)*256;			channel_2 = ((*(((int8_t*)lpSample)+1))-(int)128)*256;		} else if(lpStreamInfos->format==A2DPD_PCM_FORMAT_S16_LE) {			channel_1 = *(((int16_t*)lpSample)+0);			channel_2 = *(((int16_t*)lpSample)+1);		}	}	// Convert to destination format	if(lpDevice->a2dp_channels==1) {		if(lpDevice->a2dp_bitspersample==1) {			*(int8_t*)lpConvertedSample=(channel_1+channel_2)/(2*256);		} else if(lpDevice->a2dp_bitspersample==2) {			*(int16_t*)lpConvertedSample=(channel_1+channel_2)/(2);		}	} else if(lpDevice->a2dp_channels==2) {		if(lpDevice->a2dp_bitspersample==1) {			*(((int8_t*)lpConvertedSample)+0)=channel_1/256;			*(((int8_t*)lpConvertedSample)+1)=channel_2/256;		} else if(lpDevice->a2dp_bitspersample==2) {			*(((int16_t*)lpConvertedSample)+0)=channel_1;			*(((int16_t*)lpConvertedSample)+1)=channel_2;		}	} else {		memset(lpConvertedSample, 0, lpDevice->a2dp_bitspersample*lpDevice->a2dp_channels);		if(lpDevice->a2dp_bitspersample==1) {			*(((int8_t*)lpConvertedSample)+0)=channel_1/256;			*(((int8_t*)lpConvertedSample)+1)=channel_2/256;		} else if(lpDevice->a2dp_bitspersample==2) {			*(((int16_t*)lpConvertedSample)+0)=channel_1;			*(((int16_t*)lpConvertedSample)+1)=channel_2;		}	}}// This function convert a buffer to sample rate and format needed for devicevoid convert_rate(BTA2DPPERDEVICEDATA* lpDevice, BTA2DPPERCLIENTDATA* lpClientData, void* pcm_buffer, int pcm_buffer_size, AUDIOSTREAMINFOS* lpStreamInfos, AUDIOPACKETHEADER* lpHdr){	// We need this structure accross calls	CONVERTBUFFER* lpConvert = &lpClientData->conv;	if(lpConvert && lpStreamInfos && lpStreamInfos->bitspersample) {		unsigned int pcm_buffer_index = 0;		unsigned int pcm_buffer_index_0 = 0;		unsigned int pcm_buffer_frame_bytes = (lpStreamInfos->channels*lpStreamInfos->bitspersample);		unsigned int pcm_buffer_nframes = pcm_buffer_size/pcm_buffer_frame_bytes;		unsigned int rate_multiplier = ((unsigned int)lpStreamInfos->rate)*256 / ((unsigned int)lpDevice->a2dp_rate);		unsigned int convert_frame_bytes = (lpDevice->a2dp_channels*lpDevice->a2dp_bitspersample);		void* lpConvertedSample = mymalloc(convert_frame_bytes);		void* lpSample = NULL;		//int i;		lpConvert->index_0 = lpConvert->index_to_construct;		lpConvert->index_to_construct = 0;		while(pcm_buffer_index<pcm_buffer_nframes) {			// Allocate destination if needed			if(lpConvert->lpVoid==NULL) {				lpConvert->lpVoid = mymalloc(POOLENTRYSIZE_A2DP/*lpDevice->a2dp_framesize*/);				lpConvert->size = lpDevice->a2dp_framesize;				/*				for(i=0; i<lpConvert->size; i++)				{					((char*)lpConvert->lpVoid)[i]=(char)0xFA;				}				*/				lpConvert->index_to_construct = 0;				lpConvert->index_0 = 0;			}			// Get pointer to sample to convert			lpSample = pcm_buffer+(pcm_buffer_index*pcm_buffer_frame_bytes);			// Conversion of individual samples			convert_sample(lpStreamInfos, lpSample, lpConvertedSample, lpDevice);			// Append converted sample to constructed blocks, Can be avoided by converting in destination buffer			void* lpDest = lpConvert->lpVoid+((lpConvert->index_0+lpConvert->index_to_construct)*convert_frame_bytes);			memcpy(lpDest, lpConvertedSample, convert_frame_bytes);			// Fill next index			lpConvert->index_to_construct++;			// The index to fill will be mapped according to rates			pcm_buffer_index = pcm_buffer_index_0 + ((lpConvert->index_to_construct*rate_multiplier)/256);			// If constructed block is full, enqueue and allocate new			if(((lpConvert->index_0+lpConvert->index_to_construct)*convert_frame_bytes)>=lpConvert->size) {				/*				if(checkbuffer(lpConvert->lpVoid))				{					DBG("Buffer overflow: %d,%d", lpConvert->index_0+lpConvert->index_to_construct, lpDevice->a2dp_framesize/convert_frame_bytes);				}				int state=0;				int count=0;				int total=0;				for(i=0; i<lpConvert->size/2; i+=2) {					if(state==0) {						//DBG("%08X | %08X   %d | %d", ((int16_t*)lpConvert->lpVoid)[i], ((int16_t*)lpConvert->lpVoid)[i+1], ((int16_t*)lpConvert->lpVoid)[i], ((int16_t*)lpConvert->lpVoid)[i+1]);						if(((int16_t*)lpConvert->lpVoid)[i]==(int16_t)0xFAFA) {							state=1;							count++;							total++;						} else {							state=0;						}					} else if(state==1) {						if(((int16_t*)lpConvert->lpVoid)[i]==(int16_t)0xFAFA) {							count++;							total++;						} else {							//DBG("Gap in the data %d,%d", count, i);							state=0;							count=0;						}					}				}				if(state==1) {					DBG("Gap in the data: %d, total=%d", count, total);				}				//exit(0);				*/				// Enqueue in ring buffer				append_to_ring_buffer(lpClientData, lpConvert, lpHdr);				// Store next index to read				pcm_buffer_index_0 = pcm_buffer_index;				pcm_buffer_index = pcm_buffer_index_0;			}		}		safefree(lpConvertedSample);	}}// This function manage volume change wanted by clientsvoid a2dpd_plugin_ctl_write(LPA2DPDCLIENT lpClient){	AUDIOMIXERDATA AudioMixerData = INVALIDAUDIOMIXERDATA;	DBG("CTL WRITE thread %d started", lpClient->sockfd);	if (recv_socket(lpClient->sockfd, &AudioMixerData, sizeof(AudioMixerData)) == sizeof(AudioMixerData)) {		pthread_mutex_lock(&lpClient->lpDevice->mutex);		if (AudioMixerData.volume_speaker_left != -1)			lpClient->lpDevice->mixer.volume_speaker_left = AudioMixerData.volume_speaker_left;		if (AudioMixerData.volume_speaker_left != -1)			lpClient->lpDevice->mixer.volume_speaker_right = AudioMixerData.volume_speaker_right;		if (AudioMixerData.volume_micro_left != -1)			lpClient->lpDevice->mixer.volume_micro_left = AudioMixerData.volume_micro_left;		if (AudioMixerData.volume_micro_left != -1)			lpClient->lpDevice->mixer.volume_micro_right = AudioMixerData.volume_micro_right;		pthread_mutex_unlock(&lpClient->lpDevice->mutex);		// Notify other clients		int notifyfd = make_udp_socket();		send_socket(notifyfd, &AudioMixerData, sizeof(AudioMixerData));		close_socket(&notifyfd);	}}// This function manage volume read for clientvoid a2dpd_plugin_ctl_read(LPA2DPDCLIENT lpClient){	AUDIOMIXERDATA AudioMixerData = INVALIDAUDIOMIXERDATA;	DBG("CTL READ thread %d started", lpClient->sockfd);	pthread_mutex_lock(&lpClient->lpDevice->mutex);	AudioMixerData = lpClient->lpDevice->mixer;	pthread_mutex_unlock(&lpClient->lpDevice->mutex);	send_socket(lpClient->sockfd, &AudioMixerData, sizeof(AudioMixerData));}// Retrieve an index in client table for deviceint get_index_for_client(LPBTA2DPPERDEVICEDATA lpDevice){	int client_index = -1;	// Find an index in clients table for the mixer	//pthread_mutex_lock(&lpDevice->mutex);	for (client_index = 0; client_index < MAXCLIENTSPERDEVICE; client_index++) {		if (lpDevice->clients[client_index].lives == 0) {			// FIXME Not sure this is safe but this is very unlikely to happen			lpDevice->clients[client_index].lives = 1;			lpDevice->clients[client_index].state = CLIENT_STATE_NEW;			lpDevice->clients[client_index].ring_in = 0;			lpDevice->clients[client_index].ring_out = 0;			lpDevice->nb_clients++;			break;		}	}	//pthread_mutex_unlock(&lpDevice->mutex);	return client_index;}int poll_incoming_clients_sockets(LPBTA2DPPERDEVICEDATA lpDevice, int delay){	int ipoll = -1;	int i;	int pollfdcount = 0;	int pollfdidx = 0;	struct pollfd pollfds[MAXCLIENTSPERDEVICE];	memset(pollfds, 0, sizeof(pollfds));	// pthread_mutex_lock(&lpDevice->mutex);	// Retrieve data for client where it is available	for (i = 0; i < MAXCLIENTSPERDEVICE; i++) {		if(lpDevice->clients[i].lives) {			pollfds[pollfdcount].fd = lpDevice->clients[i].socket;			pollfds[pollfdcount].events = POLLIN | POLLERR | POLLHUP;			pollfds[pollfdcount].revents = 0;			pollfdcount++;		}	}	if(pollfdcount>0) {		// DBG("Polling %d clients for %d ms", pollfdcount, (delay/1000));		// Poll		ipoll = poll(pollfds, pollfdcount, (delay/1000));		if(ipoll>0) {			// Retrieve data for client where it is available			for (i = 0; i < MAXCLIENTSPERDEVICE; i++) {				// Valid client				if(lpDevice->clients[i].lives) {					int bError = 1;					// Some data to read?					if (pollfds[pollfdidx].revents & POLLIN) {						AUDIOPACKETHEADER hdr;						int client_type = INVALID_CLIENT_TYPE;						AUDIOSTREAMINFOS StreamInfos;						int result;						char* tmpcapture;						int tmpcapturelen;						uint32_t dummy;						// Already streaming?						switch(lpDevice->clients[i].state) {						case CLIENT_STATE_NEW:							bError = 1;							// Receive type of client							if(recv_socket(lpDevice->clients[i].socket, &client_type, sizeof(client_type))==sizeof(client_type)) {								// This client wants to send us pcm control data								if (client_type == A2DPD_PLUGIN_CTL_WRITE) {									DBG("Plugin ctl write ignored");									//a2dpd_plugin_ctl_write(&lpDevice->clients[i]);								}								// This client wants to read our control status								if (client_type == A2DPD_PLUGIN_CTL_READ) {									DBG("Plugin ctl read ignored");									//a2dpd_plugin_ctl_read(&lpDevice->clients[i]);								}								// This client wants to send us pcm stream								if (client_type == A2DPD_PLUGIN_PCM_WRITE) {									lpDevice->clients[i].state = CLIENT_STATE_STREAMINGSETUP;									bError = 0;								}								// This client wants to send us pcm stream								if (client_type == A2DPD_PLUGIN_PCM_READ) {									lpDevice->clients[i].state = CLIENT_STATE_CAPTURESETUP;									bError = 0;								}							}							break;						case CLIENT_STATE_STREAMINGSETUP:							if(recv_socket(lpDevice->clients[i].socket, &StreamInfos, sizeof(StreamInfos))==sizeof(StreamInfos)) {								lpDevice->clients[i].StreamInfos = StreamInfos;								lpDevice->clients[i].state = CLIENT_STATE_STREAMING;								DBG("PLAYBACK thread client_index=%d, socket=%d, id=%d started (%d Hz, %d channels, %d bits)", i, lpDevice->clients[i].socket, StreamInfos.streamid, StreamInfos.rate, StreamInfos.channels, StreamInfos.bitspersample*8);								bError = 0;							} else {								DBG("Playback stream setup failed");							}							break;						case CLIENT_STATE_STREAMING:							result = recv_socket(lpDevice->clients[i].socket, &hdr, sizeof(hdr));							if (result == sizeof(hdr) && hdr.pcm_buffer_size <= A2DPD_BLOCK_SIZE) {								// Display reception delay								struct timeval now;								gettimeofday(&now, NULL);								timersub(&now, &hdr.packet_date, &now);								//DBG("delay at recv_socket: %d µs", (int)now.tv_usec);								char *pcm_buffer = mymalloc(hdr.pcm_buffer_size);								if(pcm_buffer) {									int result2 = recv_socket(lpDevice->clients[i].socket, pcm_buffer, hdr.pcm_buffer_size);									if (result2 == hdr.pcm_buffer_size) {										// Rate conversion										convert_rate(lpDevice, &lpDevice->clients[i], pcm_buffer, result2, &lpDevice->clients[i].StreamInfos, &hdr);										bError = 0;									} else {										DBG("Receive stream failed (%d/%d)", result2, hdr.pcm_buffer_size);									}									safefree(pcm_buffer);								} else {									DBG("Couldn't alloc buffer %d", hdr.pcm_buffer_size);								}							} else {								DBG("Did not receive pkt_hdr");							}							break;						case CLIENT_STATE_CAPTURESETUP:							if(recv_socket(lpDevice->clients[i].socket, &StreamInfos, sizeof(StreamInfos))==sizeof(StreamInfos)) {								lpDevice->clients[i].StreamInfos = StreamInfos;								lpDevice->clients[i].state = CLIENT_STATE_CAPTURE;								DBG("CAPTURE thread %d.%d started (%d Hz, %d channels, %d bits)", i, lpDevice->clients[i].socket, StreamInfos.rate, StreamInfos.channels, StreamInfos.bitspersample*8);								bError = 0;							} else {								DBG("Capture stream setup failed");							}							break;						case CLIENT_STATE_CAPTURE:							// Read ring buffer data and write to client							DBG("Capturing");							tmpcapture = NULL;							tmpcapturelen = 0;							pthread_mutex_lock(&lpDevice->capture_mutex);							if (lpDevice->ring_in != lpDevice->ring_out) {								tmpcapture = lpDevice->ring[lpDevice->ring_out].buf;								tmpcapturelen = lpDevice->ring[lpDevice->ring_out].len;								DBG("Dequeue sco incoming stream %d", lpDevice->ring_out);								// Move to next ring								int next_ring = ((lpDevice->ring_out + 1) % MAXCLIENTSRINGSIZE);								lpDevice->ring_out = next_ring;							}							pthread_mutex_unlock(&lpDevice->capture_mutex);							if(recv_socket(lpDevice->clients[i].socket, &dummy, sizeof(dummy))==sizeof(dummy)) {								DBG("RECEIVED sync from plugin");								if(send_socket(lpDevice->clients[i].socket, &tmpcapturelen, sizeof(tmpcapturelen)) == sizeof(tmpcapturelen)) {									if(tmpcapture != NULL) {										if(send_socket(lpDevice->clients[i].socket, tmpcapture, tmpcapturelen) == tmpcapturelen) {											bError = 0;											DBG("Wrote stream %d", tmpcapturelen);										} else {											DBG("Couldn't write capture stream");										}										safefree(tmpcapture);									} else {										DBG("No capture sent");									}								} else {									DBG("Couldn't send");								}

⌨️ 快捷键说明

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