summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMisael Lopez Cruz2013-11-08 02:26:44 -0600
committerMisael Lopez Cruz2013-11-11 17:12:33 -0600
commit9298ec8849f12a2d30ec1a9bffe1400badf1304b (patch)
treea66759707aa87acf8d6dd634894ba1963c162a7f /audio/multizone/AudioHw.cpp
parentd25b28640179643da45a8107efab7922be3d8e54 (diff)
downloaddevice-ti-jacinto6evm-9298ec8849f12a2d30ec1a9bffe1400badf1304b.tar.gz
device-ti-jacinto6evm-9298ec8849f12a2d30ec1a9bffe1400badf1304b.tar.xz
device-ti-jacinto6evm-9298ec8849f12a2d30ec1a9bffe1400badf1304b.zip
audio: Multizone: Add support for voice call
Voice call is supported using two data pipes: Uplink: PcmWriter <-- MonoPipe <-- PcmReader | | McASP7 McASP3 | | Bluetooth Mic Downlink: PcmReader --> MonoPipe --> PcmWriter | | McASP7 McASP3 | | Bluetooth Speaker Voice call reuses the PcmWriter associated with Cabin/Speaker that is otherwise used for media. So, when the voice call starts any ongoing media stream active on that writer has to be re-routed to a null writer and routed back to the actual writer when the voice call ends. The null writer is a PcmWriter that writes data to a null output port. The null port consumes the data at the same rate that the actual port does. IOW, media streams going to the Cabin output (primary output) during voice call will not be rendered on the actual hardware output. Change-Id: I7856b67ab1cf788ea2f2cb251d9097e57e487cb5 Signed-off-by: Misael Lopez Cruz <misael.lopez@ti.com>
Diffstat (limited to 'audio/multizone/AudioHw.cpp')
-rw-r--r--audio/multizone/AudioHw.cpp325
1 files changed, 316 insertions, 9 deletions
diff --git a/audio/multizone/AudioHw.cpp b/audio/multizone/AudioHw.cpp
index 9b432e9..a7e3586 100644
--- a/audio/multizone/AudioHw.cpp
+++ b/audio/multizone/AudioHw.cpp
@@ -36,8 +36,8 @@ AudioStreamOut::AudioStreamOut(AudioHwDevice *hwDev,
36 const PcmParams &params, 36 const PcmParams &params,
37 const SlotMap &map, 37 const SlotMap &map,
38 audio_devices_t devices) 38 audio_devices_t devices)
39 : mHwDev(hwDev), mWriter(writer), 39 : mHwDev(hwDev), mNullWriter(&mNullPort, params), mWriter(writer),
40 mParams(params), mDevices(devices), mStandby(true) 40 mParams(params), mDevices(devices), mStandby(true), mUsedForVoiceCall(false)
41{ 41{
42 if (mWriter) 42 if (mWriter)
43 mStream = new AdaptedOutStream(params, map); 43 mStream = new AdaptedOutStream(params, map);
@@ -134,7 +134,21 @@ int AudioStreamOut::setFormat(audio_format_t format)
134/* must be called with mLock */ 134/* must be called with mLock */
135int AudioStreamOut::resume() 135int AudioStreamOut::resume()
136{ 136{
137 int ret = mWriter->registerStream(mStream); 137 ALOGV("AudioStreamOut: resume using %s writer",
138 mUsedForVoiceCall ? "null" : "regular");
139
140 /*
141 * Switching PCM writers is done under the assumption that the non-null
142 * writer (mWriter) is always open (but possibly in standby), which is
143 * achieved by using the primary output for voice calls.
144 */
145 PcmWriter *writer;
146 if (mUsedForVoiceCall)
147 writer = &mNullWriter;
148 else
149 writer = mWriter;
150
151 int ret = writer->registerStream(mStream);
138 if (ret) { 152 if (ret) {
139 ALOGE("AudioStreamOut: failed to register stream %d", ret); 153 ALOGE("AudioStreamOut: failed to register stream %d", ret);
140 return ret; 154 return ret;
@@ -143,7 +157,7 @@ int AudioStreamOut::resume()
143 ret = mStream->start(); 157 ret = mStream->start();
144 if (ret) { 158 if (ret) {
145 ALOGE("AudioStreamOut: failed to start stream %d", ret); 159 ALOGE("AudioStreamOut: failed to start stream %d", ret);
146 mWriter->unregisterStream(mStream); 160 writer->unregisterStream(mStream);
147 } 161 }
148 162
149 return ret; 163 return ret;
@@ -152,8 +166,17 @@ int AudioStreamOut::resume()
152/* must be called with mLock */ 166/* must be called with mLock */
153void AudioStreamOut::idle() 167void AudioStreamOut::idle()
154{ 168{
169 ALOGV("AudioStreamOut: idle using %s writer",
170 mUsedForVoiceCall ? "null" : "regular");
171
172 PcmWriter *writer;
173 if (mUsedForVoiceCall)
174 writer = &mNullWriter;
175 else
176 writer = mWriter;
177
155 mStream->stop(); 178 mStream->stop();
156 mWriter->unregisterStream(mStream); 179 writer->unregisterStream(mStream);
157} 180}
158 181
159int AudioStreamOut::standby() 182int AudioStreamOut::standby()
@@ -170,6 +193,31 @@ int AudioStreamOut::standby()
170 return 0; 193 return 0;
171} 194}
172 195
196void AudioStreamOut::setVoiceCall(bool on)
197{
198 ALOGV("AudioStreamOut: standby()");
199
200 AutoMutex lock(mLock);
201
202 /*
203 * Voice call reuses one of the PCM writers that is otherwise used
204 * for media. Media has to be re-routed to a null writer (that only
205 * consumes the data but doesn't write it to the hardware) when the
206 * voice call starts and routed back to the actual writer when the
207 * voice call stops.
208 * Temporarily entering standby helps transitioning to the null writer
209 * the next time that data is written to the stream if the voice call
210 * occurs at mid-stream.
211 */
212 if (mUsedForVoiceCall != on) {
213 if (!mStandby) {
214 idle();
215 mStandby = true;
216 }
217 mUsedForVoiceCall = on;
218 }
219}
220
173int AudioStreamOut::dump(int fd) const 221int AudioStreamOut::dump(int fd) const
174{ 222{
175 ALOGV("AudioStreamOut: dump()"); 223 ALOGV("AudioStreamOut: dump()");
@@ -549,8 +597,11 @@ uint32_t AudioStreamIn::getInputFramesLost()
549 597
550/* ---------------------------------------------------------------------------------------- */ 598/* ---------------------------------------------------------------------------------------- */
551 599
600const char *AudioHwDevice::kCabinVolumeHP = "HP DAC Playback Volume";
601const char *AudioHwDevice::kCabinVolumeLine = "Line DAC Playback Volume";
602
552AudioHwDevice::AudioHwDevice(uint32_t card) 603AudioHwDevice::AudioHwDevice(uint32_t card)
553 : mCardId(card), mMixer(mCardId), mMicMute(false) 604 : mCardId(card), mMixer(mCardId), mMicMute(false), mMode(AUDIO_MODE_NORMAL)
554{ 605{
555 ALOGI("AudioHwDevice: create hw device for card hw:%u", card); 606 ALOGI("AudioHwDevice: create hw device for card hw:%u", card);
556 607
@@ -583,6 +634,34 @@ AudioHwDevice::AudioHwDevice(uint32_t card)
583 writer = new PcmWriter(mOutPorts[kJAMR3PortId], params1); 634 writer = new PcmWriter(mOutPorts[kJAMR3PortId], params1);
584 mWriters.push_back(writer); 635 mWriters.push_back(writer);
585 636
637 /* Voice call */
638 PcmParams paramsBT(kBTNumChannels, kSampleSize, kBTSampleRate, kBTFrameCount);
639 writer = new PcmWriter(mOutPorts[kBTPortId], paramsBT);
640 mWriters.push_back(writer);
641 reader = new PcmReader(mInPorts[kBTPortId], paramsBT);
642 mReaders.push_back(reader);
643
644 /* BT is configured as stereo but only the left channel carries data */
645 SlotMap slots;
646 slots[0] = 0;
647 slots[1] = 0;
648
649 /* Voice call uplink */
650 mULPipe = new tiaudioutils::MonoPipe(paramsBT,
651 (kVoiceCallPipeMs * paramsBT.sampleRate) / 1000);
652 mULPipeWriter = new PipeWriter(mULPipe);
653 mULPipeReader = new PipeReader(mULPipe);
654 mVoiceULInStream = new InStream(paramsBT, slots, mULPipeWriter);
655 mVoiceULOutStream = new OutStream(paramsBT, slots, mULPipeReader);
656
657 /* Voice call downlink */
658 mDLPipe = new tiaudioutils::MonoPipe(paramsBT,
659 (kVoiceCallPipeMs * params0.sampleRate) / 1000);
660 mDLPipeWriter = new PipeWriter(mDLPipe);
661 mDLPipeReader = new PipeReader(mDLPipe);
662 mVoiceDLInStream = new InStream(paramsBT, slots, mDLPipeWriter);
663 mVoiceDLOutStream = new OutStream(paramsBT, slots, mDLPipeReader);
664
586 mMixer.initRoutes(); 665 mMixer.initRoutes();
587} 666}
588 667
@@ -590,6 +669,24 @@ AudioHwDevice::~AudioHwDevice()
590{ 669{
591 ALOGI("AudioHwDevice: destroy hw device for card hw:%u", mCardId); 670 ALOGI("AudioHwDevice: destroy hw device for card hw:%u", mCardId);
592 671
672 if (mDLPipeWriter)
673 delete mDLPipeWriter;
674
675 if (mDLPipeReader)
676 delete mDLPipeReader;
677
678 if (mDLPipe)
679 delete mDLPipe;
680
681 if (mULPipeWriter)
682 delete mULPipeWriter;
683
684 if (mULPipeReader)
685 delete mULPipeReader;
686
687 if (mULPipe)
688 delete mULPipe;
689
593 for (WriterVect::const_iterator i = mWriters.begin(); i != mWriters.end(); ++i) { 690 for (WriterVect::const_iterator i = mWriters.begin(); i != mWriters.end(); ++i) {
594 delete (*i); 691 delete (*i);
595 } 692 }
@@ -640,13 +737,49 @@ int AudioHwDevice::initCheck() const
640 } 737 }
641 } 738 }
642 739
740 if ((mULPipe == NULL) || !mULPipe->initCheck() ||
741 (mULPipeReader == NULL) || !mULPipeReader->initCheck() ||
742 (mULPipeWriter == NULL) || !mULPipeWriter->initCheck()) {
743 ALOGE("AudioHwDevice: voice call uplink init check failed");
744 return -ENODEV;
745 }
746
747 if ((mDLPipe == NULL) || !mDLPipe->initCheck() ||
748 (mDLPipeReader == NULL) || !mDLPipeReader->initCheck() ||
749 (mDLPipeWriter == NULL) || !mDLPipeWriter->initCheck()) {
750 ALOGE("AudioHwDevice: voice call downlink init check failed");
751 return -ENODEV;
752 }
753
754 if ((mVoiceULInStream == NULL) || !mVoiceULInStream->initCheck() ||
755 (mVoiceULOutStream == NULL) || !mVoiceULOutStream->initCheck()) {
756 ALOGE("AudioHwDevice: voice call uplink streams init check failed");
757 return -ENODEV;
758 }
759
760 if ((mVoiceDLInStream == NULL) || !mVoiceDLInStream->initCheck() ||
761 (mVoiceDLOutStream == NULL) || !mVoiceDLOutStream->initCheck()) {
762 ALOGE("AudioHwDevice: voice call downlink streams init check failed");
763 return -ENODEV;
764 }
765
643 return 0; 766 return 0;
644} 767}
645 768
646int AudioHwDevice::setVoiceVolume(float volume) 769int AudioHwDevice::setVoiceVolume(float volume)
647{ 770{
648 ALOGV("AudioHwDevice: setVoiceVolume() vol=%.4f", volume); 771 /* Linear interpolation between voice dB limits */
649 return -ENOSYS; 772 float dB = (kVoiceDBMax - kVoiceDBMin) * volume + kVoiceDBMin;
773
774 /* Output stage gain (-59.0dB, 0dB) with steps of 0.5dB */
775 int val = 2 * (dB + 59.0f);
776
777 ALOGV("AudioHwDevice: setVoiceVolume() vol=%.4f dB=%.4f", volume, dB, val);
778
779 mMixer.set(ALSAControl(kCabinVolumeHP, val), true);
780 mMixer.set(ALSAControl(kCabinVolumeLine, val), true);
781
782 return 0;
650} 783}
651 784
652int AudioHwDevice::setMasterVolume(float volume) 785int AudioHwDevice::setMasterVolume(float volume)
@@ -677,7 +810,162 @@ int AudioHwDevice::setMode(audio_mode_t mode)
677{ 810{
678 ALOGV("AudioHwDevice: setMode() %s", getModeName(mode)); 811 ALOGV("AudioHwDevice: setMode() %s", getModeName(mode));
679 812
680 return 0; 813 AutoMutex lock(mLock);
814 if (mMode == mode) {
815 ALOGW("AudioHwDevice: already in mode %s", getModeName(mode));
816 return 0;
817 }
818
819 int ret = 0;
820 if (mode == AUDIO_MODE_IN_CALL) {
821 ret = enterVoiceCall();
822 ALOGE_IF(ret, "AudioHwDevice: failed to enter voice call %d", ret);
823 } else {
824 leaveVoiceCall();
825 }
826
827 if (!ret)
828 mMode = mode;
829
830 return ret;
831}
832
833int AudioHwDevice::enableVoiceCall()
834{
835 ALOGV("AudioHwDevice: enable voice call paths");
836
837 sp<AudioStreamOut> outStream = mPrimaryStreamOut.promote();
838 if (outStream == NULL) {
839 ALOGE("AudioHwDevice: primary output stream is not valid");
840 return -ENODEV;
841 }
842
843 /* Playback stream will free the writer and switch to a null writer */
844 outStream->setVoiceCall(true);
845
846 /* Uplink input stream: Mic -> Pipe */
847 int ret = mReaders[kCPUPortId]->registerStream(mVoiceULInStream);
848 if (ret) {
849 ALOGE("AudioHwDevice: failed to register uplink in stream %d", ret);
850 return ret;
851 }
852
853 /* Uplink output stream: Pipe -> Bluetooth */
854 ret = mWriters[kBTPortId]->registerStream(mVoiceULOutStream);
855 if (ret) {
856 ALOGE("AudioHwDevice: failed to register uplink out stream %d", ret);
857 return ret;
858 }
859
860 /* Downlink input stream: Bluetooth -> Pipe */
861 ret = mReaders[kBTPortId]->registerStream(mVoiceDLInStream);
862 if (ret) {
863 ALOGE("AudioHwDevice: failed to register downlink in stream %d", ret);
864 return ret;
865 }
866
867 /* Downlink output stream: Pipe -> Speaker */
868 ret = outStream->mWriter->registerStream(mVoiceDLOutStream);
869 if (ret) {
870 ALOGE("AudioHwDevice: failed to register downlink out stream %d", ret);
871 }
872
873 return ret;
874}
875
876void AudioHwDevice::disableVoiceCall()
877{
878 ALOGV("AudioHwDevice: disable voice call paths");
879
880 sp<AudioStreamOut> outStream = mPrimaryStreamOut.promote();
881 if (outStream != NULL) {
882 outStream->setVoiceCall(false);
883 if (outStream->mWriter->isStreamRegistered(mVoiceDLOutStream))
884 outStream->mWriter->unregisterStream(mVoiceDLOutStream);
885 } else {
886 ALOGE("AudioHwDevice: primary output stream is not valid");
887 }
888
889 if (mReaders[kBTPortId]->isStreamRegistered(mVoiceDLInStream))
890 mReaders[kBTPortId]->unregisterStream(mVoiceDLInStream);
891
892 if (mWriters[kBTPortId]->isStreamRegistered(mVoiceULOutStream))
893 mWriters[kBTPortId]->unregisterStream(mVoiceULOutStream);
894
895 if (mReaders[kCPUPortId]->isStreamRegistered(mVoiceULInStream))
896 mReaders[kCPUPortId]->unregisterStream(mVoiceULInStream);
897}
898
899int AudioHwDevice::enterVoiceCall()
900{
901 ALOGI("AudioHwDevice: enter voice call");
902
903 /* Setup uplink and downlink pipes */
904 int ret = enableVoiceCall();
905 if (ret) {
906 ALOGE("AudioHwDevice: failed to enable voice call path %d", ret);
907 return ret;
908 }
909
910 /* Uplink input stream: Mic -> Pipe */
911 ret = mVoiceULInStream->start();
912 if (ret) {
913 ALOGE("AudioHwDevice: failed to start uplink in stream %d", ret);
914 return ret;
915 }
916
917 /* Downlink input stream: Bluetooth -> Pipe */
918 ret = mVoiceDLInStream->start();
919 if (ret) {
920 ALOGE("AudioHwDevice: failed to start downlink in stream %d", ret);
921 return ret;
922 }
923
924 /*
925 * Wait till pipe is half full to give a head start to the output streams.
926 * The time to wait consists of the actual pipe size, the ADC settle time
927 * used in the kernel and the time needed to produce a BT audio buffer.
928 * Only the pipe size related time contributes to the steady state latency.
929 */
930 usleep((kVoiceCallPipeMs * 5000) + (kADCSettleMs * 1000) +
931 (kBTFrameCount * 1000) / kBTSampleRate);
932
933 /* Downlink output stream: Pipe -> Speaker */
934 ret = mVoiceDLOutStream->start();
935 if (ret) {
936 ALOGE("AudioHwDevice: failed to start downlink out stream %d", ret);
937 }
938
939 /* Uplink output stream: Pipe -> Bluetooth */
940 ret = mVoiceULOutStream->start();
941 if (ret) {
942 ALOGE("AudioHwDevice: failed to start uplink out stream %d", ret);
943 return ret;
944 }
945
946 return ret;
947}
948
949void AudioHwDevice::leaveVoiceCall()
950{
951 ALOGI("AudioHwDevice: leave voice call");
952
953 if (mVoiceDLOutStream->isStarted())
954 mVoiceDLOutStream->stop();
955
956 if (mVoiceULInStream->isStarted())
957 mVoiceULInStream->stop();
958
959 if (mVoiceULOutStream->isStarted())
960 mVoiceULOutStream->stop();
961
962 if (mVoiceDLInStream->isStarted())
963 mVoiceDLInStream->stop();
964
965 disableVoiceCall();
966
967 /* Reset the cabin volume for media */
968 setVoiceVolume(1.0f);
681} 969}
682 970
683int AudioHwDevice::setMicMute(bool state) 971int AudioHwDevice::setMicMute(bool state)
@@ -716,6 +1004,7 @@ size_t AudioHwDevice::getInputBufferSize(const struct audio_config *config) cons
716{ 1004{
717 ALOGV("AudioHwDevice: getInputBufferSize()"); 1005 ALOGV("AudioHwDevice: getInputBufferSize()");
718 1006
1007 AutoMutex lock(mLock);
719 size_t size; 1008 size_t size;
720 1009
721 /* Take resampling ratio into account and align to the nearest 1010 /* Take resampling ratio into account and align to the nearest
@@ -788,6 +1077,12 @@ AudioStreamIn* AudioHwDevice::openInputStream(audio_io_handle_t handle,
788 } 1077 }
789 1078
790 SlotMap slotMap(srcMask, dstMask); 1079 SlotMap slotMap(srcMask, dstMask);
1080 if (!slotMap.isValid()) {
1081 ALOGE("AudioHwDevice: failed to create slot map");
1082 return NULL;
1083 }
1084
1085 AutoMutex lock(mLock);
791 1086
792 /* Set the parameters for the internal input stream. Don't change the 1087 /* Set the parameters for the internal input stream. Don't change the
793 * parameters for capture. The resampler is used if needed. */ 1088 * parameters for capture. The resampler is used if needed. */
@@ -810,6 +1105,8 @@ void AudioHwDevice::closeInputStream(AudioStreamIn *in)
810{ 1105{
811 ALOGV("AudioHwDevice: closeInputStream()"); 1106 ALOGV("AudioHwDevice: closeInputStream()");
812 1107
1108 AutoMutex lock(mLock);
1109
813 if (mInStreams.find(in) == mInStreams.end()) { 1110 if (mInStreams.find(in) == mInStreams.end()) {
814 ALOGW("AudioHwDevice: input stream %p is not open", in); 1111 ALOGW("AudioHwDevice: input stream %p is not open", in);
815 return; 1112 return;
@@ -856,6 +1153,8 @@ AudioStreamOut* AudioHwDevice::openOutputStream(audio_io_handle_t handle,
856 return NULL; 1153 return NULL;
857 } 1154 }
858 1155
1156 AutoMutex lock(mLock);
1157
859 /* Set the parameters for the internal output stream */ 1158 /* Set the parameters for the internal output stream */
860 params.frameCount = mWriters[port]->getParams().frameCount; 1159 params.frameCount = mWriters[port]->getParams().frameCount;
861 params.sampleRate = config->sample_rate; /* Use stream's resampler if needed */ 1160 params.sampleRate = config->sample_rate; /* Use stream's resampler if needed */
@@ -883,6 +1182,9 @@ AudioStreamOut* AudioHwDevice::openOutputStream(audio_io_handle_t handle,
883 return NULL; 1182 return NULL;
884 } 1183 }
885 1184
1185 if (flags & AUDIO_OUTPUT_FLAG_PRIMARY)
1186 mPrimaryStreamOut = out;
1187
886 mOutStreams.insert(out); 1188 mOutStreams.insert(out);
887 1189
888 return out.get(); 1190 return out.get();
@@ -892,11 +1194,16 @@ void AudioHwDevice::closeOutputStream(AudioStreamOut *out)
892{ 1194{
893 ALOGV("AudioHwDevice: closeOutputStream()"); 1195 ALOGV("AudioHwDevice: closeOutputStream()");
894 1196
1197 AutoMutex lock(mLock);
1198
895 if (mOutStreams.find(out) == mOutStreams.end()) { 1199 if (mOutStreams.find(out) == mOutStreams.end()) {
896 ALOGW("AudioHwDevice: output stream %p is not open", out); 1200 ALOGW("AudioHwDevice: output stream %p is not open", out);
897 return; 1201 return;
898 } 1202 }
899 1203
1204 if (mPrimaryStreamOut == out)
1205 mPrimaryStreamOut = NULL;
1206
900 mOutStreams.erase(out); 1207 mOutStreams.erase(out);
901 1208
902 out = NULL; 1209 out = NULL;