slesTestRecBuffQueue.cpp revision 086a6f51a7b12880ed114962136972f89ed70da2
1ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi/* 2ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * Copyright (C) 2010 The Android Open Source Project 3ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * 4ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License"); 5ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * you may not use this file except in compliance with the License. 6ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * You may obtain a copy of the License at 7ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * 8ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * http://www.apache.org/licenses/LICENSE-2.0 9ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * 10ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * Unless required by applicable law or agreed to in writing, software 11ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS, 12ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * See the License for the specific language governing permissions and 14ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi * limitations under the License. 15ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi */ 16ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 177126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten/* Audio Record Test 187126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten 197126c25d7c037e5086216cf540ecf40779c3585aGlenn KastenFirst run the program from shell: 207126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten # slesTest_recBuffQueue /sdcard/myrec.raw 4 217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten 227126c25d7c037e5086216cf540ecf40779c3585aGlenn KastenThese use adb on host to retrive the file: 237126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten % adb pull /sdcard/myrec.raw myrec.raw 247126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten 257126c25d7c037e5086216cf540ecf40779c3585aGlenn KastenHow to examine the output with Audacity: 267126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten Project / Import raw data 277126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten Select myrec.raw file, then click Open button 287126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten Choose these options: 297126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten Signed 16-bit PCM 307126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten Little-endian 317126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten 1 Channel (Mono) 327126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten Sample rate 22050 Hz 337126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten Click Import button 347126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten 35ecccdd9e99a753d3a9e105ec4b9b02e7afe60ebeGlenn KastenHow to convert with sox: 36ecccdd9e99a753d3a9e105ec4b9b02e7afe60ebeGlenn Kasten sox -r 22050 -s -2 myrec.raw myrec.wav 37ecccdd9e99a753d3a9e105ec4b9b02e7afe60ebeGlenn Kasten 387126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten*/ 397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten 407126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten 41ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi#include <stdlib.h> 42ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi#include <stdio.h> 43ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi#include <string.h> 44ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi#include <unistd.h> 45ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi#include <sys/time.h> 46ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi#include <fcntl.h> 47ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 48c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES.h> 49c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES_Android.h> 50ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 514dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten/* Preset number to use for recording */ 524dd1fab74463de4852b86af64481006f87d48b54Glenn KastenSLuint32 presetValue = SL_ANDROID_RECORDING_PRESET_NONE; 534dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten 5401e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten/* Explicitly requesting SL_IID_ANDROIDSIMPLEBUFFERQUEUE and SL_IID_ANDROIDCONFIGURATION 55b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi * on the AudioRecorder object */ 56b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi#define NUM_EXPLICIT_INTERFACES_FOR_RECORDER 2 57ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 58ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi/* Size of the recording buffer queue */ 59ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi#define NB_BUFFERS_IN_QUEUE 1 60ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi/* Size of each buffer in the queue */ 61ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi#define BUFFER_SIZE_IN_SAMPLES 1024 62a384948fc96e81947a9b689fc65ea0e7b93df25cJean-Michel Trivi#define BUFFER_SIZE_IN_BYTES (2*BUFFER_SIZE_IN_SAMPLES) 63ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 64ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi/* Local storage for Audio data */ 65ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Triviint8_t pcmData[NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES]; 66ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 67ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi/* destination for recorded data */ 68ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivistatic FILE* gFp; 69ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 70ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi//----------------------------------------------------------------- 71ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi/* Exits the application if an error is encountered */ 72ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi#define ExitOnError(x) ExitOnErrorFunc(x,__LINE__) 73ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 74ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivivoid ExitOnErrorFunc( SLresult result , int line) 75ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi{ 76ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi if (SL_RESULT_SUCCESS != result) { 7758432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten fprintf(stdout, "%u error code encountered at line %d, exiting\n", result, line); 78c2303eb5497c488db786dcb2b8514db229452536Glenn Kasten exit(EXIT_FAILURE); 79ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi } 80ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi} 81ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 82ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi//----------------------------------------------------------------- 83ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi/* Structure for passing information to callback function */ 84ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivitypedef struct CallbackCntxt_ { 85ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLPlayItf playItf; 86ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLuint32 size; 87ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLint8* pDataBase; // Base address of local audio data storage 88ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLint8* pData; // Current address of local audio data storage 89ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi} CallbackCntxt; 90ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 919bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi 929bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi//----------------------------------------------------------------- 939bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi/* Callback for recording buffer queue events */ 949bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivivoid RecCallback( 959bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi SLRecordItf caller, 96086a6f51a7b12880ed114962136972f89ed70da2Glenn Kasten void *pContext __unused, 979bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi SLuint32 event) 989bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi{ 999bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi if (SL_RECORDEVENT_HEADATNEWPOS & event) { 1009bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi SLmillisecond pMsec = 0; 1019bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi (*caller)->GetPosition(caller, &pMsec); 10258432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten fprintf(stdout, "SL_RECORDEVENT_HEADATNEWPOS current position=%ums\n", pMsec); 1039bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi } 1049bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi 1059bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi if (SL_RECORDEVENT_HEADATMARKER & event) { 1069bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi SLmillisecond pMsec = 0; 1079bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi (*caller)->GetPosition(caller, &pMsec); 10858432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten fprintf(stdout, "SL_RECORDEVENT_HEADATMARKER current position=%ums\n", pMsec); 1099bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi } 1109bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi} 1119bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi 112ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi//----------------------------------------------------------------- 113ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi/* Callback for recording buffer queue events */ 114ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivivoid RecBufferQueueCallback( 11501e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten SLAndroidSimpleBufferQueueItf queueItf, 116ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi void *pContext) 117ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi{ 11804c7354b8a9afcf2151c00c1dfbc64d0ba5d33ccGlenn Kasten //fprintf(stdout, "RecBufferQueueCallback called\n"); 119ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 120ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi CallbackCntxt *pCntxt = (CallbackCntxt*)pContext; 121ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 122ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Save the recorded data */ 123ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fwrite(pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES, 1, gFp); 124ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 125ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Increase data pointer by buffer size */ 126ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi pCntxt->pData += BUFFER_SIZE_IN_BYTES; 127ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 128ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi if (pCntxt->pData >= pCntxt->pDataBase + (NB_BUFFERS_IN_QUEUE * BUFFER_SIZE_IN_BYTES)) { 129ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi pCntxt->pData = pCntxt->pDataBase; 130ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi } 131ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 132ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError( (*queueItf)->Enqueue(queueItf, pCntxt->pDataBase, BUFFER_SIZE_IN_BYTES) ); 133ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 13401e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten SLAndroidSimpleBufferQueueState recQueueState; 135ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError( (*queueItf)->GetState(queueItf, &recQueueState) ); 136ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 13704c7354b8a9afcf2151c00c1dfbc64d0ba5d33ccGlenn Kasten /*fprintf(stderr, "\tRecBufferQueueCallback now has pCntxt->pData=%p queue: " 13858432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten "count=%u playIndex=%u\n", 13904c7354b8a9afcf2151c00c1dfbc64d0ba5d33ccGlenn Kasten pCntxt->pData, recQueueState.count, recQueueState.index);*/ 140ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi} 141ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 142ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi//----------------------------------------------------------------- 143ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 14464ae6e1913b9330ad7ebd1c3ae62cdcf2d45b758Jean-Michel Trivi/* Record to an audio path by opening a file descriptor on that path */ 145ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivivoid TestRecToBuffQueue( SLObjectItf sl, const char* path, SLAint64 durationInSeconds) 146ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi{ 147ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi gFp = fopen(path, "w"); 148ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi if (NULL == gFp) { 149ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(SL_RESULT_RESOURCE_ERROR); 150ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi } 151ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 152ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLresult result; 153ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLEngineItf EngineItf; 154ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 155ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Objects this application uses: one audio recorder */ 156ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLObjectItf recorder; 157ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 158ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Interfaces for the audio recorder */ 15901e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten SLAndroidSimpleBufferQueueItf recBuffQueueItf; 160b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi SLRecordItf recordItf; 161b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi SLAndroidConfigurationItf configItf; 162ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 163ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Source of audio data for the recording */ 164ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLDataSource recSource; 165ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLDataLocator_IODevice ioDevice; 166ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 167ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Data sink for recorded audio */ 168ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLDataSink recDest; 16901e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten SLDataLocator_AndroidSimpleBufferQueue recBuffQueue; 170ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLDataFormat_PCM pcm; 171ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 172ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLboolean required[NUM_EXPLICIT_INTERFACES_FOR_RECORDER]; 173ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLInterfaceID iidArray[NUM_EXPLICIT_INTERFACES_FOR_RECORDER]; 174ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 175ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Get the SL Engine Interface which is implicit */ 176ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi result = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void*)&EngineItf); 177ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 178ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 179ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Initialize arrays required[] and iidArray[] */ 180ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi for (int i=0 ; i < NUM_EXPLICIT_INTERFACES_FOR_RECORDER ; i++) { 181ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi required[i] = SL_BOOLEAN_FALSE; 182ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi iidArray[i] = SL_IID_NULL; 183ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi } 184ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 185ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 186ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* ------------------------------------------------------ */ 187ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Configuration of the recorder */ 188ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 18901e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten /* Request the AndroidSimpleBufferQueue and AndroidConfiguration interfaces */ 190ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi required[0] = SL_BOOLEAN_TRUE; 19101e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten iidArray[0] = SL_IID_ANDROIDSIMPLEBUFFERQUEUE; 192b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi required[1] = SL_BOOLEAN_TRUE; 193b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi iidArray[1] = SL_IID_ANDROIDCONFIGURATION; 194ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 195ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Setup the data source */ 196ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ioDevice.locatorType = SL_DATALOCATOR_IODEVICE; 197ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ioDevice.deviceType = SL_IODEVICE_AUDIOINPUT; 198ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ioDevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT; 199ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ioDevice.device = NULL; 200ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi recSource.pLocator = (void *) &ioDevice; 2012246c698482ab6860906672229f0ae6d886e6302Glenn Kasten recSource.pFormat = NULL; 202ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 203ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Setup the data sink */ 20401e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten recBuffQueue.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE; 205ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi recBuffQueue.numBuffers = NB_BUFFERS_IN_QUEUE; 206ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* set up the format of the data in the buffer queue */ 207ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi pcm.formatType = SL_DATAFORMAT_PCM; 208ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi pcm.numChannels = 1; 209ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi pcm.samplesPerSec = SL_SAMPLINGRATE_22_05; 210ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16; 211ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi pcm.containerSize = 16; 212ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi pcm.channelMask = SL_SPEAKER_FRONT_LEFT; 213ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi pcm.endianness = SL_BYTEORDER_LITTLEENDIAN; 214ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 215ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi recDest.pLocator = (void *) &recBuffQueue; 216ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi recDest.pFormat = (void * ) &pcm; 217ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 218ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Create the audio recorder */ 219b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi result = (*EngineItf)->CreateAudioRecorder(EngineItf, &recorder, &recSource, &recDest, 220b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi NUM_EXPLICIT_INTERFACES_FOR_RECORDER, iidArray, required); 221ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 222ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fprintf(stdout, "Recorder created\n"); 223ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 224b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi /* Get the Android configuration interface which is explicit */ 225b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi result = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDCONFIGURATION, (void*)&configItf); 226b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi ExitOnError(result); 227b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi 228b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi /* Use the configuration interface to configure the recorder before it's realized */ 2294dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten if (presetValue != SL_ANDROID_RECORDING_PRESET_NONE) { 2304dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET, 2314dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten &presetValue, sizeof(SLuint32)); 2324dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten ExitOnError(result); 2334dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten fprintf(stdout, "Recorder parameterized with preset %u\n", presetValue); 2344dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten } else { 2354dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten printf("Using default record preset\n"); 2364dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten } 237b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi 2384dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten SLuint32 presetRetrieved = SL_ANDROID_RECORDING_PRESET_NONE; 239b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi SLuint32 presetSize = 2*sizeof(SLuint32); // intentionally too big 240b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi result = (*configItf)->GetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET, 2414dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten &presetSize, (void*)&presetRetrieved); 242b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi ExitOnError(result); 2434dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten if (presetValue == SL_ANDROID_RECORDING_PRESET_NONE) { 2444dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten printf("The default record preset appears to be %u\n", presetRetrieved); 2454dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten } else if (presetValue != presetRetrieved) { 24668686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten fprintf(stderr, "Error retrieving recording preset as %u instead of %u\n", presetRetrieved, 24768686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten presetValue); 248b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi ExitOnError(SL_RESULT_INTERNAL_ERROR); 249b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi } 250b3e52a63baaea367cf411348b68ecd8fd429b029Jean-Michel Trivi 251ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Realize the recorder in synchronous mode. */ 252ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi result = (*recorder)->Realize(recorder, SL_BOOLEAN_FALSE); 253ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 254ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fprintf(stdout, "Recorder realized\n"); 255ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 256ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Get the record interface which is implicit */ 257ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi result = (*recorder)->GetInterface(recorder, SL_IID_RECORD, (void*)&recordItf); 258ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 259ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 2609bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi /* Set up the recorder callback to get events during the recording */ 2619bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi result = (*recordItf)->SetMarkerPosition(recordItf, 2000); 2629bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi ExitOnError(result); 2639bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi result = (*recordItf)->SetPositionUpdatePeriod(recordItf, 500); 2649bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi ExitOnError(result); 2659bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi result = (*recordItf)->SetCallbackEventsMask(recordItf, 2669bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi SL_RECORDEVENT_HEADATMARKER | SL_RECORDEVENT_HEADATNEWPOS); 2679bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi ExitOnError(result); 2689bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi result = (*recordItf)->RegisterCallback(recordItf, RecCallback, NULL); 2699bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi ExitOnError(result); 2709bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi fprintf(stdout, "Recorder callback registered\n"); 2719bc234ed758273259e334144cc6e1643b2494175Jean-Michel Trivi 272ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Get the buffer queue interface which was explicitly requested */ 2735e3b06982dbf1eae237cc74326e66d51d3cdd664Glenn Kasten result = (*recorder)->GetInterface(recorder, SL_IID_ANDROIDSIMPLEBUFFERQUEUE, 2745e3b06982dbf1eae237cc74326e66d51d3cdd664Glenn Kasten (void*)&recBuffQueueItf); 275ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 276ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 277ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* ------------------------------------------------------ */ 278ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Initialize the callback and its context for the recording buffer queue */ 279ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi CallbackCntxt cntxt; 280ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi cntxt.pDataBase = (int8_t*)&pcmData; 281ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi cntxt.pData = cntxt.pDataBase; 282ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi cntxt.size = sizeof(pcmData); 283ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi result = (*recBuffQueueItf)->RegisterCallback(recBuffQueueItf, RecBufferQueueCallback, &cntxt); 284ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 285ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 286ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Enqueue buffers to map the region of memory allocated to store the recorded data */ 287ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fprintf(stdout,"Enqueueing buffer "); 288ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi for(int i = 0 ; i < NB_BUFFERS_IN_QUEUE ; i++) { 289ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fprintf(stdout,"%d ", i); 290ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi result = (*recBuffQueueItf)->Enqueue(recBuffQueueItf, cntxt.pData, BUFFER_SIZE_IN_BYTES); 291ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 292ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi cntxt.pData += BUFFER_SIZE_IN_BYTES; 293ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi } 294ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fprintf(stdout,"\n"); 295ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi cntxt.pData = cntxt.pDataBase; 296ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 297ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* ------------------------------------------------------ */ 298ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Start recording */ 299ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_RECORDING); 300ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 301ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fprintf(stdout, "Starting to record\n"); 302ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 303ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Record for at least a second */ 304ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi if (durationInSeconds < 1) { 305ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi durationInSeconds = 1; 306ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi } 307ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi usleep(durationInSeconds * 1000 * 1000); 308ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 309ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* ------------------------------------------------------ */ 310ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* End of recording */ 311ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 312ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Stop recording */ 313ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi result = (*recordItf)->SetRecordState(recordItf, SL_RECORDSTATE_STOPPED); 314ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 315ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fprintf(stdout, "Stopped recording\n"); 316ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 317ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Destroy the AudioRecorder object */ 318ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi (*recorder)->Destroy(recorder); 319ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 320ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fclose(gFp); 321ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi} 322ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 323ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi//----------------------------------------------------------------- 324ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Triviint main(int argc, char* const argv[]) 325ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi{ 326ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLresult result; 327ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLObjectItf sl; 328ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 3294dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten const char *prog = argv[0]; 3305e3b06982dbf1eae237cc74326e66d51d3cdd664Glenn Kasten fprintf(stdout, "OpenSL ES test %s: exercises SLRecordItf and SLAndroidSimpleBufferQueueItf ", 3314dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten prog); 332ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi fprintf(stdout, "on an AudioRecorder object\n"); 333ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 3344dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten int i; 3354dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten for (i = 1; i < argc; ++i) { 3364dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten const char *arg = argv[i]; 3374dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten if (arg[0] != '-') { 3384dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten break; 3394dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten } 3404dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten switch (arg[1]) { 3414dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten case 'p': // preset number 3424dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten presetValue = atoi(&arg[2]); 3434dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten break; 3444dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten default: 3454dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten fprintf(stderr, "%s: unknown option %s\n", prog, arg); 3464dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten break; 3474dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten } 3484dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten } 3494dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten 3504dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten if (argc-i < 2) { 35168686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten printf("Usage: \t%s [-p#] destination_file duration_in_seconds\n", prog); 35268686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten printf(" -p# is the preset value which defaults to SL_ANDROID_RECORDING_PRESET_NONE\n"); 35368686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten printf(" possible values are:\n"); 35468686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten printf(" -p%d SL_ANDROID_RECORDING_PRESET_NONE\n", 35568686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten SL_ANDROID_RECORDING_PRESET_NONE); 35668686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten printf(" -p%d SL_ANDROID_RECORDING_PRESET_GENERIC\n", 35768686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten SL_ANDROID_RECORDING_PRESET_GENERIC); 35868686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten printf(" -p%d SL_ANDROID_RECORDING_PRESET_CAMCORDER\n", 35968686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten SL_ANDROID_RECORDING_PRESET_CAMCORDER); 36068686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten printf(" -p%d SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION\n", 36168686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION); 36268686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten printf(" -p%d SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION\n", 36368686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION); 36468686bd0cb31f99f07ebc176176f8b51adf8d1d5Glenn Kasten printf("Example: \"%s /sdcard/myrec.raw 4\" \n", prog); 365c2303eb5497c488db786dcb2b8514db229452536Glenn Kasten exit(EXIT_FAILURE); 366ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi } 367ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 368ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi SLEngineOption EngineOption[] = { 369ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi {(SLuint32) SL_ENGINEOPTION_THREADSAFE, (SLuint32) SL_BOOLEAN_TRUE} 370ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi }; 371ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 372ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi result = slCreateEngine( &sl, 1, EngineOption, 0, NULL, NULL); 373ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 374ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 375ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Realizing the SL Engine in synchronous mode. */ 376ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi result = (*sl)->Realize(sl, SL_BOOLEAN_FALSE); 377ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi ExitOnError(result); 378ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 3794dd1fab74463de4852b86af64481006f87d48b54Glenn Kasten TestRecToBuffQueue(sl, argv[i], (SLAint64)atoi(argv[i+1])); 380ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 381ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi /* Shutdown OpenSL ES */ 382ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi (*sl)->Destroy(sl); 383ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi 384c2303eb5497c488db786dcb2b8514db229452536Glenn Kasten return EXIT_SUCCESS; 385ece0014725c0f3b8ff6c369aeabd27a71f03510bJean-Michel Trivi} 386