source: svn/newcon3bcm2_21bu/BSEAV/api/src/nexus/bsettop_pcm_playback.c

Last change on this file was 76, checked in by megakiss, 10 years ago

1W 대기전력을 만족시키기 위하여 POWEROFF시 튜너를 Standby 상태로 함

  • Property svn:executable set to *
File size: 12.0 KB
Line 
1/***************************************************************************
2 * Copyright (c) 2003-2009, Broadcom Corporation
3 * All Rights Reserved
4 * Confidential Property of Broadcom Corporation
5 *
6 *  THIS SOFTWARE MAY ONLY BE USED SUBJECT TO AN EXECUTED SOFTWARE LICENSE
7 *  AGREEMENT  BETWEEN THE USER AND BROADCOM.  YOU HAVE NO RIGHT TO USE OR
8 *  EXPLOIT THIS MATERIAL EXCEPT SUBJECT TO THE TERMS OF SUCH AN AGREEMENT.
9 *
10 * $brcm_Workfile: bsettop_pcm_playback.c $
11 * $brcm_Revision: 8 $
12 * $brcm_Date: 12/3/09 4:06p $
13 *
14 * Module Description:
15 *
16 * Revision History:
17 *
18 * $brcm_Log: /BSEAV/api/src/nexus/bsettop_pcm_playback.c $
19 *
20 * 8   12/3/09 4:06p jgarrett
21 * SW7405-3452: Setting default playback start threshold to 0
22 *
23 * 7   11/19/09 8:02p jgarrett
24 * SW7405-3357: Adding audio output routing for decode and pcm playback
25 * prior to start
26 *
27 * 6   4/3/08 7:26p jgarrett
28 * PR 40017: Fixing race between decode and pcm
29 *
30 * 5   4/3/08 5:41p jgarrett
31 * PR 41312: Setting callback events
32 *
33 * 4   3/12/08 3:17p jgarrett
34 * PR 40017: Adding PCM support
35 *
36 * 3   12/20/07 10:28a erickson
37 * PR37590: fix warnings
38 *
39 * 2   10/16/07 12:35p erickson
40 * PR36068: brutus up over settop api/nexus
41 *
42 ***************************************************************************/
43#include "bsettop_impl.h"
44#include "nexus_audio_playback.h"
45#include "nexus_audio_input.h"
46#include "nexus_audio_output.h"
47
48/* This is hardcoded in bconfig right now */
49#define B_N_PCM_PLAYS 2
50
51BDBG_OBJECT_ID(bpcm_play);
52
53BDBG_MODULE(pcm);
54
55static bpcm_play g_pcmplays[B_N_PCM_PLAYS];
56static void bpcm_play_p_callback(void *pParam1, int param2);
57static void bpcm_play_p_callback_handler(void *context);
58
59void bpcm_play_settings_init(bpcm_play_settings *settings, bpcm_play_t pcmplay)
60{
61    BDBG_ASSERT(NULL != settings);
62    BSTD_UNUSED(pcmplay);
63    BKNI_Memset(settings, 0, sizeof(*settings));
64    settings->pcm.bits_per_sample=16;
65    settings->pcm.channels = 2;
66    settings->pcm.sample_rate = 44100;  /* This was the settop API default, brutus relies on that */
67}
68
69bpcm_play_t bpcm_play_open(bobject_t id)
70{
71    bpcm_play_t pcmplay;
72    unsigned index = B_ID_GET_INDEX(id);
73
74    if ( index >= B_N_PCM_PLAYS )
75    {
76        BSETTOP_ERROR(berr_invalid_parameter);
77        return NULL;
78    }
79
80    pcmplay = &g_pcmplays[index];
81    BDBG_MSG(("Opening PCM play %d (first=%d)", index));
82
83    if ( pcmplay->opened )
84    {
85        BDBG_ERR(("PCM Playback %d (%p) already open (opened=%d)", index, pcmplay, pcmplay->opened));
86        return NULL;
87    }
88
89    BDBG_OBJECT_SET(pcmplay, bpcm_play);
90
91    pcmplay->nPlayback = NEXUS_AudioPlayback_Open(index, NULL);
92    if ( NULL == pcmplay->nPlayback )
93    {
94        BDBG_ERR(("Unable to open nexus audio playback channel"));
95        BDBG_OBJECT_UNSET(pcmplay, bpcm_play);
96        return NULL;
97    }
98    pcmplay->event = B_Event_Create(NULL);
99    if ( NULL == pcmplay->event )
100    {
101        BSETTOP_ERROR(berr_external_error);
102        NEXUS_AudioPlayback_Close(pcmplay->nPlayback);
103        BDBG_OBJECT_UNSET(pcmplay, bpcm_play);
104        return NULL;
105    }
106    pcmplay->eventId = b_event_register(pcmplay->event, bpcm_play_p_callback_handler, pcmplay);
107    if ( NULL == pcmplay->eventId )
108    {
109        BSETTOP_ERROR(berr_external_error);
110        B_Event_Destroy(pcmplay->event);
111        NEXUS_AudioPlayback_Close(pcmplay->nPlayback);
112        BDBG_OBJECT_UNSET(pcmplay, bpcm_play);
113        return NULL;
114    }
115    pcmplay->display = NULL;
116    pcmplay->opened = true;
117    pcmplay->disabled = false;
118
119    return pcmplay;
120}
121
122void bpcm_play_close(bpcm_play_t pcmplay)
123{
124    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
125    BDBG_ASSERT(pcmplay->opened);
126
127    b_event_unregister(pcmplay->eventId);
128    B_Event_Destroy(pcmplay->event);
129
130    if ( pcmplay->display )
131    {
132        BDBG_WRN(("Forcing stop on pcm playback channel %p", pcmplay));
133        bpcm_play_stop(pcmplay);
134    }
135
136    NEXUS_AudioPlayback_Close(pcmplay->nPlayback);
137    pcmplay->opened = false;
138    BDBG_OBJECT_UNSET(pcmplay, bpcm_play);
139}
140
141bresult bpcm_play_start(bpcm_play_t pcmplay, bdisplay_t display, const bpcm_play_settings *settings)
142{
143    NEXUS_Error errCode;
144
145    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
146    BDBG_ASSERT(pcmplay->opened);
147    BDBG_ASSERT(NULL != display);
148    BDBG_ASSERT(NULL != settings);
149
150    BDBG_ASSERT(false == pcmplay->disabled);
151
152    BDBG_MSG(("play start"));
153
154    if ( pcmplay->output_settings.display )
155    {
156        if ( display != pcmplay->output_settings.display )
157        {
158            BDBG_ERR(("PCM Playback %p is bound to display %p.  Cannot start on display %p", pcmplay, pcmplay->output_settings.display, display));
159            return BSETTOP_ERROR(berr_invalid_parameter);
160        }
161    }
162
163    if ( pcmplay->display )
164    {
165        BDBG_WRN(("Stopping existing playback"));
166        bpcm_play_stop(pcmplay);
167    }
168
169    NEXUS_AudioPlayback_GetDefaultStartSettings(&pcmplay->nSettings);
170    pcmplay->nSettings.bitsPerSample = settings->pcm.bits_per_sample;
171    pcmplay->nSettings.sampleRate = settings->pcm.sample_rate;
172    pcmplay->nSettings.signedData = true;
173    pcmplay->nSettings.stereo = (settings->pcm.channels == 1)?false:true;
174    pcmplay->nSettings.startThreshold = 0;  /* Start immediately, don't wait for data */
175    pcmplay->callback = settings->callback;
176    pcmplay->context = settings->callback_context;
177    if ( pcmplay->callback )
178    {
179        pcmplay->nSettings.dataCallback.callback = bpcm_play_p_callback;
180        pcmplay->nSettings.dataCallback.context = pcmplay;
181    }
182
183    if ( NULL == pcmplay->output_settings.display )
184    {
185        /* Hook up to mixer */
186        bdisplay_p_enable_audio(display, false);
187        errCode = NEXUS_AudioMixer_AddInput(display->nAudioMixer,
188                                            NEXUS_AudioPlayback_GetConnector(pcmplay->nPlayback));
189        bdisplay_p_enable_audio(display, true);
190        if ( errCode )
191        {
192            return BSETTOP_ERROR(berr_external_error);
193        }
194    }
195
196    /* Start Playback */
197    BDBG_MSG(("Starting Nexus Playback"));
198    errCode = NEXUS_AudioPlayback_Start(pcmplay->nPlayback, &pcmplay->nSettings);
199    if ( errCode )
200    {
201        bdisplay_p_enable_audio(display, false);
202        NEXUS_AudioMixer_RemoveInput(display->nAudioMixer,
203                                     NEXUS_AudioPlayback_GetConnector(pcmplay->nPlayback));
204        bdisplay_p_enable_audio(display, true);
205        return BSETTOP_ERROR(berr_external_error);
206    }
207    display->mixerInputsStarted++;
208
209    /* Bind to display */
210    pcmplay->display = display;
211
212    /* Success */
213    BDBG_MSG(("Playback Started"));
214    return b_ok;
215}
216
217bresult bpcm_play_get_status(bpcm_play_t pcmplay, bpcm_play_status *status)
218{
219    NEXUS_AudioPlaybackStatus nStatus;
220
221    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
222    BDBG_ASSERT(pcmplay->opened);
223
224    BKNI_Memset(status, 0, sizeof(*status));
225    NEXUS_AudioPlayback_GetStatus(pcmplay->nPlayback, &nStatus);
226    status->started = (NULL == pcmplay->display)?false:true;
227    status->fifo_size = nStatus.fifoSize;
228    if ( status->started )
229    {
230        status->queued_bytes = nStatus.queuedBytes;
231        status->buffer_base = NULL;                     /* N/A */
232    }
233
234    return b_ok;
235}
236
237bresult bpcm_play_get_buffer(bpcm_play_t pcmplay, void **data, size_t *length)
238{
239    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
240    BDBG_ASSERT(pcmplay->opened);
241    BDBG_ASSERT(NULL != data);
242    BDBG_ASSERT(NULL != length);
243
244    /*BDBG_MSG(("Get Buffer"));*/
245
246    if ( NULL == pcmplay->display )
247    {
248        BDBG_WRN(("PCM Playback %p not started", pcmplay));
249        return BSETTOP_ERROR(berr_invalid_parameter);
250    }
251
252    if ( NEXUS_AudioPlayback_GetBuffer(pcmplay->nPlayback, data, length) )
253    {
254        return BSETTOP_ERROR(berr_external_error);
255    }
256
257    return b_ok;
258}
259
260bresult bpcm_play_write_complete(bpcm_play_t pcmplay, size_t amount_written)
261{
262    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
263    BDBG_ASSERT(pcmplay->opened);
264
265    /*BDBG_MSG(("Write Complete"));*/
266
267    if ( NULL == pcmplay->display )
268    {
269        BDBG_WRN(("PCM Playback %p not started", pcmplay));
270        return BSETTOP_ERROR(berr_invalid_parameter);
271    }
272
273    if ( NEXUS_AudioPlayback_ReadComplete(pcmplay->nPlayback, amount_written) )
274    {
275        return BSETTOP_ERROR(berr_external_error);
276    }
277
278    return b_ok;
279}
280
281bresult bpcm_play_stop(bpcm_play_t pcmplay)
282{
283    bdisplay_t display;
284    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
285    BDBG_ASSERT(pcmplay->opened);
286
287    BDBG_ASSERT(false == pcmplay->disabled);
288
289    BDBG_MSG(("play stop"));
290
291    display = pcmplay->display;
292    if ( NULL == display )
293    {
294        BDBG_MSG(("Stopping an un-started playback"));
295        return b_ok;
296    }
297
298    pcmplay->display = NULL;    /* Must do this before disabling audio */
299    NEXUS_AudioPlayback_Stop(pcmplay->nPlayback);
300    display->mixerInputsStarted--;
301    if ( NULL == pcmplay->output_settings.display )
302    {
303        bdisplay_p_enable_audio(display, false);
304        NEXUS_AudioMixer_RemoveInput(display->nAudioMixer,
305                                     NEXUS_AudioPlayback_GetConnector(pcmplay->nPlayback));
306        bdisplay_p_enable_audio(display, true);
307    }
308
309    return b_ok;
310}
311
312void bpcm_play_p_enable(bdisplay_t display, bool enabled)
313{
314    int i;
315
316    B_LOCK_ASSERT();
317    BDBG_MSG(("%sabling pcm", enabled?"en":"dis"));
318
319    for ( i = 0; i < B_N_PCM_PLAYS; i++ )
320    {
321        bpcm_play_t pcmplay = &g_pcmplays[i];
322        BDBG_MSG(("pcmplay %p open %d display %p check %p", pcmplay, pcmplay->opened, pcmplay->display, display));
323        if ( pcmplay->opened && pcmplay->display == display )
324        {
325            if ( enabled )
326            {
327                pcmplay->disabled = false;
328                NEXUS_AudioPlayback_Start(pcmplay->nPlayback, &pcmplay->nSettings);
329                B_Event_Set(pcmplay->event);
330            }
331            else
332            {
333                pcmplay->disabled = true;
334                BDBG_MSG(("Forcing stop of PCM playback channel %p", pcmplay));
335                NEXUS_AudioPlayback_Stop(pcmplay->nPlayback);
336            }
337        }
338    }
339}
340
341static void bpcm_play_p_callback(void *pParam1, int param2)
342{
343    bpcm_play_t pcmplay = pParam1;
344    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
345    BSTD_UNUSED(param2);
346    B_Event_Set(pcmplay->event);
347}
348
349static void bpcm_play_p_callback_handler(void *context)
350{
351    bpcm_play_t pcmplay = context;
352    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
353
354    if ( pcmplay->callback )
355    {
356        b_unlock();
357        pcmplay->callback(pcmplay->context);
358        b_lock();
359    }
360}
361
362void bpcm_play_get_output_settings(
363    bpcm_play_t pcmplay,
364    bpcm_play_output_settings *settings /* [out] */
365    )
366{
367    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
368    BDBG_ASSERT(NULL != settings);
369    *settings = pcmplay->output_settings;
370}
371
372bresult bpcm_play_set_output_settings(
373    bpcm_play_t pcmplay,
374    const bpcm_play_output_settings *settings
375    )
376{
377    BDBG_OBJECT_ASSERT(pcmplay, bpcm_play);
378    BDBG_ASSERT(NULL != settings);
379    /* See if we're running */
380    if ( pcmplay->display )
381    {
382        return BSETTOP_ERROR(berr_busy);
383    }
384    /* If we're already attached to a display, make sure nothing else is using it. */
385    if ( pcmplay->output_settings.display )
386    {
387        if ( pcmplay->output_settings.display->mixerInputsStarted > 0 )
388        {
389            return BSETTOP_ERROR(berr_busy);
390        }
391        /* Remove ourself from the current display */
392        if ( NEXUS_AudioMixer_RemoveInput(pcmplay->output_settings.display->nAudioMixer, 
393                                          NEXUS_AudioPlayback_GetConnector(pcmplay->nPlayback)) )
394        {
395            return BSETTOP_ERROR(berr_external_error);
396        }
397        pcmplay->output_settings.display = NULL;
398    }
399    if ( settings->display )
400    {
401        if ( settings->display->mixerInputsStarted > 0 )
402        {
403            return BSETTOP_ERROR(berr_busy);
404        }
405        /* Add to the new display */
406        if ( NEXUS_AudioMixer_AddInput(settings->display->nAudioMixer,
407                                       NEXUS_AudioPlayback_GetConnector(pcmplay->nPlayback)) )
408        {
409            return BSETTOP_ERROR(berr_external_error);
410        }
411    }
412    /* Successful, save settings */
413    pcmplay->output_settings = *settings;
414    return b_ok;
415}
416
Note: See TracBrowser for help on using the repository browser.