source: trunk/src/multimedia/audio/qaudio_symbian_p.cpp@ 890

Last change on this file since 890 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 18.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtMultimedia module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qaudio_symbian_p.h"
43#include <mmffourcc.h>
44
45QT_BEGIN_NAMESPACE
46
47namespace SymbianAudio {
48namespace Utils {
49
50//-----------------------------------------------------------------------------
51// Static data
52//-----------------------------------------------------------------------------
53
54// Sample rate / frequency
55
56typedef TMMFSampleRate SampleRateNative;
57typedef int SampleRateQt;
58
59const int SampleRateCount = 12;
60
61const SampleRateNative SampleRateListNative[SampleRateCount] = {
62 EMMFSampleRate8000Hz
63 , EMMFSampleRate11025Hz
64 , EMMFSampleRate12000Hz
65 , EMMFSampleRate16000Hz
66 , EMMFSampleRate22050Hz
67 , EMMFSampleRate24000Hz
68 , EMMFSampleRate32000Hz
69 , EMMFSampleRate44100Hz
70 , EMMFSampleRate48000Hz
71 , EMMFSampleRate64000Hz
72 , EMMFSampleRate88200Hz
73 , EMMFSampleRate96000Hz
74};
75
76const SampleRateQt SampleRateListQt[SampleRateCount] = {
77 8000
78 , 11025
79 , 12000
80 , 16000
81 , 22050
82 , 24000
83 , 32000
84 , 44100
85 , 48000
86 , 64000
87 , 88200
88 , 96000
89};
90
91// Channels
92
93typedef TMMFMonoStereo ChannelsNative;
94typedef int ChannelsQt;
95
96const int ChannelsCount = 2;
97
98const ChannelsNative ChannelsListNative[ChannelsCount] = {
99 EMMFMono
100 , EMMFStereo
101};
102
103const ChannelsQt ChannelsListQt[ChannelsCount] = {
104 1
105 , 2
106};
107
108// Encoding
109
110const int EncodingCount = 6;
111
112const TUint32 EncodingFourCC[EncodingCount] = {
113 KMMFFourCCCodePCM8 // 0
114 , KMMFFourCCCodePCMU8 // 1
115 , KMMFFourCCCodePCM16 // 2
116 , KMMFFourCCCodePCMU16 // 3
117 , KMMFFourCCCodePCM16B // 4
118 , KMMFFourCCCodePCMU16B // 5
119};
120
121// The characterised DevSound API specification states that the iEncoding
122// field in TMMFCapabilities is ignored, and that the FourCC should be used
123// to specify the PCM encoding.
124// See "SGL.GT0287.102 Multimedia DevSound Baseline Compatibility.doc" in the
125// mm_info/mm_docs repository.
126const TMMFSoundEncoding EncodingNative[EncodingCount] = {
127 EMMFSoundEncoding16BitPCM // 0
128 , EMMFSoundEncoding16BitPCM // 1
129 , EMMFSoundEncoding16BitPCM // 2
130 , EMMFSoundEncoding16BitPCM // 3
131 , EMMFSoundEncoding16BitPCM // 4
132 , EMMFSoundEncoding16BitPCM // 5
133};
134
135
136const int EncodingSampleSize[EncodingCount] = {
137 8 // 0
138 , 8 // 1
139 , 16 // 2
140 , 16 // 3
141 , 16 // 4
142 , 16 // 5
143};
144
145const QAudioFormat::Endian EncodingByteOrder[EncodingCount] = {
146 QAudioFormat::LittleEndian // 0
147 , QAudioFormat::LittleEndian // 1
148 , QAudioFormat::LittleEndian // 2
149 , QAudioFormat::LittleEndian // 3
150 , QAudioFormat::BigEndian // 4
151 , QAudioFormat::BigEndian // 5
152};
153
154const QAudioFormat::SampleType EncodingSampleType[EncodingCount] = {
155 QAudioFormat::SignedInt // 0
156 , QAudioFormat::UnSignedInt // 1
157 , QAudioFormat::SignedInt // 2
158 , QAudioFormat::UnSignedInt // 3
159 , QAudioFormat::SignedInt // 4
160 , QAudioFormat::UnSignedInt // 5
161};
162
163
164//-----------------------------------------------------------------------------
165// Private functions
166//-----------------------------------------------------------------------------
167
168// Helper functions for implementing parameter conversions
169
170template<typename Input>
171bool findValue(const Input *inputArray, int length, Input input, int &index) {
172 bool result = false;
173 for (int i=0; !result && i<length; ++i)
174 if (inputArray[i] == input) {
175 index = i;
176 result = true;
177 }
178 return result;
179}
180
181template<typename Input, typename Output>
182bool convertValue(const Input *inputArray, const Output *outputArray,
183 int length, Input input, Output &output) {
184 int index;
185 const bool result = findValue<Input>(inputArray, length, input, index);
186 if (result)
187 output = outputArray[index];
188 return result;
189}
190
191/**
192 * Macro which is used to generate the implementation of the conversion
193 * functions. The implementation is just a wrapper around the templated
194 * convertValue function, e.g.
195 *
196 * CONVERSION_FUNCTION_IMPL(SampleRate, Qt, Native)
197 *
198 * expands to
199 *
200 * bool SampleRateQtToNative(int input, TMMFSampleRate &output) {
201 * return convertValue<SampleRateQt, SampleRateNative>
202 * (SampleRateListQt, SampleRateListNative, SampleRateCount,
203 * input, output);
204 * }
205 */
206#define CONVERSION_FUNCTION_IMPL(FieldLc, Field, Input, Output) \
207bool FieldLc##Input##To##Output(Field##Input input, Field##Output &output) { \
208 return convertValue<Field##Input, Field##Output>(Field##List##Input, \
209 Field##List##Output, Field##Count, input, output); \
210}
211
212//-----------------------------------------------------------------------------
213// Local helper functions
214//-----------------------------------------------------------------------------
215
216CONVERSION_FUNCTION_IMPL(sampleRate, SampleRate, Qt, Native)
217CONVERSION_FUNCTION_IMPL(sampleRate, SampleRate, Native, Qt)
218CONVERSION_FUNCTION_IMPL(channels, Channels, Qt, Native)
219CONVERSION_FUNCTION_IMPL(channels, Channels, Native, Qt)
220
221bool sampleInfoQtToNative(int inputSampleSize,
222 QAudioFormat::Endian inputByteOrder,
223 QAudioFormat::SampleType inputSampleType,
224 TUint32 &outputFourCC,
225 TMMFSoundEncoding &outputEncoding) {
226
227 bool found = false;
228
229 for (int i=0; i<EncodingCount && !found; ++i) {
230 if ( EncodingSampleSize[i] == inputSampleSize
231 && EncodingByteOrder[i] == inputByteOrder
232 && EncodingSampleType[i] == inputSampleType) {
233 outputFourCC = EncodingFourCC[i];
234 outputEncoding = EncodingNative[i]; // EMMFSoundEncoding16BitPCM
235 found = true;
236 }
237 }
238
239 return found;
240}
241
242void capabilitiesNativeToQt(const TMMFCapabilities &caps,
243 const TFourCC &fourcc,
244 QList<int> &frequencies,
245 QList<int> &channels,
246 QList<int> &sampleSizes,
247 QList<QAudioFormat::Endian> &byteOrders,
248 QList<QAudioFormat::SampleType> &sampleTypes) {
249
250 frequencies.clear();
251 sampleSizes.clear();
252 byteOrders.clear();
253 sampleTypes.clear();
254 channels.clear();
255
256 for (int i=0; i<SampleRateCount; ++i)
257 if (caps.iRate & SampleRateListNative[i])
258 frequencies += SampleRateListQt[i];
259
260 for (int i=0; i<ChannelsCount; ++i)
261 if (caps.iChannels & ChannelsListNative[i])
262 channels += ChannelsListQt[i];
263
264 for (int i=0; i<EncodingCount; ++i) {
265 if (fourcc == EncodingFourCC[i]) {
266 sampleSizes += EncodingSampleSize[i];
267 byteOrders += EncodingByteOrder[i];
268 sampleTypes += EncodingSampleType[i];
269 }
270 }
271}
272
273bool formatQtToNative(const QAudioFormat &inputFormat,
274 TUint32 &outputFourCC,
275 TMMFCapabilities &outputFormat) {
276
277 bool result = false;
278
279 // Need to use temporary variables because TMMFCapabilities fields are all
280 // TInt, rather than MMF enumerated types.
281 TMMFSampleRate outputSampleRate;
282 TMMFMonoStereo outputChannels;
283 TMMFSoundEncoding outputEncoding;
284
285 if (inputFormat.codec() == QLatin1String("audio/pcm")) {
286 result =
287 sampleRateQtToNative(inputFormat.frequency(), outputSampleRate)
288 && channelsQtToNative(inputFormat.channels(), outputChannels)
289 && sampleInfoQtToNative(inputFormat.sampleSize(),
290 inputFormat.byteOrder(),
291 inputFormat.sampleType(),
292 outputFourCC,
293 outputEncoding);
294 }
295
296 if (result) {
297 outputFormat.iRate = outputSampleRate;
298 outputFormat.iChannels = outputChannels;
299 outputFormat.iEncoding = outputEncoding;
300 }
301
302 return result;
303}
304
305QAudio::State stateNativeToQt(State nativeState)
306{
307 switch (nativeState) {
308 case ClosedState:
309 return QAudio::StoppedState;
310 case InitializingState:
311 return QAudio::StoppedState;
312 case ActiveState:
313 return QAudio::ActiveState;
314 case IdleState:
315 return QAudio::IdleState;
316 case SuspendedPausedState:
317 case SuspendedStoppedState:
318 return QAudio::SuspendedState;
319 default:
320 Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid state");
321 return QAudio::StoppedState; // suppress compiler warning
322 }
323}
324
325qint64 bytesToSamples(const QAudioFormat &format, qint64 length)
326{
327 return length / ((format.sampleSize() / 8) * format.channels());
328}
329
330qint64 samplesToBytes(const QAudioFormat &format, qint64 samples)
331{
332 return samples * (format.sampleSize() / 8) * format.channels();
333}
334
335} // namespace Utils
336
337
338//-----------------------------------------------------------------------------
339// DevSoundWrapper
340//-----------------------------------------------------------------------------
341
342DevSoundWrapper::DevSoundWrapper(QAudio::Mode mode, QObject *parent)
343 : QObject(parent)
344 , m_mode(mode)
345 , m_state(StateIdle)
346 , m_devsound(0)
347 , m_fourcc(0)
348{
349 QT_TRAP_THROWING(m_devsound = CMMFDevSound::NewL());
350
351 switch (mode) {
352 case QAudio::AudioOutput:
353 m_nativeMode = EMMFStatePlaying;
354 break;
355
356 case QAudio::AudioInput:
357 m_nativeMode = EMMFStateRecording;
358 break;
359
360 default:
361 Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid mode");
362 }
363
364 getSupportedCodecs();
365}
366
367DevSoundWrapper::~DevSoundWrapper()
368{
369 delete m_devsound;
370}
371
372const QList<QString>& DevSoundWrapper::supportedCodecs() const
373{
374 return m_supportedCodecs;
375}
376
377void DevSoundWrapper::initialize(const QString& codec)
378{
379 Q_ASSERT(StateInitializing != m_state);
380 m_state = StateInitializing;
381 if (QLatin1String("audio/pcm") == codec) {
382 m_fourcc = KMMFFourCCCodePCM16;
383 TRAPD(err, m_devsound->InitializeL(*this, m_fourcc, m_nativeMode));
384 if (KErrNone != err) {
385 m_state = StateIdle;
386 emit initializeComplete(err);
387 }
388 } else {
389 emit initializeComplete(KErrNotSupported);
390 }
391}
392
393const QList<int>& DevSoundWrapper::supportedFrequencies() const
394{
395 Q_ASSERT(StateInitialized == m_state);
396 return m_supportedFrequencies;
397}
398
399const QList<int>& DevSoundWrapper::supportedChannels() const
400{
401 Q_ASSERT(StateInitialized == m_state);
402 return m_supportedChannels;
403}
404
405const QList<int>& DevSoundWrapper::supportedSampleSizes() const
406{
407 Q_ASSERT(StateInitialized == m_state);
408 return m_supportedSampleSizes;
409}
410
411const QList<QAudioFormat::Endian>& DevSoundWrapper::supportedByteOrders() const
412{
413 Q_ASSERT(StateInitialized == m_state);
414 return m_supportedByteOrders;
415}
416
417const QList<QAudioFormat::SampleType>& DevSoundWrapper::supportedSampleTypes() const
418{
419 Q_ASSERT(StateInitialized == m_state);
420 return m_supportedSampleTypes;
421}
422
423bool DevSoundWrapper::isFormatSupported(const QAudioFormat &format) const
424{
425 Q_ASSERT(StateInitialized == m_state);
426 return m_supportedCodecs.contains(format.codec())
427 && m_supportedFrequencies.contains(format.frequency())
428 && m_supportedChannels.contains(format.channels())
429 && m_supportedSampleSizes.contains(format.sampleSize())
430 && m_supportedSampleTypes.contains(format.sampleType())
431 && m_supportedByteOrders.contains(format.byteOrder());
432}
433
434int DevSoundWrapper::samplesProcessed() const
435{
436 int result = 0;
437 if (StateInitialized == m_state) {
438 switch (m_mode) {
439 case QAudio::AudioInput:
440 result = m_devsound->SamplesRecorded();
441 break;
442 case QAudio::AudioOutput:
443 result = m_devsound->SamplesPlayed();
444 break;
445 }
446 }
447 return result;
448}
449
450bool DevSoundWrapper::setFormat(const QAudioFormat &format)
451{
452 Q_ASSERT(StateInitialized == m_state);
453 bool result = false;
454 TUint32 fourcc;
455 TMMFCapabilities nativeFormat;
456 if (Utils::formatQtToNative(format, fourcc, nativeFormat)) {
457 TMMFCapabilities currentNativeFormat = m_devsound->Config();
458 nativeFormat.iBufferSize = currentNativeFormat.iBufferSize;
459 TRAPD(err, m_devsound->SetConfigL(nativeFormat));
460 result = (KErrNone == err);
461 }
462 return result;
463}
464
465bool DevSoundWrapper::start()
466{
467 Q_ASSERT(StateInitialized == m_state);
468 int err = KErrArgument;
469 switch (m_mode) {
470 case QAudio::AudioInput:
471 TRAP(err, m_devsound->RecordInitL());
472 break;
473 case QAudio::AudioOutput:
474 TRAP(err, m_devsound->PlayInitL());
475 break;
476 }
477 return (KErrNone == err);
478}
479
480bool DevSoundWrapper::pause()
481{
482 Q_ASSERT(StateInitialized == m_state);
483 const bool canPause = isResumeSupported();
484 if (canPause)
485 m_devsound->Pause();
486 else
487 stop();
488 return canPause;
489}
490
491void DevSoundWrapper::resume()
492{
493 Q_ASSERT(StateInitialized == m_state);
494 Q_ASSERT(isResumeSupported());
495 // TODO: QTBUG-13625
496}
497
498void DevSoundWrapper::stop()
499{
500 m_devsound->Stop();
501}
502
503void DevSoundWrapper::bufferProcessed()
504{
505 Q_ASSERT(StateInitialized == m_state);
506 switch (m_mode) {
507 case QAudio::AudioInput:
508 m_devsound->RecordData();
509 break;
510 case QAudio::AudioOutput:
511 m_devsound->PlayData();
512 break;
513 }
514}
515
516void DevSoundWrapper::getSupportedCodecs()
517{
518/*
519 * TODO: once we support formats other than PCM, this function should
520 * convert the array of FourCC codes into MIME types for each codec.
521 *
522 RArray<TFourCC> fourcc;
523 QT_TRAP_THROWING(CleanupClosePushL(&fourcc));
524
525 TMMFPrioritySettings settings;
526 switch (mode) {
527 case QAudio::AudioOutput:
528 settings.iState = EMMFStatePlaying;
529 m_devsound->GetSupportedInputDataTypesL(fourcc, settings);
530 break;
531
532 case QAudio::AudioInput:
533 settings.iState = EMMFStateRecording;
534 m_devsound->GetSupportedInputDataTypesL(fourcc, settings);
535 break;
536
537 default:
538 Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid mode");
539 }
540
541 CleanupStack::PopAndDestroy(); // fourcc
542*/
543
544 m_supportedCodecs.append(QLatin1String("audio/pcm"));
545}
546
547void DevSoundWrapper::populateCapabilities()
548{
549 m_supportedFrequencies.clear();
550 m_supportedChannels.clear();
551 m_supportedSampleSizes.clear();
552 m_supportedByteOrders.clear();
553 m_supportedSampleTypes.clear();
554
555 const TMMFCapabilities caps = m_devsound->Capabilities();
556
557 for (int i=0; i<Utils::SampleRateCount; ++i)
558 if (caps.iRate & Utils::SampleRateListNative[i])
559 m_supportedFrequencies += Utils::SampleRateListQt[i];
560
561 for (int i=0; i<Utils::ChannelsCount; ++i)
562 if (caps.iChannels & Utils::ChannelsListNative[i])
563 m_supportedChannels += Utils::ChannelsListQt[i];
564
565 for (int i=0; i<Utils::EncodingCount; ++i) {
566 if (m_fourcc == Utils::EncodingFourCC[i]) {
567 m_supportedSampleSizes += Utils::EncodingSampleSize[i];
568 m_supportedByteOrders += Utils::EncodingByteOrder[i];
569 m_supportedSampleTypes += Utils::EncodingSampleType[i];
570 }
571 }
572}
573
574bool DevSoundWrapper::isResumeSupported() const
575{
576 // TODO: QTBUG-13625
577 return false;
578}
579
580void DevSoundWrapper::InitializeComplete(TInt aError)
581{
582 Q_ASSERT(StateInitializing == m_state);
583 if (KErrNone == aError) {
584 m_state = StateInitialized;
585 populateCapabilities();
586 } else {
587 m_state = StateIdle;
588 }
589 emit initializeComplete(aError);
590}
591
592void DevSoundWrapper::ToneFinished(TInt aError)
593{
594 Q_UNUSED(aError)
595 // This class doesn't use DevSound's tone playback functions, so should
596 // never receive this callback.
597 Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
598}
599
600void DevSoundWrapper::BufferToBeFilled(CMMFBuffer *aBuffer)
601{
602 Q_ASSERT(QAudio::AudioOutput == m_mode);
603 emit bufferToBeProcessed(aBuffer);
604}
605
606void DevSoundWrapper::PlayError(TInt aError)
607{
608 Q_ASSERT(QAudio::AudioOutput == m_mode);
609 emit processingError(aError);
610}
611
612void DevSoundWrapper::BufferToBeEmptied(CMMFBuffer *aBuffer)
613{
614 Q_ASSERT(QAudio::AudioInput == m_mode);
615 emit bufferToBeProcessed(aBuffer);
616}
617
618void DevSoundWrapper::RecordError(TInt aError)
619{
620 Q_ASSERT(QAudio::AudioInput == m_mode);
621 emit processingError(aError);
622}
623
624void DevSoundWrapper::ConvertError(TInt aError)
625{
626 Q_UNUSED(aError)
627 // This class doesn't use DevSound's format conversion functions, so
628 // should never receive this callback.
629 Q_ASSERT_X(false, Q_FUNC_INFO, "Unexpected callback");
630}
631
632void DevSoundWrapper::DeviceMessage(TUid aMessageType, const TDesC8 &aMsg)
633{
634 Q_UNUSED(aMessageType)
635 Q_UNUSED(aMsg)
636 // Ignore this callback.
637}
638
639
640} // namespace SymbianAudio
641
642QT_END_NAMESPACE
643
644
Note: See TracBrowser for help on using the repository browser.