qtmobility/examples/audiorecorder/audiorecorder.cpp
changeset 15 1f895d8a5b2b
parent 14 6fbed849b4f4
equal deleted inserted replaced
14:6fbed849b4f4 15:1f895d8a5b2b
    52 AudioRecorder::AudioRecorder()
    52 AudioRecorder::AudioRecorder()
    53 {
    53 {
    54     audiosource = new QAudioCaptureSource;
    54     audiosource = new QAudioCaptureSource;
    55     capture = new QMediaRecorder(audiosource);
    55     capture = new QMediaRecorder(audiosource);
    56 
    56 
    57     if (capture->supportedAudioCodecs().size() > 0) {
       
    58         QAudioEncoderSettings audioSettings;
       
    59         audioSettings.setQuality(QtMultimedia::LowQuality);
       
    60         audioSettings.setEncodingMode(QtMultimedia::ConstantQualityEncoding);
       
    61         audioSettings.setCodec(capture->supportedAudioCodecs().first());
       
    62         capture->setEncodingSettings(audioSettings,QVideoEncoderSettings(),
       
    63                 capture->supportedContainers().first());
       
    64     }
       
    65 
       
    66     // set a default file
    57     // set a default file
    67 #ifdef Q_OS_SYMBIAN
    58 #ifdef Q_OS_SYMBIAN
    68     capture->setOutputLocation(recordPathAudio(QUrl()));    
    59     capture->setOutputLocation(recordPathAudio(QUrl()));
    69 #else
    60 #else
    70     capture->setOutputLocation(QUrl("test.raw"));
    61     capture->setOutputLocation(QUrl("test.raw"));
    71 #endif
    62 #endif
    72 
    63 
    73     QWidget *window = new QWidget;
    64     QWidget *window = new QWidget;
    96 
    87 
    97     QLabel* codecLabel = new QLabel;
    88     QLabel* codecLabel = new QLabel;
    98     codecLabel->setText(tr("Audio Codec"));
    89     codecLabel->setText(tr("Audio Codec"));
    99     codecsBox = new QComboBox(this);
    90     codecsBox = new QComboBox(this);
   100     codecsBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
    91     codecsBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
   101     codecsBox->setMinimumSize(200,10);    
    92     codecsBox->setMinimumSize(200,10);
   102     
    93 
   103     QLabel* sampleRateLabel = new QLabel;
    94     QLabel* sampleRateLabel = new QLabel;
   104     sampleRateLabel->setText(tr("Sample Rate"));
    95     sampleRateLabel->setText(tr("Sample Rate"));
   105     sampleRateBox = new QComboBox(this);
    96     sampleRateBox = new QComboBox(this);
   106     sampleRateBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
    97     sampleRateBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
   107     sampleRateBox->setMinimumSize(200,10);
    98     sampleRateBox->setMinimumSize(200,10);
   108     
    99 
   109     QLabel* channelLabel = new QLabel;
   100     QLabel* channelLabel = new QLabel;
   110     channelLabel->setText(tr("Channel count"));
   101     channelLabel->setText(tr("Channel count"));
   111     channelBox = new QComboBox(this);
   102     channelBox = new QComboBox(this);
   112     channelBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
   103     channelBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
   113     channelBox->setMinimumSize(200,10);
   104     channelBox->setMinimumSize(200,10);
   114     
   105 
   115     QLabel* qualityLabel = new QLabel;
   106     QLabel* qualityLabel = new QLabel;
   116     qualityLabel->setText(tr("Audio Quality"));
   107     qualityLabel->setText(tr("Audio Quality"));
   117     qualityBox = new QComboBox(this);
   108     qualityBox = new QComboBox(this);
   118     qualityBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
   109     qualityBox->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
   119     qualityBox->setMinimumSize(200,10);
   110     qualityBox->setMinimumSize(200,10);
   135 
   126 
   136     QStringList containers = capture->supportedContainers();
   127     QStringList containers = capture->supportedContainers();
   137     for(int i = 0; i < containers.count(); i++)
   128     for(int i = 0; i < containers.count(); i++)
   138         containersBox->addItem(containers.at(i));
   129         containersBox->addItem(containers.at(i));
   139 
   130 
   140     QList<int> samplerates = capture->supportedAudioSampleRates();    
   131     QList<int> samplerates = capture->supportedAudioSampleRates();
   141     for(int i = 0; i < samplerates.count(); i++) {        
   132     for(int i = 0; i < samplerates.count(); i++) {
   142         QString rateString = QString("%1").arg(samplerates.at(i));
   133         QString rateString = QString("%1").arg(samplerates.at(i));
   143         sampleRateBox->addItem(rateString, QVariant(samplerates.at(i))); 
   134         sampleRateBox->addItem(rateString, QVariant(samplerates.at(i)));
   144     }
   135     }
   145     
   136 
   146     QList<int> channels;
   137     QList<int> channels;
   147     channels <<1<<2;     
   138     channels <<1<<2;
   148     for(int i = 0; i < channels.count(); i++) {        
   139     for(int i = 0; i < channels.count(); i++) {
   149         QString channelString = QString("%1").arg(channels.at(i));
   140         QString channelString = QString("%1").arg(channels.at(i));
   150         channelBox->addItem(channelString, QVariant(channels.at(i))); 
   141         channelBox->addItem(channelString, QVariant(channels.at(i)));
   151     }
   142     }
   152       
   143 
   153     qualityBox->addItem(tr("Low"));
   144     qualityBox->addItem(tr("Low"));
   154     qualityBox->addItem(tr("Medium"));
   145     qualityBox->addItem(tr("Medium"));
   155     qualityBox->addItem(tr("High"));
   146     qualityBox->addItem(tr("High"));
   156 
   147 
   157     connect(capture, SIGNAL(durationChanged(qint64)), this, SLOT(updateProgress(qint64)));
   148     connect(capture, SIGNAL(durationChanged(qint64)), this, SLOT(updateProgress(qint64)));
   158     connect(capture, SIGNAL(stateChanged(QMediaRecorder::State)), this, SLOT(stateChanged(QMediaRecorder::State)));
   149     connect(capture, SIGNAL(stateChanged(QMediaRecorder::State)), this, SLOT(stateChanged(QMediaRecorder::State)));
   159     connect(capture, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(errorChanged(QMediaRecorder::Error)));
   150     connect(capture, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(errorChanged(QMediaRecorder::Error)));
   160 
   151 
   161     if (codecs.count() > 0) {
   152     if (codecs.count() > 0) {
   162     QAudioEncoderSettings audioSettings;
   153     QAudioEncoderSettings audioSettings;
   163     audioSettings.setQuality(QtMultimedia::LowQuality);
   154     audioSettings.setQuality(QtMultimediaKit::LowQuality);
   164     audioSettings.setEncodingMode(QtMultimedia::ConstantQualityEncoding);
   155     audioSettings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding);
   165     audioSettings.setCodec(codecs.first());
   156     audioSettings.setCodec(codecs.first());
   166     capture->setEncodingSettings(audioSettings,QVideoEncoderSettings(),
   157     capture->setEncodingSettings(audioSettings,QVideoEncoderSettings(),
   167             containers.first());
   158             containers.first());
   168     }
   159     }
   169 
   160 
   180     layout->addWidget(containersBox,2,1,1,3,Qt::AlignLeft);
   171     layout->addWidget(containersBox,2,1,1,3,Qt::AlignLeft);
   181 
   172 
   182     layout->addWidget(codecLabel,3,0,Qt::AlignHCenter);
   173     layout->addWidget(codecLabel,3,0,Qt::AlignHCenter);
   183     connect(codecsBox,SIGNAL(activated(int)),SLOT(codecChanged(int)));
   174     connect(codecsBox,SIGNAL(activated(int)),SLOT(codecChanged(int)));
   184     layout->addWidget(codecsBox,3,1,1,3,Qt::AlignLeft);
   175     layout->addWidget(codecsBox,3,1,1,3,Qt::AlignLeft);
   185     
   176 
   186     layout->addWidget(sampleRateLabel,4,0,Qt::AlignHCenter);
   177     layout->addWidget(sampleRateLabel,4,0,Qt::AlignHCenter);
   187     connect(sampleRateBox,SIGNAL(activated(int)),SLOT(sampleRateChanged(int)));
   178     connect(sampleRateBox,SIGNAL(activated(int)),SLOT(sampleRateChanged(int)));
   188     layout->addWidget(sampleRateBox,4,1,1,3,Qt::AlignLeft);
   179     layout->addWidget(sampleRateBox,4,1,1,3,Qt::AlignLeft);
   189     
   180 
   190     layout->addWidget(channelLabel,5,0,Qt::AlignHCenter);
   181     layout->addWidget(channelLabel,5,0,Qt::AlignHCenter);
   191     connect(channelBox,SIGNAL(activated(int)),SLOT(channelCountChanged(int)));
   182     connect(channelBox,SIGNAL(activated(int)),SLOT(channelCountChanged(int)));
   192     layout->addWidget(channelBox,5,1,1,3,Qt::AlignLeft);
   183     layout->addWidget(channelBox,5,1,1,3,Qt::AlignLeft);
   193     
   184 
   194     layout->addWidget(qualityLabel,6,0,Qt::AlignHCenter);
   185     layout->addWidget(qualityLabel,6,0,Qt::AlignHCenter);
   195     connect(qualityBox,SIGNAL(activated(int)),SLOT(qualityChanged(int)));
   186     connect(qualityBox,SIGNAL(activated(int)),SLOT(qualityChanged(int)));
   196     layout->addWidget(qualityBox,6,1,1,3,Qt::AlignLeft);
   187     layout->addWidget(qualityBox,6,1,1,3,Qt::AlignLeft);
   197 
   188 
   198     fileButton = new QPushButton(this);
   189     fileButton = new QPushButton(this);
   199     fileButton->setText(tr("Output File"));    
   190     fileButton->setText(tr("Output File"));
   200     connect(fileButton,SIGNAL(clicked()),SLOT(selectOutputFile()));
   191     connect(fileButton,SIGNAL(clicked()),SLOT(selectOutputFile()));
   201     layout->addWidget(fileButton,7,0,Qt::AlignHCenter);
   192     layout->addWidget(fileButton,7,0,Qt::AlignHCenter);
   202     
   193 
   203     pauseButton = new QPushButton(this);    
   194     pauseButton = new QPushButton(this);
   204     pauseButton->setText(tr("Pause"));
   195     pauseButton->setText(tr("Pause"));
   205     connect(pauseButton,SIGNAL(clicked()),SLOT(togglePause()));
   196     connect(pauseButton,SIGNAL(clicked()),SLOT(togglePause()));
   206     layout->addWidget(pauseButton,7,1,Qt::AlignHCenter);
   197     layout->addWidget(pauseButton,7,1,Qt::AlignHCenter);
   207 
   198 
   208     button = new QPushButton(this);
   199     button = new QPushButton(this);
   214     statusLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
   205     statusLabel->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::Fixed);
   215     statusLabel->setMinimumSize(130,10);
   206     statusLabel->setMinimumSize(130,10);
   216     statusLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
   207     statusLabel->setFrameStyle(QFrame::Panel | QFrame::Sunken);
   217     statusLabel->setLineWidth(1);
   208     statusLabel->setLineWidth(1);
   218     layout->addWidget(statusLabel,8,0,Qt::AlignHCenter);
   209     layout->addWidget(statusLabel,8,0,Qt::AlignHCenter);
   219     
   210 
   220     QLabel* durationLabel = new QLabel;
   211     QLabel* durationLabel = new QLabel;
   221     durationLabel->setText(tr("Duration"));
   212     durationLabel->setText(tr("Duration"));
   222     layout->addWidget(durationLabel,8,1,Qt::AlignRight);
   213     layout->addWidget(durationLabel,8,1,Qt::AlignRight);
   223 
   214 
   224     recTime = new QLabel;
   215     recTime = new QLabel;
   225     layout->addWidget(recTime,8,2,Qt::AlignLeft);
   216     layout->addWidget(recTime,8,2,Qt::AlignLeft);
   226     
   217 
   227     window->setLayout(layout);
   218     window->setLayout(layout);
   228     setCentralWidget(window);
   219     setCentralWidget(window);
   229     window->show();
   220     window->show();
   230 
   221 
   231     active = false;
   222     active = false;
   232     paused = false;
   223     paused = false;
   233 }
   224 }
   234 
   225 
   235 QUrl AudioRecorder::recordPathAudio(QUrl filePath)
   226 QUrl AudioRecorder::recordPathAudio(QUrl filePath)
   236 {   
   227 {
   237     if (!filePath.isEmpty())
   228     if (!filePath.isEmpty())
   238         return filePath;  
   229         return filePath;
   239     
   230 
   240     QDir outputDir(QDir::rootPath());
   231     QDir outputDir(QDir::rootPath());
   241     
   232 
   242     int lastImage = 0;  
   233     int lastImage = 0;
   243     int fileCount = 0;
   234     int fileCount = 0;
   244     foreach(QString fileName, outputDir.entryList(QStringList() << "testclip_*")) {        
   235     foreach(QString fileName, outputDir.entryList(QStringList() << "testclip_*")) {
   245         int imgNumber = fileName.mid(5, fileName.size()-9).toInt();
   236         int imgNumber = fileName.mid(5, fileName.size()-9).toInt();
   246         lastImage = qMax(lastImage, imgNumber);
   237         lastImage = qMax(lastImage, imgNumber);
   247         if (outputDir.exists(fileName))             
   238         if (outputDir.exists(fileName))
   248             fileCount+=1;        
   239             fileCount+=1;
   249     }    
   240     }
   250     lastImage+=fileCount;    
   241     lastImage+=fileCount;
   251     QUrl location(QDir::toNativeSeparators(outputDir.canonicalPath()+QString("/testclip_%1").arg(lastImage+1,4,10,QLatin1Char('0'))));
   242     QUrl location(QDir::toNativeSeparators(outputDir.canonicalPath()+QString("/testclip_%1").arg(lastImage+1,4,10,QLatin1Char('0'))));
   252     return location;
   243     return location;
   253 }
   244 }
   254 
   245 
   255 AudioRecorder::~AudioRecorder()
   246 AudioRecorder::~AudioRecorder()
   309     settings.setCodec(codecsBox->itemText(idx));
   300     settings.setCodec(codecsBox->itemText(idx));
   310     capture->setEncodingSettings(settings);
   301     capture->setEncodingSettings(settings);
   311 }
   302 }
   312 
   303 
   313 void AudioRecorder::sampleRateChanged(int idx)
   304 void AudioRecorder::sampleRateChanged(int idx)
   314 {    
   305 {
   315     QAudioEncoderSettings settings = capture->audioSettings();
   306     QAudioEncoderSettings settings = capture->audioSettings();
   316     settings.setSampleRate((sampleRateBox->itemData(idx).toInt()));
   307     settings.setSampleRate((sampleRateBox->itemData(idx).toInt()));
   317     capture->setEncodingSettings(settings);
   308     capture->setEncodingSettings(settings);
   318 }
   309 }
   319 
   310 
   320 void AudioRecorder::channelCountChanged(int idx)
   311 void AudioRecorder::channelCountChanged(int idx)
   321 {    
   312 {
   322     QAudioEncoderSettings settings = capture->audioSettings();
   313     QAudioEncoderSettings settings = capture->audioSettings();
   323     settings.setChannelCount((channelBox->itemData(idx).toInt()));
   314     settings.setChannelCount((channelBox->itemData(idx).toInt()));
   324     capture->setEncodingSettings(settings);
   315     capture->setEncodingSettings(settings);
   325 }
   316 }
   326 
   317 
   327 void AudioRecorder::qualityChanged(int idx)
   318 void AudioRecorder::qualityChanged(int idx)
   328 { 
   319 {
   329     QAudioEncoderSettings settings = capture->audioSettings();    
   320     QAudioEncoderSettings settings = capture->audioSettings();
   330     
   321 
   331     switch(idx) {
   322     switch(idx) {
   332     case 0:
   323     case 0:
   333         settings.setQuality(QtMultimedia::LowQuality);
   324         settings.setQuality(QtMultimediaKit::LowQuality);
   334         break;
   325         break;
   335     case 1:
   326     case 1:
   336         settings.setQuality(QtMultimedia::NormalQuality);
   327         settings.setQuality(QtMultimediaKit::NormalQuality);
   337         break;
   328         break;
   338     default:
   329     default:
   339         settings.setQuality(QtMultimedia::HighQuality);
   330         settings.setQuality(QtMultimediaKit::HighQuality);
   340     }
   331     }
   341     capture->setEncodingSettings(settings);
   332     capture->setEncodingSettings(settings);
   342 }
   333 }
   343 
   334 
   344 void AudioRecorder::encmodeChanged(int idx)
   335 void AudioRecorder::encmodeChanged(int idx)
   345 {
   336 {
   346     QAudioEncoderSettings settings = capture->audioSettings();
   337     QAudioEncoderSettings settings = capture->audioSettings();
   347 
   338 
   348     switch(idx) {
   339     switch(idx) {
   349     case 0:
   340     case 0:
   350         settings.setEncodingMode(QtMultimedia::ConstantQualityEncoding);
   341         settings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding);
   351         break;
   342         break;
   352     case 1:
   343     case 1:
   353         settings.setEncodingMode(QtMultimedia::ConstantBitRateEncoding);
   344         settings.setEncodingMode(QtMultimediaKit::ConstantBitRateEncoding);
   354         break;
   345         break;
   355     default:
   346     default:
   356         settings.setEncodingMode(QtMultimedia::ConstantQualityEncoding);
   347         settings.setEncodingMode(QtMultimediaKit::ConstantQualityEncoding);
   357     }
   348     }
   358     capture->setEncodingSettings(settings);
   349     capture->setEncodingSettings(settings);
   359 }
   350 }
   360 
   351 
   361 void AudioRecorder::toggleRecord()
   352 void AudioRecorder::toggleRecord()
   363     if(!active) {
   354     if(!active) {
   364         if(!paused) {
   355         if(!paused) {
   365             recTime->setText("0");
   356             recTime->setText("0");
   366             currentTime = 0;
   357             currentTime = 0;
   367         }
   358         }
   368 #ifdef Q_OS_SYMBIAN    
   359 #ifdef Q_OS_SYMBIAN
   369     if (!paused)    
   360     if (!paused)
   370         capture->setOutputLocation(recordPathAudio(destination));
   361         capture->setOutputLocation(recordPathAudio(destination));
   371 #endif
   362 #endif
   372         capture->record();        
   363         capture->record();
   373         active = true;
   364         active = true;
   374         paused = false;
   365         paused = false;
   375     } else {
   366     } else {
   376         capture->stop();        
   367         capture->stop();
   377         active = false;
   368         active = false;
   378     }
   369     }
   379 }
   370 }
   380 
   371 
   381 void AudioRecorder::togglePause()
   372 void AudioRecorder::togglePause()
   382 {
   373 {
   383     if(active && !paused) {       
   374     if(active && !paused) {
   384         capture->pause();        
   375         capture->pause();
   385         active = false;
   376         active = false;
   386         paused = true;
   377         paused = true;
   387     }
   378     }
   388 }
   379 }
   389 
   380 
   398         fileNames = dialog.selectedFiles();
   389         fileNames = dialog.selectedFiles();
   399 
   390 
   400     if(fileNames.size() > 0)
   391     if(fileNames.size() > 0)
   401 #ifdef Q_OS_SYMBIAN
   392 #ifdef Q_OS_SYMBIAN
   402         destination = QUrl(fileNames.first());
   393         destination = QUrl(fileNames.first());
   403 #else    
   394 #else
   404         capture->setOutputLocation(QUrl(fileNames.first()));
   395         capture->setOutputLocation(QUrl(fileNames.first()));
   405         
   396 
   406 #endif    
   397 #endif
   407 }
   398 }
   408 
   399 
   409 void AudioRecorder::errorChanged(QMediaRecorder::Error err)
   400 void AudioRecorder::errorChanged(QMediaRecorder::Error err)
   410 {
   401 {
   411     Q_UNUSED(err)
   402     Q_UNUSED(err)
   415 
   406 
   416 void AudioRecorder::updateSamplerates(int idx)
   407 void AudioRecorder::updateSamplerates(int idx)
   417 {
   408 {
   418     QAudioEncoderSettings settings;
   409     QAudioEncoderSettings settings;
   419     settings.setCodec(codecsBox->itemText(idx));
   410     settings.setCodec(codecsBox->itemText(idx));
   420     
   411 
   421     QList<int> supportedSampleRates = capture->supportedAudioSampleRates(settings);
   412     QList<int> supportedSampleRates = capture->supportedAudioSampleRates(settings);
   422     sampleRateBox->clear();    
   413     sampleRateBox->clear();
   423     for(int i = 0; i < supportedSampleRates.count(); i++) {        
   414     for(int i = 0; i < supportedSampleRates.count(); i++) {
   424         QString rateString = QString("%1").arg(supportedSampleRates.at(i));
   415         QString rateString = QString("%1").arg(supportedSampleRates.at(i));
   425         sampleRateBox->addItem(rateString, QVariant(supportedSampleRates.at(i))); 
   416         sampleRateBox->addItem(rateString, QVariant(supportedSampleRates.at(i)));
   426     }    
   417     }
   427 }
   418 }
   428 
   419 
   429 void AudioRecorder::updateChannelCount(int idx)
   420 void AudioRecorder::updateChannelCount(int idx)
   430 {    
   421 {
   431     QMediaControl *control = audiosource->service()->requestControl(QAudioEncoderControl_iid);
   422     QMediaControl *control = audiosource->service()->requestControl(QAudioEncoderControl_iid);
   432     if (!control)
   423     if (!control)
   433         return;
   424         return;
   434 
   425 
   435     QAudioEncoderControl *audioEncoder = qobject_cast<QAudioEncoderControl*>(control);
   426     QAudioEncoderControl *audioEncoder = qobject_cast<QAudioEncoderControl*>(control);
   443     QList<int> channels;
   434     QList<int> channels;
   444     if (list.contains("channels"))
   435     if (list.contains("channels"))
   445         channels <<1<<2;
   436         channels <<1<<2;
   446     else
   437     else
   447         channels <<1;
   438         channels <<1;
   448     for(int i = 0; i < channels.count(); i++) {        
   439     for(int i = 0; i < channels.count(); i++) {
   449         QString channelString = QString("%1").arg(channels.at(i));
   440         QString channelString = QString("%1").arg(channels.at(i));
   450         channelBox->addItem(channelString, QVariant(channels.at(i))); 
   441         channelBox->addItem(channelString, QVariant(channels.at(i)));
   451     }        
   442     }
   452 }
   443 }
   453 
   444 
   454 void AudioRecorder::updateQuality(int idx)
   445 void AudioRecorder::updateQuality(int idx)
   455 {    
   446 {
   456     QMediaControl *control = audiosource->service()->requestControl(QAudioEncoderControl_iid);
   447     QMediaControl *control = audiosource->service()->requestControl(QAudioEncoderControl_iid);
   457     if (!control)
   448     if (!control)
   458         return;
   449         return;
   459 
   450 
   460     QAudioEncoderControl *audioEncoder = qobject_cast<QAudioEncoderControl*>(control);
   451     QAudioEncoderControl *audioEncoder = qobject_cast<QAudioEncoderControl*>(control);
   470         qualityBox->addItem(tr("Low"));
   461         qualityBox->addItem(tr("Low"));
   471         qualityBox->addItem(tr("Medium"));
   462         qualityBox->addItem(tr("Medium"));
   472         qualityBox->addItem(tr("High"));
   463         qualityBox->addItem(tr("High"));
   473     }else {
   464     }else {
   474         qualityBox->addItem(tr("Low"));
   465         qualityBox->addItem(tr("Low"));
   475     }           
   466     }
   476 }
   467 }