| /* |
| * Copyright (C) 2017 Amlogic Corporation. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <stdbool.h> |
| #include <stdint.h> |
| #include <time.h> |
| #include <pthread.h> |
| #include <unistd.h> |
| |
| |
| #include "audio_if.h" |
| #include <IpcBuffer/IpcBuffer_c.h> |
| #include "hal_bt_capture.h" |
| |
| |
| |
| #define NSEC_PER_SEC 1000000000L |
| #define CAP_SAMPLE_RATE 48000 |
| #define CAP_SAMPLE_SIZE 4 |
| #define CAP_DEFAULT_SIZE (10240*4) |
| #define CAP_DEFAULT_THRESHOLD (CAP_DEFAULT_SIZE / 4) |
| #define CAP_BUFFER_NAME "blu_capture_test" |
| |
| |
| |
| typedef enum { |
| STATE_INIT = 0, |
| STATE_STARTED = 1, |
| STATE_STOPPED = 2 |
| } cap_state_e; |
| |
| struct AML_AudioCapture_Struct { |
| /* states & settings */ |
| cap_state_e next_state; |
| cap_state_e cur_state; |
| AML_AudioCapture_Settings next_settings; |
| AML_AudioCapture_Settings cur_settings; |
| AML_AudioCapture_Status status; |
| |
| /* working thread */ |
| pthread_t thread; |
| /* protect current state and capture buffer */ |
| pthread_mutex_t mutex; |
| pthread_cond_t condition; |
| bool exit; |
| |
| /* temp working buffer */ |
| unsigned char *data; |
| |
| /* capture buffer interface */ |
| struct audio_hw_device *dev; |
| unsigned char *cap_buf; |
| uint64_t rd_ptr; |
| uint64_t wr_ptr; |
| unsigned buffer_size; |
| }; |
| |
| typedef struct AML_AudioCapture_Struct *AML_AudioCaptureHandle; |
| |
| /* protect singleton AML_AudioCapture_Struct for AML APIs */ |
| static pthread_mutex_t rmf_lock = PTHREAD_MUTEX_INITIALIZER; |
| static struct AML_AudioCapture_Struct *control; |
| AML_AudioCapture_Settings settings; //operate setting |
| |
| |
| |
| static inline uint64_t bytes_to_ns(unsigned bytes) |
| { |
| return (uint64_t)bytes * NSEC_PER_SEC / CAP_SAMPLE_SIZE / CAP_SAMPLE_RATE; |
| } |
| |
| static inline unsigned int _buffer_level ( |
| AML_AudioCaptureHandle handle |
| ) { |
| return (handle->wr_ptr - handle->rd_ptr) % handle->buffer_size; |
| } |
| |
| static inline bool _buffer_overflow ( |
| AML_AudioCaptureHandle handle |
| ) { |
| return (handle->wr_ptr - handle->rd_ptr) > handle->buffer_size; |
| } |
| |
| static inline void _buffer_normalize ( |
| AML_AudioCaptureHandle handle |
| ) { |
| handle->rd_ptr = handle->wr_ptr - _buffer_level(handle); |
| } |
| |
| static void* _AML_AudioCapture_Thread ( |
| void *arg |
| ) { |
| AML_AudioCaptureHandle handle = (AML_AudioCaptureHandle)arg; |
| struct timespec ts; |
| |
| while (1) { |
| uint64_t n; |
| bool update_status = false; |
| pthread_mutex_lock(&control->mutex); |
| clock_gettime(CLOCK_MONOTONIC, &ts); |
| |
| n = ts.tv_nsec + bytes_to_ns(control->cur_settings.threshold); |
| ts.tv_nsec = n % NSEC_PER_SEC; |
| ts.tv_sec += n / NSEC_PER_SEC; |
| pthread_cond_timedwait(&control->condition,&control->mutex, &ts); |
| /* state switching */ |
| if (handle->cur_state != handle->next_state) { |
| char cmd[32] = {0}; |
| if (handle->next_state == STATE_STARTED) { |
| handle->cur_settings = handle->next_settings; |
| |
| handle->rd_ptr = 0; |
| handle->wr_ptr = 0; |
| handle->buffer_size = (handle->cur_settings.fifoSize == 0) ? CAP_DEFAULT_SIZE : handle->cur_settings.fifoSize; |
| handle->data = (unsigned char *)malloc(handle->buffer_size); |
| memset(handle->data,0,handle->buffer_size); |
| handle->status.started = 0; |
| handle->status.format = Format_e16BitStereo; |
| handle->status.samplingFreq = Freq_e48000; |
| snprintf(cmd, sizeof(cmd), "cap_buffer=" CAP_BUFFER_NAME ",%d", control->buffer_size); |
| handle->dev->set_parameters(handle->dev, cmd); |
| handle->cap_buf = IpcBuffer_get_ptr(CAP_BUFFER_NAME); |
| handle->status.started = 1; |
| update_status = true; |
| } |
| else if (handle->next_state == STATE_STOPPED) { |
| snprintf(cmd, sizeof(cmd), "cap_buffer=" CAP_BUFFER_NAME ",0"); |
| control->dev->set_parameters(handle->dev, cmd); |
| handle->cap_buf = IpcBuffer_get_ptr(CAP_BUFFER_NAME); |
| printf("%s,%d:handle->cap_buf=%p\n",handle->cap_buf); |
| handle->status.started = 0; |
| |
| if (handle->data) { |
| free(handle->data); |
| handle->data = NULL; |
| } |
| |
| update_status = true; |
| } |
| |
| handle->cur_state = handle->next_state; |
| } |
| |
| pthread_mutex_unlock(&handle->mutex); |
| |
| if (handle->exit) { |
| break; |
| } |
| |
| if (handle->status.started ) { |
| handle->wr_ptr = IpcBuffer_get_wr_pos(CAP_BUFFER_NAME); |
| _buffer_normalize(handle); |
| |
| if (handle->cap_buf && handle->data) { |
| long unsigned int len = _buffer_level(handle);//write point-read point % buf_size=can read |
| long unsigned int offset; |
| offset = handle->rd_ptr % handle->buffer_size; |
| if (len <= (handle->buffer_size - offset)) { |
| //memcpy(handle->data, handle->cap_buf + offset, len); |
| audio_dump_audio_bitstreams("/data/audio/capture.pcm",handle->cap_buf + offset,len); |
| } else { |
| unsigned copied = handle->buffer_size - offset; |
| audio_dump_audio_bitstreams("/data/audio/capture.pcm",handle->cap_buf + offset,copied); |
| audio_dump_audio_bitstreams("/data/audio/capture.pcm",handle->cap_buf,len - copied); |
| } |
| handle->rd_ptr += len; |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| |
| int _AML_AudioCapture_Control_Init ( |
| AML_AudioCaptureHandle handle |
| ) { |
| pthread_condattr_t attr; |
| |
| pthread_condattr_init(&attr); |
| pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); |
| pthread_cond_init(&control->condition, &attr); |
| pthread_mutex_init(&control->mutex, NULL); |
| |
| if ( audio_hw_load_interface(&handle->dev) ) { |
| return fail; |
| } |
| if (handle->dev->init_check(handle->dev)) { |
| printf("device not inited, quit\n"); |
| audio_hw_unload_interface(handle->dev); |
| return fail; |
| } |
| handle->cur_settings.threshold = CAP_DEFAULT_THRESHOLD; |
| handle->cur_state = STATE_INIT; |
| handle->next_state = STATE_INIT; |
| if (pthread_create(&handle->thread, NULL, _AML_AudioCapture_Thread, handle)) { |
| printf("pthread_create failed\n"); |
| struct audio_hw_device *dev = handle->dev; |
| dev->common.close(&dev->common); |
| audio_hw_unload_interface(dev); |
| return fail; |
| } |
| |
| return success; |
| } |
| |
| |
| struct AML_AudioCapture_Struct * |
| AML_AudioCapture_Open () { |
| pthread_mutex_lock(&rmf_lock); |
| |
| if (control) { |
| pthread_mutex_unlock(&rmf_lock); |
| return NULL; |
| } |
| |
| control = (struct AML_AudioCapture_Struct *)malloc(sizeof(struct AML_AudioCapture_Struct)); |
| if (!control) { |
| pthread_mutex_unlock(&rmf_lock); |
| return NULL; |
| } |
| memset(control, 0, sizeof(struct AML_AudioCapture_Struct)); |
| |
| if (!_AML_AudioCapture_Control_Init(control)) { |
| pthread_mutex_unlock(&rmf_lock); |
| return NULL; |
| } |
| pthread_mutex_unlock(&rmf_lock); |
| |
| return control; |
| } |
| |
| int |
| AML_AudioCapture_GetDefaultSettings ( |
| AML_AudioCapture_Settings* settings |
| ) { |
| settings->fifoSize = CAP_DEFAULT_SIZE; |
| settings->threshold = CAP_DEFAULT_THRESHOLD; |
| settings->format = Format_e16BitStereo; |
| settings->samplingFreq = Freq_e48000; |
| |
| return success; |
| } |
| |
| |
| int |
| AML_AudioCapture_Start ( |
| AML_AudioCaptureHandle handle, |
| AML_AudioCapture_Settings* settings |
| ) { |
| pthread_mutex_lock(&rmf_lock); |
| |
| pthread_mutex_lock(&handle->mutex); |
| if (handle->cur_state == STATE_STARTED) { |
| pthread_mutex_unlock(&handle->mutex); |
| pthread_mutex_unlock(&rmf_lock); |
| return fail; |
| } |
| handle->next_settings = *settings; |
| handle->next_state = STATE_STARTED; |
| pthread_cond_signal(&handle->condition); |
| pthread_mutex_unlock(&handle->mutex); |
| |
| pthread_mutex_unlock(&rmf_lock); |
| |
| return success; |
| } |
| |
| |
| int |
| AML_AudioCapture_Stop_Locked ( |
| AML_AudioCaptureHandle handle |
| ) { |
| pthread_mutex_lock(&handle->mutex); |
| if (handle->cur_state != STATE_STARTED) { |
| pthread_mutex_unlock(&handle->mutex); |
| pthread_mutex_unlock(&rmf_lock); |
| return fail; |
| } |
| |
| handle->next_state = STATE_STOPPED; |
| |
| pthread_cond_signal(&handle->condition); |
| pthread_mutex_unlock(&handle->mutex); |
| |
| return success; |
| } |
| |
| int |
| AML_AudioCapture_Stop ( |
| AML_AudioCaptureHandle handle |
| ) { |
| int ret; |
| pthread_mutex_lock(&rmf_lock); |
| ret = AML_AudioCapture_Stop_Locked(handle); |
| pthread_mutex_unlock(&rmf_lock); |
| |
| return ret; |
| } |
| |
| int |
| AML_AudioCapture_Close ( |
| AML_AudioCaptureHandle handle |
| ) { |
| pthread_mutex_lock(&rmf_lock); |
| |
| if (handle != control) { |
| pthread_mutex_unlock(&rmf_lock); |
| return fail; |
| } |
| |
| AML_AudioCapture_Stop_Locked(handle); |
| |
| pthread_mutex_lock(&handle->mutex); |
| handle->exit = true; |
| pthread_cond_signal(&handle->condition); |
| pthread_mutex_unlock(&handle->mutex); |
| |
| /* avoid dead lock from RMF_AudioCapture_GetStatus triggered by status change call back */ |
| pthread_mutex_unlock(&rmf_lock); |
| |
| pthread_join(handle->thread, NULL); |
| |
| pthread_mutex_lock(&rmf_lock); |
| |
| if (handle->data) { |
| free(handle->data); |
| } |
| free(handle); |
| control = NULL; |
| |
| handle->dev->common.close(&handle->dev->common); |
| audio_hw_unload_interface(handle->dev); |
| |
| pthread_mutex_unlock(&rmf_lock); |
| return success; |
| } |
| |
| int audio_dump_audio_bitstreams(const char *path, const void *buf, size_t bytes) |
| { |
| if (!path) { |
| return fail; |
| } |
| |
| int flen; |
| FILE *fp = fopen(path, "ab+"); |
| if (fp) { |
| flen = fwrite((char *)buf, 1, bytes, fp); |
| fclose(fp); |
| return flen; |
| } |
| printf("fail to open path=%s, errno=%d/%s", path, errno, strerror(errno)); |
| return -1; |
| |
| } |
| |
| |
| int main(int argc ,void **argv) |
| { |
| |
| int len; |
| //get operation interface |
| AML_AudioCaptureHandle handle=NULL; |
| handle=(AML_AudioCaptureHandle) AML_AudioCapture_Open(); |
| if (handle == NULL) { |
| printf("open error\n"); |
| return fail; |
| } |
| //get_default_setting |
| if (!AML_AudioCapture_GetDefaultSettings(&settings)) { |
| printf("get default_setting error\n"); |
| return fail; |
| } |
| //audio capture start |
| if (!AML_AudioCapture_Start(handle,&settings)) { |
| printf("AudioCapture Start error\n"); |
| return fail; |
| } |
| printf("Audio Capturing .....\n"); |
| while ( 1 ); |
| //Sleep(300); |
| //AML_AudioCapture_Stop(handle); |
| //AML_AudioCapture_Close(handle); |
| return success; |
| } |