diff options
Diffstat (limited to 'audio/pcm_bluetooth.c')
| -rw-r--r-- | audio/pcm_bluetooth.c | 110 | 
1 files changed, 68 insertions, 42 deletions
| diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c index 0dec0a12..cc1df64f 100644 --- a/audio/pcm_bluetooth.c +++ b/audio/pcm_bluetooth.c @@ -952,7 +952,7 @@ static int avdtp_write(struct bluetooth_data *data)  	header->timestamp = htonl(a2dp->nsamples);  	header->ssrc = htonl(1); -        ret = send(data->stream.fd, a2dp->buffer, a2dp->count, MSG_DONTWAIT); +	ret = send(data->stream.fd, a2dp->buffer, a2dp->count, MSG_DONTWAIT);  	if (ret < 0) {  		DBG("send returned %d errno %s.", ret, strerror(errno));  		ret = -errno; @@ -974,8 +974,7 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,  	struct bluetooth_data *data = io->private_data;  	struct bluetooth_a2dp *a2dp = &data->a2dp;  	snd_pcm_sframes_t ret = 0; -	snd_pcm_uframes_t frames_to_read, frames_left = size; -	int frame_size, encoded, written; +	int frame_size, encoded, written, bytes_left;  	uint8_t *buff;  	DBG("areas->step=%u areas->first=%u offset=%lu size=%lu", @@ -983,12 +982,19 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,  	DBG("hw_ptr=%lu appl_ptr=%lu diff=%lu", io->hw_ptr, io->appl_ptr,  			io->appl_ptr - io->hw_ptr); +	/* Calutate starting pointers */ +	frame_size = areas->step / 8; +	bytes_left = size * frame_size; +	buff = (uint8_t *) areas->addr + +				(areas->first + areas->step * (offset)) / 8; + +	/* Check for underrun */  	if (io->hw_ptr > io->appl_ptr) {  		ret = bluetooth_playback_stop(io);  		if (ret == 0)  			ret = -EPIPE;  		data->reset = 1; -		goto done; +		return ret;  	}  	/* Check if we should autostart */ @@ -1003,77 +1009,97 @@ static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,  			if (io->appl_ptr >= threshold) {  				ret = snd_pcm_start(io->pcm);  				if (ret != 0) -					goto done; +					return ret;  			}  		}  		snd_pcm_sw_params_free(swparams);  	} -	while (frames_left > 0) { -		frame_size = areas->step / 8; - -		if ((data->count + frames_left * frame_size) <= a2dp->codesize) -			frames_to_read = frames_left; -		else -			frames_to_read = (a2dp->codesize - data->count) / frame_size; +	/* Check if we have any left over data from the last write */ +	if (data->count > 0 && (bytes_left - data->count) >= a2dp->codesize) { +		int additional_bytes_needed = a2dp->codesize - data->count; -		DBG("count=%d frames_to_read=%lu", data->count, frames_to_read); -		DBG("a2dp.count=%d data.link_mtu=%d", a2dp->count, data->link_mtu); - -		/* FIXME: If state is not streaming then return */ - -		/* Ready for more data */ -		buff = (uint8_t *) areas->addr + -			(areas->first + areas->step * (offset + ret)) / 8;  		memcpy(data->buffer + data->count, buff, -				frame_size * frames_to_read); - -		/* Remember we have some frames in the pipe now */ -		data->count += frames_to_read * frame_size; -		if (data->count != a2dp->codesize) { -			ret = frames_to_read; -			goto done; -		} +						additional_bytes_needed);  		/* Enough data to encode (sbc wants 1k blocks) */ -		encoded = sbc_encode(&(a2dp->sbc), data->buffer, a2dp->codesize, +		encoded = sbc_encode(&a2dp->sbc, data->buffer, a2dp->codesize,  					a2dp->buffer + a2dp->count,  					sizeof(a2dp->buffer) - a2dp->count, -					&written); +								&written);  		if (encoded <= 0) {  			DBG("Encoding error %d", encoded);  			goto done;  		} -		data->count -= encoded; +		/* Increment a2dp buffers */  		a2dp->count += written;  		a2dp->frame_count++;  		a2dp->samples += encoded / frame_size;  		a2dp->nsamples += encoded / frame_size; -		DBG("encoded=%d  written=%d count=%d", encoded, -				written, a2dp->count); -  		/* No space left for another frame then send */  		if (a2dp->count + written >= data->link_mtu) {  			avdtp_write(data);  			DBG("sending packet %d, count %d, link_mtu %u",  					a2dp->seq_num, a2dp->count, -					data->link_mtu); +							data->link_mtu); +		} + +		/* Increment up buff pointer to take into account +		 * the data processed */ +		buff += additional_bytes_needed; +		bytes_left -= additional_bytes_needed; + +		/* Since data has been process mark it as zero */ +		data->count = 0; +	} + + +	/* Process this buffer in full chunks */ +	while (bytes_left >= a2dp->codesize) { +		/* Enough data to encode (sbc wants 1k blocks) */ +		encoded = sbc_encode(&a2dp->sbc, buff, a2dp->codesize, +					a2dp->buffer + a2dp->count, +					sizeof(a2dp->buffer) - a2dp->count, +								&written); +		if (encoded <= 0) { +			DBG("Encoding error %d", encoded); +			goto done;  		} -		ret += frames_to_read; -		frames_left -= frames_to_read; +		/* Increment up buff pointer to take into account +		 * the data processed */ +		buff += a2dp->codesize; +		bytes_left -= a2dp->codesize; + +		/* Increment a2dp buffers */ +		a2dp->count += written; +		a2dp->frame_count++; +		a2dp->samples += encoded / frame_size; +		a2dp->nsamples += encoded / frame_size; + +		/* No space left for another frame then send */ +		if (a2dp->count + written >= data->link_mtu) { +			avdtp_write(data); +			printf("sending packet %d, count %d, link_mtu %u", +						a2dp->seq_num, a2dp->count, +							data->link_mtu); +		}  	} -	/* note: some ALSA apps will get confused otherwise */ -	if (ret > size) -		ret = size; +	/* Copy the extra to our temp buffer for the next write */ +	if (bytes_left > 0) { +		memcpy(data->buffer + data->count, buff, bytes_left); +		data->count += bytes_left; +		bytes_left = 0; +	}  done: -	DBG("returning %ld", ret); -	return ret; +	DBG("returning %ld", size - bytes_left / frame_size); + +	return size - bytes_left / frame_size;  }  static int bluetooth_playback_delay(snd_pcm_ioplug_t *io, | 
