Форум автозвука и установки музыки в автомобиль
Показано с 1 по 10 из 177

Андроид зеркало на Allwinner A13

Древовидный режим

  1. #11
    Ушел в ЛАС Технический директор Array Репутация: лучше не знать Аватар для HoSStiA
    Регистрация
    11.01.2004
    Город/село
    Столиця
    Сообщений
    13,050
    Спасибо (Раздал)
    11289
    Спасибо (Получил)
    14942

    Re: Андроид зеркало на Allwinner A13

    Несколько недель изысканий, и реализация низкоуровневых поканальных задержек для устройств на Allwinner A13 (в т.ч. и этого зеркала) привела к, на удивление (!), весьма компактному коду, легко портируемому на практически любые устройства, в т.ч. и на такие, где надстройка ALSA не предусмотрена вообще.

    Поканальные задержки внедрены непосредственно в обработчик выходного потока, перед отправкой в буфер PCM. Сначала планировал реализовать это, расширив библиотеку speex, из которой сам Андроид активно использует ресемплер, но в итоге быстрее оказалось решить задачу на более "низком" уровне.

    Есть еще на чем поработать, в частности нужно внимательно проверить стыковки при смене буфера, но это уже в процессе "эксплуатации".

    Значения задержек в секундах (можно использовать дробные значения) необходимо поместить в файл /etc/audio_delays.conf, по одному числу на каждую строку для каждого канала последовательно, т.е., к примеру:
    Код:
    0.245678
    0.019735325
    установят задержку 0.245678 сек на левый канал, и 0.019735325 на правый канал.

    Все изменения от предыдущих релизов сосредоточены в библиотеке /system/lib/hw/audio.primary.exDroid.so.


    Код:
    diff -r 81bbd579644e softwinner/pmp3670b/libraries/audio/audio_hw.c
    --- a/softwinner/pmp3670b/libraries/audio/audio_hw.c	Fri Oct 24 19:23:15 2014 +0400
    +++ b/softwinner/pmp3670b/libraries/audio/audio_hw.c	Sat Oct 25 11:25:12 2014 +0400
    @@ -22,6 +22,7 @@
     #include <stdint.h>
     #include <sys/time.h>
     #include <sys/stat.h>
    +#include <stdio.h>
     #include <stdlib.h>
     
     #include <cutils/log.h>
    @@ -239,7 +240,7 @@
         },
     	{
     		.ctl_name = NULL,
    -	},
    +		},
     };
     
     struct route_setting line_in_rec_routing[] = {
    @@ -372,6 +373,8 @@
         struct echo_reference_itfe *echo_reference;
         struct sunxi_audio_device *dev;
         int write_threshold;
    +    unsigned long *channel_delay;	
    +    char **delay_chunk;
     };
     
     #define MAX_PREPROCESSORS 3 /* maximum one AGC + one NS + one AEC per input stream */
    @@ -783,6 +786,51 @@
         }
     }
     
    +static unsigned int audio_format_to_bytes(enum pcm_format format)
    +{
    +    switch (format) {
    +    case PCM_FORMAT_S32_LE:
    +    case PCM_FORMAT_S24_LE:
    +        return 32 >> 3;
    +    default:
    +    case PCM_FORMAT_S16_LE:
    +        return 16 >> 3;
    +    };
    +}
    +
    +static unsigned long get_delay_config (unsigned short channel, uint32_t rate) {
    +	unsigned long delay = 0;
    +
    +	FILE * fp ;
    +	
    +	size_t MAXLINE = 12;
    +	char line[MAXLINE];
    +
    +	unsigned short current_channel = 0;
    +	char filename[] = "/etc/audio_delays.conf";
    +
    +	fp = fopen(filename, "r");
    +
    +	if(fp != NULL){
    +    		while(!feof(fp)){
    +			fgets(line, MAXLINE, fp);
    +         		if (current_channel == channel) {
    +				delay = (unsigned long)(atof(line) * rate);
    +				break;
    +			}
    +			current_channel++;
    +   	 	}
    +	} else {
    +    	       delay = 0;
    +	}
    +	
    +	if (fp != NULL) {
    +	       fclose(fp);
    +	}
    +
    +       return delay;
    +}
    +
     /* must be called with hw device and output stream mutexes locked */
     static int start_output_stream(struct sunxi_stream_out *out)
     {
    @@ -891,7 +939,19 @@
         out->write_threshold = PLAYBACK_PERIOD_COUNT * LONG_PERIOD_SIZE;
         out->config.start_threshold = SHORT_PERIOD_SIZE * 2;
         out->config.avail_min = LONG_PERIOD_SIZE;
    -	
    +
    +    unsigned long delay_config[out->config.channels];
    +    unsigned short channel;
    +    char *delay_buffer[out->config.channels];
    +
    +    for (channel = 0; channel < out->config.channels; channel++) { 
    +        delay_config[channel] = get_delay_config(channel, out->config.rate);
    +	delay_buffer[channel] = malloc(delay_config[channel] * audio_format_to_bytes(out->config.format));
    +	memset(delay_buffer[channel],0,delay_config[channel] * audio_format_to_bytes(out->config.format));
    +    }
    +
    +    out->channel_delay = delay_config;
    +    out->delay_chunk = delay_buffer;
         LOGD("start_output_stream: card:%d, port:%d, rate:%d", card, port, out->config.rate);
     
     //    out->pcm = pcm_open_req(card, port, PCM_OUT | PCM_MMAP | PCM_NOIRQ, &out->config, DEFAULT_OUT_SAMPLING_RATE);
    @@ -1279,6 +1339,40 @@
         out->config.avail_min = SHORT_PERIOD_SIZE;
     	pcm_set_avail_min(out->pcm, out->config.avail_min);
     
    +    /* applay delays per channel */
    +    unsigned short current_channel = 0;
    +    unsigned long max_delay_range = 0;
    +	
    +	/* check at least one channel delay present */
    +    while(current_channel < out->config.channels) {
    +	if (out->channel_delay[current_channel] > max_delay_range)
    +		max_delay_range = out->channel_delay[current_channel];
    +	current_channel++;
    +    }
    +
    +    if (max_delay_range > 0) {
    +    	size_t current_frame, current_offset;
    +    	size_t bytes_in_frame = frame_size/out->config.channels;
    +    	char *c, *cc;
    +	
    +    	cc = malloc(bytes_in_frame);
    +	/* shift data in each channel frame by frame */
    +    	for(current_frame = 0, current_offset = 0;
    +			   current_frame < in_frames; 
    +			   current_frame++, current_offset += frame_size) {
    +		for(current_channel = 0; current_channel < out->config.channels; current_channel++) {
    +			if (out->channel_delay[current_channel] > 0) {
    +				c = (char *)buffer + current_offset + current_channel*bytes_in_frame;
    +
    +				memcpy(cc, c, bytes_in_frame);
    +				memcpy(c, out->delay_chunk[current_channel], bytes_in_frame);
    +				memmove(out->delay_chunk[current_channel],out->delay_chunk[current_channel]+bytes_in_frame,(out->channel_delay[current_channel]-1)*bytes_in_frame);
    +				memcpy(out->delay_chunk[current_channel]+(out->channel_delay[current_channel]-1)*bytes_in_frame, cc, bytes_in_frame);
    +			}	
    +		}
    +    	}
    +    }
    +
         /* only use resampler if required */
         if (out->resampler) {
             out->resampler->resample_from_input(out->resampler,
    @@ -2099,7 +2193,7 @@
         *sample_rate = out_get_sample_rate(&out->stream.common);
     
     	LOGV("+++++++++++++++ adev_open_output_stream: req_sample_rate: %d, fmt: %x, channel_count: %d",
    -		*sample_rate, *format, *channels);
    +		*sample_rate, *format, *channels); 
     
         *stream_out = &out->stream;
         return 0;
    @@ -2120,6 +2214,8 @@
             free(out->buffer);
         if (out->resampler)
             release_resampler(out->resampler);
    +    if (out->delay_chunk)
    +	free(out->delay_chunk);
         free(stream);
     }


    Вложения

Социальные закладки

Социальные закладки

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •  
  cc by-nc-sa