[go: nahoru, domu]

199e53b86eebb605b70dd7591b89bf61a9414ed0eGlenn Kasten/*
265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian**
365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian** Copyright 2007, The Android Open Source Project
465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian**
565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian** Licensed under the Apache License, Version 2.0 (the "License");
665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian** you may not use this file except in compliance with the License.
765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian** You may obtain a copy of the License at
865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian**
965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian**     http://www.apache.org/licenses/LICENSE-2.0
1065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian**
1165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian** Unless required by applicable law or agreed to in writing, software
1265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian** distributed under the License is distributed on an "AS IS" BASIS,
1365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian** See the License for the specific language governing permissions and
1565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian** limitations under the License.
1665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*/
1765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifndef ANDROID_AUDIO_MIXER_H
1965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ANDROID_AUDIO_MIXER_H
2065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <stdint.h>
2265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <sys/types.h>
2365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2436802bd18b7b4e8c87fa019c7e3068bee330d174Dan Albert#include <hardware/audio_effect.h>
2536802bd18b7b4e8c87fa019c7e3068bee330d174Dan Albert#include <media/AudioBufferProvider.h>
265a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia#include <media/AudioResamplerPublic.h>
2736802bd18b7b4e8c87fa019c7e3068bee330d174Dan Albert#include <media/nbaio/NBLog.h>
2836802bd18b7b4e8c87fa019c7e3068bee330d174Dan Albert#include <system/audio.h>
2936802bd18b7b4e8c87fa019c7e3068bee330d174Dan Albert#include <utils/Compat.h>
307d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi#include <utils/threads.h>
317d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi
3265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResampler.h"
33857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung#include "BufferProviders.h"
3465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
35c56f3426099a3cf2d07ccff8886050c7fbce140fGlenn Kasten// FIXME This is actually unity gain, which might not be max in future, expressed in U.12
3697ae82408469286426d8dc57a361350f74e24a8bAndy Hung#define MAX_GAIN_INT AudioMixer::UNITY_GAIN_INT
37c56f3426099a3cf2d07ccff8886050c7fbce140fGlenn Kasten
3865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiannamespace android {
3965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
4065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
4165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
4265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianclass AudioMixer
4365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
4465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianpublic:
455c94b6c7689a335e26a86e8a0d04b56dc627738eGlenn Kasten                            AudioMixer(size_t frameCount, uint32_t sampleRate,
465c94b6c7689a335e26a86e8a0d04b56dc627738eGlenn Kasten                                       uint32_t maxNumTracks = MAX_NUM_TRACKS);
4765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
48c19e22450e6e3d07594c935c7a9522e85e909e82Glenn Kasten    /*virtual*/             ~AudioMixer();  // non-virtual saves a v-table, restore if sub-classed
4965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
50599fabc596687efa4b71b8f3ebbb957c7cae0c72Glenn Kasten
51599fabc596687efa4b71b8f3ebbb957c7cae0c72Glenn Kasten    // This mixer has a hard-coded upper limit of 32 active track inputs.
52599fabc596687efa4b71b8f3ebbb957c7cae0c72Glenn Kasten    // Adding support for > 32 tracks would require more than simply changing this value.
5365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    static const uint32_t MAX_NUM_TRACKS = 32;
547d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi    // maximum number of channels supported by the mixer
55599fabc596687efa4b71b8f3ebbb957c7cae0c72Glenn Kasten
56e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    // This mixer has a hard-coded upper limit of 8 channels for output.
57e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    static const uint32_t MAX_NUM_CHANNELS = 8;
58e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    static const uint32_t MAX_NUM_VOLUMES = 2; // stereo volume only
597d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi    // maximum number of channels supported for the content
60e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    static const uint32_t MAX_NUM_CHANNELS_TO_DOWNMIX = AUDIO_CHANNEL_COUNT_MAX;
6165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
6297ae82408469286426d8dc57a361350f74e24a8bAndy Hung    static const uint16_t UNITY_GAIN_INT = 0x1000;
6336802bd18b7b4e8c87fa019c7e3068bee330d174Dan Albert    static const CONSTEXPR float UNITY_GAIN_FLOAT = 1.0f;
6465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
6565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    enum { // names
6665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
679c56d4ae6212c21ce5fd71ed534eb195983a07c1Glenn Kasten        // track names (MAX_NUM_TRACKS units)
6865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        TRACK0          = 0x1000,
6965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
701c48c3c61970527b97892ab6a2daae8eaac26964Glenn Kasten        // 0x2000 is unused
7165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
7265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // setParameter targets
7365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        TRACK           = 0x3000,
7465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        RESAMPLE        = 0x3001,
7565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        RAMP_VOLUME     = 0x3002, // ramp to new volume
7665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        VOLUME          = 0x3003, // don't ramp
77c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung        TIMESTRETCH     = 0x3004,
7865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
7965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // set Parameter names
8065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // for target TRACK
810d255b2d9061ba31f13ada3fc0f7e51916407176Jean-Michel Trivi        CHANNEL_MASK    = 0x4000,
8265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        FORMAT          = 0x4001,
8365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        MAIN_BUFFER     = 0x4002,
8465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        AUX_BUFFER      = 0x4003,
857d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi        DOWNMIX_TYPE    = 0X4004,
86788207057ed4b8df4719ed8089f376ef52de9ca1Andy Hung        MIXER_FORMAT    = 0x4005, // AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
87e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        MIXER_CHANNEL_MASK = 0x4006, // Channel mask for mixer output
88362c4e697d8e9c034e964ac7b40227e054491547Glenn Kasten        // for target RESAMPLE
894e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten        SAMPLE_RATE     = 0x4100, // Configure sample rate conversion on this track name;
904e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten                                  // parameter 'value' is the new sample rate in Hz.
914e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten                                  // Only creates a sample rate converter the first time that
924e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten                                  // the track sample rate is different from the mix sample rate.
934e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten                                  // If the new sample rate is the same as the mix sample rate,
944e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten                                  // and a sample rate converter already exists,
954e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten                                  // then the sample rate converter remains present but is a no-op.
964e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten        RESET           = 0x4101, // Reset sample rate converter without changing sample rate.
974e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten                                  // This clears out the resampler's input buffer.
984e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten        REMOVE          = 0x4102, // Remove the sample rate converter on this track name;
994e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten                                  // the track is restored to the mix sample rate.
100362c4e697d8e9c034e964ac7b40227e054491547Glenn Kasten        // for target RAMP_VOLUME and VOLUME (8 channels max)
101c56f3426099a3cf2d07ccff8886050c7fbce140fGlenn Kasten        // FIXME use float for these 3 to improve the dynamic range
10265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        VOLUME0         = 0x4200,
10365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        VOLUME1         = 0x4201,
10465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        AUXLEVEL        = 0x4210,
105c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung        // for target TIMESTRETCH
106c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung        PLAYBACK_RATE   = 0x4300, // Configure timestretch on this track name;
107c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung                                  // parameter 'value' is a pointer to the new playback rate.
10865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    };
10965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
11065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1119c56d4ae6212c21ce5fd71ed534eb195983a07c1Glenn Kasten    // For all APIs with "name": TRACK0 <= name < TRACK0 + MAX_NUM_TRACKS
11217a736c3e1d062d7fc916329eb32aef8935614afGlenn Kasten
11317a736c3e1d062d7fc916329eb32aef8935614afGlenn Kasten    // Allocate a track name.  Returns new track name if successful, -1 on failure.
114e8a1ced4da17dc6c07803dc2af8060f62a8389c1Andy Hung    // The failure could be because of an invalid channelMask or format, or that
115e8a1ced4da17dc6c07803dc2af8060f62a8389c1Andy Hung    // the track capacity of the mixer is exceeded.
116e8a1ced4da17dc6c07803dc2af8060f62a8389c1Andy Hung    int         getTrackName(audio_channel_mask_t channelMask,
117e8a1ced4da17dc6c07803dc2af8060f62a8389c1Andy Hung                             audio_format_t format, int sessionId);
11817a736c3e1d062d7fc916329eb32aef8935614afGlenn Kasten
11917a736c3e1d062d7fc916329eb32aef8935614afGlenn Kasten    // Free an allocated track by name
12065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    void        deleteTrackName(int name);
12165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
12217a736c3e1d062d7fc916329eb32aef8935614afGlenn Kasten    // Enable or disable an allocated track by name
1239c56d4ae6212c21ce5fd71ed534eb195983a07c1Glenn Kasten    void        enable(int name);
1249c56d4ae6212c21ce5fd71ed534eb195983a07c1Glenn Kasten    void        disable(int name);
12565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1269c56d4ae6212c21ce5fd71ed534eb195983a07c1Glenn Kasten    void        setParameter(int name, int target, int param, void *value);
12765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1289c56d4ae6212c21ce5fd71ed534eb195983a07c1Glenn Kasten    void        setBufferProvider(int name, AudioBufferProvider* bufferProvider);
129d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten    void        process();
13065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
13165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    uint32_t    trackNames() const { return mTrackNames; }
13265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
133c59c004a3a6042c0990d71179f88eee2ce781e3cGlenn Kasten    size_t      getUnreleasedFrames(int name) const;
134071ccd5a9702500f3f7d62ef881300914926184dEric Laurent
135e8a1ced4da17dc6c07803dc2af8060f62a8389c1Andy Hung    static inline bool isValidPcmTrackFormat(audio_format_t format) {
136abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung        switch (format) {
137abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung        case AUDIO_FORMAT_PCM_8_BIT:
138abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung        case AUDIO_FORMAT_PCM_16_BIT:
139abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung        case AUDIO_FORMAT_PCM_24_BIT_PACKED:
140abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung        case AUDIO_FORMAT_PCM_32_BIT:
141abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung        case AUDIO_FORMAT_PCM_FLOAT:
142abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung            return true;
143abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung        default:
144abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung            return false;
145abdb990953ffe94a9dc544aea0bed17ef7d5f484Andy Hung        }
146e8a1ced4da17dc6c07803dc2af8060f62a8389c1Andy Hung    }
147e8a1ced4da17dc6c07803dc2af8060f62a8389c1Andy Hung
14865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianprivate:
14965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
15065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    enum {
151d6fadf0479b489b09b764070974d8a59855ede64Glenn Kasten        // FIXME this representation permits up to 8 channels
1527d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi        NEEDS_CHANNEL_COUNT__MASK   = 0x00000007,
15365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    };
15465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
15565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    enum {
156d6fadf0479b489b09b764070974d8a59855ede64Glenn Kasten        NEEDS_CHANNEL_1             = 0x00000000,   // mono
157d6fadf0479b489b09b764070974d8a59855ede64Glenn Kasten        NEEDS_CHANNEL_2             = 0x00000001,   // stereo
15865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
159d6fadf0479b489b09b764070974d8a59855ede64Glenn Kasten        // sample format is not explicitly specified, and is assumed to be AUDIO_FORMAT_PCM_16_BIT
16065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
161d6fadf0479b489b09b764070974d8a59855ede64Glenn Kasten        NEEDS_MUTE                  = 0x00000100,
162d6fadf0479b489b09b764070974d8a59855ede64Glenn Kasten        NEEDS_RESAMPLE              = 0x00001000,
163d6fadf0479b489b09b764070974d8a59855ede64Glenn Kasten        NEEDS_AUX                   = 0x00010000,
16465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    };
16565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
16665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    struct state_t;
16765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    struct track_t;
16865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
16985ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten    typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp,
17085ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten                           int32_t* aux);
17165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    static const int BLOCKSIZE = 16; // 4 cache lines
17265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
17365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    struct track_t {
17465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        uint32_t    needs;
17565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1765e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        // TODO: Eventually remove legacy integer volume settings
17765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        union {
178e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        int16_t     volume[MAX_NUM_VOLUMES]; // U4.12 fixed point (top bit should be zero)
17965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int32_t     volumeRL;
18065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        };
18165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
182e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        int32_t     prevVolume[MAX_NUM_VOLUMES];
18365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1843b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten        // 16-byte boundary
1853b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten
186e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        int32_t     volumeInc[MAX_NUM_VOLUMES];
18765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int32_t     auxInc;
18865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int32_t     prevAuxLevel;
18965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1903b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten        // 16-byte boundary
1913b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten
1923b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten        int16_t     auxLevel;       // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance
19365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        uint16_t    frameCount;
19465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1953b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten        uint8_t     channelCount;   // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
196ef7c7fbd0e3fb36af14cd7d39f64c949031516a5Andy Hung        uint8_t     unused_padding; // formerly format, was always 16
1973b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten        uint16_t    enabled;        // actually bool
1987d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi        audio_channel_mask_t channelMask;
19965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2007d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi        // actual buffer provider used by the track hooks, see DownmixerBufferProvider below
2017d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi        //  for how the Track buffer provider is wrapped by another one when dowmixing is required
20265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        AudioBufferProvider*                bufferProvider;
2033b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten
2043b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten        // 16-byte boundary
2053b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten
2063b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten        mutable AudioBufferProvider::Buffer buffer; // 8 bytes
20765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
20865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        hook_t      hook;
20954c3b66444ebfb9f2265ee70ac3b76ccefa0506aGlenn Kasten        const void* in;             // current location in buffer
21065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2113b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten        // 16-byte boundary
2123b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten
21365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        AudioResampler*     resampler;
21465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        uint32_t            sampleRate;
21565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int32_t*           mainBuffer;
21665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int32_t*           auxBuffer;
21765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2183b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten        // 16-byte boundary
2197f47549516ae5938759b5c834c8423378a60b3d8Andy Hung
2207f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        /* Buffer providers are constructed to translate the track input data as needed.
2217f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         *
222c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung         * TODO: perhaps make a single PlaybackConverterProvider class to move
223c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung         * all pre-mixer track buffer conversions outside the AudioMixer class.
224c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung         *
2257f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         * 1) mInputBufferProvider: The AudioTrack buffer provider.
2267f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         * 2) mReformatBufferProvider: If not NULL, performs the audio reformat to
2277f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         *    match either mMixerInFormat or mDownmixRequiresFormat, if the downmixer
2287f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         *    requires reformat. For example, it may convert floating point input to
2297f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         *    PCM_16_bit if that's required by the downmixer.
2307f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         * 3) downmixerBufferProvider: If not NULL, performs the channel remixing to match
2317f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         *    the number of channels required by the mixer sink.
2327f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         * 4) mPostDownmixReformatBufferProvider: If not NULL, performs reformatting from
2337f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         *    the downmixer requirements to the mixer engine input requirements.
234c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung         * 5) mTimestretchBufferProvider: Adds timestretching for playback rate
2357f47549516ae5938759b5c834c8423378a60b3d8Andy Hung         */
2361b2fdcb005f9fbe5ad465cec46ec5992b718b5e3Andy Hung        AudioBufferProvider*     mInputBufferProvider;    // externally provided buffer provider.
237857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung        PassthruBufferProvider*  mReformatBufferProvider; // provider wrapper for reformatting.
238857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung        PassthruBufferProvider*  downmixerBufferProvider; // wrapper for channel conversion.
239857d5a20a956ef61b64ae07b018ecc2f1eb0a503Andy Hung        PassthruBufferProvider*  mPostDownmixReformatBufferProvider;
240c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung        PassthruBufferProvider*  mTimestretchBufferProvider;
2417d5b26230a179cd7bcc01f6578cd80d8c15a92a5Jean-Michel Trivi
242d06e132358d44f02c22527b4f463df1f58da9216Jean-Michel Trivi        int32_t     sessionId;
243d06e132358d44f02c22527b4f463df1f58da9216Jean-Michel Trivi
244e8a1ced4da17dc6c07803dc2af8060f62a8389c1Andy Hung        audio_format_t mMixerFormat;     // output mix format: AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
245e8a1ced4da17dc6c07803dc2af8060f62a8389c1Andy Hung        audio_format_t mFormat;          // input track format
246ef7c7fbd0e3fb36af14cd7d39f64c949031516a5Andy Hung        audio_format_t mMixerInFormat;   // mix internal format AUDIO_FORMAT_PCM_(FLOAT|16_BIT)
247ef7c7fbd0e3fb36af14cd7d39f64c949031516a5Andy Hung                                         // each track must be converted to this format.
2487f47549516ae5938759b5c834c8423378a60b3d8Andy Hung        audio_format_t mDownmixRequiresFormat;  // required downmixer format
2497f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                                                // AUDIO_FORMAT_PCM_16_BIT if 16 bit necessary
2507f47549516ae5938759b5c834c8423378a60b3d8Andy Hung                                                // AUDIO_FORMAT_INVALID if no required format
251ef7c7fbd0e3fb36af14cd7d39f64c949031516a5Andy Hung
252e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        float          mVolume[MAX_NUM_VOLUMES];     // floating point set volume
253e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        float          mPrevVolume[MAX_NUM_VOLUMES]; // floating point previous volume
254e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        float          mVolumeInc[MAX_NUM_VOLUMES];  // floating point volume increment
2555e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
2565e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        float          mAuxLevel;                     // floating point set aux level
2575e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        float          mPrevAuxLevel;                 // floating point prev aux level
2585e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        float          mAuxInc;                       // floating point aux increment
2593b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten
260e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        audio_channel_mask_t mMixerChannelMask;
261e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        uint32_t             mMixerChannelCount;
2623b81acab52b7140c1b8b20be2d67be3e221637e7Glenn Kasten
2635a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia        AudioPlaybackRate    mPlaybackRate;
264c5656cc900aeb4a705e27508dd82c70030a97709Andy Hung
265296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        bool        needsRamp() { return (volumeInc[0] | volumeInc[1] | auxInc) != 0; }
266e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung        bool        setResampler(uint32_t trackSampleRate, uint32_t devSampleRate);
267c59c004a3a6042c0990d71179f88eee2ce781e3cGlenn Kasten        bool        doesResample() const { return resampler != NULL; }
268c59c004a3a6042c0990d71179f88eee2ce781e3cGlenn Kasten        void        resetResampler() { if (resampler != NULL) resampler->reset(); }
2695e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        void        adjustVolumeRamp(bool aux, bool useFloat = false);
270c59c004a3a6042c0990d71179f88eee2ce781e3cGlenn Kasten        size_t      getUnreleasedFrames() const { return resampler != NULL ?
271c59c004a3a6042c0990d71179f88eee2ce781e3cGlenn Kasten                                                    resampler->getUnreleasedFrames() : 0; };
2720f451e92f09e089e588f303f729425a54fcd804bAndy Hung
2730f451e92f09e089e588f303f729425a54fcd804bAndy Hung        status_t    prepareForDownmix();
2740f451e92f09e089e588f303f729425a54fcd804bAndy Hung        void        unprepareForDownmix();
2750f451e92f09e089e588f303f729425a54fcd804bAndy Hung        status_t    prepareForReformat();
2760f451e92f09e089e588f303f729425a54fcd804bAndy Hung        void        unprepareForReformat();
2775a8a95de6dad1a3bcf3da5a37b35766e89086e13Ricardo Garcia        bool        setPlaybackRate(const AudioPlaybackRate &playbackRate);
2780f451e92f09e089e588f303f729425a54fcd804bAndy Hung        void        reconfigureBufferProviders();
27965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    };
28065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
281d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten    typedef void (*process_hook_t)(state_t* state);
282296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
28365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // pad to 32-bytes to fill cache line
28465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    struct state_t {
28565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        uint32_t        enabledTracks;
28665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        uint32_t        needsChanged;
28765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        size_t          frameCount;
288296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        process_hook_t  hook;   // one of process__*, never NULL
28965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int32_t         *outputTemp;
29065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int32_t         *resampleTemp;
291ab7d72f0804fbb7e91ad9d2a16f826d97e20e5d0Glenn Kasten        NBLog::Writer*  mLog;
292ab7d72f0804fbb7e91ad9d2a16f826d97e20e5d0Glenn Kasten        int32_t         reserved[1];
2935c94b6c7689a335e26a86e8a0d04b56dc627738eGlenn Kasten        // FIXME allocate dynamically to save some memory when maxNumTracks < MAX_NUM_TRACKS
29401d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kasten        track_t         tracks[MAX_NUM_TRACKS] __attribute__((aligned(32)));
29565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    };
29665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2979c56d4ae6212c21ce5fd71ed534eb195983a07c1Glenn Kasten    // bitmask of allocated track names, where bit 0 corresponds to TRACK0 etc.
29865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    uint32_t        mTrackNames;
2995c94b6c7689a335e26a86e8a0d04b56dc627738eGlenn Kasten
3005c94b6c7689a335e26a86e8a0d04b56dc627738eGlenn Kasten    // bitmask of configured track names; ~0 if maxNumTracks == MAX_NUM_TRACKS,
3015c94b6c7689a335e26a86e8a0d04b56dc627738eGlenn Kasten    // but will have fewer bits set if maxNumTracks < MAX_NUM_TRACKS
3025c94b6c7689a335e26a86e8a0d04b56dc627738eGlenn Kasten    const uint32_t  mConfiguredNames;
3035c94b6c7689a335e26a86e8a0d04b56dc627738eGlenn Kasten
30465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    const uint32_t  mSampleRate;
30565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
306ab7d72f0804fbb7e91ad9d2a16f826d97e20e5d0Glenn Kasten    NBLog::Writer   mDummyLog;
307ab7d72f0804fbb7e91ad9d2a16f826d97e20e5d0Glenn Kastenpublic:
308ab7d72f0804fbb7e91ad9d2a16f826d97e20e5d0Glenn Kasten    void            setLog(NBLog::Writer* log);
309ab7d72f0804fbb7e91ad9d2a16f826d97e20e5d0Glenn Kastenprivate:
31065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    state_t         mState __attribute__((aligned(32)));
31165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
3124e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten    // Call after changing either the enabled status of a track, or parameters of an enabled track.
3134e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten    // OK to call more often than that, but unnecessary.
31465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    void invalidateState(uint32_t mask);
3154e2293f29f2e719af1245d365747ea06d074b345Glenn Kasten
316e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    bool setChannelMasks(int name,
317e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung            audio_channel_mask_t trackChannelMask, audio_channel_mask_t mixerChannelMask);
318e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung
31985ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
32085ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten            int32_t* aux);
32165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
32285ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten    static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
32385ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten            int32_t* aux);
32485ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten    static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp,
32585ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten            int32_t* aux);
32685ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp,
32785ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten            int32_t* aux);
32885ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten    static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp,
32985ab62c4b433df3f1a9826bed1c9bec07a86c750Glenn Kasten            int32_t* aux);
33065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
331d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten    static void process__validate(state_t* state);
332d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten    static void process__nop(state_t* state);
333d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten    static void process__genericNoResampling(state_t* state);
334d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten    static void process__genericResampling(state_t* state);
335d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten    static void process__OneTrack16BitsStereoNoResampling(state_t* state);
3364ff14bae91075eb274eb1c2975982358946e7e63John Grossman
33752008f821a5202502a82a8ba2c024e69bd336350Glenn Kasten    static pthread_once_t   sOnceControl;
33852008f821a5202502a82a8ba2c024e69bd336350Glenn Kasten    static void             sInitRoutine();
339296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
3405e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    /* multi-format volume mixing function (calls template functions
3415e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung     * in AudioMixerOps.h).  The template parameters are as follows:
3425e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung     *
3435e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung     *   MIXTYPE     (see AudioMixerOps.h MIXTYPE_* enumeration)
3445e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung     *   USEFLOATVOL (set to true if float volume is used)
3455e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung     *   ADJUSTVOL   (set to true if volume ramp parameters needs adjustment afterwards)
3465e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung     *   TO: int32_t (Q4.27) or float
3475e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung     *   TI: int32_t (Q4.27) or int16_t (Q0.15) or float
3485e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung     *   TA: int32_t (Q4.27)
3495e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung     */
350e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    template <int MIXTYPE, bool USEFLOATVOL, bool ADJUSTVOL,
3515e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        typename TO, typename TI, typename TA>
3525e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    static void volumeMix(TO *out, size_t outFrames,
3535e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung            const TI *in, TA *aux, bool ramp, AudioMixer::track_t *t);
3545e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung
355296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    // multi-format process hooks
356e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    template <int MIXTYPE, typename TO, typename TI, typename TA>
357d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten    static void process_NoResampleOneTrack(state_t* state);
358296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
359296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    // multi-format track hooks
360e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    template <int MIXTYPE, typename TO, typename TI, typename TA>
361296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static void track__Resample(track_t* t, TO* out, size_t frameCount,
362296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            TO* temp __unused, TA* aux);
363e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    template <int MIXTYPE, typename TO, typename TI, typename TA>
364296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static void track__NoResample(track_t* t, TO* out, size_t frameCount,
365296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            TO* temp __unused, TA* aux);
366296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
367296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    static void convertMixerFormat(void *out, audio_format_t mixerOutFormat,
368296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            void *in, audio_format_t mixerInFormat, size_t sampleCount);
369296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
370296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    // hook types
371296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    enum {
372296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        PROCESSTYPE_NORESAMPLEONETRACK,
373296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    };
374296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    enum {
375296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        TRACKTYPE_NOP,
376296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        TRACKTYPE_RESAMPLE,
377296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        TRACKTYPE_NORESAMPLE,
378296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung        TRACKTYPE_NORESAMPLEMONO,
379296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    };
380296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung
381296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung    // functions for determining the proper process and track hooks.
382e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    static process_hook_t getProcessHook(int processType, uint32_t channelCount,
383296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            audio_format_t mixerInFormat, audio_format_t mixerOutFormat);
384e93b6b7347a7846c8fd746542364ec11b0cd5124Andy Hung    static hook_t getTrackHook(int trackType, uint32_t channelCount,
385296b741e8eb38e749e3202182f703a2e30ee5f1fAndy Hung            audio_format_t mixerInFormat, audio_format_t mixerOutFormat);
38665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian};
38765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
38865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
38963238efb0d674758902918e3cdaac322126484b7Glenn Kasten} // namespace android
39065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
39165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ANDROID_AUDIO_MIXER_H
392