1/*---------------------------------------------------------------------------*
2 *  RecognizerResultImpl.c  *
3 *                                                                           *
4 *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5 *                                                                           *
6 *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7 *  you may not use this file except in compliance with the License.         *
8 *                                                                           *
9 *  You may obtain a copy of the License at                                  *
10 *      http://www.apache.org/licenses/LICENSE-2.0                           *
11 *                                                                           *
12 *  Unless required by applicable law or agreed to in writing, software      *
13 *  distributed under the License is distributed on an 'AS IS' BASIS,        *
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 *  See the License for the specific language governing permissions and      *
16 *  limitations under the License.                                           *
17 *                                                                           *
18 *---------------------------------------------------------------------------*/
19
20#include "SR_RecognizerResult.h"
21#include "SR_RecognizerResultImpl.h"
22#include "SR_SemanticResult.h"
23#include "SR_SemanticResultImpl.h"
24#include "SR_SemprocDefinitions.h"
25#include "plog.h"
26#include "pmemory.h"
27#include "ESR_Locale.h"
28
29#define MTAG NULL
30
31ESR_ReturnCode SR_RecognizerResult_Create(SR_RecognizerResult** self, SR_RecognizerImpl* recogImpl)
32{
33  SR_RecognizerResultImpl* impl;
34
35  if (self == NULL || recogImpl == NULL)
36  {
37    PLogError(L("ESR_INVALID_ARGUMENT"));
38    return ESR_INVALID_ARGUMENT;
39  }
40  impl = NEW(SR_RecognizerResultImpl, MTAG);
41  if (impl == NULL)
42  {
43    PLogError(L("ESR_OUT_OF_MEMORY"));
44    return ESR_OUT_OF_MEMORY;
45  }
46  impl->Interface.getWaveform = &SR_RecognizerResult_GetWaveform;
47  impl->Interface.getSize = &SR_RecognizerResult_GetSize;
48  impl->Interface.getKeyCount = &SR_RecognizerResult_GetKeyCount;
49  impl->Interface.getKeyList = &SR_RecognizerResult_GetKeyList;
50  impl->Interface.getValue = &SR_RecognizerResult_GetValue;
51  impl->Interface.getLocale = &SR_RecognizerResult_GetLocale;
52
53  impl->nbestList = NULL;
54  impl->nbestListSize = 0;
55  impl->results = NULL;
56  impl->recogImpl = recogImpl;
57  *self = (SR_RecognizerResult*) impl;
58  return ESR_SUCCESS;
59}
60
61ESR_ReturnCode SR_RecognizerResult_GetWaveform(const SR_RecognizerResult* self,
62																							 const asr_int16_t** waveform, size_t* size)
63{
64  SR_RecognizerResultImpl* impl = (SR_RecognizerResultImpl*) self;
65
66  if (waveform == NULL)
67  {
68    PLogError(L("ESR_INVALID_ARGUMENT"));
69    return ESR_INVALID_ARGUMENT;
70  }
71
72  // just point to the circular buffer read start point
73  if (impl->recogImpl->waveformBuffer->overflow_count == 0)
74  {
75    *waveform = (asr_int16_t*)(((unsigned char *) impl->recogImpl->waveformBuffer->cbuffer) +
76      sizeof(CircularBuffer) + impl->recogImpl->waveformBuffer->cbuffer->readIdx);
77
78    *size = impl->recogImpl->waveformBuffer->read_size;
79    return ESR_SUCCESS;
80  }
81  else
82  {
83    PLogMessage(L("Warning: Voice Enrollment audio buffer overflow (spoke too much, over by %d bytes)\n"),
84                impl->recogImpl->waveformBuffer->overflow_count);
85
86    *waveform = (asr_int16_t*)(((unsigned char *) impl->recogImpl->waveformBuffer->cbuffer) + sizeof(CircularBuffer) + impl->recogImpl->waveformBuffer->cbuffer->readIdx);
87    *size = impl->recogImpl->waveformBuffer->read_size;
88    return ESR_SUCCESS;
89  }
90}
91
92ESR_ReturnCode SR_RecognizerResult_GetSize(const SR_RecognizerResult* self, size_t* count)
93{
94  SR_RecognizerResultImpl* impl = (SR_RecognizerResultImpl*) self;
95  ESR_ReturnCode rc;
96
97  CHKLOG(rc, ArrayListGetSize(impl->results, count));
98  return ESR_SUCCESS;
99CLEANUP:
100  return rc;
101}
102
103ESR_ReturnCode SR_RecognizerResult_GetKeyCount(const SR_RecognizerResult* self,
104																							 const size_t nbest, size_t* count)
105{
106  SR_RecognizerResultImpl* impl = (SR_RecognizerResultImpl*) self;
107  ESR_ReturnCode rc;
108  ArrayList* results;
109	SR_SemanticResult* result;
110
111	/* Choose nbest-list entry */
112	CHKLOG(rc, impl->results->get(impl->results, nbest, (void **)&results));
113  /*
114   * Currently we only support one semantic result per nbestlist entry,
115   * so we grab the first available one.
116   */
117  CHKLOG(rc, results->get(results, 0, (void **)&result));
118  CHKLOG(rc, result->getKeyCount(result , count));
119  return ESR_SUCCESS;
120CLEANUP:
121  return rc;
122}
123
124ESR_ReturnCode SR_RecognizerResult_GetKeyList(const SR_RecognizerResult* self,
125																							const size_t nbest, LCHAR** list, size_t* listSize)
126{
127  SR_RecognizerResultImpl* impl = (SR_RecognizerResultImpl*) self;
128  ArrayList* results;
129  SR_SemanticResult* result;
130  ESR_ReturnCode rc;
131
132  /* Choose nbest-list entry */
133  CHKLOG(rc, impl->results->get(impl->results, nbest, (void **)&results));
134
135  /*
136   * Currently we only support one semantic result per nbestlist entry,
137   * so we grab the first available one.
138   */
139  CHKLOG(rc, results->get(results, 0, (void **)&result));
140  CHKLOG(rc, result->getKeyList(result, list, listSize));
141
142  return ESR_SUCCESS;
143CLEANUP:
144  return rc;
145}
146
147ESR_ReturnCode SR_RecognizerResult_GetValue(const SR_RecognizerResult* self, const size_t nbest,
148																						const LCHAR* key, LCHAR* value, size_t* len)
149{
150  SR_RecognizerResultImpl* impl = (SR_RecognizerResultImpl*) self;
151  ArrayList* results;
152  SR_SemanticResult* result;
153  SR_SemanticResultImpl* resultImpl;
154  LCHAR* lValue;
155  size_t actualLen = 0, i, resultCount;
156  ESR_ReturnCode rc;
157  ESR_BOOL noMatch = ESR_TRUE;
158
159  /* Choose nbest-list entry */
160  CHKLOG(rc, impl->results->get(impl->results, nbest, (void **)&results));
161  /* Get the number of semantic results for the entry */
162  CHKLOG(rc, results->getSize(results, &resultCount));
163
164  for (i = 0; i < resultCount; ++i)
165  {
166    /* Choose semantic result */
167    CHKLOG(rc, results->get(results, i, (void **)&result));
168    resultImpl = (SR_SemanticResultImpl*) result;
169    rc = resultImpl->results->get(resultImpl->results, key, (void**) & lValue);
170    if (rc == ESR_SUCCESS)
171    {
172      noMatch = ESR_FALSE;
173      actualLen += LSTRLEN(lValue);
174    }
175    else if (rc != ESR_NO_MATCH_ERROR)
176      return rc;
177  }
178  if (noMatch)
179    return ESR_NO_MATCH_ERROR;
180  ++actualLen;
181
182  /* Check for overflow */
183  if (actualLen + 1 > *len)
184  {
185/* Unfortunately some people are using get value functions to get the size of the value by
186 * passing a zero length buffer which causes errors to be logged. I am adding code so
187 * that the error is not logged when the length is zero, thus preventing lots of logs from
188 * flooding the system.  SteveR
189 */
190    if ( ( *len ) != 0 )
191      PLogError(L("Buffer Overflow while fetching value for %s of choice %d Len %d"),
192		key, nbest, *len );
193    *len = actualLen + 1;
194    return ESR_BUFFER_OVERFLOW;
195  }
196  *len = actualLen;
197
198  LSTRCPY(value, L(""));
199  for (i = 0; i < resultCount; ++i)
200  {
201    /* Choose semantic result */
202    CHKLOG(rc, results->get(results, i, (void **)&result));
203    resultImpl = (SR_SemanticResultImpl*) result;
204    rc = resultImpl->results->get(resultImpl->results, key, (void **) & lValue);
205    if (rc == ESR_SUCCESS)
206      LSTRCAT(value, lValue);
207    else if (rc != ESR_NO_MATCH_ERROR)
208      return rc;
209
210    /* Separate semantic results with '#' token */
211	if (i < resultCount - 1) {
212		int len = LSTRLEN(value);
213		value[len] = MULTIPLE_MEANING_JOIN_CHAR;
214        value[len+1] = 0;
215	}
216  }
217  return ESR_SUCCESS;
218CLEANUP:
219  return rc;
220}
221
222ESR_ReturnCode SR_RecognizerResult_Destroy(SR_RecognizerResult* self)
223{
224  SR_RecognizerResultImpl* impl = (SR_RecognizerResultImpl*) self;
225  ArrayList* semanticList;
226  SR_SemanticResult* semanticResult;
227  size_t nbest, i, j, num_semanticResults;
228  ESR_ReturnCode rc;
229
230  /* each nbest list entry has an ArrayList of Semantic Results... need to destroy them too */
231  if (impl->results != NULL)
232  {
233    CHKLOG(rc, impl->results->getSize(impl->results, &nbest));
234    for (i = 0; i < nbest; ++i)
235    {
236      CHKLOG(rc, impl->results->get(impl->results, 0, (void **)&semanticList));
237      if (semanticList == NULL)
238        continue;
239
240      CHKLOG(rc, semanticList->getSize(semanticList, &num_semanticResults));
241      for (j = 0; j < num_semanticResults; ++j)
242      {
243        LCHAR literal[256];
244        size_t len;
245
246        CHKLOG(rc, semanticList->get(semanticList, 0, (void **)&semanticResult));
247        CHKLOG(rc, semanticList->remove(semanticList, semanticResult));
248        len = sizeof(literal) / sizeof(LCHAR);
249        CHKLOG(rc, semanticResult->getValue(semanticResult, "literal", (LCHAR*) &literal, &len));
250        CHKLOG(rc, semanticResult->destroy(semanticResult));
251      }
252      CHKLOG(rc, impl->results->remove(impl->results, semanticList));
253      CHKLOG(rc, semanticList->destroy(semanticList));
254    }
255    CHKLOG(rc, impl->results->destroy(impl->results));
256    impl->results = NULL;
257  }
258
259  if (impl->nbestList != NULL)
260  {
261    CA_DeleteNBestList(impl->nbestList);
262    impl->nbestList = NULL;
263  }
264  FREE(impl);
265  return ESR_SUCCESS;
266CLEANUP:
267  passert(rc != ESR_BUFFER_OVERFLOW);
268  return rc;
269}
270
271ESR_ReturnCode SR_RecognizerResult_GetLocale(const SR_RecognizerResult* self, ESR_Locale* locale)
272{
273  SR_RecognizerResultImpl* impl = (SR_RecognizerResultImpl*) self;
274  *locale = impl->locale;
275  return ESR_SUCCESS;
276}
277