| 1 | /****************************************************************************** |
|---|
| 2 | * (c)2008-2009 Broadcom Corporation |
|---|
| 3 | * |
|---|
| 4 | * This program is the proprietary software of Broadcom Corporation and/or its licensors, |
|---|
| 5 | * and may only be used, duplicated, modified or distributed pursuant to the terms and |
|---|
| 6 | * conditions of a separate, written license agreement executed between you and Broadcom |
|---|
| 7 | * (an "Authorized License"). Except as set forth in an Authorized License, Broadcom grants |
|---|
| 8 | * no license (express or implied), right to use, or waiver of any kind with respect to the |
|---|
| 9 | * Software, and Broadcom expressly reserves all rights in and to the Software and all |
|---|
| 10 | * intellectual property rights therein. IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU |
|---|
| 11 | * HAVE NO RIGHT TO USE THIS SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY |
|---|
| 12 | * NOTIFY BROADCOM AND DISCONTINUE ALL USE OF THE SOFTWARE. |
|---|
| 13 | * |
|---|
| 14 | * Except as expressly set forth in the Authorized License, |
|---|
| 15 | * |
|---|
| 16 | * 1. This program, including its structure, sequence and organization, constitutes the valuable trade |
|---|
| 17 | * secrets of Broadcom, and you shall use all reasonable efforts to protect the confidentiality thereof, |
|---|
| 18 | * and to use this information only in connection with your use of Broadcom integrated circuit products. |
|---|
| 19 | * |
|---|
| 20 | * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS" |
|---|
| 21 | * AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES, REPRESENTATIONS OR |
|---|
| 22 | * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO |
|---|
| 23 | * THE SOFTWARE. BROADCOM SPECIFICALLY DISCLAIMS ANY AND ALL IMPLIED WARRANTIES |
|---|
| 24 | * OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, |
|---|
| 25 | * LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION |
|---|
| 26 | * OR CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT OF |
|---|
| 27 | * USE OR PERFORMANCE OF THE SOFTWARE. |
|---|
| 28 | * |
|---|
| 29 | * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR ITS |
|---|
| 30 | * LICENSORS BE LIABLE FOR (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR |
|---|
| 31 | * EXEMPLARY DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO YOUR |
|---|
| 32 | * USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM HAS BEEN ADVISED OF |
|---|
| 33 | * THE POSSIBILITY OF SUCH DAMAGES; OR (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT |
|---|
| 34 | * ACTUALLY PAID FOR THE SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE |
|---|
| 35 | * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF |
|---|
| 36 | * ANY LIMITED REMEDY. |
|---|
| 37 | * |
|---|
| 38 | * $brcm_Workfile: bsettop_audio_capture.c $ |
|---|
| 39 | * $brcm_Revision: 2 $ |
|---|
| 40 | * $brcm_Date: 10/22/09 10:50a $ |
|---|
| 41 | * |
|---|
| 42 | * Module Description: Audio capture can capture PCM sample of the decoded audio in |
|---|
| 43 | * raw PCM format. To enable Audio capture export enviornment variable audio_capture=y. |
|---|
| 44 | * To enable capture in .wav format in addition audio capture=y define audio_capture_wav=y |
|---|
| 45 | * |
|---|
| 46 | * Revision History: |
|---|
| 47 | * |
|---|
| 48 | * $brcm_Log: /BSEAV/api/src/nexus/bsettop_audio_capture.c $ |
|---|
| 49 | * |
|---|
| 50 | * 2 10/22/09 10:50a jrubio |
|---|
| 51 | * SW7340-54: Add PEP for 7340/7342 |
|---|
| 52 | * |
|---|
| 53 | * 1 8/25/09 11:24a katrep |
|---|
| 54 | * SW7405-2934:add suppoort for audio capture to a file |
|---|
| 55 | * |
|---|
| 56 | * |
|---|
| 57 | *****************************************************************************/ |
|---|
| 58 | #include <stdio.h> |
|---|
| 59 | #include <string.h> |
|---|
| 60 | #include <stdlib.h> /* atoi */ |
|---|
| 61 | #include "bsettop_impl.h" |
|---|
| 62 | #include "nexus_core_utils.h" |
|---|
| 63 | |
|---|
| 64 | |
|---|
| 65 | BDBG_MODULE(audio_capture); |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | #if BCHP_CHIP==7405 || BCHP_CHIP == 7335 || BCHP_CHIP==7325 || BCHP_CHIP== 7340 || BCHP_CHIP == 7342 |
|---|
| 69 | |
|---|
| 70 | #define CAPTURE_FILE_NAME "audio_capture.dat" |
|---|
| 71 | #define CAPTURE_FILE_NAME_WAV "audio_capture.wav" |
|---|
| 72 | |
|---|
| 73 | static FILE *g_pFile; |
|---|
| 74 | |
|---|
| 75 | static void capture_callback(void *pParam, int param) |
|---|
| 76 | { |
|---|
| 77 | NEXUS_AudioCaptureHandle capture = pParam; |
|---|
| 78 | FILE *pFile = (FILE *)param; |
|---|
| 79 | NEXUS_Error errCode; |
|---|
| 80 | |
|---|
| 81 | for ( ;; ) |
|---|
| 82 | { |
|---|
| 83 | void *pBuffer; |
|---|
| 84 | size_t bufferSize; |
|---|
| 85 | |
|---|
| 86 | /* Check available buffer space */ |
|---|
| 87 | errCode = NEXUS_AudioCapture_GetBuffer(capture, (void **)&pBuffer, &bufferSize); |
|---|
| 88 | if ( errCode ) |
|---|
| 89 | { |
|---|
| 90 | BDBG_ERR(("Error getting capture buffer\n")); |
|---|
| 91 | NEXUS_AudioCapture_Stop(capture); |
|---|
| 92 | return; |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | if ( bufferSize > 0 ) |
|---|
| 96 | { |
|---|
| 97 | /* Write samples to disk */ |
|---|
| 98 | if ( 1 != fwrite(pBuffer, bufferSize, 1, pFile) ) |
|---|
| 99 | { |
|---|
| 100 | BDBG_ERR(("Error writing to disk\n")); |
|---|
| 101 | NEXUS_AudioCapture_Stop(capture); |
|---|
| 102 | return; |
|---|
| 103 | } |
|---|
| 104 | |
|---|
| 105 | /*fprintf(stderr, "Data callback - Wrote %d bytes\n", (int)bufferSize);*/ |
|---|
| 106 | errCode = NEXUS_AudioCapture_WriteComplete(capture, bufferSize); |
|---|
| 107 | if ( errCode ) |
|---|
| 108 | { |
|---|
| 109 | BDBG_ERR(("Error committing capture buffer\n")); |
|---|
| 110 | NEXUS_AudioCapture_Stop(capture); |
|---|
| 111 | return; |
|---|
| 112 | } |
|---|
| 113 | } |
|---|
| 114 | else |
|---|
| 115 | { |
|---|
| 116 | break; |
|---|
| 117 | } |
|---|
| 118 | } |
|---|
| 119 | } |
|---|
| 120 | |
|---|
| 121 | int baudio_capture_open(baudio_decode_t audio) |
|---|
| 122 | { |
|---|
| 123 | BDBG_ASSERT(audio); |
|---|
| 124 | if(bsettop_get_config("audio_capture_wav") ) |
|---|
| 125 | { |
|---|
| 126 | BDBG_WRN(("opening %s",CAPTURE_FILE_NAME_WAV)); |
|---|
| 127 | g_pFile = fopen(CAPTURE_FILE_NAME_WAV,"wb+"); |
|---|
| 128 | } |
|---|
| 129 | else |
|---|
| 130 | { |
|---|
| 131 | BDBG_WRN(("opening %s",CAPTURE_FILE_NAME)); |
|---|
| 132 | g_pFile = fopen(CAPTURE_FILE_NAME, "wb+"); |
|---|
| 133 | } |
|---|
| 134 | if ( NULL == g_pFile) |
|---|
| 135 | { |
|---|
| 136 | BDBG_ERR(("Unable to open file '%s' for writing\n", CAPTURE_FILE_NAME)); |
|---|
| 137 | return -1; |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | audio->nAudioCapture = NEXUS_AudioCapture_Open(0, NULL); |
|---|
| 141 | if ( NULL == audio->nAudioCapture ) |
|---|
| 142 | { |
|---|
| 143 | BDBG_ERR(("Unable to open capture channel\n")); |
|---|
| 144 | return -1; |
|---|
| 145 | } |
|---|
| 146 | return 0; |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | int baudio_capture_close(baudio_decode_t audio) |
|---|
| 150 | { |
|---|
| 151 | BDBG_WRN(("closing audio capture")); |
|---|
| 152 | BDBG_ASSERT(audio); |
|---|
| 153 | fflush(g_pFile); |
|---|
| 154 | fclose(g_pFile); |
|---|
| 155 | /*NEXUS_AudioOutput_RemoveAllInputs(NEXUS_AudioCapture_GetConnector(audio->nAudioCapture));*/ |
|---|
| 156 | NEXUS_AudioOutput_Shutdown(NEXUS_AudioCapture_GetConnector(audio->nAudioCapture)); |
|---|
| 157 | NEXUS_AudioCapture_Close(audio->nAudioCapture); |
|---|
| 158 | audio->nAudioCapture = NULL; |
|---|
| 159 | return 0; |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | |
|---|
| 163 | int baudio_capture_start(baudio_decode_t audio) |
|---|
| 164 | { |
|---|
| 165 | NEXUS_AudioCaptureStartSettings captureSettings; |
|---|
| 166 | |
|---|
| 167 | BDBG_WRN(("Start audio capture")); |
|---|
| 168 | |
|---|
| 169 | /* Setup WAV file if desired (*always little-endian) */ |
|---|
| 170 | if ( bsettop_get_config("audio_capture_wav") ) |
|---|
| 171 | { |
|---|
| 172 | fwrite("RIFF", 4, 1, g_pFile); /* Byte 0..3 RIFF */ |
|---|
| 173 | fputc(0, g_pFile); /* Byte 4..7 file size - 4*/ |
|---|
| 174 | fputc(0, g_pFile); |
|---|
| 175 | fputc(0, g_pFile); |
|---|
| 176 | fputc(0, g_pFile); |
|---|
| 177 | fwrite("WAVE", 4, 1, g_pFile); /* Byte 8..11 WAVE */ |
|---|
| 178 | fwrite("fmt ", 4, 1, g_pFile); /* Byte 12..15 fmt */ |
|---|
| 179 | fputc(16, g_pFile); /* Byte 16..19 format chunk length (16 bytes) */ |
|---|
| 180 | fputc(0, g_pFile); |
|---|
| 181 | fputc(0, g_pFile); |
|---|
| 182 | fputc(0, g_pFile); |
|---|
| 183 | fputc(1, g_pFile); /* Byte 20..21 compression code (1=PCM) */ |
|---|
| 184 | fputc(0, g_pFile); |
|---|
| 185 | fputc(2, g_pFile); /* Byte 22..23 Number of channels (2) */ |
|---|
| 186 | fputc(0, g_pFile); |
|---|
| 187 | fputc(0, g_pFile); /* Byte 24..27 Sample Rate (actual value later from decoder) */ |
|---|
| 188 | fputc(0, g_pFile); |
|---|
| 189 | fputc(0, g_pFile); |
|---|
| 190 | fputc(0, g_pFile); |
|---|
| 191 | fputc(0, g_pFile); /* Byte 28..31 Average Bytes/Second (actual value later from decder) */ |
|---|
| 192 | fputc(0, g_pFile); |
|---|
| 193 | fputc(0, g_pFile); |
|---|
| 194 | fputc(0, g_pFile); |
|---|
| 195 | fputc(2, g_pFile); /* Byte 32..33 Block Align (4 -- 2 bytes/channel * 2 channels) */ |
|---|
| 196 | fputc(0, g_pFile); |
|---|
| 197 | fputc(16, g_pFile); /* Byte 34..35 Bits Per Sample (16) */ |
|---|
| 198 | fputc(0, g_pFile); |
|---|
| 199 | fwrite("data", 4, 1, g_pFile); /* Byte 36..39 data */ |
|---|
| 200 | fputc(0, g_pFile); /* Byte 40..43 data size - 4*/ |
|---|
| 201 | fputc(0, g_pFile); |
|---|
| 202 | fputc(0, g_pFile); |
|---|
| 203 | fputc(0, g_pFile); |
|---|
| 204 | } |
|---|
| 205 | /* Connect capture to decoder */ |
|---|
| 206 | NEXUS_AudioOutput_AddInput(NEXUS_AudioCapture_GetConnector(audio->nAudioCapture), |
|---|
| 207 | NEXUS_AudioDecoder_GetConnector(audio->nAudioDecoder, NEXUS_AudioDecoderConnectorType_eStereo)); |
|---|
| 208 | /* Start the capture -- no data will be received until the decoder starts */ |
|---|
| 209 | NEXUS_AudioCapture_GetDefaultStartSettings(&captureSettings); |
|---|
| 210 | captureSettings.dataCallback.callback = capture_callback; |
|---|
| 211 | captureSettings.dataCallback.context = audio->nAudioCapture; |
|---|
| 212 | captureSettings.dataCallback.param = (int)g_pFile; |
|---|
| 213 | NEXUS_AudioCapture_Start(audio->nAudioCapture, &captureSettings); |
|---|
| 214 | return 0; |
|---|
| 215 | } |
|---|
| 216 | |
|---|
| 217 | int baudio_capture_stop(baudio_decode_t audio) |
|---|
| 218 | { |
|---|
| 219 | BDBG_WRN(("Stop audio capture")); |
|---|
| 220 | NEXUS_StopCallbacks(audio->nAudioCapture); |
|---|
| 221 | /* After StopCallbacks, we are guaranteed no more callbacks will arrive. If we're writing raw data, we're done. |
|---|
| 222 | If we're writing a .wav file, seek back to the beginning and finish up the header */ |
|---|
| 223 | if ( bsettop_get_config("audio_capture_wav") ) |
|---|
| 224 | { |
|---|
| 225 | unsigned long fileLength; |
|---|
| 226 | NEXUS_AudioDecoderStatus decoderStatus; |
|---|
| 227 | |
|---|
| 228 | fileLength = ftell(g_pFile); |
|---|
| 229 | |
|---|
| 230 | BDBG_WRN(("%lu bytes written to file\n", fileLength)); |
|---|
| 231 | if ( fileLength == 44 ) |
|---|
| 232 | { |
|---|
| 233 | BDBG_WRN(("Warning, empty file detected. Double-check data source\n")); |
|---|
| 234 | } |
|---|
| 235 | |
|---|
| 236 | NEXUS_AudioDecoder_GetStatus(audio->nAudioDecoder, &decoderStatus); |
|---|
| 237 | |
|---|
| 238 | fseek(g_pFile, 4, SEEK_SET); /* Need to write file size - 4 to this offset */ |
|---|
| 239 | fileLength -= 4; |
|---|
| 240 | fputc(fileLength & 0xff, g_pFile); |
|---|
| 241 | fputc((fileLength >> 8) & 0xff, g_pFile); |
|---|
| 242 | fputc((fileLength >> 16) & 0xff, g_pFile); |
|---|
| 243 | fputc((fileLength >> 24) & 0xff, g_pFile); |
|---|
| 244 | fseek(g_pFile, 24, SEEK_SET); /* Need to write sample rate here */ |
|---|
| 245 | fputc(decoderStatus.sampleRate & 0xff, g_pFile); |
|---|
| 246 | fputc((decoderStatus.sampleRate>>8) & 0xff, g_pFile); |
|---|
| 247 | fputc((decoderStatus.sampleRate>>16) & 0xff, g_pFile); |
|---|
| 248 | fputc((decoderStatus.sampleRate>>24) & 0xff, g_pFile); |
|---|
| 249 | /* Need to write sampleRate * 4 here */ |
|---|
| 250 | decoderStatus.sampleRate *= 4; |
|---|
| 251 | fputc(decoderStatus.sampleRate & 0xff, g_pFile); |
|---|
| 252 | fputc((decoderStatus.sampleRate>>8) & 0xff, g_pFile); |
|---|
| 253 | fputc((decoderStatus.sampleRate>>16) & 0xff, g_pFile); |
|---|
| 254 | fputc((decoderStatus.sampleRate>>24) & 0xff, g_pFile); |
|---|
| 255 | fseek(g_pFile, 40, SEEK_SET); /* Need to write data size (file size - 44) to this offset */ |
|---|
| 256 | fileLength -= 40; |
|---|
| 257 | fputc(fileLength & 0xff, g_pFile); |
|---|
| 258 | fputc((fileLength >> 8) & 0xff, g_pFile); |
|---|
| 259 | fputc((fileLength >> 16) & 0xff, g_pFile); |
|---|
| 260 | fputc((fileLength >> 24) & 0xff, g_pFile); |
|---|
| 261 | } |
|---|
| 262 | NEXUS_AudioCapture_Stop(audio->nAudioCapture); |
|---|
| 263 | NEXUS_AudioOutput_RemoveInput(NEXUS_AudioCapture_GetConnector(audio->nAudioCapture), |
|---|
| 264 | NEXUS_AudioDecoder_GetConnector(audio->nAudioDecoder, NEXUS_AudioDecoderConnectorType_eStereo)); |
|---|
| 265 | return 0; |
|---|
| 266 | } |
|---|
| 267 | |
|---|
| 268 | #else |
|---|
| 269 | int baudio_capture_open(baudio_decode_t audio) |
|---|
| 270 | { |
|---|
| 271 | BSTD_UNUSED(audio); |
|---|
| 272 | return 0; |
|---|
| 273 | } |
|---|
| 274 | int baudio_capture_close(baudio_decode_t audio) |
|---|
| 275 | { |
|---|
| 276 | BSTD_UNUSED(audio); |
|---|
| 277 | return 0; |
|---|
| 278 | } |
|---|
| 279 | int baudio_capture_start(baudio_decode_t audio) |
|---|
| 280 | { |
|---|
| 281 | BSTD_UNUSED(audio); |
|---|
| 282 | return 0; |
|---|
| 283 | } |
|---|
| 284 | int baudio_capture_stop(baudio_decode_t audio) |
|---|
| 285 | { |
|---|
| 286 | BSTD_UNUSED(audio); |
|---|
| 287 | return 0; |
|---|
| 288 | } |
|---|
| 289 | #endif |
|---|
| 290 | |
|---|
| 291 | |
|---|