static snd_pcm_sframes_t io_capture_transfer(struct snd_pcm_plugin *plugin, const struct snd_pcm_plugin_channel *src_channels, struct snd_pcm_plugin_channel *dst_channels, snd_pcm_uframes_t frames) { if (snd_BUG_ON(!plugin)) return -ENXIO; if (snd_BUG_ON(!dst_channels)) return -ENXIO; if (plugin->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED) { return pcm_read(plugin->plug, dst_channels->area.addr, frames); } else { int channel, channels = plugin->dst_format.channels; void **bufs = (void**)plugin->extra_data; if (snd_BUG_ON(!bufs)) return -ENXIO; for (channel = 0; channel < channels; channel++) { if (dst_channels[channel].enabled) bufs[channel] = dst_channels[channel].area.addr; else bufs[channel] = NULL; } return pcm_readv(plugin->plug, bufs, frames); } return 0; }
//读取flash参数 void read_flash( void ) { lcd_clear(BLACK); if (FR_OK != lcd_font16(0,0,BLACK,BLACK," ","song16.zk") ) { lcd_mem_err(250,200,RED,BLACK); while (1); } pcm_read(); //从flash读取上位机参数 prm_read(); //从flash区读取系统参数 prv_read(); //从flash读取特权参数 pHmi = pcm_hmi_get(); //获取人机界面的杂项参数 formate_flash(); //格式化FLASH pTest = pcm_test_get(pHmi->test_standard_index); //从FLASH获取试验索引以及数据,放入内存 smpl_name = KZ_KY_judge(pHmi->test_standard_index); //判断当前通道,为了后面设置保护模式 cur_model = cur_model_get(); //获取机型 cur_model_type = model_type_get(); //获取机型类型 // LCD_light_set(pHmi->lcd_light_use); //设置背光 boot_link(); //上电后联机 LinkInit(); //与PC联机初始化 set_page(mainpage); //默认进入主界面 }
static int caf_info(caf_reader_t *reader, int64_t chunk_size) { char *buf, *key, *val, *end; size_t len; if (chunk_size < 4 || (buf = malloc(chunk_size)) == 0) return -1; pcm_read(&reader->io, buf, chunk_size); key = buf + 4; end = buf + chunk_size; do { if ((val = key + strlen(key) + 1) < end) { len = strlen(val); if (reader->tag_callback) reader->tag_callback(reader->tag_ctx, key, val, len); key = val + len + 1; } } while (key < end && val < end); if (reader->tag_callback) reader->tag_callback(reader->tag_ctx, 0, 0, 0); free(buf); return 0; }
/*------------------------------------------------------------ * Function Name : ReadFlash * Description : 读取FLASH * Input : None * Output : None * Return : None *------------------------------------------------------------*/ void ReadFlash( void ) { lcd_clear(WHITE); pcm_read(); //从flash读取上位机参数 prm_read(); //从flash区读取系统参数 prv_read(); //从flash读取特权参数 pHmi = pcm_hmi_get(); //获取人机界面的杂项参数 FormateFlash(); //格式化FLASH pTest = pcm_test_get(pHmi->test_standard_index); //从FLASH获取试验索引以及数据,放入内存 AutoBackUpSystem(); //自动备份 HandlerNearExpire(); //接近到期警告 ChangeTestType(); //防止抗折机使用抗压试验,抗压机使用抗折试验 BootLink(); //上电后联机 get_key(0x00000000); //熄灭全部LED SetPage(MAIN_PAGE); //默认进入主界面 }
int pcm_read32be(pcm_io_context_t *io, uint32_t *value) { if (pcm_read(io, value, 4) == 4) { *value = m4af_btoh32(*value); return 0; } return -1; }
int pcm_read16be(pcm_io_context_t *io, uint16_t *value) { if (pcm_read(io, value, 2) == 2) { *value = m4af_btoh16(*value); return 0; } return -1; }
int pcm_read64be(pcm_io_context_t *io, uint64_t *value) { if (pcm_read(io, value, 8) == 8) { *value = m4af_btoh64(*value); return 0; } return -1; }
unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels, unsigned int rate, enum pcm_format format, unsigned int period_size, unsigned int period_count) { struct pcm_config config; struct pcm *pcm; char *buffer; unsigned int size; unsigned int bytes_read = 0; memset(&config, 0, sizeof(config)); config.channels = channels; config.rate = rate; config.period_size = period_size; config.period_count = period_count; config.format = format; config.start_threshold = 0; config.stop_threshold = 0; config.silence_threshold = 0; pcm = pcm_open(card, device, PCM_IN, &config); if (!pcm || !pcm_is_ready(pcm)) { fprintf(stderr, "Unable to open PCM device (%s)\n", pcm_get_error(pcm)); return 0; } size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm)); buffer = malloc(size); if (!buffer) { fprintf(stderr, "Unable to allocate %d bytes\n", size); free(buffer); pcm_close(pcm); return 0; } printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate, pcm_format_to_bits(format)); while (capturing && !pcm_read(pcm, buffer, size)) { if (fwrite(buffer, 1, size, file) != size) { fprintf(stderr,"Error capturing sample\n"); break; } bytes_read += size; } free(buffer); pcm_close(pcm); return pcm_bytes_to_frames(pcm, bytes_read); }
unsigned int capture_sample(FILE *file, unsigned int device, unsigned int channels, unsigned int rate, unsigned int bits) { struct pcm_config config; struct pcm *pcm; char *buffer; unsigned int size; unsigned int bytes_read = 0; config.channels = channels; config.rate = rate; config.period_size = 1024; config.period_count = 4; if (bits == 32) config.format = PCM_FORMAT_S32_LE; else if (bits == 16) config.format = PCM_FORMAT_S16_LE; pcm = pcm_open(0, device, PCM_IN, &config); if (!pcm || !pcm_is_ready(pcm)) { fprintf(stderr, "Unable to open PCM device (%s)\n", pcm_get_error(pcm)); return 0; } size = pcm_get_buffer_size(pcm); buffer = malloc(size); if (!buffer) { fprintf(stderr, "Unable to allocate %d bytes\n", size); free(buffer); pcm_close(pcm); return 0; } printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate, bits); while (capturing && !pcm_read(pcm, buffer, size)) { if (fwrite(buffer, 1, size, file) != size) { fprintf(stderr,"Error capturing sample\n"); break; } bytes_read += size; } free(buffer); pcm_close(pcm); return bytes_read / ((bits / 8) * channels); }
static int caf_read_frames(pcm_reader_t *preader, void *buffer, unsigned nframes) { int rc; unsigned i, j, nbytes; caf_reader_t *reader = (caf_reader_t *)preader; unsigned bpf = reader->sample_format.bytes_per_frame; unsigned nchannels = reader->sample_format.channels_per_frame; unsigned bpc = bpf / nchannels; uint8_t tmp[64]; /* enough room for maximum bpf: 8ch float64 */ uint8_t *bp; uint8_t *chanmap = reader->chanmap; if (nframes > reader->length - reader->position) nframes = reader->length - reader->position; nbytes = nframes * bpf; if (nbytes) { if ((rc = pcm_read(&reader->io, buffer, nbytes)) < 0) return -1; nframes = rc / bpf; for (bp = buffer, i = 0; i < nframes; ++i, bp += bpf) { memcpy(tmp, bp, bpf); for (j = 0; j < nchannels; ++j) memcpy(bp + bpc * j, tmp + bpc * chanmap[j], bpc); } reader->position += nframes; } if (nframes == 0) { /* fetch info after data chunk */ uint32_t fcc; int64_t chunk_size; while ((fcc = caf_next_chunk(reader, &chunk_size)) != 0) { if (fcc == M4AF_FOURCC('i','n','f','o')) TRY_IO(caf_info(reader, chunk_size)); else TRY_IO(pcm_skip(&reader->io, chunk_size)); } } return nframes; FAIL: return 0; }
bool AudioRecordingLocal::doPlaybackOrRecord(android::sp<Buffer>& buffer) { int toRead = mSizes; if (buffer->amountToHandle() < (size_t)mSizes) { toRead = buffer->amountToHandle(); } LOGD("recording will read %d", toRead); while (toRead > 0) { int readSize = (toRead > mBufferSize) ? mBufferSize : toRead; if (pcm_read(mPcmHandle, buffer->getUnhanledData(), readSize)) { LOGE("AudioRecordingLocal error %s", pcm_get_error(mPcmHandle)); return false; } buffer->increaseHandled(readSize); toRead -= readSize; } LOGV("AudioRecordingLocal::doPlaybackOrRecord %d", buffer->amountHandled()); return true; }
/*------------------------------------------------------------ * Function Name : FormateFlash * Description : 用于第一次使用时格式化FLASH * Input : None * Output : None * Return : None *------------------------------------------------------------*/ void FormateFlash( void ) { SetFormateFlashTimeOut(1000); while (GetFormateFlashTimeOut() == TIMEIN) { if (KEY_STOP != get_key(0xffffffff)) { return; } } if (EraseFlashAskHandler() == DISABLE) { return; } SetPage(USER_LOGIN_PAGE); if (FAILED == LoadManagerLogin() ) { lcd_clear(COLOR_BACK); return; } memset(get_pcm(),0x00,PCM_MEM_SIZE); memset(get_prm(),0x00,PRM_MEM_SIZE); memset(get_prv(),0x00,PRV_MEM_SIZE); pHmi->test_standard_index = KYSNJS; //设置默认试验 pHmi->lcd_light_use = 5; //设置默认亮度 pcm_save(); prm_save(); prv_save(); pcm_read(); prm_read(); prv_read(); lcd_clear(COLOR_BACK); }
static ssize_t in_read(struct audio_stream_in *stream, void *buffer, size_t bytes) { struct stream_in *in = (struct stream_in *)stream; struct audio_device *adev = in->dev; int i, ret = -1; ALOGV("%s enter",__func__); pthread_mutex_lock(&in->lock); if (in->standby) { pthread_mutex_lock(&adev->lock); ret = start_input_stream(in); pthread_mutex_unlock(&adev->lock); if (ret != 0) { goto exit; } in->standby = false; } if (in->pcm) { ret = pcm_read(in->pcm, buffer, bytes); } ALOGV("in_read returned %d bytes ret = %d",bytes,ret); exit: pthread_mutex_unlock(&in->lock); if (ret != 0) { in_standby(&in->stream.common); uint64_t duration_ms = ((bytes * 1000)/ (audio_stream_frame_size(&in->stream.common)) / (in_get_sample_rate(&in->stream.common))); ALOGV("%s : silence read - read failed", __func__); usleep(duration_ms * 1000); } ALOGV("%s exit",__func__); return bytes; }
int read_producer_stream(bionet_stream_t *stream) { stream_info_t *sinfo = bionet_stream_get_user_data(stream); alsa_t *alsa = sinfo->info.producer.alsa; int r; int frames, bytes; if (!check_alsa_poll(alsa)) { return 0; } r = pcm_read(alsa); if (r < 0) { // FIXME printf("read error on stream %s\n", bionet_stream_get_local_name(stream)); return 1; } frames = r; bytes = (frames * alsa->bytes_per_frame); hab_publish_stream(stream, alsa->audio_buffer, bytes); #if 0 FIXME r = write(client->socket, client->alsa->audio_buffer, bytes); if (r < 0) { printf("error writing stream %s to consumer: %s\n", bionet_stream_get_local_name(stream), strerror(errno)); disconnect_client(stream, client); return 1; } else if (r < bytes) { printf("short write to stream %s consumer", bionet_stream_get_local_name(stream)); disconnect_client(stream, client); return 1; } #endif return 0; }
int record_file(unsigned rate, unsigned channels, int fd, unsigned count) { struct pcm *pcm; unsigned avail, xfer, bufsize; char *data, *next; int r; pcm = pcm_open(PCM_IN|PCM_MONO); if (!pcm_ready(pcm)) { pcm_close(pcm); goto fail; } bufsize = pcm_buffer_size(pcm); data = malloc(bufsize); if (!data) { fprintf(stderr,"could not allocate %d bytes\n", count); return -1; } while (!pcm_read(pcm, data, bufsize)) { if (write(fd, data, bufsize) != bufsize) { fprintf(stderr,"could not write %d bytes\n", bufsize); return -1; } } close(fd); pcm_close(pcm); return 0; fail: fprintf(stderr,"pcm error: %s\n", pcm_error(pcm)); return -1; }
//格式化FLASH,用于第一次烧录本程序的新板子 void formate_flash( void ) { uint8_t *pStart_addr = NULL; HMI_TypeDef *pPcm = NULL; uint32_t len; if (pHmi->check_flash == 0xff) { if (ask_dialog_box() == DISABLE) { return; } pPcm = pcm_hmi_get(); len = sizeof(PCM_TypeDef); memset(pPcm,0x00,len); //清空FLASH参数区 pStart_addr = get_prm(); memset(pStart_addr,0x00,PRM_MEM_SIZE_2CH); pHmi->test_standard_index = KZSNJS; //设置默认试验 pHmi->lcd_light_use = 5; //设置默认亮度 pcm_save(); prm_save(); prv_save(); pcm_read(); prm_read(); prv_read(); #ifdef ENABLE_BEEP BEEP_RING_WARN(); #endif } }
ssize_t InStream::read(void* buffer, size_t bytes) { int ret = 0; LOGFUNC("%s(%p, %p, %d)", __func__, this, buffer, bytes); AutoMutex lock(mLock); if (mStandby) { if (startInputStream()) return -EBUSY; } ret = pcm_read(mPcm, buffer, bytes); ALOGV("pcm_read(%p, %p, %d) returned %d", mPcm, buffer, bytes, ret); if (ret >= 0 && mDev.mMicMute) memset(buffer, 0, bytes); if (ret < 0) { ALOGE("pcm_read(%p, %p, %d) returned %d", mPcm, buffer, bytes, ret); usleep(bytes * 1000000 / audio_stream_frame_size(&audio_stream_in()->common) / mConfig.rate); } return bytes; }
static int stream_transfer(struct stream_transfer *stream_transfer) { struct dev_stream *stream_sender; struct dev_stream *stream_receiver; int size_transfer = 0; int ret =0; int exit_flag =0; int i =0; short* Srcptr; short* Drcptr; stream_sender = stream_transfer->stream_sender; stream_receiver = stream_transfer->stream_receiver; size_transfer = stream_sender->buf_size; #ifdef START_ZERO_BUFFER /* 消除开头杂音 */ memset(stream_sender->buf, 0, stream_sender->buf_size); pcm_write(stream_receiver->dev, stream_sender->buf, stream_sender->buf_size); #endif while( 1 ){ if ( (!stream_transfer->voice_thread_run_flag) || (exit_flag == 1)){ break; } ret = pcm_read(stream_sender->dev, stream_sender->buf, size_transfer); if (ret != 0) { exit_flag = 1; ALOGE("err: read codec err:%s, ret=%d", strerror(errno), ret); break; } if ( (!stream_transfer->voice_thread_run_flag) || (exit_flag == 1)){ break; } ret = pcm_write(stream_receiver->dev, stream_sender->buf, size_transfer); if (ret != 0) { exit_flag = 1; ALOGE("err: write pcm err:%s, ret=%d", strerror(errno), ret); } if ( (!stream_transfer->voice_thread_run_flag) || (exit_flag == 1)){ break; } if (stream_transfer->record_flag == 1){ //是上行,还是下行. if (stream_transfer->voice_direction == UPSTREAM){ Srcptr = (short*)(stream_sender->buf); Drcptr = (short*)(record_data.record_buf + (record_data.lenwriteup%record_data.record_lenth)); if(record_data.lenwriteup >= record_data.lenwritedown) { memcpy(Drcptr,Srcptr,size_transfer); } else { int i; for(i=0;i<size_transfer/2;i++,Drcptr++) { *Drcptr = (*Drcptr + *Srcptr++)/2; } record_data.lenwrite += size_transfer; // sem_post(&sem_record); } record_data.lenwriteup += size_transfer; //ALOGD("stream is upload"); } else { Srcptr = (short*)(stream_sender->buf); Drcptr = (short*)(record_data.record_buf + (record_data.lenwritedown%record_data.record_lenth)); if(record_data.lenwritedown >= record_data.lenwriteup) { memcpy(Drcptr,Srcptr,size_transfer); } else { for(i=0;i<size_transfer/2;i++,Drcptr++) { *Drcptr = ((int)*Drcptr + (int)(*Srcptr++))/2; } record_data.lenwrite += size_transfer; // sem_post(&sem_record); } record_data.lenwritedown += size_transfer; //ALOGD("stream is download"); } sem_post(&sem_record); } //ALOGD("pcm running ... , type=%d ",stream_sender->type); if ( (!stream_transfer->voice_thread_run_flag) || (exit_flag == 1)){ break; } } return 0; }
void *AudioALSACaptureDataProviderNormal::readThread(void *arg) { status_t retval = NO_ERROR; AudioALSACaptureDataProviderNormal *pDataProvider = static_cast<AudioALSACaptureDataProviderNormal *>(arg); uint32_t open_index = pDataProvider->mOpenIndex; char nameset[32]; sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType); prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0); #ifdef MTK_AUDIO_ADJUST_PRIORITY // force to set priority struct sched_param sched_p; sched_getparam(0, &sched_p); sched_p.sched_priority = RTPM_PRIO_AUDIO_RECORD + 1; if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) { ALOGE("[%s] failed, errno: %d", __FUNCTION__, errno); } else { sched_p.sched_priority = RTPM_PRIO_AUDIO_RECORD + 1; sched_getparam(0, &sched_p); ALOGD("sched_setscheduler ok, priority: %d", sched_p.sched_priority); } #endif ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=%x, open_index=%d", __FUNCTION__, getpid(), gettid(), kReadBufferSize, open_index); // read raw data from alsa driver char linear_buffer[kReadBufferSize]; uint32_t Read_Size = kReadBufferSize; uint32_t kReadBufferSize_new; while (pDataProvider->mEnable == true) { if (open_index != pDataProvider->mOpenIndex) { ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex); break; } retval = pDataProvider->mEnableLock.lock_timeout(300); ASSERT(retval == NO_ERROR); if (pDataProvider->mEnable == false) { pDataProvider->mEnableLock.unlock(); break; } ASSERT(pDataProvider->mPcm != NULL); clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime); pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime); pDataProvider->mOldtime = pDataProvider->mNewtime; if (pDataProvider->mCaptureDropSize > 0) { Read_Size = (pDataProvider->mCaptureDropSize > kReadBufferSize) ? kReadBufferSize : pDataProvider->mCaptureDropSize; int retval = pcm_read(pDataProvider->mPcm, linear_buffer, Read_Size); if (retval != 0) { ALOGE("%s(), pcm_read() drop error, retval = %d", __FUNCTION__, retval); } ALOGD("%s(), mCaptureDropSize = %d, Read_Size=%d", __FUNCTION__, pDataProvider->mCaptureDropSize, Read_Size); pDataProvider->mCaptureDropSize -= Read_Size; pDataProvider->mEnableLock.unlock(); continue; } else { int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize); if (retval != 0) { ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval); } } clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime); pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime); pDataProvider->mOldtime = pDataProvider->mNewtime; //struct timespec tempTimeStamp; pDataProvider->GetCaptureTimeStamp(&pDataProvider->mStreamAttributeSource.Time_Info, kReadBufferSize); #ifdef RECORD_INPUT_24BITS // 24bit record uint32_t *ptr32bit_r = (uint32_t *)linear_buffer; int16_t *ptr16bit_w = (int16_t *)linear_buffer; int i; ALOGV("24bit record, kReadBufferSize=%d, init ptr32bit_r=0x%x, ptr16bit_w =0x%x", kReadBufferSize, ptr32bit_r, ptr16bit_w); for (i = 0; i < kReadBufferSize / 4; i++) { *(ptr16bit_w + i) = (int16_t)(*(ptr32bit_r + i) >> 8); } kReadBufferSize_new = kReadBufferSize >> 1; #else kReadBufferSize_new = kReadBufferSize; #endif #ifdef MTK_VOW_SUPPORT //copy data to DC Cal pDataProvider->copyCaptureDataToDCCalBuffer(linear_buffer, kReadBufferSize_new); #endif // use ringbuf format to save buffer info pDataProvider->mPcmReadBuf.pBufBase = linear_buffer; pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize_new + 1; // +1: avoid pRead == pWrite pDataProvider->mPcmReadBuf.pRead = linear_buffer; pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize_new; pDataProvider->mEnableLock.unlock(); pDataProvider->provideCaptureDataToAllClients(open_index); clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime); pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime); pDataProvider->mOldtime = pDataProvider->mNewtime; ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]); } ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid()); pthread_exit(NULL); return NULL; }
static void capture(char *orig_name) { int tostdout=0; /* boolean which describes output stream */ int filecount=0; /* number of files written */ char *name = orig_name; /* current filename */ char namebuf[PATH_MAX+1]; off64_t count, rest; /* number of bytes to capture */ /* get number of bytes to capture */ count = calc_count(); if (count == 0) count = LLONG_MAX; /* WAVE-file should be even (I'm not sure), but wasting one byte isn't a problem (this can only be in 8 bit mono) */ if (count < LLONG_MAX) count += count % 2; else count -= count % 2; printf("arecord: Recording audio to: %s\n", name); /* setup sound hardware */ set_params(); /* write to stdout? */ if (!name || !strcmp(name, "-")) { fd = fileno(stdout); name = "stdout"; tostdout=1; if (count > fmt_rec_table[file_type].max_filesize) count = fmt_rec_table[file_type].max_filesize; } do { /* open a file to write */ if(!tostdout) { /* upon the second file we start the numbering scheme */ if (filecount) { filecount = new_capture_file(orig_name, namebuf, sizeof(namebuf), filecount); name = namebuf; } /* open a new file */ remove(name); if ((fd = open64(name, O_WRONLY | O_CREAT, 0644)) == -1) { perror(name); exit(EXIT_FAILURE); } filecount++; } rest = count; if (rest > fmt_rec_table[file_type].max_filesize) rest = fmt_rec_table[file_type].max_filesize; /* setup sample header */ if (fmt_rec_table[file_type].start) fmt_rec_table[file_type].start(fd, rest); /* capture */ fdcount = 0; while (rest > 0 && capture_stop == 0) { size_t c = (rest <= (off64_t)chunk_bytes) ? (size_t)rest : chunk_bytes; size_t f = c * 8 / bits_per_frame; if (pcm_read(audiobuf, f) != f) break; if (write(fd, audiobuf, c) != c) { perror(name); exit(EXIT_FAILURE); } count -= c; rest -= c; fdcount += c; } /* finish sample container */ if (fmt_rec_table[file_type].end && !tostdout) { fmt_rec_table[file_type].end(fd); fd = -1; } /* repeat the loop when format is raw without timelimit or * requested counts of data are recorded */ } while ( ((file_type == FORMAT_RAW && !timelimit) || count > 0) && capture_stop == 0); printf("arecord: Stopping capturing audio.\n"); }
int proxy_read(const alsa_device_proxy * proxy, void *data, unsigned int count) { return pcm_read(proxy->pcm, data, count); }
/*------------------------------------------------------------ * Function Name : SystemRestoreStart * Description : 开始还原 * Input : None * Output : None * Return : None *------------------------------------------------------------*/ void SystemRestoreStart( void ) { FunctionalState RETURN = DISABLE; ASK_WARN_TypeDef ASK; uint8_t SaveMedium = 0xff; FRESULT result[3]; if (SystemRestore.Account == MANAGER) { if (NO == CheckBackUpFileExist(SystemRestore.data[RESTORM_DATE])) { SetErr(&GeneralWarning,PCM_ERR,0xff,2,&SystemRestoreWarn[8]); return; } } SetErr(&GeneralWarning,PCM_ERR,0xfe,1,&SystemRestoreWarn[1]); SystemRestoreConfigAskWarn(&ASK); while (1) { /* 上位机警告 */ RETURN = ASK_WarningHandlerProcess(&ASK); if (RETURN == ENABLE) { if (ASK.NewFunc == ENABLE) { if (SystemRestoreAsk() == ENABLE) { SetPage(PID_CALIBRATION); return; } SaveMedium = SelectRestoreMediumProcess(); if (SaveMedium == BACKUP_USB) { if (Get_USB_Status() == ERROR) { SetErr(&GeneralWarning,PCM_ERR,0xff,1,&SystemRestoreWarn[10]); return; } } lcd_show_image(MAIN_FUNC_POS3_X,MAIN_FUNC_POS_Y,BUTTON_RESTOREING); if (SystemRestore.Account == TEST_CUSTOM) { result[0] = pcm_recover(SaveMedium); result[1] = prm_recover(SaveMedium); result[2] = prv_recover(SaveMedium); } else { result[0] = PcmRecoverWithDate(SystemRestore.data[RESTORM_DATE]); result[1] = PrmRecoverWithDate(SystemRestore.data[RESTORM_DATE]); result[2] = PrvRecoverWithDate(SystemRestore.data[RESTORM_DATE]); } if ((result[0]==FR_OK) && (result[1]==FR_OK) && (result[2]==FR_OK)) { SetErr(&GeneralWarning,PCM_ERR,0xff,1,&SystemRestoreWarn[2]); } else { SetErr(&GeneralWarning,PCM_ERR,0xff,1,&SystemRestoreWarn[11]); return; } pcm_save(); prm_save(); prv_save(); pcm_read(); prm_read(); prv_read(); } else { SetErr(&GeneralWarning,PCM_ERR,0xff,1,&SystemRestoreWarn[3]); } return; } } }
int libao_play (AUDIOCTX * actx) { ao_device *device; ao_PRIVATE *priv = (ao_PRIVATE *) actx->driverprivate; bool quit = false; assert (priv != NULL); device = (ao_device *) priv->device; /* Driver loop */ for (;;) { unsigned char buf[8192]; ssize_t r; /* Fetch state lock */ pthread_mutex_lock (&priv->lock); switch (priv->state) { case AO_END: quit = true; break; case AO_PAUSED: /* Wait for unpause signal */ pthread_cond_wait (&priv->pause, &priv->lock); break; case AO_PLAYING: case AO_IDLE: default: break; } pthread_mutex_unlock (&priv->lock); if (quit) break; /* Read some data ... */ r = pcm_read (actx->pcmprivate, (char *) buf, sizeof (buf), 0, 2, 1, NULL); if (r == OV_HOLE) { /* vorbis got garbage */ DSFYDEBUG ("pcm_read() == OV_HOLE\n"); continue; } if (r <= 0) { DSFYDEBUG ("pcm_read() == %zd\n", r); if (r == 0) /* EOF */ break; exit (-1); } /* ... and play it */ if (ao_play (device, (char *) buf, (int) r) == 0) { DSFYDEBUG ("ao_play() failed\n"); exit (-1); } } if (ao_close (device) == 0) { DSFYDEBUG ("ao_close() failed\n"); exit (-1); } pthread_mutex_destroy (&priv->lock); pthread_cond_destroy (&priv->pause); DSFYfree(actx->driverprivate); /* This will kill the thread */ DSFYDEBUG ("libao thread exiting\n"); return 0; }
void *AudioALSACaptureDataProviderEchoRefExt::readThread(void *arg) { status_t retval = NO_ERROR; AudioALSACaptureDataProviderEchoRefExt *pDataProvider = static_cast<AudioALSACaptureDataProviderEchoRefExt *>(arg); uint32_t open_index = pDataProvider->mOpenIndex; char nameset[32]; sprintf(nameset, "%s%d", __FUNCTION__, pDataProvider->mCaptureDataProviderType); prctl(PR_SET_NAME, (unsigned long)nameset, 0, 0, 0); #ifdef MTK_AUDIO_ADJUST_PRIORITY // force to set priority struct sched_param sched_p; sched_getparam(0, &sched_p); sched_p.sched_priority = RTPM_PRIO_AUDIO_RECORD + 5; if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) { ALOGE("[%s] failed, errno: %d", __FUNCTION__, errno); } else { sched_p.sched_priority = RTPM_PRIO_AUDIO_RECORD + 5; sched_getparam(0, &sched_p); ALOGD("sched_setscheduler ok, priority: %d", sched_p.sched_priority); } #endif ALOGD("+%s(), pid: %d, tid: %d, kReadBufferSize=%x", __FUNCTION__, getpid(), gettid(), kReadBufferSize); // read raw data from alsa driver char linear_buffer[kReadBufferSize]; while (pDataProvider->mEnable == true) { if (open_index != pDataProvider->mOpenIndex) { ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex); break; } retval = pDataProvider->mEnableLock.lock_timeout(300); ASSERT(retval == NO_ERROR); if (pDataProvider->mEnable == false) { pDataProvider->mEnableLock.unlock(); break; } ASSERT(pDataProvider->mPcm != NULL); clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime); pDataProvider->timerec[0] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime); pDataProvider->mOldtime = pDataProvider->mNewtime; int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize); if (retval != 0) { ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval); } clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime); pDataProvider->timerec[1] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime); pDataProvider->mOldtime = pDataProvider->mNewtime; pDataProvider->GetCaptureTimeStamp(&pDataProvider->mStreamAttributeSource.Time_Info, kReadBufferSize); // use ringbuf format to save buffer info pDataProvider->mPcmReadBuf.pBufBase = linear_buffer; pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite pDataProvider->mPcmReadBuf.pRead = linear_buffer; pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize; pDataProvider->mEnableLock.unlock(); //Provide EchoRef data #if 0 //for check the echoref data got pDataProvider->provideCaptureDataToAllClients(open_index); #else pDataProvider->provideEchoRefCaptureDataToAllClients(open_index); #endif clock_gettime(CLOCK_REALTIME, &pDataProvider->mNewtime); pDataProvider->timerec[2] = calc_time_diff(pDataProvider->mNewtime, pDataProvider->mOldtime); pDataProvider->mOldtime = pDataProvider->mNewtime; ALOGD("%s, latency_in_us,%1.6lf,%1.6lf,%1.6lf", __FUNCTION__, pDataProvider->timerec[0], pDataProvider->timerec[1], pDataProvider->timerec[2]); } ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid()); pthread_exit(NULL); return NULL; }
//打印系统参数 void PrintSystemParameter( void ) { int32_t temp_u = 0; float temp_f = 0.0f; uint8_t i,segs; pcm_read(); //从flash读取上位机参数 prm_read(); //从flash区读取系统参数 prv_read(); //从flash读取特权参数 temp_u = ctrl_max_get(); printf("最大控制量 = %d\r\n",temp_u); delay_ms(10); temp_u = ctrl_max_cnt_get(); printf("最大控制量保护次数 = %d\r\n",temp_u); delay_ms(10); temp_u = ctrl_max_one_get(); printf("单步最大控制量 = %d\r\n",temp_u); delay_ms(10); temp_u = ctrl_min_one_get(); printf("单步最小控制量 = %d\r\n",temp_u); delay_ms(10); temp_u = ctrl_open_get(); printf("开环控制量 = %d\r\n",temp_u); delay_ms(10); temp_u = spcl_unload_delay_get(SMPL_KY_NUM); printf("卸载延时 = %d\r\n",temp_u); delay_ms(10); temp_u = spcl_valve_init_get(SMPL_KY_NUM); printf("初始开度 = %d\r\n",temp_u); delay_ms(10); temp_u = spcl_valve_back_get(SMPL_KY_NUM); printf("回退量 = %d\r\n",temp_u); delay_ms(10); temp_u = spcl_valve_middle_get(SMPL_KY_NUM); printf("中位开度 = %d\r\n",temp_u); delay_ms(10); temp_u = spcl_quick_up_get(SMPL_KY_NUM); printf("快升开度 = %d\r\n",temp_u); delay_ms(10); temp_u = spcl_quick_down_get(SMPL_KY_NUM); printf("快降开度 = %d\r\n",temp_u); delay_ms(10); temp_u = spcl_slow_up_get(SMPL_KY_NUM); printf("慢升开度 = %d\r\n",temp_u); delay_ms(10); temp_u = spcl_slow_down_get(SMPL_KY_NUM); printf("慢降开度 = %d\r\n",temp_u); delay_ms(10); temp_f = smpl_ctrl_entry_get(SMPL_KY_NUM); printf("控制入口力 = %f\r\n",temp_f); delay_ms(10); temp_f = smpl_ctrl_full_p_get(SMPL_KY_NUM); printf("正向最大力 = %f\r\n",temp_f); delay_ms(10); temp_f = smpl_ctrl_full_n_get(SMPL_KY_NUM); printf("负向最大力 = %f\r\n",temp_f); delay_ms(10); temp_f = smpl_cof_ahead_get(SMPL_KY_NUM); printf("提前保持系数 = %f\r\n",temp_f); delay_ms(10); temp_f = smpl_cof_spd_get(SMPL_KY_NUM); printf("速度保持系数 = %f\r\n",temp_f); delay_ms(10); temp_f = smpl_cof_break_get(SMPL_KY_NUM); printf("制动保持系数 = %f\r\n",temp_f); delay_ms(10); temp_f = smpl_ctrl_crash_get(SMPL_KY_NUM); printf("预碰撞保护 = %f\r\n",temp_f); delay_ms(10); temp_f = smpl_ctrl_overspeed_get(SMPL_KY_NUM); printf("过速保护 = %f\r\n",temp_f); delay_ms(10); temp_u = smpl_pid_segs_get(SMPL_KY_NUM); printf("PID分段数 = %d\r\n",temp_u); segs = temp_u; for (i=0; i<segs; ++i) { temp_f = smpl_pid_node_get(SMPL_KY_NUM,i); printf("截止力值 = %f\r\n",temp_f); delay_ms(10); temp_u = smpl_pid_kp_get(SMPL_KY_NUM,i); printf("KP = %d\r\n",temp_u); delay_ms(10); temp_u = smpl_pid_ki_get(SMPL_KY_NUM,i); printf("KI = %d\r\n",temp_u); delay_ms(10); temp_u = smpl_pid_kd_get(SMPL_KY_NUM,i); printf("KD = %d\r\n",temp_u); delay_ms(10); } temp_u = smpl_tab_num_get(SMPL_KY_NUM); printf("标定表分段数 = %d\r\n",temp_u); segs = temp_u; for (i=0; i<segs; ++i) { temp_f = smpl_tab_value_get(SMPL_KY_NUM,i); printf("值 = %f\r\n",temp_f); delay_ms(10); temp_u = smpl_tab_code_get(SMPL_KY_NUM,i); printf("码 = %d\r\n",temp_u); delay_ms(10); } }
bool audio_capture_buffer(audio_t *c, unsigned char *buffer) { return pcm_read(c->pcm, buffer, c->buffer_size) == 0; }
void *SpeechANCController::readThread_ANCLog_ADC2(void *arg) { prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0); SpeechANCController *pSpeechANCController = (SpeechANCController *)arg; // force to set priority struct sched_param sched_p; sched_getparam(0, &sched_p); sched_p.sched_priority = RTPM_PRIO_AUDIO_RECORD + 1; if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) { ALOGE("[%s] failed, errno: %d", __FUNCTION__, errno); } else { sched_p.sched_priority = RTPM_PRIO_AUDIO_CCCI_THREAD; sched_getparam(0, &sched_p); ALOGD("sched_setscheduler ok, priority: %d", sched_p.sched_priority); } ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid()); ssize_t buffer_size, write_bytes = 0; pSpeechANCController->mIndexPcmIn_ADC2 = pSpeechANCController->ConfigPCM(keypcmADC2AWB, &buffer_size); // config attribute memset(&pSpeechANCController->mConfig_ADC2, 0, sizeof(pSpeechANCController->mConfig_ADC2)); pSpeechANCController->mConfig_ADC2.channels = 2; //pSpeechANCController->mConfig_ADC2.rate = 192000; pSpeechANCController->mConfig_ADC2.rate = 48000;//actural samplerate 26000 // Buffer size: 2048(period_size) * 2(ch) * 2(byte) * 8(period_count) = 64 kb pSpeechANCController->mConfig_ADC2.period_count = 4; pSpeechANCController->mConfig_ADC2.format = PCM_FORMAT_S16_LE; pSpeechANCController->mConfig_ADC2.start_threshold = 0; pSpeechANCController->mConfig_ADC2.stop_threshold = 0; pSpeechANCController->mConfig_ADC2.silence_threshold = 0; pSpeechANCController->mConfig_ADC2.period_size = (buffer_size / (pSpeechANCController->mConfig_ADC2.channels * pSpeechANCController->mConfig_ADC2.period_count)) / ((pSpeechANCController->mConfig_ADC2.format == PCM_FORMAT_S16_LE) ? 2 : 4); pSpeechANCController->StartPCMIn(2, pSpeechANCController->mIndexPcmIn_ADC2, pSpeechANCController->mConfig_ADC2); // read raw data from stream manager char *buffer = new char[kReadBufferSize]; memset(buffer, 0, sizeof(char)*kReadBufferSize); while (pSpeechANCController->mEnable_ANCLog_ADC2 == true) { if (pSpeechANCController->mEnable_ANCLog_ADC2 == false) { break; } //pcm read // bytes_read = StreamInANCLog1->read(buffer, bytes); ASSERT(pSpeechANCController->mPcmIn_ADC2 != NULL); int retval = pcm_read(pSpeechANCController->mPcmIn_ADC2, buffer, kReadBufferSize); if (mDumpFile_ADC2 != NULL) { // ALOGD("%s(),fwrite file=0x%x, kReadBufferSize=%d", __FUNCTION__, mDumpFile_ADC2, kReadBufferSize); // write data to sd card write_bytes += fwrite((void *)buffer, sizeof(char), kReadBufferSize, mDumpFile_ADC2); } else { ALOGE("%s(), mDumpFile_ADC2 == NULL!!!!!!!!!!!!!!!!!!!!!!!!", __FUNCTION__); } if (retval != 0) { ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval); } } // close file if (mDumpFile_ADC2 != NULL) { fflush(mDumpFile_ADC2); fclose(mDumpFile_ADC2); mDumpFile_ADC2 = NULL; } pcm_stop(pSpeechANCController->mPcmIn_ADC2); pcm_close(pSpeechANCController->mPcmIn_ADC2); pSpeechANCController->mPcmIn_ADC2 = NULL; ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid()); pthread_exit(NULL); return NULL; }
static int stream_transfer(struct stream_transfer *stream_transfer) { struct dev_stream *stream_sender; struct dev_stream *stream_receiver; short* Srcptr; short* Drcptr; int size_transfer = 0; int ret =0; int exit_flag =0; int i=0; stream_sender = stream_transfer->stream_sender; stream_receiver = stream_transfer->stream_receiver; size_transfer = stream_sender->buf_size; #ifdef START_ZERO_BUFFER /* 消除开头杂音 */ memset(stream_sender->buf, 0, stream_sender->buf_size); pcm_write(stream_receiver->dev, stream_sender->buf, stream_sender->buf_size); #endif ret =pcm_wait(stream_sender->dev, 0); ret =pcm_wait(stream_receiver->dev, 0); pcm_stop(stream_receiver->dev); pcm_start(stream_receiver->dev); /* 消除开头pa音 */ memset(stream_sender->buf, 0, stream_sender->buf_size); pcm_write(stream_receiver->dev, stream_sender->buf, stream_sender->buf_size); while( 1 ){ if ( (!stream_transfer->voice_thread_run_flag)){ break; } #if 0 if (SNDRV_PCM_STATE_XRUN == get_pcm_state(stream_sender->dev) ){ //ALOGD("read SNDRV_PCM_STATE_XRUN "); if(ioctl(stream_sender->dev->fd, SNDRV_PCM_IOCTL_PREPARE)){ ALOGE("in read, fail to prepare SNDRV_PCM_STATE_XRUN "); } //usleep(3 * 1000); ret =pcm_wait(stream_sender->dev, 0); //ALOGD("pcm_read, pcm_wait ret=%d", ret); //ALOGD("read after prepare state:%d ",get_pcm_state(stream_sender->dev)); } #endif ret = pcm_read(stream_sender->dev, stream_sender->buf, size_transfer); if (ret != 0) { //exit_flag = 1; ALOGE("err: read codec err:%s, ret=%d", strerror(errno), ret); //break; } if ( (!stream_transfer->voice_thread_run_flag)){ break; } #if 0 if (SNDRV_PCM_STATE_XRUN == get_pcm_state(stream_receiver->dev) ){ //ALOGD("write SNDRV_PCM_STATE_XRUN "); pcm_stop(stream_receiver->dev); usleep(3 * 1000); //ALOGD("write after stop state:%d ",get_pcm_state(stream_receiver->dev)); pcm_start(stream_receiver->dev); ret =pcm_wait(stream_receiver->dev, 0); //ALOGD("pcm_write, pcm_wait ret=%d", ret); //usleep(3 * 1000); //ALOGD("write after prepare state:%d ",get_pcm_state(stream_receiver->dev)); } #endif ret = pcm_write(stream_receiver->dev, stream_sender->buf, size_transfer); if (ret != 0) { //exit_flag = 1; ALOGE("err: write pcm err:%s, ret=%d", strerror(errno), ret); } if ( (!stream_transfer->voice_thread_run_flag)){ break; } if (stream_transfer->record_flag == 1){ //是上行,还是下行. if (stream_transfer->voice_direction == UPSTREAM){ Srcptr = (short*)(stream_sender->buf); Drcptr = (short*)(record_data.record_buf + (record_data.lenwriteup%record_data.record_lenth)); if(record_data.lenwriteup >= record_data.lenwritedown) { memcpy(Drcptr,Srcptr,size_transfer); } else { int i; for(i=0;i<size_transfer/2;i++,Drcptr++) { *Drcptr = (*Drcptr + *Srcptr++)/2; } record_data.lenwrite += size_transfer; } record_data.lenwriteup += size_transfer; //ALOGD("stream is upload"); } else { Srcptr = (short*)(stream_sender->buf); Drcptr = (short*)(record_data.record_buf + (record_data.lenwritedown%record_data.record_lenth)); if(record_data.lenwritedown >= record_data.lenwriteup) { memcpy(Drcptr,Srcptr,size_transfer); } else { for(i=0;i<size_transfer/2;i++,Drcptr++) { *Drcptr = ((int)*Drcptr + (int)(*Srcptr++))/2; } record_data.lenwrite += size_transfer; } record_data.lenwritedown += size_transfer; } sem_post(&g_sem_record); } if ( (!stream_transfer->voice_thread_run_flag)){ break; } } return 0; }
void *AudioALSACaptureDataProviderTDM::readThread(void *arg) { prctl(PR_SET_NAME, (unsigned long)__FUNCTION__, 0, 0, 0); #ifdef MTK_AUDIO_ADJUST_PRIORITY // force to set priority struct sched_param sched_p; sched_getparam(0, &sched_p); sched_p.sched_priority = RTPM_PRIO_AUDIO_RECORD + 1; if (0 != sched_setscheduler(0, SCHED_RR, &sched_p)) { ALOGE("[%s] failed, errno: %d", __FUNCTION__, errno); } else { sched_p.sched_priority = RTPM_PRIO_AUDIO_RECORD + 1; sched_getparam(0, &sched_p); ALOGD("sched_setscheduler ok, priority: %d", sched_p.sched_priority); } #endif ALOGD("+%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid()); status_t retval = NO_ERROR; AudioALSACaptureDataProviderTDM *pDataProvider = static_cast<AudioALSACaptureDataProviderTDM *>(arg); uint32_t open_index = pDataProvider->mOpenIndex; // read raw data from alsa driver char linear_buffer[kReadBufferSize]; while (pDataProvider->mEnable == true) { if (open_index != pDataProvider->mOpenIndex) { ALOGD("%s(), open_index(%d) != mOpenIndex(%d), return", __FUNCTION__, open_index, pDataProvider->mOpenIndex); break; } retval = pDataProvider->mEnableLock.lock_timeout(300); ASSERT(retval == NO_ERROR); if (pDataProvider->mEnable == false) { pDataProvider->mEnableLock.unlock(); break; } ASSERT(pDataProvider->mPcm != NULL); int retval = pcm_read(pDataProvider->mPcm, linear_buffer, kReadBufferSize); if (retval != 0) { ALOGE("%s(), pcm_read() error, retval = %d", __FUNCTION__, retval); } // use ringbuf format to save buffer info pDataProvider->mPcmReadBuf.pBufBase = linear_buffer; pDataProvider->mPcmReadBuf.bufLen = kReadBufferSize + 1; // +1: avoid pRead == pWrite pDataProvider->mPcmReadBuf.pRead = linear_buffer; pDataProvider->mPcmReadBuf.pWrite = linear_buffer + kReadBufferSize; pDataProvider->mEnableLock.unlock(); pDataProvider->provideCaptureDataToAllClients(open_index); } ALOGD("-%s(), pid: %d, tid: %d", __FUNCTION__, getpid(), gettid()); pthread_exit(NULL); return NULL; }
int pulseaudio_play (AUDIOCTX * actx) { int error; pa_simple *s; pa_PRIVATE *priv = (pa_PRIVATE *) actx->driverprivate; bool quit = false; assert (priv != NULL); s = (pa_simple *) priv->pa_simple; /* Driver loop */ for (;;) { uint8_t buf[1024]; ssize_t r; /* Fetch state lock */ pthread_mutex_lock (&priv->lock); switch (priv->state) { case PU_END: quit = true; break; case PU_PAUSED: /* Wait for unpause signal */ pthread_cond_wait (&priv->pause, &priv->lock); break; case PU_PLAYING: case PU_IDLE: default: break; } pthread_mutex_unlock (&priv->lock); if (quit) break; /* Read some data ... */ r = pcm_read (actx->pcmprivate, (char *) buf, sizeof (buf), 0, 2, 1, NULL); if (r == OV_HOLE) { /* vorbis got garbage */ DSFYDEBUG ("pcm_read() == %s\n", "OV_HOLE"); continue; } if (r <= 0) { if (r == 0) /* EOF */ break; DSFYDEBUG ("pcm_read() failed == %zd\n", r); exit (-1); } /* ... and play it */ if (pa_simple_write (s, buf, (size_t) r, &error) < 0) { DSFYDEBUG ("pa_simple_write() failed: %s\n", pa_strerror (error)) exit (-1); } } /* Make sure that every single sample was played */ if (pa_simple_drain (s, &error) < 0) { DSFYDEBUG ("pa_simple_drain() failed: %s\n", pa_strerror (error)) exit (-1); } if (s) pa_simple_free (s); pthread_cond_signal (&priv->end); /* This will kill the thread */ return 0; }