Hi

Did you test other resample methods? There are quite a few available
and "trivial" is definitely the worst of them.

Although it maybe depend on CPU, Is there any recommend setting for
resampling-method?
Could you tell me a character for each parameters in resampling-method?


> Sorry, currently I have no idea what goes wrong. The number of 96 bytes /
> 10ms
> sounds weird and does not match any of the involved sample rates / formats.
> Is your code available somewhere so that I can take a look?
>

I attached source code to control pulseaudio.Could you take a look my code?
start function
 usbbtf_hs_start()
read callback
 usbbtf_hs_stream_read_cb()

I got 96bytes voice data as a parameter of usbbtf_hs_stream_read_cb().
So I didn't have a clue to find any hint on this code.

Is there any sample code for implement to control pulseaudio?
Is it possibly code for parec and another command for pulseaudio?
I refered to Linux Sound Programming.

Best Regards,
Shinnosuke Suzuki
2018-02-11 6:12 GMT+09:00 Georg Chini <ge...@chini.tk>:

> On 10.02.2018 02:11, Shinnosuke Suzuki wrote:
>
> Hi
>
> PA 11.1 should work fine with your kernel and bluez version.
>
>
> Thank you, I’ll try that.
>
> When you record from the BT headset, the BT headset is set to HSP/HFP.
> This means that recording and playback stream are at 8kHz, not 16kHz.
>
>
> I want to handle voice packet as Linear 16bit little endian 16000Hz,
> I configure stream as follows.
>
>  static pa_sample_spec samplespec = {
>      .format = PA_SAMPLE_S16LE, /* Linear 16bit */
>      .rate = 16000, /* 16000Hz */
>      .channels = 1 /* mono */
>  }
>
> Does it means .rate should be 8000?
>
>
> It should work if you specify 16kHz because PA will do the resampling.
> But I would try with 8kHz, just to see if something changes.
> Did you try another source? Does parecord work with your headset?
>
>
> You should not expect to get a fixed number of bytes in a fixed time
> interval. This is only true on average but not for a single callback. Are
> the 96 bytes an average value?
> If your application needs constant size data packets, you may have to
> buffer some data.
> Did you take a look at the pacat code to see how reading data from
> a stream is done correctly?
>
>
> I don’t expect fixed number of bytes. So, I implemented to  buffer voice
> packets in read callback.
> However I got voice packet on my callback at 96 bytes per 10ms constantly.
> It means I couldn’t get sufficient voice packet because voice packet needs
> at least 320bytes per 10ms in case of Linear 16bit little endian 16000Hz.
>
> I read pacat how to handle voice packet in read callback.
> I implemented like pacat except silence hole using pa_silence_memory().
>
>
> Sorry, currently I have no idea what goes wrong. The number of 96 bytes /
> 10ms
> sounds weird and does not match any of the involved sample rates / formats.
> Is your code available somewhere so that I can take a look?
>


-- 
--
Shinnosuke Suzuki
E-mail : suzuk...@gmail.com
#include <stdio.h>
#include <string.h>
#include <pulse/pulseaudio.h>
#include <unistd.h>

/* Protottype definition */
void usbbtf_hs_stream_read_cb (pa_stream *s, size_t length, void *userdata);
void usbbtf_hs_stream_state_cb_record (pa_stream *s, void *userdata);
void usbbtf_hs_stream_state_cb_playback (pa_stream *s, void *userdata);
void usbbtf_hs_context_state_cb (pa_context *c, void *userdata);

int usbbtf_hs_stream_write (void *data, int length);

/* Global Table */
extern struct usbbt_task_tbl u_task_tbl;

static pa_sample_spec sample_spec = {
    .format = PA_SAMPLE_S16LE, /* Linear 16bit Little Endian */
    .rate = 16000, /* 16kHz */
    .channels = 1 /* mono */
};

static pa_stream_flags_t flags = 0;
static pa_stream *istream = NULL,
                 *ostream = NULL;

#define USBBT_DSP_MEDIA_PACKET_SIZE 320
static char hs_media_buff[USBBT_DSP_MEDIA_PACKET_SIZE];
static int buff_pos = 0;

extern void mcf_DecodeMedia(char*data,int len);

extern int usbbt_conn_mode;

/************************************************************************
************************************************************************/
void usbbtf_hs_stream_read_cb (pa_stream *s, size_t length, void *userdata){
    const void *data;
    size_t len;
    int diff_len = 0;
    struct timespec log_time;

    printf("PA_r len:%d\n", length);
    
    while (pa_stream_readable_size(s) > 0) {

        if (pa_stream_peek(s, &data, &len) < 0) {
            printf("Read failed\n");
            return;
        }

        memset(&log_time, 0, sizeof(log_time));
        clock_gettime(CLOCK_REALTIME, &log_time);
        printf("HSET_r <- PA len: %d %ld %s", len, log_time.tv_nsec, ctime(&log_time.tv_sec));
        
        if((buff_pos + len) >= USBBT_DSP_MEDIA_PACKET_SIZE){
            diff_len = USBBT_DSP_MEDIA_PACKET_SIZE - buff_pos;
            memcpy(hs_media_buff + buff_pos, data, diff_len);

        	/* send dsp */
            mcf_DecodeMedia(hs_media_buff, USBBT_DSP_MEDIA_PACKET_SIZE);
                
            memset(hs_media_buff, 0, sizeof(hs_media_buff));                
            memcpy(hs_media_buff, data + diff_len, len - diff_len);
            buff_pos = len - diff_len;
        } else {
            memcpy(hs_media_buff + buff_pos, data, len);
            buff_pos += len;
        }
            
        // swallow the data peeked at before
        pa_stream_drop(s);
    }

    return ;
}

/************************************************************************
************************************************************************/
int usbbtf_hs_stream_write (void *data, int length){

    if(data == NULL){
        return F_NG;
    }

    usbbt_conn_mode = USBBT_CONN_HEADSET;

    if(u_task_tbl.media_sender_fd != -1){
        write(u_task_tbl.media_sender_fd, data, length);
    }
    
    return F_OK;
}

/************************************************************************
************************************************************************/
int usbbtf_hs_stream_sender_write (void *data, int length){

    struct timespec log_time;
    
    if(data == NULL){
        return F_NG;
    }

    if(ostream != NULL){

        memset(&log_time, 0, sizeof(log_time));
        clock_gettime(CLOCK_REALTIME, &log_time);
        printf("HSET_W -> PA len: %d %ld %s", length, log_time.tv_nsec, ctime(&log_time.tv_sec));
        
        if (pa_stream_write(ostream, (uint8_t*) data,
                            length, NULL, 0, PA_SEEK_RELATIVE) < 0) {
            printf("pa_stream_write() failed \n");
            return F_NG;
        } else {
            printf("pa_stream_write() OK len = %d\n", length);
        }
    }
    
    return F_OK;
}

/************************************************************************
************************************************************************/
void usbbtf_hs_stream_state_cb_record (pa_stream *s, void *userdata){

    printf("record status (%d)\n", pa_stream_get_state(s));
    printf("usbbtf_hs_stream_state_cb_record Nop \n");
    switch(pa_stream_get_state(s)){
    case PA_STREAM_CREATING:
        printf("Stream creating \n");

        memset(hs_media_buff, 0, sizeof(hs_media_buff));
        buff_pos = 0;
        
        break;

    case PA_STREAM_UNCONNECTED:
    case PA_STREAM_READY:
    case PA_STREAM_TERMINATED:
        break;
        
    case PA_STREAM_FAILED:
        printf("Stream failed %s \n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
        break;
    }
    
}

/************************************************************************
************************************************************************/
void usbbtf_hs_stream_state_cb_playback (pa_stream *s, void *userdata){
        
    printf("playback status (%d)\n", pa_stream_get_state(s));
    printf("usbbtf_hs_stream_state_cb_playback Nop \n");
    switch(pa_stream_get_state(s)){
    case PA_STREAM_CREATING:
        printf("Stream creating \n");
        break;

    case PA_STREAM_UNCONNECTED:
    case PA_STREAM_READY:
    case PA_STREAM_TERMINATED:
        break;
        
    case PA_STREAM_FAILED:
        printf("Stream failed %s \n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
        break;
    }

}

/************************************************************************
************************************************************************/
void usbbtf_hs_context_state_cb (pa_context *c, void *userdata){
    
    pa_context_state_t state;
    pa_buffer_attr buffer_attr;

    state = pa_context_get_state(c);
    printf("State changed (%d)\n", state);
    switch  (state) {
    case PA_CONTEXT_UNCONNECTED:
    case PA_CONTEXT_CONNECTING:
    case PA_CONTEXT_AUTHORIZING:
    case PA_CONTEXT_SETTING_NAME:
        break;

    case PA_CONTEXT_FAILED:
    case PA_CONTEXT_TERMINATED:

        break;
    case PA_CONTEXT_READY:
        if (!(istream = pa_stream_new(c, "IPKTRecord", &sample_spec, NULL))) {
            printf("pa_stream_new() failed: %s", pa_strerror(pa_context_errno(c)));
            return;
        }

        if (!(ostream = pa_stream_new(c, "IPKTPlayback", &sample_spec, NULL))) {
            printf("pa_stream_new() failed: %s", pa_strerror(pa_context_errno(c)));
            return;
        }

        pa_stream_set_state_callback(istream, usbbtf_hs_stream_state_cb_record, NULL);
        pa_stream_set_read_callback(istream, usbbtf_hs_stream_read_cb, NULL);

        memset(&buffer_attr, 0, sizeof(buffer_attr));
        buffer_attr.maxlength = (uint32_t) -1;
        buffer_attr.prebuf = (uint32_t) -1;
        buffer_attr.minreq = (uint32_t) -1;
        buffer_attr.tlength = (uint32_t) -1;
        buffer_attr.fragsize = (uint32_t) -1;
        
        if (pa_stream_connect_record(istream, NULL, &buffer_attr, 0) < 0) {
            printf("pa_stream_connect_record() failed: %s", pa_strerror(pa_context_errno(c)));
            return;
        } else {
            printf("Set record callback\n");
        }

        if (pa_stream_connect_playback(ostream, NULL, &buffer_attr, flags,
                                       NULL, 
                                       NULL) < 0) {
            printf("pa_stream_connect_playback() failed: %s", pa_strerror(pa_context_errno(c)));
            return;
        } else {
            printf("Set playback callback\n");
        }
        break;
    default:
        printf("Unknown context status\n");
    }

    return;
}

/************************************************************************
************************************************************************/
int usbbtf_hs_start(){

    pa_mainloop_api *pa_mlapi;
    
    /* Create a threaded mainloop API and connection to the default server */
    u_task_tbl.pa_ml = pa_threaded_mainloop_new();
    pa_mlapi = pa_threaded_mainloop_get_api(u_task_tbl.pa_ml);
    u_task_tbl.pa_ctx = pa_context_new(pa_mlapi, "ipkt_hs");
    pa_threaded_mainloop_set_name(u_task_tbl.pa_ml, "ipkt_headset");
    
    pa_context_connect(u_task_tbl.pa_ctx, NULL, 0, NULL);

    /* This function defines a callback so the server will tell us its state. */
    pa_context_set_state_callback(u_task_tbl.pa_ctx, usbbtf_hs_context_state_cb, NULL);

    if (pa_threaded_mainloop_start(u_task_tbl.pa_ml) < 0) {
        printf("pa_mainloop_start() failed.");
        return F_NG;
    }

    return F_OK;
}

/************************************************************************
************************************************************************/
int usbbtf_hs_stop(){

    if(u_task_tbl.pa_ctx == NULL || u_task_tbl.pa_ml == NULL){
        return F_NG;
    }

    pa_context_disconnect(u_task_tbl.pa_ctx);
    
    pa_threaded_mainloop_stop(u_task_tbl.pa_ml);
    pa_threaded_mainloop_free(u_task_tbl.pa_ml);
    u_task_tbl.pa_ctx = NULL;
    u_task_tbl.pa_ml = NULL;
    
    return F_OK;
}
_______________________________________________
pulseaudio-discuss mailing list
pulseaudio-discuss@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/pulseaudio-discuss

Reply via email to