audio_hal.c revision 6b1c0fef801c9435ed3446d53cc45d1b1f6fd07e
119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson/*
219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * Copyright (C) 2012 The Android Open Source Project
319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *
419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * Licensed under the Apache License, Version 2.0 (the "License");
519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * you may not use this file except in compliance with the License.
619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * You may obtain a copy of the License at
719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *
819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *      http://www.apache.org/licenses/LICENSE-2.0
919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson *
1019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * Unless required by applicable law or agreed to in writing, software
1119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * distributed under the License is distributed on an "AS IS" BASIS,
1219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * See the License for the specific language governing permissions and
1419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson * limitations under the License.
1519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson */
1619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#define LOG_TAG "usb_audio_hw"
18cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean/*#define LOG_NDEBUG 0*/
1919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
2019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <errno.h>
2188e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn#include <inttypes.h>
2219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <pthread.h>
2319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdint.h>
2419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <stdlib.h>
2588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn#include <sys/time.h>
2619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
2788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn#include <log/log.h>
2819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/str_parms.h>
2919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <cutils/properties.h>
3019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
31e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean#include <hardware/audio.h>
32e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean#include <hardware/audio_alsaops.h>
3319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <hardware/hardware.h>
34e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
3519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <system/audio.h>
3619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
3719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson#include <tinyalsa/asoundlib.h>
3819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
39eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* This is the default configuration to hand to The Framework on the initial
40eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * adev_open_output_stream(). Actual device attributes will be used on the subsequent
41eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * adev_open_output_stream() after the card and device number have been set in out_set_parameters()
42eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
43eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_PERIOD_SIZE 1024
44eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_PERIOD_COUNT 4
45eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define OUT_SAMPLING_RATE 44100
46eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
47eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct pcm_config default_alsa_out_config = {
4819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .channels = 2,
49eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .rate = OUT_SAMPLING_RATE,
50eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .period_size = OUT_PERIOD_SIZE,
51eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .period_count = OUT_PERIOD_COUNT,
5219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .format = PCM_FORMAT_S16_LE,
5319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
5419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
55eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
56eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Input defaults.  See comment above.
57eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
58eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_PERIOD_SIZE 1024
59eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_PERIOD_COUNT 4
60eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean#define IN_SAMPLING_RATE 44100
61eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
62eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct pcm_config default_alsa_in_config = {
63eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .channels = 2,
64eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .rate = IN_SAMPLING_RATE,
65eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .period_size = IN_PERIOD_SIZE,
66eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .period_count = IN_PERIOD_COUNT,
67eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .format = PCM_FORMAT_S16_LE,
68eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .start_threshold = 1,
69eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    .stop_threshold = (IN_PERIOD_SIZE * IN_PERIOD_COUNT),
70eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
71eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
7219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_device {
7319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_hw_device hw_device;
7419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
7519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
76eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
77eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* output */
78eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int out_card;
79eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int out_device;
80eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
81eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* input */
82eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int in_card;
83eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int in_device;
84eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
8519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
8619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
8719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
8819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct stream_out {
8919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_stream_out stream;
9019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
91eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_t lock;               /* see note below on mutex acquisition order */
92eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct pcm *pcm;                    /* state of the stream */
93eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool standby;
94eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
95eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *dev;           /* hardware information */
96eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
97eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    void * conversion_buffer;           /* any conversions are put into here
98eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * they could come from here too if
99eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                                         * there was a previous conversion */
100eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    size_t conversion_buffer_size;      /* in bytes */
101eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean};
102eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
103eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
104eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Output Configuration Cache
1056b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * FIXME(pmclean) This is not reentrant. Should probably be moved into the stream structure.
106eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
107eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic struct pcm_config cached_output_hardware_config;
108eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic bool output_hardware_config_is_cached = false;
109eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
110eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstruct stream_in {
111eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_stream_in stream;
112eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
11319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_t lock; /* see note below on mutex acquisition order */
11419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct pcm *pcm;
11519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    bool standby;
11619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
11719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *dev;
118eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
119eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_config hal_pcm_config;
120eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1216b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* this is the format the framework thinks it's using. We may need to convert from the actual
1226b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * (24-bit, 32-bit?) format to this theoretical (framework, probably 16-bit)
1236b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * format in in_read() */
1246b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    enum pcm_format input_framework_format;
1256b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
126eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//    struct resampler_itfe *resampler;
127eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean//    struct resampler_buffer_provider buf_provider;
12830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
129eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int read_status;
13030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
13130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // We may need to read more data from the device in order to data reduce to 16bit, 4chan */
13230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * conversion_buffer;           /* any conversions are put into here
13330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * they could come from here too if
13430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                         * there was a previous conversion */
13530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t conversion_buffer_size;      /* in bytes */
13619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
13719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
138eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
13930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Input Configuration Cache
14030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * FIXME(pmclean) This is not reentrant. Should probably be moved into the stream structure
14130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * but that will involve changes in The Framework.
14230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
14330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic struct pcm_config cached_input_hardware_config;
14430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic bool input_hardware_config_is_cached = false;
14530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
14630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
147eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Utility
148eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
149eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
150eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Data Conversions
151eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
152eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
15330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of packed (3-byte) PCM24LE samples to PCM16LE samples.
15430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM24LE samples
155eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   num_in_samples size of input buffer in SAMPLES
15630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
15730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
15830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
15930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
16030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support PCM24_3LE (24-bit, packed).
16130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE:
16230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
163e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module.
16430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
165e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic size_t convert_24_3_to_16(const unsigned char * in_buff, size_t num_in_samples,
166e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                 short * out_buff)
167e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{
16830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /*
16930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * Move from front to back so that the conversion can be done in-place
17030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * i.e. in_buff == out_buff
17130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     */
17230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* we need 2 bytes in the output for every 3 bytes in the input */
17330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    unsigned char* dst_ptr = (unsigned char*)out_buff;
17488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const unsigned char* src_ptr = in_buff;
17530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    size_t src_smpl_index;
17630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
17730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        src_ptr++;               /* lowest-(skip)-byte */
17830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* low-byte */
17930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        *dst_ptr++ = *src_ptr++; /* high-byte */
18030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
18130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
18230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* return number of *bytes* generated: */
18330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_in_samples * 2;
18430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
18530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
18630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
1876b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Convert a buffer of packed (3-byte) PCM32 samples to PCM16LE samples.
1886b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   in_buff points to the buffer of PCM32 samples
1896b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   num_in_samples size of input buffer in SAMPLES
1906b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   out_buff points to the buffer to receive converted PCM16LE LE samples.
1916b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * returns
1926b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   the number of BYTES of output data.
1936b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * We are doing this since we *always* present to The Framework as A PCM16LE device, but need to
1946b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * support PCM_FORMAT_S32_LE (32-bit).
1956b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * NOTE:
1966b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean *   This conversion is safe to do in-place (in_buff == out_buff).
1976b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * TODO Move this to a utilities module.
1986b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */
1996b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic size_t convert_32_to_16(const int32_t * in_buff, size_t num_in_samples, short * out_buff)
2006b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean{
2016b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /*
2026b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * Move from front to back so that the conversion can be done in-place
2036b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. in_buff == out_buff
2046b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     */
2056b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
2066b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    short * dst_ptr = out_buff;
2076b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    const int32_t* src_ptr = in_buff;
2086b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    size_t src_smpl_index;
2096b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    for (src_smpl_index = 0; src_smpl_index < num_in_samples; src_smpl_index++) {
2106b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        *dst_ptr++ = *src_ptr++ >> 16;
2116b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
2126b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
2136b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* return number of *bytes* generated: */
2146b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    return num_in_samples * 2;
2156b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean}
2166b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
2176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean/*
21830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of N-channel, interleaved PCM16 samples to M-channel PCM16 channels
21930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (where N < M).
22030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM16 samples
22130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff_channels Specifies the number of channels in the input buffer.
222eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean *   out_buff points to the buffer to receive converted PCM16 samples.
22330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff_channels Specifies the number of channels in the output buffer.
22430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   num_in_samples size of input buffer in SAMPLES
22530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
22630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
22730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE
22830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   channels > N are filled with silence.
22930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff)
230eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * We are doing this since we *always* present to The Framework as STEREO device, but need to
231eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * support 4-channel devices.
232e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module.
233eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
23488e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzynstatic size_t expand_channels_16(const short* in_buff, int in_buff_chans,
23530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                 short* out_buff, int out_buff_chans,
236e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                 size_t num_in_samples)
237e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{
238eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
239eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * Move from back to front so that the conversion can be done in-place
240eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * i.e. in_buff == out_buff
24130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans
24230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     */
24330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans;
24430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
24530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    short* dst_ptr = out_buff + num_out_samples - 1;
24688e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t src_index;
24788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const short* src_ptr = in_buff + num_in_samples - 1;
24830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_zero_chans = out_buff_chans - in_buff_chans;
24930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) {
25030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        int dst_offset;
251e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        for (dst_offset = 0; dst_offset < num_zero_chans; dst_offset++) {
25230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            *dst_ptr-- = 0;
25330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
254e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        for (; dst_offset < out_buff_chans; dst_offset++) {
25530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            *dst_ptr-- = *src_ptr--;
25630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
25730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
25830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
25930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /* return number of *bytes* generated */
26030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_out_samples * sizeof(short);
26130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
26230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
26330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/*
26430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * Convert a buffer of N-channel, interleaved PCM16 samples to M-channel PCM16 channels
26530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * (where N > M).
26630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff points to the buffer of PCM16 samples
26730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   in_buff_channels Specifies the number of channels in the input buffer.
26830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff points to the buffer to receive converted PCM16 samples.
26930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   out_buff_channels Specifies the number of channels in the output buffer.
27030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   num_in_samples size of input buffer in SAMPLES
27130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * returns
27230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   the number of BYTES of output data.
27330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * NOTE
27430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   channels > N are thrown away.
27530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean *   This conversion is safe to do in-place (in_buff == out_buff)
27630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * We are doing this since we *always* present to The Framework as STEREO device, but need to
27730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean * support 4-channel devices.
278e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * TODO Move this to a utilities module.
27930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean */
28030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic size_t contract_channels_16(short* in_buff, int in_buff_chans,
28130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                   short* out_buff, int out_buff_chans,
282e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                   size_t num_in_samples)
283e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{
28430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    /*
28530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * Move from front to back so that the conversion can be done in-place
28630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * i.e. in_buff == out_buff
28730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean     * NOTE: num_in_samples * out_buff_channels must be an even multiple of in_buff_chans
288eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
28930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_out_samples = (num_in_samples * out_buff_chans)/in_buff_chans;
29030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
29130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_skip_samples = in_buff_chans - out_buff_chans;
29230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
29330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    short* dst_ptr = out_buff;
29430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    short* src_ptr = in_buff;
29588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t src_index;
29630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    for (src_index = 0; src_index < num_in_samples; src_index += in_buff_chans) {
29730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        int dst_offset;
298e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        for (dst_offset = 0; dst_offset < out_buff_chans; dst_offset++) {
29930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            *dst_ptr++ = *src_ptr++;
30030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
30130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        src_ptr += num_skip_samples;
302eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
303eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
304eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /* return number of *bytes* generated */
30530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_out_samples * sizeof(short);
306eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
307eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
308eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
309eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * ALSA Utilities
310eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
311e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*TODO This table and the function that uses it should be moved to a utilities module (probably) */
312e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*
313e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * Maps bit-positions in a pcm_mask to the corresponding AUDIO_ format string.
314e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean */
315e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic const char * const format_string_map[] = {
316e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    "AUDIO_FORMAT_PCM_8_BIT",           /* 00 - SNDRV_PCM_FORMAT_S8 */
317e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    "AUDIO_FORMAT_PCM_8_BIT",           /* 01 - SNDRV_PCM_FORMAT_U8 */
318e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    "AUDIO_FORMAT_PCM_16_BIT",          /* 02 - SNDRV_PCM_FORMAT_S16_LE */
319e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 03 - SNDRV_PCM_FORMAT_S16_BE */
320e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 04 - SNDRV_PCM_FORMAT_U16_LE */
321e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 05 - SNDRV_PCM_FORMAT_U16_BE */
322e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    "AUDIO_FORMAT_PCM_24_BIT_PACKED",   /* 06 - SNDRV_PCM_FORMAT_S24_LE */
323e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 07 - SNDRV_PCM_FORMAT_S24_BE */
324e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 08 - SNDRV_PCM_FORMAT_U24_LE */
325e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 09 - SNDRV_PCM_FORMAT_U24_BE */
326e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    "AUDIO_FORMAT_PCM_32_BIT",          /* 10 - SNDRV_PCM_FORMAT_S32_LE */
327e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 11 - SNDRV_PCM_FORMAT_S32_BE */
328e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 12 - SNDRV_PCM_FORMAT_U32_LE */
329e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 13 - SNDRV_PCM_FORMAT_U32_BE */
330e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    "AUDIO_FORMAT_PCM_FLOAT",           /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */
331e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */
332e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */
333e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */
334e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */
335e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */
336e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 20 - SNDRV_PCM_FORMAT_MU_LAW */
337e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 21 - SNDRV_PCM_FORMAT_A_LAW */
338e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */
339e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 23 - SNDRV_PCM_FORMAT_MPEG */
340e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 24 - SNDRV_PCM_FORMAT_GSM */
341e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL, NULL, NULL, NULL, NULL, NULL, /* 25 -> 30 (not assigned) */
342e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 31 - SNDRV_PCM_FORMAT_SPECIAL */
343e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    "AUDIO_FORMAT_PCM_24_BIT_PACKED",   /* 32 - SNDRV_PCM_FORMAT_S24_3LE */ /* ??? */
344e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 33 - SNDRV_PCM_FORMAT_S24_3BE */
345e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 34 - SNDRV_PCM_FORMAT_U24_3LE */
346e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 35 - SNDRV_PCM_FORMAT_U24_3BE */
347e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 36 - SNDRV_PCM_FORMAT_S20_3LE */
348e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 37 - SNDRV_PCM_FORMAT_S20_3BE */
349e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 38 - SNDRV_PCM_FORMAT_U20_3LE */
350e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 39 - SNDRV_PCM_FORMAT_U20_3BE */
351e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 40 - SNDRV_PCM_FORMAT_S18_3LE */
352e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 41 - SNDRV_PCM_FORMAT_S18_3BE */
353e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 42 - SNDRV_PCM_FORMAT_U18_3LE */
354e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 43 - SNDRV_PCM_FORMAT_U18_3BE */
355e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 44 - SNDRV_PCM_FORMAT_G723_24 */
356e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */
357e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 46 - SNDRV_PCM_FORMAT_G723_40 */
358e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */
359e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL,                               /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */
360e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    NULL                                /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */
361e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean};
362e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
363e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*
364e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * Generate string containing a bar ("|") delimited list of AUDIO_ formats specified in
365e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * the mask parameter.
366e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean *
367e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean */
368e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic char* get_format_str_for_mask(struct pcm_mask* mask)
369e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean{
370e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    char buffer[256];
371e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int buffer_size = sizeof(buffer) / sizeof(buffer[0]);
372e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    buffer[0] = '\0';
373e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
374e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int num_slots = sizeof(mask->bits) / sizeof(mask->bits[0]);
375e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int bits_per_slot = sizeof(mask->bits[0]) * 8;
376e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
377e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    const char* format_str = NULL;
378e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int table_size = sizeof(format_string_map)/sizeof(format_string_map[0]);
379e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
380e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int slot_index, bit_index, table_index;
381e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    table_index = 0;
382e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int num_written = 0;
383e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    for (slot_index = 0; slot_index < num_slots; slot_index++) {
384e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        unsigned bit_mask = 1;
385e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        for (bit_index = 0; bit_index < bits_per_slot; bit_index++) {
386e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            if ((mask->bits[slot_index] & bit_mask) != 0) {
387e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                format_str = table_index < table_size
388e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                ? format_string_map[table_index]
389e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                : NULL;
390e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                if (format_str != NULL) {
391e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                    if (num_written != 0) {
392e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                        num_written += snprintf(buffer + num_written,
393e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                                buffer_size - num_written, "|");
394e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                    }
395e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                    num_written += snprintf(buffer + num_written, buffer_size - num_written,
396e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                                            "%s", format_str);
397e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                }
398e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            }
399e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            bit_mask <<= 1;
400e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            table_index++;
401e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        }
402e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
403e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
404e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    return strdup(buffer);
405e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean}
406e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
407eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
408e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * Maps from bit position in pcm_mask to AUDIO_ format constants.
409eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
4106b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic audio_format_t const format_value_map[] = {
411e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_PCM_8_BIT,           /* 00 - SNDRV_PCM_FORMAT_S8 */
412e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_PCM_8_BIT,           /* 01 - SNDRV_PCM_FORMAT_U8 */
413e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_PCM_16_BIT,          /* 02 - SNDRV_PCM_FORMAT_S16_LE */
414e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 03 - SNDRV_PCM_FORMAT_S16_BE */
415e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 04 - SNDRV_PCM_FORMAT_U16_LE */
416e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 05 - SNDRV_PCM_FORMAT_U16_BE */
4176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    AUDIO_FORMAT_INVALID,             /* 06 - SNDRV_PCM_FORMAT_S24_LE */
418e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 07 - SNDRV_PCM_FORMAT_S24_BE */
419e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 08 - SNDRV_PCM_FORMAT_U24_LE */
420e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 09 - SNDRV_PCM_FORMAT_U24_BE */
421e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_PCM_32_BIT,          /* 10 - SNDRV_PCM_FORMAT_S32_LE */
422e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 11 - SNDRV_PCM_FORMAT_S32_BE */
423e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 12 - SNDRV_PCM_FORMAT_U32_LE */
424e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 13 - SNDRV_PCM_FORMAT_U32_BE */
425e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_PCM_FLOAT,           /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */
426e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */
427e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */
428e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */
429e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */
430e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */
431e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 20 - SNDRV_PCM_FORMAT_MU_LAW */
432e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 21 - SNDRV_PCM_FORMAT_A_LAW */
433e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */
434e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 23 - SNDRV_PCM_FORMAT_MPEG */
435e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 24 - SNDRV_PCM_FORMAT_GSM */
436e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 25 -> 30 (not assigned) */
437e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,
438e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,
439e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,
440e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,
441e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,
442e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 31 - SNDRV_PCM_FORMAT_SPECIAL */
4436b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    AUDIO_FORMAT_PCM_24_BIT_PACKED,   /* 32 - SNDRV_PCM_FORMAT_S24_3LE */
444e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 33 - SNDRV_PCM_FORMAT_S24_3BE */
445e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 34 - SNDRV_PCM_FORMAT_U24_3LE */
446e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 35 - SNDRV_PCM_FORMAT_U24_3BE */
447e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 36 - SNDRV_PCM_FORMAT_S20_3LE */
448e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 37 - SNDRV_PCM_FORMAT_S20_3BE */
449e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 38 - SNDRV_PCM_FORMAT_U20_3LE */
450e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 39 - SNDRV_PCM_FORMAT_U20_3BE */
451e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 40 - SNDRV_PCM_FORMAT_S18_3LE */
452e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 41 - SNDRV_PCM_FORMAT_S18_3BE */
453e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 42 - SNDRV_PCM_FORMAT_U18_3LE */
454e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 43 - SNDRV_PCM_FORMAT_U18_3BE */
455e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 44 - SNDRV_PCM_FORMAT_G723_24 */
456e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */
457e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 46 - SNDRV_PCM_FORMAT_G723_40 */
458e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */
459e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID,             /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */
460e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    AUDIO_FORMAT_INVALID              /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */
461e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean};
462e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
4636b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean/*
4646b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean * Returns true if mask indicates support for PCM_16.
4656b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean */
4666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLeanstatic bool mask_has_pcm_16(struct pcm_mask* mask) {
4676b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    return (mask->bits[0] & 0x0004) != 0;
4686b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean}
4696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
470e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic int get_format_for_mask(struct pcm_mask* mask)
47119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
472e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int num_slots = sizeof(mask->bits)/ sizeof(mask->bits[0]);
473e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int bits_per_slot = sizeof(mask->bits[0]) * 8;
474e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
475e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int table_size = sizeof(format_value_map) / sizeof(format_value_map[0]);
476e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
477e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int slot_index, bit_index, table_index;
478e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    table_index = 0;
479e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int num_written = 0;
480e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    for (slot_index = 0; slot_index < num_slots; slot_index++) {
481e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        unsigned bit_mask = 1;
482e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        for (bit_index = 0; bit_index < bits_per_slot; bit_index++) {
483e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            if ((mask->bits[slot_index] & bit_mask) != 0) {
484e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                /* just return the first one */
485e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                return table_index < table_size
486e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                           ? format_value_map[table_index]
487e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                           : AUDIO_FORMAT_INVALID;
488e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            }
489e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            bit_mask <<= 1;
490e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            table_index++;
491e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        }
492e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
493e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
494e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    return AUDIO_FORMAT_INVALID;
495e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean}
496e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
497e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*
498e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean * Maps from bit position in pcm_mask to AUDIO_ format constants.
499e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean */
500e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic int const pcm_format_value_map[] = {
501e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    PCM_FORMAT_S8,          /* 00 - SNDRV_PCM_FORMAT_S8 */
502e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 01 - SNDRV_PCM_FORMAT_U8 */
503e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    PCM_FORMAT_S16_LE,      /* 02 - SNDRV_PCM_FORMAT_S16_LE */
504e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 03 - SNDRV_PCM_FORMAT_S16_BE */
505e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 04 - SNDRV_PCM_FORMAT_U16_LE */
506e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 05 - SNDRV_PCM_FORMAT_U16_BE */
507e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    PCM_FORMAT_S24_3LE,     /* 06 - SNDRV_PCM_FORMAT_S24_LE */
508e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 07 - SNDRV_PCM_FORMAT_S24_BE */
509e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 08 - SNDRV_PCM_FORMAT_U24_LE */
510e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 09 - SNDRV_PCM_FORMAT_U24_BE */
511e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    PCM_FORMAT_S32_LE,      /* 10 - SNDRV_PCM_FORMAT_S32_LE */
512e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 11 - SNDRV_PCM_FORMAT_S32_BE */
513e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 12 - SNDRV_PCM_FORMAT_U32_LE */
514e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 13 - SNDRV_PCM_FORMAT_U32_BE */
515e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 14 - SNDRV_PCM_FORMAT_FLOAT_LE */
516e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 15 - SNDRV_PCM_FORMAT_FLOAT_BE */
517e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 16 - SNDRV_PCM_FORMAT_FLOAT64_LE */
518e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 17 - SNDRV_PCM_FORMAT_FLOAT64_BE */
519e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 18 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE */
520e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 19 - SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE */
521e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 20 - SNDRV_PCM_FORMAT_MU_LAW */
522e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 21 - SNDRV_PCM_FORMAT_A_LAW */
523e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 22 - SNDRV_PCM_FORMAT_IMA_ADPCM */
524e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 23 - SNDRV_PCM_FORMAT_MPEG */
525e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 24 - SNDRV_PCM_FORMAT_GSM */
526e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 25 -> 30 (not assigned) */
527e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,
528e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,
529e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,
530e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,
531e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,
532e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 31 - SNDRV_PCM_FORMAT_SPECIAL */
533e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    PCM_FORMAT_S24_3LE,     /* 32 - SNDRV_PCM_FORMAT_S24_3LE */ /* ??? */
534e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 33 - SNDRV_PCM_FORMAT_S24_3BE */
535e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 34 - SNDRV_PCM_FORMAT_U24_3LE */
536e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 35 - SNDRV_PCM_FORMAT_U24_3BE */
537e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 36 - SNDRV_PCM_FORMAT_S20_3LE */
538e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 37 - SNDRV_PCM_FORMAT_S20_3BE */
539e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 38 - SNDRV_PCM_FORMAT_U20_3LE */
540e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 39 - SNDRV_PCM_FORMAT_U20_3BE */
541e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 40 - SNDRV_PCM_FORMAT_S18_3LE */
542e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 41 - SNDRV_PCM_FORMAT_S18_3BE */
543e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 42 - SNDRV_PCM_FORMAT_U18_3LE */
544e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 43 - SNDRV_PCM_FORMAT_U18_3BE */
545e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 44 - SNDRV_PCM_FORMAT_G723_24 */
546e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 45 - SNDRV_PCM_FORMAT_G723_24_1B */
547e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 46 - SNDRV_PCM_FORMAT_G723_40 */
548e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 47 - SNDRV_PCM_FORMAT_G723_40_1B */
549e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0,                      /* 48 - SNDRV_PCM_FORMAT_DSD_U8 */
550e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    0                       /* 49 - SNDRV_PCM_FORMAT_DSD_U16_LE */
551e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean};
552e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
553e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic int get_pcm_format_for_mask(struct pcm_mask* mask) {
554e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int num_slots = sizeof(mask->bits)/ sizeof(mask->bits[0]);
555e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int bits_per_slot = sizeof(mask->bits[0]) * 8;
556e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
557e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int table_size = sizeof(pcm_format_value_map) / sizeof(pcm_format_value_map[0]);
558e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
559e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int slot_index, bit_index, table_index;
560e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    table_index = 0;
561e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int num_written = 0;
562e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    for (slot_index = 0; slot_index < num_slots; slot_index++) {
563e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        unsigned bit_mask = 1;
564e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        for (bit_index = 0; bit_index < bits_per_slot; bit_index++) {
565e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            if ((mask->bits[slot_index] & bit_mask) != 0) {
566e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                /* just return the first one */
567e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                return table_index < table_size
568e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                           ? pcm_format_value_map[table_index]
569e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                           : AUDIO_FORMAT_INVALID;
570e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            }
571e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            bit_mask <<= 1;
572e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            table_index++;
57330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
574eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
575e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
576e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    return 0; // is this right?
577e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean}
578e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
579e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLeanstatic void log_pcm_mask(const char* mask_name, struct pcm_mask* mask) {
580e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    char buff[512];
581e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    char bit_buff[32];
582e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int buffSize = sizeof(buff)/sizeof(buff[0]);
583e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
584e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    buff[0] = '\0';
585e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
586e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int num_slots = sizeof(mask->bits) / sizeof(mask->bits[0]);
587e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int bits_per_slot = sizeof(mask->bits[0]) * 8;
588e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
589e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    int slot_index, bit_index;
590e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    strcat(buff, "[");
591e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    for (slot_index = 0; slot_index < num_slots; slot_index++) {
592e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        unsigned bit_mask = 1;
593e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        for (bit_index = 0; bit_index < bits_per_slot; bit_index++) {
594e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            strcat(buff, (mask->bits[slot_index] & bit_mask) != 0 ? "1" : "0");
595e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            bit_mask <<= 1;
596e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        }
597e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        if (slot_index < num_slots - 1) {
598e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            strcat(buff, ",");
599e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        }
600e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    }
601e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    strcat(buff, "]");
602e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
603e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    ALOGV("usb:audio_hw - %s mask:%s", mask_name, buff);
604eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
60519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
606cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLeanstatic void log_pcm_params(struct pcm_params * alsa_hw_params) {
607cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_SAMPLE_BITS min:%u, max:%u",
608cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_SAMPLE_BITS),
609cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_SAMPLE_BITS));
610cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_FRAME_BITS min:%u, max:%u",
611cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_FRAME_BITS),
612cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_FRAME_BITS));
613e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    log_pcm_mask("PCM_PARAM_FORMAT", pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT));
614e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    log_pcm_mask("PCM_PARAM_SUBFORMAT", pcm_params_get_mask(alsa_hw_params, PCM_PARAM_SUBFORMAT));
615cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_CHANNELS min:%u, max:%u",
616cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS),
617cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS));
618cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_RATE min:%u, max:%u",
619cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE),
620cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE));
621cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_TIME min:%u, max:%u",
622cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_TIME),
623cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_TIME));
624cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_SIZE min:%u, max:%u",
625cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_SIZE),
626cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_SIZE));
627cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_PERIOD_BYTES min:%u, max:%u",
628cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIOD_BYTES),
629cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIOD_BYTES));
630cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_PERIODS min:%u, max:%u",
631cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS),
632cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_PERIODS));
633cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_TIME min:%u, max:%u",
634cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_TIME),
635cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_TIME));
636cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_SIZE min:%u, max:%u",
637cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_SIZE),
638cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_SIZE));
639cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_BUFFER_BYTES min:%u, max:%u",
640cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_BYTES),
641cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_BUFFER_BYTES));
642cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    ALOGV("usb:audio_hw - PCM_PARAM_TICK_TIME min:%u, max:%u",
643cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_min(alsa_hw_params, PCM_PARAM_TICK_TIME),
644cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean          pcm_params_get_max(alsa_hw_params, PCM_PARAM_TICK_TIME));
645cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean}
646cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean
647eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
64833a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean * Returns the supplied value rounded up to the next even multiple of 16
64933a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean */
65033a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLeanstatic unsigned int round_to_16_mult(unsigned int size) {
65133a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    return (size + 15) & 0xFFFFFFF0;
65233a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean}
65333a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean
654e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*TODO - Evaluate if this value should/can be retrieved from a device-specific property */
65533a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean#define MIN_BUFF_TIME   5   /* milliseconds */
65633a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean
65733a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean/*
65833a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean * Returns the system defined minimum period size based on the supplied sample rate
65933a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean */
66033a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLeanstatic unsigned int calc_min_period_size(unsigned int sample_rate) {
66133a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    unsigned int period_size = (sample_rate * MIN_BUFF_TIME) / 1000;
66233a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    return round_to_16_mult(period_size);
66333a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean}
66433a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean
66533a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean/*
666eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * Reads and decodes configuration info from the specified ALSA card/device
667eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
668eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int read_alsa_device_config(int card, int device, int io_type, struct pcm_config * config)
669eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
67030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw - read_alsa_device_config(c:%d d:%d t:0x%X)",card, device, io_type);
67119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
672eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (card < 0 || device < 0) {
673eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -EINVAL;
674eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
67519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
676eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct pcm_params * alsa_hw_params = pcm_params_get(card, device, io_type);
677eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (alsa_hw_params == NULL) {
678eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -EINVAL;
67919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
68019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
681eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
682eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * This Logging will be useful when testing new USB devices.
683eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
684cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean    /* log_pcm_params(alsa_hw_params); */
685eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
686eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->channels = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
687eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->rate = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
68833a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    config->period_size = pcm_params_get_min(alsa_hw_params, PCM_PARAM_BUFFER_SIZE);
68933a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    /* round this up to a multiple of 16 */
69033a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    config->period_size = round_to_16_mult(config->period_size);
69133a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    /* make sure it is above a minimum value to minimize jitter */
69233a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    unsigned int min_period_size = calc_min_period_size(config->rate);
69333a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    if (config->period_size < min_period_size) {
69433a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean        config->period_size = min_period_size;
69533a6b171baaf5b3e1eb1b8269bdf30b06b79ba0cPaul McLean    }
696eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    config->period_count = pcm_params_get_min(alsa_hw_params, PCM_PARAM_PERIODS);
697eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
698e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    config->format = get_pcm_format_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT));
69919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
70019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
70119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
702eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/*
703eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * HAl Functions
704eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
705eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/**
706eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * NOTE: when multiple mutexes have to be acquired, always respect the
707eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean * following order: hw device > out stream
708eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean */
70919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
710eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */
71119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_sample_rate(const struct audio_stream *stream)
71219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
713eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return cached_output_hardware_config.rate;
71419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
71519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
71619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
71719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
71819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
71919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
72019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
72119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t out_get_buffer_size(const struct audio_stream *stream)
72219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
723eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return cached_output_hardware_config.period_size * audio_stream_frame_size(stream);
72419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
72519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
72619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_channels(const struct audio_stream *stream)
72719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
728eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Always Stero for now. We will do *some* conversions in this HAL.
729e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    /* TODO When AudioPolicyManager & AudioFlinger supports arbitrary channels
730e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean       rewrite this to return the ACTUAL channel format */
73119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return AUDIO_CHANNEL_OUT_STEREO;
73219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
73319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
73419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic audio_format_t out_get_format(const struct audio_stream *stream)
73519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
736e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    return audio_format_from_pcm_format(cached_output_hardware_config.format);
73719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
73819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
73919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_format(struct audio_stream *stream, audio_format_t format)
74019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
741e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    cached_output_hardware_config.format = pcm_format_from_audio_format(format);
74219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
74319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
74419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
74519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_standby(struct audio_stream *stream)
74619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
74719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
74819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
74919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
75019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
75119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
75219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out->standby) {
75319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        pcm_close(out->pcm);
75419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->pcm = NULL;
75519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = true;
75619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
75719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
75819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
75919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
76019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
76119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
76219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
76319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
76419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_dump(const struct audio_stream *stream, int fd)
76519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
76619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
76719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
76819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
76919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
77019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
771eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out out_set_parameters() keys:%s", kvpairs);
772eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
77319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
77419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = out->dev;
77519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct str_parms *parms;
77619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    char value[32];
777eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
77819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int routing = 0;
779eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
78019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
78119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    parms = str_parms_create_str(kvpairs);
78219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&adev->lock);
78319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
784eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    bool recache_device_params = false;
785eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
786eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
787eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->out_card = atoi(value);
788eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
789eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
790eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
791eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
792eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
793eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->out_device = atoi(value);
794eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        recache_device_params = true;
795eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
79619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
797eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (recache_device_params && adev->out_card >= 0 && adev->out_device >= 0) {
798eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        ret_value = read_alsa_device_config(adev->out_card, adev->out_device, PCM_OUT,
79930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                            &cached_output_hardware_config);
800eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        output_hardware_config_is_cached = (ret_value == 0);
801eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
80219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
80319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&adev->lock);
80419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    str_parms_destroy(parms);
80519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
806eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
80719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
80819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
809e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*TODO it seems like both out_get_parameters() and in_get_parameters()
810e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean  could be written in terms of a get_device_parameters(io_type) */
811eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
81230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * out_get_parameters(const struct audio_stream *stream, const char *keys)
81330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
81430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out out_get_parameters() keys:%s", keys);
81530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
816eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_out *out = (struct stream_out *) stream;
817eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = out->dev;
818eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
81930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (adev->out_card < 0 || adev->out_device < 0)
82030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return strdup("");
82130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
822eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    unsigned min, max;
823eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
824eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct str_parms *query = str_parms_create_str(keys);
825eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct str_parms *result = str_parms_create();
826eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
827eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_written = 0;
828eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char buffer[256];
829eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int buffer_size = sizeof(buffer) / sizeof(buffer[0]);
830eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char* result_str = NULL;
831eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
832eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct pcm_params * alsa_hw_params = pcm_params_get(adev->out_card, adev->out_device, PCM_OUT);
833eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
834eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // These keys are from hardware/libhardware/include/audio.h
835eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // supported sample rates
836eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
837eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so
838eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // if they are different, return a list containing those two values, otherwise just the one.
839eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
840eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE);
84188e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn        num_written = snprintf(buffer, buffer_size, "%u", min);
842eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (min != max) {
84388e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn            snprintf(buffer + num_written, buffer_size - num_written, "|%u", max);
844eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
845eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
846eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                          buffer);
847eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES
848eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
849eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // supported channel counts
850eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
851eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        // Similarly for output channels count
852e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        /* TODO - This is wrong, we need format strings, not numbers (another CL) */
853eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
854eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);
85588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn        num_written = snprintf(buffer, buffer_size, "%u", min);
856eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (min != max) {
85788e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn            snprintf(buffer + num_written, buffer_size - num_written, "|%u", max);
858eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
859eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, buffer);
860eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_CHANNELS
861eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
862eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // supported sample formats
863eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
864e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        char * format_params =
865e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            get_format_str_for_mask(pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT));
866e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, format_params);
867e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        free(format_params);
868eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_FORMATS
869eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
870eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    result_str = str_parms_to_str(result);
871eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
872eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // done with these...
873eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(query);
874eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(result);
875eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
876e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    ALOGV("usb:audio_hw::out out_get_parameters() = %s", result_str);
877e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
878eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return result_str;
87919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
88019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
88119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic uint32_t out_get_latency(const struct audio_stream_out *stream)
88219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
88330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_out *out = (struct stream_out *) stream;
884eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
885e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    /*TODO Do we need a term here for the USB latency (as reported in the USB descriptors)? */
88630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    uint32_t latency = (cached_output_hardware_config.period_size
887e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                    * cached_output_hardware_config.period_count * 1000)
888e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean                    / out_get_sample_rate(&stream->common);
889eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return latency;
89019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
89119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
89230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_set_volume(struct audio_stream_out *stream, float left, float right)
89319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
89419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
89519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
89619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
897eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* must be called with hw device and output stream mutexes locked */
898eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int start_output_stream(struct stream_out *out)
899eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
900eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = out->dev;
901eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int return_val = 0;
902eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
90330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out start_output_stream(card:%d device:%d)",
90430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          adev->out_card, adev->out_device);
905eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
906eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->pcm = pcm_open(adev->out_card, adev->out_device, PCM_OUT, &cached_output_hardware_config);
907e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean
908eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (out->pcm == NULL) {
909eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
910eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
911eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
912eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (out->pcm && !pcm_is_ready(out->pcm)) {
913eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        ALOGE("audio_hw audio_hw pcm_open() failed: %s", pcm_get_error(out->pcm));
914eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        pcm_close(out->pcm);
915eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
916eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
917eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
918eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
919eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
920eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
921eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic ssize_t out_write(struct audio_stream_out *stream, const void* buffer, size_t bytes)
92219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
92319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    int ret;
92419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
92519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
92619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->dev->lock);
92719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_lock(&out->lock);
92819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (out->standby) {
92919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        ret = start_output_stream(out);
93019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        if (ret != 0) {
93119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson            goto err;
93219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        }
93319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        out->standby = false;
93419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
93519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
93630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // Setup conversion buffer
93730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // compute maximum potential buffer size.
93830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // * 2 for stereo -> quad conversion
93930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // * 3/2 for 16bit -> 24 bit conversion
94088e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t required_conversion_buffer_size = (bytes * 3 * 2) / 2;
94130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (required_conversion_buffer_size > out->conversion_buffer_size) {
942e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        /* TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
943e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean           (and do these conversions themselves) */
94430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        out->conversion_buffer_size = required_conversion_buffer_size;
94530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        out->conversion_buffer = realloc(out->conversion_buffer, out->conversion_buffer_size);
94630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
94730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
94888e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    const void * write_buff = buffer;
949eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_write_buff_bytes = bytes;
950eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
951eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    /*
952eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     * Num Channels conversion
953eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean     */
954eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_device_channels = cached_output_hardware_config.channels;
955eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int num_req_channels = 2; /* always, for now */
95630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
957eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        num_write_buff_bytes =
95830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                expand_channels_16(write_buff, num_req_channels,
95930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                   out->conversion_buffer, num_device_channels,
96030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                   num_write_buff_bytes / sizeof(short));
961eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        write_buff = out->conversion_buffer;
962eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
963eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
964eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (write_buff != NULL && num_write_buff_bytes != 0) {
965eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        pcm_write(out->pcm, write_buff, num_write_buff_bytes);
966eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
96719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
96819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
96919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->dev->lock);
97019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
97119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
97219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
97319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr:
97419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    pthread_mutex_unlock(&out->lock);
975f9953b7d52bcf560b15efde807f41cf0903e875dAmit Shekhar    pthread_mutex_unlock(&out->dev->lock);
97619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (ret != 0) {
97719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
97819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson               out_get_sample_rate(&stream->common));
97919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    }
98019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
98119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return bytes;
98219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
98319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
98430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_render_position(const struct audio_stream_out *stream, uint32_t *dsp_frames)
98519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
98619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
98719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
98819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
98919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
99019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
99119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
99219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
99319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
99419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
99519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
99619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
99719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
99819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
99930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int out_get_next_write_timestamp(const struct audio_stream_out *stream, int64_t *timestamp)
100019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
100119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -EINVAL;
100219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
100319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
100419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_open_output_stream(struct audio_hw_device *dev,
100546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_io_handle_t handle,
100646a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_devices_t devices,
100746a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   audio_output_flags_t flags,
100846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                   struct audio_config *config,
100919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                   struct audio_stream_out **stream_out)
101019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
101130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::out adev_open_output_stream() handle:0x%X, device:0x%X, flags:0x%X",
1012eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean          handle, devices, flags);
1013eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
101419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct audio_device *adev = (struct audio_device *)dev;
1015eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
101619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out;
101719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
101819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
101919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!out)
102019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
102119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1022eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // setup function pointers
102319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_sample_rate = out_get_sample_rate;
102419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_sample_rate = out_set_sample_rate;
102519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_buffer_size = out_get_buffer_size;
102619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_channels = out_get_channels;
102719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_format = out_get_format;
102819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_format = out_set_format;
102919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.standby = out_standby;
103019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.dump = out_dump;
103119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.set_parameters = out_set_parameters;
103219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.get_parameters = out_get_parameters;
103319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.add_audio_effect = out_add_audio_effect;
103419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.common.remove_audio_effect = out_remove_audio_effect;
103519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_latency = out_get_latency;
103619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.set_volume = out_set_volume;
103719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.write = out_write;
103819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_render_position = out_get_render_position;
103919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
104019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
104119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out->dev = adev;
104219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1043eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (output_hardware_config_is_cached) {
1044eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->sample_rate = cached_output_hardware_config.rate;
104519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1046e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        config->format = audio_format_from_pcm_format(cached_output_hardware_config.format);
104719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1048eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->channel_mask =
1049eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean                audio_channel_out_mask_from_count(cached_output_hardware_config.channels);
1050eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        if (config->channel_mask != AUDIO_CHANNEL_OUT_STEREO) {
1051eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // Always report STEREO for now.  AudioPolicyManagerBase/AudioFlinger dont' understand
1052eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            // formats with more channels, so we won't get chosen (say with a 4-channel DAC).
1053e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            /*TODO remove this when the above restriction is removed. */
1054eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean            config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
1055eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        }
1056eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    } else {
1057eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        cached_output_hardware_config = default_alsa_out_config;
1058eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1059eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->format = out_get_format(&out->stream.common);
1060eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->channel_mask = out_get_channels(&out->stream.common);
1061eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        config->sample_rate = out_get_sample_rate(&out->stream.common);
1062eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
1063eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1064eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
1065eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
1066eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1067eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->standby = true;
106846a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood
106919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = &out->stream;
107019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
107119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
107219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonerr_open:
107319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(out);
107419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *stream_out = NULL;
1075eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
107619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
107719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
107819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic void adev_close_output_stream(struct audio_hw_device *dev,
107919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                     struct audio_stream_out *stream)
108019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1081eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    ALOGV("usb:audio_hw::out adev_close_output_stream()");
108219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    struct stream_out *out = (struct stream_out *)stream;
108319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1084e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    // Close the pcm device
108519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    out_standby(&stream->common);
1086eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1087eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    free(out->conversion_buffer);
1088eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer = NULL;
1089eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    out->conversion_buffer_size = 0;
1090eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
109119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(stream);
109219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
109319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
109419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
109519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
109619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
109719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
109819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
109930f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * adev_get_parameters(const struct audio_hw_device *dev, const char *keys)
110019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
110119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return strdup("");
110219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
110319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
110419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_init_check(const struct audio_hw_device *dev)
110519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
110619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
110719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
110819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
110919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
111019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
111119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
111219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
111319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
111419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_master_volume(struct audio_hw_device *dev, float volume)
111519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
111619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
111719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
111819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
111919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
112019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
112119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
112219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
112319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
112419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
112519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
112619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
112719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
112819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
112919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
113019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
113119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return -ENOSYS;
113219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
113319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
113419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
113546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                         const struct audio_config *config)
113619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
113719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
113819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
113919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1140eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean/* Helper functions */
1141eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_sample_rate(const struct audio_stream *stream)
1142eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
114330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return cached_input_hardware_config.rate;
1144eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1145eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1146eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
1147eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
1148eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
1149eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1150eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1151eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic size_t in_get_buffer_size(const struct audio_stream *stream)
1152eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
115388e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    ALOGV("usb: in_get_buffer_size() = %zu",
115430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          cached_input_hardware_config.period_size * audio_stream_frame_size(stream));
115530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return cached_input_hardware_config.period_size * audio_stream_frame_size(stream);
1156eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1157eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1158eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic uint32_t in_get_channels(const struct audio_stream *stream)
1159eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
116030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // just report stereo for now
116130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return AUDIO_CHANNEL_IN_STEREO;
1162eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1163eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1164eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic audio_format_t in_get_format(const struct audio_stream *stream)
1165eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
11666b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    const struct stream_in * in_stream = (const struct stream_in *)stream;
11676b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
11686b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    ALOGV("in_get_format() = %d -> %d", in_stream->input_framework_format,
11696b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean          audio_format_from_pcm_format(in_stream->input_framework_format));
11706b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* return audio_format_from_pcm_format(cached_input_hardware_config.format); */
11716b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    return audio_format_from_pcm_format(in_stream->input_framework_format);
1172eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1173eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1174eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_format(struct audio_stream *stream, audio_format_t format)
1175eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
1176eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return -ENOSYS;
1177eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1178eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1179eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_standby(struct audio_stream *stream)
1180eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
118130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *) stream;
118230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
118330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
118430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
118530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
118630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (!in->standby) {
118730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        pcm_close(in->pcm);
118830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->pcm = NULL;
118930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = true;
119030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
119130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
119230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
119330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->dev->lock);
119430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
1195eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1196eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1197eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1198eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_dump(const struct audio_stream *stream, int fd)
1199eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
1200eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1201eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1202eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1203eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
1204eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
120530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb: audio_hw::in in_set_parameters() keys:%s", kvpairs);
1206eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1207eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)stream;
1208eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = in->dev;
1209eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct str_parms *parms;
1210eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    char value[32];
1211eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int param_val;
1212eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int routing = 0;
1213eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    int ret_value = 0;
1214eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1215eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    parms = str_parms_create_str(kvpairs);
1216eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_lock(&adev->lock);
1217eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
121830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    bool recache_device_params = false;
121930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
1220eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // Card/Device
1221eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "card", value, sizeof(value));
1222eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
1223eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->in_card = atoi(value);
122430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        recache_device_params = true;
1225eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
1226eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1227eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    param_val = str_parms_get_str(parms, "device", value, sizeof(value));
1228eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (param_val >= 0) {
1229eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        adev->in_device = atoi(value);
123030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        recache_device_params = true;
1231eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
1232eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
123330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (recache_device_params && adev->in_card >= 0 && adev->in_device >= 0) {
123430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        ret_value = read_alsa_device_config(adev->in_card, adev->in_device,
123530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                            PCM_IN, &(cached_input_hardware_config));
123630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        input_hardware_config_is_cached = (ret_value == 0);
1237eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
1238eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1239eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    pthread_mutex_unlock(&adev->lock);
1240eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    str_parms_destroy(parms);
1241eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1242eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return ret_value;
1243eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1244eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1245e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/*TODO it seems like both out_get_parameters() and in_get_parameters()
1246e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean   could be written in terms of a get_device_parameters(io_type) */
1247eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
124830f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic char * in_get_parameters(const struct audio_stream *stream, const char *keys) {
124930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::in in_get_parameters() keys:%s", keys);
125030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
125130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
125230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct audio_device *adev = in->dev;
125330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
125430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (adev->in_card < 0 || adev->in_device < 0)
125530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return strdup("");
125630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
125730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct pcm_params * alsa_hw_params = pcm_params_get(adev->in_card, adev->in_device, PCM_IN);
125830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (alsa_hw_params == NULL)
125930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return strdup("");
126030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
126130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct str_parms *query = str_parms_create_str(keys);
126230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct str_parms *result = str_parms_create();
1263eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
126430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_written = 0;
126530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    char buffer[256];
126630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int buffer_size = sizeof(buffer) / sizeof(buffer[0]);
126730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    char* result_str = NULL;
1268eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
126930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    unsigned min, max;
127030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
127130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // These keys are from hardware/libhardware/include/audio.h
127230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // supported sample rates
127330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
127430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        // pcm_hw_params doesn't have a list of supported samples rates, just a min and a max, so
127530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        // if they are different, return a list containing those two values, otherwise just the one.
127630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_RATE);
127730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_RATE);
127888e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn        num_written = snprintf(buffer, buffer_size, "%u", min);
127930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (min != max) {
128088e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn            snprintf(buffer + num_written, buffer_size - num_written, "|%u", max);
128130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
128230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SAMPLING_RATE, buffer);
128330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES
1284eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
128530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // supported channel counts
128630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
128730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        // Similarly for output channels count
1288e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean        // TODO This is wrong, we need format strings, not numbers (another CL)
128930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        min = pcm_params_get_min(alsa_hw_params, PCM_PARAM_CHANNELS);
129030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        max = pcm_params_get_max(alsa_hw_params, PCM_PARAM_CHANNELS);
129188e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn        num_written = snprintf(buffer, buffer_size, "%u", min);
129230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (min != max) {
129388e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn            snprintf(buffer + num_written, buffer_size - num_written, "|%u", max);
129430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
129530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        str_parms_add_str(result, AUDIO_PARAMETER_STREAM_CHANNELS, buffer);
129630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_CHANNELS
129730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
129830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // supported sample formats
129930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
13006b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        struct pcm_mask * format_mask = pcm_params_get_mask(alsa_hw_params, PCM_PARAM_FORMAT);
13016b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        char * format_params = get_format_str_for_mask(format_mask);
13026b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        if (!mask_has_pcm_16(format_mask)) {
13036b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            /* For now, always support PCM_16 and convert locally if necessary */
13046b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            char buff[256];
13056b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            snprintf(buff, sizeof(buff), "AUDIO_FORMAT_PCM_16_BIT|%s", format_params);
13066b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            free(format_params);
13076b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, buff);
13086b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        } else {
13096b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            str_parms_add_str(result, AUDIO_PARAMETER_STREAM_SUP_FORMATS, format_params);
131030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
131130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }  // AUDIO_PARAMETER_STREAM_SUP_FORMATS
131230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
131330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    result_str = str_parms_to_str(result);
131430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
131530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // done with these...
131630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    str_parms_destroy(query);
131730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    str_parms_destroy(result);
131830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
13196b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    ALOGV("usb:audio_hw::in in_get_parameters() = %s", result_str);
13206b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
132130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return result_str;
1322eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1323eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1324eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
1325eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
1326eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1327eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1328eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1329eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLeanstatic int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
1330eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean{
1331eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1332eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1333eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
133430f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int in_set_gain(struct audio_stream_in *stream, float gain)
133530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
1336eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1337eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1338eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
133930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean/* must be called with hw device and output stream mutexes locked */
134030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int start_input_stream(struct stream_in *in) {
134130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct audio_device *adev = in->dev;
134230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int return_val = 0;
134330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
134430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    ALOGV("usb:audio_hw::start_input_stream(card:%d device:%d)",
134530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          adev->in_card, adev->in_device);
134630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
134730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->pcm = pcm_open(adev->in_card, adev->in_device, PCM_IN, &cached_input_hardware_config);
134830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->pcm == NULL) {
134930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        ALOGE("usb:audio_hw pcm_open() in->pcm == NULL");
135030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return -ENOMEM;
135130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
135230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
135330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->pcm && !pcm_is_ready(in->pcm)) {
135430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        ALOGE("usb:audio_hw audio_hw pcm_open() failed: %s", pcm_get_error(in->pcm));
135530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        pcm_close(in->pcm);
135630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        return -ENOMEM;
135730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
135830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
135930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return 0;
136030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean}
136130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
1362e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean/* TODO mutex stuff here (see out_write) */
136330f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic ssize_t in_read(struct audio_stream_in *stream, void* buffer, size_t bytes)
136430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
136588e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    size_t num_read_buff_bytes = 0;
136630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * read_buff = buffer;
136730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    void * out_buff = buffer;
136830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
136930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in * in = (struct stream_in *) stream;
137030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
137130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->dev->lock);
137230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_lock(&in->lock);
137330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
137430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (in->standby) {
137530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (start_input_stream(in) != 0) {
137630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            goto err;
137730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
137830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        in->standby = false;
137930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
138030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
138130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // OK, we need to figure out how much data to read to be able to output the requested
138230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // number of bytes in the HAL format (16-bit, stereo).
138330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    num_read_buff_bytes = bytes;
138430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_device_channels = cached_input_hardware_config.channels;
138530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    int num_req_channels = 2; /* always, for now */
138630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
138730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_device_channels != num_req_channels) {
1388cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean        num_read_buff_bytes = (num_device_channels * num_read_buff_bytes) / num_req_channels;
138930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
139030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
13916b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Assume (for now) that in->input_framework_format == PCM_FORMAT_S16_LE */
13927661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    if (cached_input_hardware_config.format == PCM_FORMAT_S24_3LE) {
13936b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 24-bit USB device */
139430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        num_read_buff_bytes = (3 * num_read_buff_bytes) / 2;
13956b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (cached_input_hardware_config.format == PCM_FORMAT_S32_LE) {
13966b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* 32-bit USB device */
13976b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        num_read_buff_bytes = num_read_buff_bytes * 2;
139830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
139930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
140030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    // Setup/Realloc the conversion buffer (if necessary).
140130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (num_read_buff_bytes != bytes) {
140230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_read_buff_bytes > in->conversion_buffer_size) {
1403e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean            /*TODO Remove this when AudioPolicyManger/AudioFlinger support arbitrary formats
1404e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean              (and do these conversions themselves) */
140530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer_size = num_read_buff_bytes;
140630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            in->conversion_buffer = realloc(in->conversion_buffer, in->conversion_buffer_size);
140730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
140830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        read_buff = in->conversion_buffer;
140930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
141030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
141130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    if (pcm_read(in->pcm, read_buff, num_read_buff_bytes) == 0) {
141230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        /*
141330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * Do any conversions necessary to send the data in the format specified to/by the HAL
141430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         * (but different from the ALSA format), such as 24bit ->16bit, or 4chan -> 2chan.
141530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean         */
14166b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        if (cached_input_hardware_config.format != PCM_FORMAT_S16_LE) {
14176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            // we need to convert
141830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            if (num_device_channels != num_req_channels) {
141930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                out_buff = read_buff;
142030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            }
142130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
14226b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            if (cached_input_hardware_config.format == PCM_FORMAT_S24_3LE) {
14236b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
14246b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_24_3_to_16(read_buff, num_read_buff_bytes / 3, out_buff);
14256b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            } else if (cached_input_hardware_config.format == PCM_FORMAT_S32_LE) {
14266b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                num_read_buff_bytes =
14276b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                    convert_32_to_16(read_buff, num_read_buff_bytes / 4, out_buff);
14286b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            }
14296b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            else {
14306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean                goto err;
14316b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean            }
143230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
1433eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
143430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        if (num_device_channels != num_req_channels) {
143530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            out_buff = buffer;
143630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean            /* Num Channels conversion */
1437cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean            if (num_device_channels < num_req_channels) {
1438cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean                num_read_buff_bytes =
1439cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean                    expand_channels_16(read_buff, num_device_channels,
1440cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean                                       out_buff, num_req_channels,
1441cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean                                       num_read_buff_bytes / sizeof(short));
1442fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent            } else {
1443fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                num_read_buff_bytes =
1444fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                    contract_channels_16(read_buff, num_device_channels,
1445fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                                         out_buff, num_req_channels,
1446fbc02dc16ea43f14e7a0c410bfb787ddcf1b89fbEric Laurent                                         num_read_buff_bytes / sizeof(short));
1447cf61191774068ffeb00153c006fbf0a9ab612fcbPaul McLean            }
144830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean        }
144930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    }
1450eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
145130f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanerr:
145230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->lock);
145330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    pthread_mutex_unlock(&in->dev->lock);
145430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
145530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    return num_read_buff_bytes;
1456eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1457eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
145830f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
145930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean{
1460eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    return 0;
1461eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean}
1462eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
146346a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwoodstatic int adev_open_input_stream(struct audio_hw_device *dev,
146446a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_io_handle_t handle,
146546a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood                                  audio_devices_t devices,
146630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean                                  struct audio_config *config,
146719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson                                  struct audio_stream_in **stream_in)
146819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
146988e458ae613d7b5450e63487f42056ddecc95b24Mark Salyzyn    ALOGV("usb: in adev_open_input_stream() rate:%" PRIu32 ", chanMask:0x%" PRIX32 ", fmt:%" PRIu8,
147030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean          config->sample_rate, config->channel_mask, config->format);
1471eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1472eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct stream_in *in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
14737661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    int ret = 0;
14747661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
1475eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    if (in == NULL)
1476eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean        return -ENOMEM;
1477eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1478eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    // setup function pointers
1479eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_sample_rate = in_get_sample_rate;
1480eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_sample_rate = in_set_sample_rate;
1481eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_buffer_size = in_get_buffer_size;
1482eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_channels = in_get_channels;
1483eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_format = in_get_format;
1484eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_format = in_set_format;
1485eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.standby = in_standby;
1486eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.dump = in_dump;
1487eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.set_parameters = in_set_parameters;
1488eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.get_parameters = in_get_parameters;
1489eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.add_audio_effect = in_add_audio_effect;
1490eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.common.remove_audio_effect = in_remove_audio_effect;
1491eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1492eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.set_gain = in_set_gain;
1493eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.read = in_read;
1494eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    in->stream.get_input_frames_lost = in_get_input_frames_lost;
1495eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
14966b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    in->input_framework_format = PCM_FORMAT_S16_LE;
14976b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean
149830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->dev = (struct audio_device *)dev;
1499eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
15006b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (!input_hardware_config_is_cached) {
15016b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        // just return defaults until we can actually query the device.
15026b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        cached_input_hardware_config = default_alsa_in_config;
15036b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
1504eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
15056b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Rate */
15066b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* TODO Check that the requested rate is valid for the connected device */
15076b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->sample_rate == 0) {
15087661a484021f6e7c3b219bd21659118eef94e45bEric Laurent        config->sample_rate = cached_input_hardware_config.rate;
15096b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else {
15106b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        cached_input_hardware_config.rate = config->sample_rate;
15116b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
15127661a484021f6e7c3b219bd21659118eef94e45bEric Laurent
15136b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* Format */
15146b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* until the framework supports format conversion, just take what it asks for
15156b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * i.e. AUDIO_FORMAT_PCM_16_BIT */
15166b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* config->format = audio_format_from_pcm_format(cached_input_hardware_config.format); */
15176b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->format == AUDIO_FORMAT_DEFAULT) {
15186b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* just return AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
15196b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
15206b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
15216b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (config->format == AUDIO_FORMAT_PCM_16_BIT) {
15226b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* Always accept AUDIO_FORMAT_PCM_16_BIT until the framework supports other input
15236b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
152430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    } else {
15256b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* When the framework support other formats, validate here */
15266b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->format = AUDIO_FORMAT_PCM_16_BIT;
15276b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        ret = -EINVAL;
15286b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    }
1529eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
15306b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    /* don't change the cached_input_hardware_config, we will open it as what it is and
15316b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean     * convert as necessary */
15326b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    if (config->channel_mask == AUDIO_CHANNEL_NONE) {
15336b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* just return AUDIO_CHANNEL_IN_STEREO until the framework supports other input
15346b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean         * formats */
15356b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
15366b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean    } else if (config->channel_mask != AUDIO_CHANNEL_IN_STEREO) {
15376b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        /* allow only stereo capture for now */
15386b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
15396b1c0fef801c9435ed3446d53cc45d1b1f6fd07ePaul McLean        ret = -EINVAL;
1540eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    }
1541eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
154230f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->standby = true;
154330f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
154430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer = NULL;
154530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in->conversion_buffer_size = 0;
154630f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
1547eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    *stream_in = &in->stream;
1548eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
15497661a484021f6e7c3b219bd21659118eef94e45bEric Laurent    return ret;
155019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
155119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
155230f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic void adev_close_input_stream(struct audio_hw_device *dev, struct audio_stream_in *stream)
155319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
155430f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    struct stream_in *in = (struct stream_in *)stream;
155530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
1556e32cbc1fdd5990ec8abc748cd3f1e1ebf5002077Paul McLean    // Close the pcm device
155730f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    in_standby(&stream->common);
155830f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
155930f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(in->conversion_buffer);
156030f4185da772fcc679db35e01148eca6eeafe15fPaul McLean
156130f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    free(stream);
156219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
156319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
156419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_dump(const audio_hw_device_t *device, int fd)
156519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
156619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
156719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
156819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
156919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic int adev_close(hw_device_t *device)
157019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
1571eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = (struct audio_device *)device;
157219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    free(device);
1573eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
1574eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    output_hardware_config_is_cached = false;
157530f4185da772fcc679db35e01148eca6eeafe15fPaul McLean    input_hardware_config_is_cached = false;
1576eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean
157719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
157819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
157919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
158030f4185da772fcc679db35e01148eca6eeafe15fPaul McLeanstatic int adev_open(const hw_module_t* module, const char* name, hw_device_t** device)
158119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson{
158219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0)
158319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -EINVAL;
158419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
1585eedc92ea4df9ab1429aaa38bbd590ab7ee20faa1Paul McLean    struct audio_device *adev = calloc(1, sizeof(struct audio_device));
158619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    if (!adev)
158719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        return -ENOMEM;
158819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
158919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.tag = HARDWARE_DEVICE_TAG;
159085e08e26258711f2fd672d9a920d88bf91410f6bEric Laurent    adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
159119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.module = (struct hw_module_t *) module;
159219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.common.close = adev_close;
159319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
159419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.init_check = adev_init_check;
159519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_voice_volume = adev_set_voice_volume;
159619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_master_volume = adev_set_master_volume;
159719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mode = adev_set_mode;
159819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_mic_mute = adev_set_mic_mute;
159919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_mic_mute = adev_get_mic_mute;
160019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.set_parameters = adev_set_parameters;
160119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_parameters = adev_get_parameters;
160219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.get_input_buffer_size = adev_get_input_buffer_size;
160319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_output_stream = adev_open_output_stream;
160419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_output_stream = adev_close_output_stream;
160519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.open_input_stream = adev_open_input_stream;
160619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.close_input_stream = adev_close_input_stream;
160719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    adev->hw_device.dump = adev_dump;
160819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
160919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    *device = &adev->hw_device.common;
161019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
161119957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    return 0;
161219957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson}
161319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
161419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstatic struct hw_module_methods_t hal_module_methods = {
161519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .open = adev_open,
161619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
161719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson
161819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilsonstruct audio_module HAL_MODULE_INFO_SYM = {
161919957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    .common = {
162019957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .tag = HARDWARE_MODULE_TAG,
162146a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
162246a9809e9cd50af84f3e554c3d4ac214a8519831Mike Lockwood        .hal_api_version = HARDWARE_HAL_API_VERSION,
162319957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .id = AUDIO_HARDWARE_MODULE_ID,
162419957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .name = "USB audio HW HAL",
162519957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .author = "The Android Open Source Project",
162619957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson        .methods = &hal_module_methods,
162719957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson    },
162819957a37a0f92257d8cccb5cbcb6e57a836d33acSimon Wilson};
1629