size_t rb_read(RingBuffer *rb, void *data, size_t count) { //assert(rb != NULL); //assert(data != NULL); if (rb->rb_head < rb->rb_tail) { int copy_sz = min(count, rb_can_read(rb)); memcpy(data, rb->rb_head, copy_sz); rb->rb_head += copy_sz; return copy_sz; } else { if (count < rb_capacity(rb)-(rb->rb_head - rb->rb_buff)) { int copy_sz = count; memcpy(data, rb->rb_head, copy_sz); rb->rb_head += copy_sz; return copy_sz; } else { int copy_sz = rb_capacity(rb) - (rb->rb_head - rb->rb_buff); memcpy(data, rb->rb_head, copy_sz); rb->rb_head = rb->rb_buff; copy_sz += rb_read(rb, (char*)data+copy_sz, count-copy_sz); return copy_sz; } } }
uint8_t Pro_GetFrame() { if(rb_can_read(&u_ring_buff) >= 1) { if(packageFlag ==0) { rb_read(&u_ring_buff, &curValue, 1); if((lastValue == 0xFF)&&(curValue == 0xFF)) { tmp_buf[0] = 0xFF; tmp_buf[1] = 0xFF; count = 2; return 1; } if((lastValue == 0xFF)&&(curValue == 0x55)) { lastValue = curValue; return 1; } tmp_buf[count] = curValue; count ++ ; lastValue = curValue; if(count ==4) { dataLen = tmp_buf[2]*256+ tmp_buf[3]; } if(count == (dataLen + 4)) { memcpy(UART_HandleStruct.Message_Buf, tmp_buf, dataLen + 4); UART_HandleStruct.Message_Len = dataLen + 4; #ifdef PROTOCOL_DEBUG Serial.print(F("[")); Serial.print(SystemTimeCount, DEC); Serial.print(F("]")); Serial.print(F(" GAgentToMCU:")); for(uint8_t i = 0; i < dataLen + 4; i++) { Serial.print(" "); Serial.print(tmp_buf[i], HEX); } Serial.println(""); #endif memset(tmp_buf, 0, (dataLen + 4)); packageFlag = 1; lastValue = curValue =0; return 0; } } } return 1; }
void print_info() { uint64_t can_read_count=rb_can_read(rb); char* offset_string; if(channel_offset>0) { asprintf(&offset_string, "(%d+)", (channel_offset)); } else { offset_string=""; } char *warn_string=""; if((float)can_read_count/max_buffer_size > 0.8) { warn_string="!"; } if((message_number>0 && relaxed_display_counter>=update_display_every_nth_cycle*port_count) || last_test_cycle==1 ) { fprintf(stderr,"\r# %" PRId64 " i: %s%d b: %.2f MB (%.2f%s) s: %.2f i: %.2f r: %" PRId64 /*" l: %" PRId64 */" d: %" PRId64 " o: %" PRId64 " p: %.1f # %" PRId64 ", %d (%d), %.2f MB%s", message_number, offset_string, input_port_count, (float)can_read_count/1000/1000, (float)can_read_count/max_buffer_size, warn_string, (float)can_read_count/(float)port_count/(float)bytes_per_sample/(float)sample_rate, time_interval_avg*1000, remote_xrun_counter,/*local_xrun_counter,*/ multi_channel_drop_counter, buffer_overflow_counter, (float)frames_since_cycle_start_avg/(float)period_size, message_number_out,last_lo_send_message_tcp_return, port_count,(float)total_bytes_successfully_sent/1000/1000, "\033[0J" ); fflush(stderr); relaxed_display_counter=0; } relaxed_display_counter++; }//end print_info
//============================================================================= void debug(rb_t *rb, int from_thread) { if(rb==NULL) { fprintf(stderr,"\nrb is NULL\n"); return; } fprintf(stderr,"can read %" PRId64 " @ %" PRId64 " can write %" PRId64 " @ %" PRId64 " %s\n" ,rb_can_read(rb) ,rb->read_index ,rb_can_write(rb) ,rb->write_index ,(from_thread==READER_THREAD ? "reader" : "writer") ); }
//============================================================================= int main() { rb_t *rb=rb_new(FLOAT_COUNT*sizeof(float)); if(rb==NULL) {return 1;} rb_debug(rb); float floats[FLOAT_COUNT]={0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8}; int wrote=rb_write(rb,(char*)floats,FLOAT_COUNT*sizeof(float)); fprintf(stderr,"wrote %d bytes (%zu floats)\n",wrote,wrote/sizeof(float)); rb_debug(rb); rb_print_regions(rb); float f1; int read=rb_read_float(rb,&f1); fprintf(stderr,"read %d bytes (%zu float) %f\n",read,read/sizeof(float),f1); int peeked=rb_peek_float(rb,&f1); fprintf(stderr,"peeked %d bytes (%zu float) %f\n",peeked,peeked/sizeof(float),f1); float f2=0.99; wrote=rb_write_float(rb,&f2); fprintf(stderr,"wrote %d bytes (%zu float) %f\n",wrote,wrote/sizeof(float),f2); int skipped=rb_skip_float(rb); fprintf(stderr,"skipped %d bytes (%zu float)\n",skipped,skipped/sizeof(float)); int peek_at=rb_can_read(rb)-sizeof(float); peeked=rb_peek_float_at(rb,&f1,peek_at); fprintf(stderr,"peeked %d bytes (%zu float) at %d %f\n",peeked,peeked/sizeof(float),peek_at,f1); rb_debug(rb); rb_print_regions(rb); rb_free(rb); return 0; }
size_t rb_can_write(RingBuffer *rb) { //assert(rb != NULL); return rb_capacity(rb) - rb_can_read(rb); }
// /audio //handler for audio messages int audio_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { if(shutdown_in_progress==1) { return 0; } //init to 0, increment before use msg_received_counter++; gettimeofday(&tv, NULL); //first blob is at data_offset+1 (one-based) int data_offset=4; //ignore first n channels/blobs data_offset+=channel_offset; message_number_prev=message_number; //the messages are numbered sequentially. first msg is numberd 1 message_number=argv[0]->h; if(message_number_prev<message_number-1) { fprintf(stderr,"\ngap in message sequence! possibly lost %" PRId64" message(s) on the way.\n" ,message_number-message_number_prev-1); fflush(stderr); } //total args count minus metadata args and channel offset count = number of blobs input_port_count=argc-data_offset; //only process useful number of channels port_count=fmin(input_port_count,output_port_count); if(port_count < 1) { fprintf(stderr,"\n\nchannel offset %d >= available input channels %d! (nothing to receive). shutting down...\n" ,channel_offset ,(argc-data_offset+channel_offset)); fflush(stderr); shutdown_in_progress=1; return 0; } //need to warn when offset + outchannels limited //check sample rate and period size if sender (re)started or values not yet initialized (=no /offer received) if(message_number_prev>message_number || message_number==1 || remote_sample_rate==0 || remote_period_size==0 ) { lo_address loa; loa = lo_message_get_source(data); strcpy(sender_host,lo_address_get_hostname(loa)); strcpy(sender_port,lo_address_get_port(loa)); remote_sample_rate=argv[3]->i; remote_period_size=lo_blob_datasize((lo_blob)argv[0+data_offset])/bytes_per_sample; fprintf(stderr,"\nsender was (re)started. "); if(remote_period_size!=period_size) { fprintf(stderr,"sender period size: %d samples (%.3f x forward period size)\n\n",remote_period_size,(float)remote_period_size/period_size); } else { fprintf(stderr,"equal sender and receiver period size\n\n"); } }//end if "no-offer init" was needed remote_xrun_counter=argv[1]->h; lo_timetag tt=argv[2]->t; double msg_time=tt.sec+(double)tt.frac/1000000; double msg_time_prev=tt_prev.sec+(double)tt_prev.frac/1000000; double time_now=tv.tv_sec+(double)tv.tv_usec/1000000; time_interval=msg_time-msg_time_prev; time_interval_sum+=time_interval; time_interval_avg=(float)time_interval_sum/msg_received_counter; tt_prev=tt; //reset avg calc, check and reset after use if(msg_received_counter>=avg_calc_interval) { msg_received_counter=0; time_interval_sum=0; } fflush(stderr); // process_enabled=1; int mc_period_bytes=period_size*bytes_per_sample*port_count; //check if a whole mc period can be written to the ringbuffer uint64_t can_write_count=rb_can_write(rb); if(can_write_count < mc_period_bytes) { buffer_overflow_counter++; ///////////////// fprintf(stderr,"\nBUFFER OVERFLOW! this is bad -----%s\n","\033[0J"); return 0; } //======================================== //new: support different period sizes on sender / receiver (still need same SR) //this needs more tests and optimization if(period_size==remote_period_size) { int i; //don't read more channels than we have outputs for(i=0;i < port_count;i++) { //get blob (=one period of one channel) unsigned char *data = lo_blob_dataptr((lo_blob)argv[i+data_offset]); //fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset])); //write to ringbuffer //========================================== int cnt=rb_write(rb, (void *) data, period_size*bytes_per_sample); } } else if(period_size>remote_period_size) { int i; //don't read more channels than we have outputs for(i=0;i < port_count;i++) { //get blob (=one period of one channel) unsigned char *data = lo_blob_dataptr((lo_blob)argv[i+data_offset]); //fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset])); //write to temporary ringbuffer until there is enough data //========================================== int cnt=rb_write(rb_helper, (void *) data, remote_period_size*bytes_per_sample); } //if enough data collected for one larger multichannel period while(rb_can_read(rb_helper) >=mc_period_bytes && rb_can_write(rb) >=mc_period_bytes) { //transfer from helper to main ringbuffer unsigned char* data; data=malloc( mc_period_bytes); //store orig pointer unsigned char* orig_data=data; rb_read(rb_helper,data, mc_period_bytes); for(i=0;i < port_count;i++) { int k; for(k=0;k<(period_size/remote_period_size);k++) { //reset pointer data=orig_data; //position in helper buffer for next sample for main buffer data+= k*remote_period_size*bytes_per_sample*port_count + i*remote_period_size*bytes_per_sample; //write one channel snipped (remote_period_size) to main buffer int w=rb_write(rb,(void *)data,remote_period_size*bytes_per_sample); } } data=orig_data; free(data); } } else if(period_size<remote_period_size) { int k; for(k=0;k<(remote_period_size/period_size);k++) { int i; //don't read more channels than we have outputs for(i=0;i < port_count;i++) { //get blob (=one period of one channel) unsigned char *data = lo_blob_dataptr((lo_blob)argv[i+data_offset]); //fprintf(stderr,"size %d\n",lo_blob_datasize((lo_blob)argv[i+data_offset])); //write to ringbuffer //========================================== data+=k*period_size*bytes_per_sample; int cnt=rb_write(rb, (void *) data, period_size*bytes_per_sample); } } } return 0; }//end audio_handler
//this is not a JACK process cylce int process() { if(shutdown_in_progress==1) { return 0; } if(process_enabled==1) { //as long as there is data ready to be sent, read and try to send //need: handle case where receiver can not read data fast enough // while(rb_can_read(rb) // >=input_port_count*bytes_per_sample*period_size) // { while(rb_can_read(rb) >=port_count*bytes_per_sample*period_size) { //fake consume // rb_advance_read_pointer(rb,port_count*bytes_per_sample*period_size); lo_message mm=lo_message_new(); //add message counter lo_message_add_int64(mm,message_number_out); //indicate how many xruns (in sender's JACK) lo_message_add_int64(mm,remote_xrun_counter); gettimeofday(&tv, NULL); lo_timetag tt; tt.sec=(long)tv.tv_sec; tt.frac=(long)tv.tv_usec; lo_message_add_timetag(mm,tt); lo_message_add_int32(mm,sample_rate); //blob array, holding one period per channel // lo_blob blob[input_port_count]; lo_blob blob[port_count]; void* membuf = malloc(period_size*bytes_per_sample); int i; for( i=0; i<port_count; i++ ) { //void* membuf = malloc(period_size*bytes_per_sample); rb_read (rb, (char*)membuf, period_size*bytes_per_sample); blob[i]=lo_blob_new(period_size*bytes_per_sample,membuf); lo_message_add_blob(mm,blob[i]); } int ret=lo_send_message(loa_tcp,"/audio",mm); last_lo_send_message_tcp_return=ret; if(ret<0) { // fprintf(stderr," TCP WARN: msg no: %" PRId64 " size: %" PRId64 " ret: %d ",message_number_out,lo_message_length(mm,"/audio"),ret); } else { total_bytes_successfully_sent+=ret; // fprintf(stderr," msg no: %" PRId64 " size: %" PRId64 " ret: %d ",message_number_out,lo_message_length(mm,"/audio"),ret); message_number_out++; } //free //lo_free(membuf); lo_message_free(mm); free(membuf); //free blobls ... for( i=0; i<port_count; i++ ) { free(blob[i]); } if(ret<0) { return ret; } }//end while has data return 0; }//end if process enabled //process not yet enabled, buffering else { if(relaxed_display_counter>=update_display_every_nth_cycle || last_test_cycle==1 ) { if((int)message_number<=0 && starting_transmission==0) { fprintf(stderr,"\rwaiting for audio input data..."); } fflush(stderr); relaxed_display_counter=0; } relaxed_display_counter++; return 0; }//end if process not enabled //return 0; } //end process