1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
29a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Use of this source code is governed by a BSD-style license
5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  that can be found in the LICENSE file in the root of the source
6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  tree. An additional intellectual property rights grant can be found
7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  in the file PATENTS.  All contributing project authors may
8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  be found in the AUTHORS file in the root of the source tree.
9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
10470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1150b2efef6ecb51a9d5818345c58533c5d236ec29andrew@webrtc.org#include "webrtc/voice_engine/output_mixer.h"
12470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
136955870806624479723addfae6dcf5d13968796cPeter Kasting#include "webrtc/base/format_macros.h"
1450b2efef6ecb51a9d5818345c58533c5d236ec29andrew@webrtc.org#include "webrtc/modules/audio_processing/include/audio_processing.h"
15ff761fba8274d93bd73e76c8b8a1f2d0776dd840Henrik Kjellander#include "webrtc/modules/utility/include/audio_frame_operations.h"
1698f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/critical_section_wrapper.h"
1798f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/file_wrapper.h"
1898f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/trace.h"
1950b2efef6ecb51a9d5818345c58533c5d236ec29andrew@webrtc.org#include "webrtc/voice_engine/include/voe_external_media.h"
2050b2efef6ecb51a9d5818345c58533c5d236ec29andrew@webrtc.org#include "webrtc/voice_engine/statistics.h"
2140ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org#include "webrtc/voice_engine/utility.h"
22470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
23470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comnamespace webrtc {
24470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comnamespace voe {
25470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
26470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
279213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgOutputMixer::NewMixedAudio(int32_t id,
28470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                           const AudioFrame& generalAudioFrame,
29470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                           const AudioFrame** uniqueAudioFrames,
309213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                           uint32_t size)
31470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
32470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
33470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::NewMixedAudio(id=%d, size=%u)", id, size);
34470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
35ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org    _audioFrame.CopyFrom(generalAudioFrame);
3663a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    _audioFrame.id_ = id;
37470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
38470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
399213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgvoid OutputMixer::PlayNotification(int32_t id, uint32_t durationMs)
40470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
41470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
42470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::PlayNotification(id=%d, durationMs=%d)",
43470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, durationMs);
44470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Not implement yet
45470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
46470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
479213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgvoid OutputMixer::RecordNotification(int32_t id,
489213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                     uint32_t durationMs)
49470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
50470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
51470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::RecordNotification(id=%d, durationMs=%d)",
52470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 id, durationMs);
53470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
54470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Not implement yet
55470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
56470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
579213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgvoid OutputMixer::PlayFileEnded(int32_t id)
58470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
59470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
60470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::PlayFileEnded(id=%d)", id);
61470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
62470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // not needed
63470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
64470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
659213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgvoid OutputMixer::RecordFileEnded(int32_t id)
66470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
67470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
68470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::RecordFileEnded(id=%d)", id);
69470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    assert(id == _instanceId);
70470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
719a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
72470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = false;
73470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
74470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::RecordFileEnded() =>"
75470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "output file recorder module is shutdown");
76470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
77470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
786141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
799213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgOutputMixer::Create(OutputMixer*& mixer, uint32_t instanceId)
80470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
81470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, instanceId,
82470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::Create(instanceId=%d)", instanceId);
83470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    mixer = new OutputMixer(instanceId);
84470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (mixer == NULL)
85470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
86470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceMemory, kTraceVoice, instanceId,
87470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "OutputMixer::Create() unable to allocate memory for"
88470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "mixer");
89470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
90470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
91470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
92470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
93470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
949213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.orgOutputMixer::OutputMixer(uint32_t instanceId) :
95470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
96470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _fileCritSect(*CriticalSectionWrapper::CreateCriticalSection()),
97c4f129f97c6e285ba9f82cacafdb1281996150a4andrew@webrtc.org    _mixerModule(*AudioConferenceMixer::Create(instanceId)),
98470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _audioLevel(),
9922963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _dtmfGenerator(instanceId),
10022963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _instanceId(instanceId),
10122963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _externalMediaCallbackPtr(NULL),
102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalMedia(false),
103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panLeft(1.0f),
104470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panRight(1.0f),
10522963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _mixingFrequencyHz(8000),
10622963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _outputFileRecorderPtr(NULL),
10722963abffe4179e75f18a2e7be1d1c58c9518089xians@google.com    _outputFileRecording(false)
108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1),
110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::OutputMixer() - ctor");
111ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
1120f4b3731c34e796da92572380855dbc7321c8cfeminyuel    if (_mixerModule.RegisterMixedStreamCallback(this) == -1)
113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "OutputMixer::OutputMixer() failed to register mixer"
116470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "callbacks");
117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
118ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _dtmfGenerator.Init();
120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comvoid
123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comOutputMixer::Destroy(OutputMixer*& mixer)
124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (mixer)
126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        delete mixer;
128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        mixer = NULL;
129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
131ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comOutputMixer::~OutputMixer()
133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_instanceId,-1),
135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::~OutputMixer() - dtor");
136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_externalMedia)
137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        DeRegisterExternalMediaProcessing();
139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
1419a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_fileCritSect);
142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (_outputFileRecorderPtr)
143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr->StopRecording();
146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
147470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            _outputFileRecorderPtr = NULL;
148470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
149470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
150470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _mixerModule.UnRegisterMixedStreamCallback();
151470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete &_mixerModule;
152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete &_callbackCritSect;
153470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    delete &_fileCritSect;
154470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
155470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1566141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
157470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comOutputMixer::SetEngineInformation(voe::Statistics& engineStatistics)
158470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
159470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
160470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::SetEngineInformation()");
161470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _engineStatisticsPtr = &engineStatistics;
162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1656141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
1666141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgOutputMixer::SetAudioProcessingModule(AudioProcessing* audioProcessingModule)
167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::SetAudioProcessingModule("
170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "audioProcessingModule=0x%x)", audioProcessingModule);
171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _audioProcessingModulePtr = audioProcessingModule;
172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint OutputMixer::RegisterExternalMediaProcessing(
176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    VoEMediaProcess& proccess_object)
177470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com               "OutputMixer::RegisterExternalMediaProcessing()");
180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1819a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalMediaCallbackPtr = &proccess_object;
183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalMedia = true;
184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
187470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint OutputMixer::DeRegisterExternalMediaProcessing()
189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
190470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::DeRegisterExternalMediaProcessing()");
192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1939a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_callbackCritSect);
194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalMedia = false;
195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _externalMediaCallbackPtr = NULL;
196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
197470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
198470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2006141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint OutputMixer::PlayDtmfTone(uint8_t eventCode, int lengthMs,
201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                              int attenuationDb)
202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId, -1),
204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::PlayDtmfTone()");
205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_dtmfGenerator.AddTone(eventCode, lengthMs, attenuationDb) != 0)
206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(VE_STILL_PLAYING_PREV_DTMF,
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           kTraceError,
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                           "OutputMixer::PlayDtmfTone()");
210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2156141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comOutputMixer::SetMixabilityStatus(MixerParticipant& participant,
2179213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                 bool mixable)
218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2190f4b3731c34e796da92572380855dbc7321c8cfeminyuel    return _mixerModule.SetMixabilityStatus(&participant, mixable);
220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2226141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
223066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.orgOutputMixer::SetAnonymousMixabilityStatus(MixerParticipant& participant,
2249213521ea98b0977c7cdabd2853060835af226f3pbos@webrtc.org                                          bool mixable)
225066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org{
2260f4b3731c34e796da92572380855dbc7321c8cfeminyuel    return _mixerModule.SetAnonymousMixabilityStatus(&participant, mixable);
227066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org}
228066f9e5a2fbb8e83ef88ceca0ab5a4ea057cc619henrike@webrtc.org
2296141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comOutputMixer::MixActiveChannels()
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return _mixerModule.Process();
233470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2366141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgOutputMixer::GetSpeechOutputLevel(uint32_t& level)
237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2386141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int8_t currentLevel = _audioLevel.Level();
2396141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    level = static_cast<uint32_t> (currentLevel);
240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetSpeechOutputLevel() => level=%u", level);
242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
2466141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgOutputMixer::GetSpeechOutputLevelFullRange(uint32_t& level)
247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2486141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int16_t currentLevel = _audioLevel.LevelFullRange();
2496141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    level = static_cast<uint32_t> (currentLevel);
250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetSpeechOutputLevelFullRange() => level=%u", level);
252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comOutputMixer::SetOutputVolumePan(float left, float right)
257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::SetOutputVolumePan()");
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panLeft = left;
261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _panRight = right;
262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comOutputMixer::GetOutputVolumePan(float& left, float& right)
267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    left = _panLeft;
269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    right = _panRight;
270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, VoEId(_instanceId,-1),
271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "GetOutputVolumePan() => left=%2.1f, right=%2.1f",
272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 left, right);
273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint OutputMixer::StartRecordingPlayout(const char* fileName,
277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       const CodecInst* codecInst)
278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::StartRecordingPlayout(fileName=%s)", fileName);
281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
282470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecording)
283470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
284470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
285470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StartRecordingPlayout() is already recording");
286470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
288470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
289470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileFormats format;
2906141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0);
291470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst dummyCodec={100,"L16",16000,320,1,320000};
292470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
29340197d7b3b347f05b299a930641dad131c853e01niklas.enbom@webrtc.org    if ((codecInst != NULL) &&
29440197d7b3b347f05b299a930641dad131c853e01niklas.enbom@webrtc.org      ((codecInst->channels < 1) || (codecInst->channels > 2)))
295470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() invalid compression");
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(codecInst == NULL)
302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatPcm16kHzFile;
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        codecInst=&dummyCodec;
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
310470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatWavFile;
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatCompressedFile;
315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3179a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
318ae1a58bba4f926d149a5f39243269c3f6625f494andrew@webrtc.org
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr)
321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
325470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _instanceId,
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (const FileFormats)format);
330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr == NULL)
331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() fileRecorder format isnot correct");
335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StartRecordingAudioFile(
339470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        fileName,
340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (const CodecInst&)*codecInst,
341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        notificationTime) != 0)
342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_FILE, kTraceError,
345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingAudioFile() failed to start file recording");
346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->StopRecording();
347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(this);
352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = true;
353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint OutputMixer::StartRecordingPlayout(OutStream* stream,
358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                       const CodecInst* codecInst)
359470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::StartRecordingPlayout()");
362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecording)
364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId,-1),
366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StartRecordingPlayout() is already recording");
367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return 0;
368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileFormats format;
3716141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    const uint32_t notificationTime(0);
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    CodecInst dummyCodec={100,"L16",16000,320,1,320000};
373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (codecInst != NULL && codecInst->channels != 1)
375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_BAD_ARGUMENT, kTraceError,
378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() invalid compression");
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return(-1);
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
381470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if(codecInst == NULL)
382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatPcm16kHzFile;
384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        codecInst=&dummyCodec;
385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else if((STR_CASE_CMP(codecInst->plname,"L16") == 0) ||
387470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMU") == 0) ||
388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (STR_CASE_CMP(codecInst->plname,"PCMA") == 0))
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatWavFile;
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    else
393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        format = kFileFormatCompressedFile;
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3979a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Destroy the old instance
400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr)
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
403470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
404470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
405470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
406470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
407470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = FileRecorder::CreateFileRecorder(
408470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _instanceId,
409470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        (const FileFormats)format);
410470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr == NULL)
411470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
412470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
413470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_INVALID_ARGUMENT, kTraceError,
414470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StartRecordingPlayout() fileRecorder format isnot correct");
415470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
416470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
417470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
418470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StartRecordingAudioFile(*stream,
419470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                        *codecInst,
420470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                                                        notificationTime) != 0)
421470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
422470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com       _engineStatisticsPtr->SetLastError(VE_BAD_FILE, kTraceError,
4234ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org           "StartRecordingAudioFile() failed to start file recording");
424470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr->StopRecording();
425470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
426470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _outputFileRecorderPtr = NULL;
427470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
428470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
4294ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org
430470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(this);
431470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = true;
432470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
433470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
434470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
435470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
436470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint OutputMixer::StopRecordingPlayout()
437470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
438470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_instanceId,-1),
439470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                 "OutputMixer::StopRecordingPlayout()");
440470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
441470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (!_outputFileRecording)
442470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
443470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceError, kTraceVoice, VoEId(_instanceId,-1),
444470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "StopRecordingPlayout() file isnot recording");
445470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
446470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
447470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4489a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
449470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
450470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_outputFileRecorderPtr->StopRecording() != 0)
451470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
452470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _engineStatisticsPtr->SetLastError(
453470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            VE_STOP_RECORDING_FAILED, kTraceError,
454470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            "StopRecording(), could not stop recording");
455470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
456470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
457470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr->RegisterModuleFileCallback(NULL);
458470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    FileRecorder::DestroyFileRecorder(_outputFileRecorderPtr);
459470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecorderPtr = NULL;
460470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _outputFileRecording = false;
461470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
462470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
463470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
464470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4654ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.orgint OutputMixer::GetMixedAudio(int sample_rate_hz,
4666955870806624479723addfae6dcf5d13968796cPeter Kasting                               size_t num_channels,
4674ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org                               AudioFrame* frame) {
4686955870806624479723addfae6dcf5d13968796cPeter Kasting  WEBRTC_TRACE(
4696955870806624479723addfae6dcf5d13968796cPeter Kasting      kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
4706955870806624479723addfae6dcf5d13968796cPeter Kasting      "OutputMixer::GetMixedAudio(sample_rate_hz=%d, num_channels=%" PRIuS ")",
4716955870806624479723addfae6dcf5d13968796cPeter Kasting      sample_rate_hz, num_channels);
472470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4734ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org  // --- Record playout if enabled
4744ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org  {
4754ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org    CriticalSectionScoped cs(&_fileCritSect);
4764ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org    if (_outputFileRecording && _outputFileRecorderPtr)
4774ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org      _outputFileRecorderPtr->RecordAudioToFile(_audioFrame);
4784ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org  }
479470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4804ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org  frame->num_channels_ = num_channels;
4814ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org  frame->sample_rate_hz_ = sample_rate_hz;
4824ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org  // TODO(andrew): Ideally the downmixing would occur much earlier, in
4834ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org  // AudioCodingModule.
48440ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org  RemixAndResample(_audioFrame, &resampler_, frame);
48540ee3d07eda24b8e8214429d9885d9ad9a2c04f7andrew@webrtc.org  return 0;
486470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
487470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
4886141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.orgint32_t
4895692531f18cae04d8a8107793dc74ae932bdf219xians@webrtc.orgOutputMixer::DoOperationsOnCombinedSignal(bool feed_data_to_apm)
490470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
49163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (_audioFrame.sample_rate_hz_ != _mixingFrequencyHz)
492470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
493470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_instanceId,-1),
494470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "OutputMixer::DoOperationsOnCombinedSignal() => "
49563a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org                     "mixing frequency = %d", _audioFrame.sample_rate_hz_);
49663a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        _mixingFrequencyHz = _audioFrame.sample_rate_hz_;
497470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
498470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
499470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Insert inband Dtmf tone
500470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_dtmfGenerator.IsAddingTone())
501470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
502470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        InsertInbandDtmfTone();
503470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
504470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
505470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // Scale left and/or right channel(s) if balance is active
506470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_panLeft != 1.0 || _panRight != 1.0)
507470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
50863a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        if (_audioFrame.num_channels_ == 1)
509470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
5104ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org            AudioFrameOperations::MonoToStereo(&_audioFrame);
511470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
512470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        else
513470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
514470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            // Pure stereo mode (we are receiving a stereo signal).
515470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
516470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
51763a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org        assert(_audioFrame.num_channels_ == 2);
518470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        AudioFrameOperations::Scale(_panLeft, _panRight, _audioFrame);
519470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
520470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
521470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Far-end Voice Quality Enhancement (AudioProcessing Module)
52266085beef83c790a69666b9be8a74bb2eee44fabpeah    if (feed_data_to_apm) {
52366085beef83c790a69666b9be8a74bb2eee44fabpeah      // Convert from mixing to AudioProcessing sample rate, similarly to how it
52466085beef83c790a69666b9be8a74bb2eee44fabpeah      // is done on the send side. Downmix to mono.
52566085beef83c790a69666b9be8a74bb2eee44fabpeah      AudioFrame frame;
52666085beef83c790a69666b9be8a74bb2eee44fabpeah      frame.num_channels_ = 1;
52766085beef83c790a69666b9be8a74bb2eee44fabpeah      frame.sample_rate_hz_ = _audioProcessingModulePtr->input_sample_rate_hz();
52866085beef83c790a69666b9be8a74bb2eee44fabpeah      RemixAndResample(_audioFrame, &audioproc_resampler_, &frame);
52966085beef83c790a69666b9be8a74bb2eee44fabpeah
53066085beef83c790a69666b9be8a74bb2eee44fabpeah      if (_audioProcessingModulePtr->AnalyzeReverseStream(&frame) != 0) {
53166085beef83c790a69666b9be8a74bb2eee44fabpeah        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
53266085beef83c790a69666b9be8a74bb2eee44fabpeah                     "AudioProcessingModule::AnalyzeReverseStream() => error");
53366085beef83c790a69666b9be8a74bb2eee44fabpeah        RTC_DCHECK(false);
53466085beef83c790a69666b9be8a74bb2eee44fabpeah      }
53566085beef83c790a69666b9be8a74bb2eee44fabpeah    }
536470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
537470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- External media processing
538470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
5399a065d1eae9ed296e1e2eaaad73d7ca1223bfe79mflodman@webrtc.org        CriticalSectionScoped cs(&_callbackCritSect);
540944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org        if (_externalMedia)
541470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
542944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org            const bool is_stereo = (_audioFrame.num_channels_ == 2);
543944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org            if (_externalMediaCallbackPtr)
544944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org            {
545944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org                _externalMediaCallbackPtr->Process(
546944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org                    -1,
547944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org                    kPlaybackAllChannelsMixed,
548944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org                    (int16_t*)_audioFrame.data_,
549944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org                    _audioFrame.samples_per_channel_,
550944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org                    _audioFrame.sample_rate_hz_,
551944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org                    is_stereo);
552944cbeb2926feb86a687e5fda9e2ac88ea8e3001henrika@webrtc.org            }
553470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
554470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
555470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
556470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // --- Measure audio level (0-9) for the combined signal
557470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _audioLevel.ComputeLevel(_audioFrame);
558470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
559470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
560470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
561470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
562470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// ----------------------------------------------------------------------------
5634ecea3e1057eebf846af9b93abf8faf8571bc576andrew@webrtc.org//                             Private methods
564470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com// ----------------------------------------------------------------------------
565470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
566470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint
567470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comOutputMixer::InsertInbandDtmfTone()
568470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
5696141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint16_t sampleRate(0);
570470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    _dtmfGenerator.GetSampleRate(sampleRate);
57163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (sampleRate != _audioFrame.sample_rate_hz_)
572470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
573470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Update sample rate of Dtmf tone since the mixing frequency changed.
574470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _dtmfGenerator.SetSampleRate(
5756141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org            (uint16_t)(_audioFrame.sample_rate_hz_));
576470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // Reset the tone to be added taking the new sample rate into account.
577470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        _dtmfGenerator.ResetTone();
578470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
579470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
5806141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    int16_t toneBuffer[320];
5816141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org    uint16_t toneSamples(0);
582470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (_dtmfGenerator.Get10msTone(toneBuffer, toneSamples) == -1)
583470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
584470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        WEBRTC_TRACE(kTraceWarning, kTraceVoice, VoEId(_instanceId, -1),
585470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "OutputMixer::InsertInbandDtmfTone() inserting Dtmf"
586470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com                     "tone failed");
587470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -1;
588470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
589470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
590470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    // replace mixed audio with Dtmf tone
59163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    if (_audioFrame.num_channels_ == 1)
592470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
593470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // mono
5946141e13873d0fdea626de08dfec2efa2c9171c76pbos@webrtc.org        memcpy(_audioFrame.data_, toneBuffer, sizeof(int16_t)
595470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com            * toneSamples);
596470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else
597470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
598470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        // stereo
599dce40cf804019a9898b6ab8d8262466b697c56e0Peter Kasting        for (size_t i = 0; i < _audioFrame.samples_per_channel_; i++)
600470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
60163a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org            _audioFrame.data_[2 * i] = toneBuffer[i];
60263a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org            _audioFrame.data_[2 * i + 1] = 0;
603470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
604470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
60563a509858d3988299726640c664b699d6229a1d4andrew@webrtc.org    assert(_audioFrame.samples_per_channel_ == toneSamples);
606470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
607470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return 0;
608470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
609470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
610d900e8bea84c474696bf0219aed1353ce65ffd8epbos@webrtc.org}  // namespace voe
611d900e8bea84c474696bf0219aed1353ce65ffd8epbos@webrtc.org}  // namespace webrtc
612