Loading plugin.xml +12 −0 Changes for plugin.xml: 12 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -58,6 +58,18 @@ id="org.apache.cordova.media" </platform> <!-- ubuntu --> <platform name="ubuntu"> <config-file target="config.xml" parent="/*"> <feature name="Media"> <param policy_group="microphone" policy_version="1" /> <param policy_group="video" policy_version="1" /> </feature> </config-file> <header-file src="src/ubuntu/media.h" /> <source-file src="src/ubuntu/media.cpp" /> </platform> <!-- ios --> <platform name="ios"> <config-file target="config.xml" parent="/*"> Loading src/ubuntu/media.cpp 0 → 100644 +128 −0 Changes for src/ubuntu/media.cpp: 128 added lines, 0 removed lines. Original line number Diff line number Diff line /* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "media.h" void Media::create(int scId, int ecId, const QString &id, const QString &src) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) != _id2Player.end()) { _id2Player[id]->stop(); _id2Player.remove(id); } _id2Player[id] = QSharedPointer<Player>(new Player(id, src, this)); } void Media::relase(int scId, int ecId, const QString &id) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; _id2Player.remove(id); } void Media::startPlayingAudio(int scId, int ecId, const QString &id, const QString &src, QVariantMap options) { Q_UNUSED(scId); Q_UNUSED(ecId); Q_UNUSED(src); Q_UNUSED(options); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->play(); } void Media::pausePlayingAudio(int scId, int ecId, const QString &id) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->pause(); } void Media::stopPlayingAudio(int scId, int ecId, const QString &id) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->stop(); } void Media::startRecordingAudio(int scId, int ecId, const QString &id, const QString &src) { Q_UNUSED(scId); Q_UNUSED(ecId); Q_UNUSED(src); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->startRecording(); } void Media::stopRecordingAudio(int scId, int ecId, const QString &id) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->stopRecording(); } void Media::getCurrentPositionAudio(int scId, int ecId, const QString &id) { Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; double position = player->getPosition(); this->cb(scId, position); } void Media::seekToAudio(int scId, int ecId, const QString &id, qint64 position) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->seekTo(position); } void Media::setVolume(int scId, int ecId, const QString &id, int volume) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->setVolume(volume); } src/ubuntu/media.h 0 → 100644 +267 −0 Changes for src/ubuntu/media.h: 267 added lines, 0 removed lines. Original line number Diff line number Diff line /* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #ifndef MEDIA_H_789768978 #define MEDIA_H_789768978 #include <QtMultimedia/QMediaPlayer> #include <QtCore> #include <QAudioRecorder> #include <QtMultimedia/QAudioEncoderSettings> #include <cplugin.h> #include <cordova.h> class Player; class Media: public CPlugin { Q_OBJECT public: explicit Media(Cordova *cordova): CPlugin(cordova) { } virtual const QString fullName() override { return Media::fullID(); } virtual const QString shortName() override { return "Media"; } static const QString fullID() { return "Media"; } enum State { MEDIA_NONE = 0, MEDIA_STARTING = 1, MEDIA_RUNNING = 2, MEDIA_PAUSED = 3, MEDIA_STOPPED = 4 }; enum ErrorCode { MEDIA_ERR_NONE_ACTIVE = 0, MEDIA_ERR_ABORTED = 1, MEDIA_ERR_NETWORK = 2, MEDIA_ERR_DECODE = 3, MEDIA_ERR_NONE_SUPPORTED = 4 }; void execJS(const QString &js) { m_cordova->execJS(js); } public slots: void create(int scId, int ecId, const QString &id, const QString &src); void relase(int scId, int ecId, const QString &id); void startRecordingAudio(int scId, int ecId, const QString &id, const QString &src); void stopRecordingAudio(int scId, int ecId, const QString &id); void startPlayingAudio(int scId, int ecId, const QString &id, const QString &src, QVariantMap options); void pausePlayingAudio(int scId, int ecId, const QString &id); void stopPlayingAudio(int scId, int ecId, const QString &id); void getCurrentPositionAudio(int scId, int ecId, const QString &id); void seekToAudio(int scId, int ecId, const QString &id, qint64 position); void setVolume(int scId, int ecId, const QString &id, int volume); private: QMap<QString, QSharedPointer<Player> > _id2Player; }; class Player: public QObject { Q_OBJECT public: Player(const QString &id, QString src, Media *plugin): _state(Media::MEDIA_NONE), _src(src), _mode(MODE_NONE), _plugin(plugin), _id(id), _stateChanged(false) { QUrl url(src, QUrl::TolerantMode); if (url.scheme().isEmpty()) { QAudioEncoderSettings audioSettings; _recorder.setEncodingSettings(audioSettings); _recorder.setOutputLocation(QFileInfo(src).absoluteFilePath()); _player.setMedia(QUrl::fromLocalFile(QFileInfo(src).absoluteFilePath())); } else { _player.setMedia(url); } QObject::connect(&_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(onMediaStatusChanged(QMediaPlayer::MediaStatus))); QObject::connect(&_recorder, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(onError(QMediaRecorder::Error))); connect(&_timer, SIGNAL(timeout()), this, SLOT(reportPosition())); } void startRecording() { if (recordMode() && _state != Media::MEDIA_RUNNING) { _recorder.record(); setState(Media::MEDIA_RUNNING); } } void stopRecording() { if (recordMode() && _state == Media::MEDIA_RUNNING) { _recorder.stop(); setState(Media::MEDIA_STOPPED); } } void setVolume(int volume) { _player.setVolume(volume); } void play() { if (playMode() && _state != Media::MEDIA_RUNNING) { _player.play(); setState(Media::MEDIA_RUNNING); } } void pause() { if (playMode() && _state == Media::MEDIA_RUNNING) { _player.pause(); setState(Media::MEDIA_PAUSED); } } void stop() { if (playMode() && (_state == Media::MEDIA_RUNNING || _state == Media::MEDIA_PAUSED)) { _player.stop(); setState(Media::MEDIA_STOPPED); } } double getDuration() { if (_mode == MODE_NONE || _player.duration() == -1) return -1; if (_mode != MODE_PLAY) return -2; return static_cast<double>(_player.duration()) / 1000.0; } double getPosition() { if (_mode != MODE_PLAY) return -1; return static_cast<double>(_player.position()) / 1000.0; } bool seekTo(qint64 position) { if (!_player.isSeekable()) return false; _player.setPosition(position * 1000); return true; } private slots: void reportPosition() { double position = getPosition(); _plugin->execJS(QString("Media.onStatus('%1', Media.MEDIA_POSITION, %2)") .arg(_id).arg(position)); double duration = getDuration(); _plugin->execJS(QString("Media.onStatus('%1', Media.MEDIA_DURATION, %2)") .arg(_id).arg(duration)); if (_stateChanged && !(_state == Media::MEDIA_RUNNING && (duration == -1 || position == 0))) { qCritical() << _id << "POSITION" << position << ":" << duration; _stateChanged = false; _plugin->execJS(QString("Media.onStatus('%1', Media.MEDIA_STATE, %2)").arg(_id).arg(_state)); } } void onMediaStatusChanged(QMediaPlayer::MediaStatus status) { if (status == QMediaPlayer::InvalidMedia) { reportError(Media::MEDIA_ERR_ABORTED, "AudioPlayer Error: The current media cannot be played."); setState(Media::MEDIA_STOPPED); } if (status == QMediaPlayer::EndOfMedia) { setState(Media::MEDIA_STOPPED); seekTo(0); } } void onError(QMediaRecorder::Error) { reportError(Media::MEDIA_ERR_NONE_SUPPORTED, "AudioPlayer Error: Device is not ready or not available."); setState(Media::MEDIA_STOPPED); } private: void reportError(int code, const QString &descr) { Q_UNUSED(descr); _plugin->execJS(QString("Media.onStatus('%1', Media.MEDIA_ERROR, {code: %2})") .arg(_id).arg(code)); } bool playMode() { switch (_mode) { case Player::MODE_NONE: _mode = MODE_PLAY; break; case Player::MODE_PLAY: break; case Player::MODE_RECORD: reportError(Media::MEDIA_ERR_NONE_SUPPORTED, "AudioPlayer Error: Can't play in record mode."); return false; break; } return true; } bool recordMode() { switch (_mode) { case Player::MODE_NONE: if (_recorder.outputLocation().isEmpty()) { reportError(Media::MEDIA_ERR_NONE_SUPPORTED, "AudioPlayer Error: unsupported output location."); return false; } _mode = MODE_RECORD; break; case Player::MODE_PLAY: reportError(Media::MEDIA_ERR_NONE_SUPPORTED, "AudioPlayer Error: Can't play in play mode."); return false; break; case Player::MODE_RECORD: break; } return true; } void setState(Media::State state) { _state = state; _stateChanged = true; _timer.start(250); } QMediaPlayer _player; QAudioRecorder _recorder; QTimer _timer; Media::State _state; QString _src; enum Mode { MODE_NONE, MODE_PLAY, MODE_RECORD }; Mode _mode; Media *_plugin; QString _id; bool _stateChanged; }; #endif Loading
plugin.xml +12 −0 Changes for plugin.xml: 12 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -58,6 +58,18 @@ id="org.apache.cordova.media" </platform> <!-- ubuntu --> <platform name="ubuntu"> <config-file target="config.xml" parent="/*"> <feature name="Media"> <param policy_group="microphone" policy_version="1" /> <param policy_group="video" policy_version="1" /> </feature> </config-file> <header-file src="src/ubuntu/media.h" /> <source-file src="src/ubuntu/media.cpp" /> </platform> <!-- ios --> <platform name="ios"> <config-file target="config.xml" parent="/*"> Loading
src/ubuntu/media.cpp 0 → 100644 +128 −0 Changes for src/ubuntu/media.cpp: 128 added lines, 0 removed lines. Original line number Diff line number Diff line /* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "media.h" void Media::create(int scId, int ecId, const QString &id, const QString &src) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) != _id2Player.end()) { _id2Player[id]->stop(); _id2Player.remove(id); } _id2Player[id] = QSharedPointer<Player>(new Player(id, src, this)); } void Media::relase(int scId, int ecId, const QString &id) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; _id2Player.remove(id); } void Media::startPlayingAudio(int scId, int ecId, const QString &id, const QString &src, QVariantMap options) { Q_UNUSED(scId); Q_UNUSED(ecId); Q_UNUSED(src); Q_UNUSED(options); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->play(); } void Media::pausePlayingAudio(int scId, int ecId, const QString &id) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->pause(); } void Media::stopPlayingAudio(int scId, int ecId, const QString &id) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->stop(); } void Media::startRecordingAudio(int scId, int ecId, const QString &id, const QString &src) { Q_UNUSED(scId); Q_UNUSED(ecId); Q_UNUSED(src); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->startRecording(); } void Media::stopRecordingAudio(int scId, int ecId, const QString &id) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->stopRecording(); } void Media::getCurrentPositionAudio(int scId, int ecId, const QString &id) { Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; double position = player->getPosition(); this->cb(scId, position); } void Media::seekToAudio(int scId, int ecId, const QString &id, qint64 position) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->seekTo(position); } void Media::setVolume(int scId, int ecId, const QString &id, int volume) { Q_UNUSED(scId); Q_UNUSED(ecId); if (_id2Player.find(id) == _id2Player.end()) return; QSharedPointer<Player> player = _id2Player[id]; player->setVolume(volume); }
src/ubuntu/media.h 0 → 100644 +267 −0 Changes for src/ubuntu/media.h: 267 added lines, 0 removed lines. Original line number Diff line number Diff line /* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #ifndef MEDIA_H_789768978 #define MEDIA_H_789768978 #include <QtMultimedia/QMediaPlayer> #include <QtCore> #include <QAudioRecorder> #include <QtMultimedia/QAudioEncoderSettings> #include <cplugin.h> #include <cordova.h> class Player; class Media: public CPlugin { Q_OBJECT public: explicit Media(Cordova *cordova): CPlugin(cordova) { } virtual const QString fullName() override { return Media::fullID(); } virtual const QString shortName() override { return "Media"; } static const QString fullID() { return "Media"; } enum State { MEDIA_NONE = 0, MEDIA_STARTING = 1, MEDIA_RUNNING = 2, MEDIA_PAUSED = 3, MEDIA_STOPPED = 4 }; enum ErrorCode { MEDIA_ERR_NONE_ACTIVE = 0, MEDIA_ERR_ABORTED = 1, MEDIA_ERR_NETWORK = 2, MEDIA_ERR_DECODE = 3, MEDIA_ERR_NONE_SUPPORTED = 4 }; void execJS(const QString &js) { m_cordova->execJS(js); } public slots: void create(int scId, int ecId, const QString &id, const QString &src); void relase(int scId, int ecId, const QString &id); void startRecordingAudio(int scId, int ecId, const QString &id, const QString &src); void stopRecordingAudio(int scId, int ecId, const QString &id); void startPlayingAudio(int scId, int ecId, const QString &id, const QString &src, QVariantMap options); void pausePlayingAudio(int scId, int ecId, const QString &id); void stopPlayingAudio(int scId, int ecId, const QString &id); void getCurrentPositionAudio(int scId, int ecId, const QString &id); void seekToAudio(int scId, int ecId, const QString &id, qint64 position); void setVolume(int scId, int ecId, const QString &id, int volume); private: QMap<QString, QSharedPointer<Player> > _id2Player; }; class Player: public QObject { Q_OBJECT public: Player(const QString &id, QString src, Media *plugin): _state(Media::MEDIA_NONE), _src(src), _mode(MODE_NONE), _plugin(plugin), _id(id), _stateChanged(false) { QUrl url(src, QUrl::TolerantMode); if (url.scheme().isEmpty()) { QAudioEncoderSettings audioSettings; _recorder.setEncodingSettings(audioSettings); _recorder.setOutputLocation(QFileInfo(src).absoluteFilePath()); _player.setMedia(QUrl::fromLocalFile(QFileInfo(src).absoluteFilePath())); } else { _player.setMedia(url); } QObject::connect(&_player, SIGNAL(mediaStatusChanged(QMediaPlayer::MediaStatus)), this, SLOT(onMediaStatusChanged(QMediaPlayer::MediaStatus))); QObject::connect(&_recorder, SIGNAL(error(QMediaRecorder::Error)), this, SLOT(onError(QMediaRecorder::Error))); connect(&_timer, SIGNAL(timeout()), this, SLOT(reportPosition())); } void startRecording() { if (recordMode() && _state != Media::MEDIA_RUNNING) { _recorder.record(); setState(Media::MEDIA_RUNNING); } } void stopRecording() { if (recordMode() && _state == Media::MEDIA_RUNNING) { _recorder.stop(); setState(Media::MEDIA_STOPPED); } } void setVolume(int volume) { _player.setVolume(volume); } void play() { if (playMode() && _state != Media::MEDIA_RUNNING) { _player.play(); setState(Media::MEDIA_RUNNING); } } void pause() { if (playMode() && _state == Media::MEDIA_RUNNING) { _player.pause(); setState(Media::MEDIA_PAUSED); } } void stop() { if (playMode() && (_state == Media::MEDIA_RUNNING || _state == Media::MEDIA_PAUSED)) { _player.stop(); setState(Media::MEDIA_STOPPED); } } double getDuration() { if (_mode == MODE_NONE || _player.duration() == -1) return -1; if (_mode != MODE_PLAY) return -2; return static_cast<double>(_player.duration()) / 1000.0; } double getPosition() { if (_mode != MODE_PLAY) return -1; return static_cast<double>(_player.position()) / 1000.0; } bool seekTo(qint64 position) { if (!_player.isSeekable()) return false; _player.setPosition(position * 1000); return true; } private slots: void reportPosition() { double position = getPosition(); _plugin->execJS(QString("Media.onStatus('%1', Media.MEDIA_POSITION, %2)") .arg(_id).arg(position)); double duration = getDuration(); _plugin->execJS(QString("Media.onStatus('%1', Media.MEDIA_DURATION, %2)") .arg(_id).arg(duration)); if (_stateChanged && !(_state == Media::MEDIA_RUNNING && (duration == -1 || position == 0))) { qCritical() << _id << "POSITION" << position << ":" << duration; _stateChanged = false; _plugin->execJS(QString("Media.onStatus('%1', Media.MEDIA_STATE, %2)").arg(_id).arg(_state)); } } void onMediaStatusChanged(QMediaPlayer::MediaStatus status) { if (status == QMediaPlayer::InvalidMedia) { reportError(Media::MEDIA_ERR_ABORTED, "AudioPlayer Error: The current media cannot be played."); setState(Media::MEDIA_STOPPED); } if (status == QMediaPlayer::EndOfMedia) { setState(Media::MEDIA_STOPPED); seekTo(0); } } void onError(QMediaRecorder::Error) { reportError(Media::MEDIA_ERR_NONE_SUPPORTED, "AudioPlayer Error: Device is not ready or not available."); setState(Media::MEDIA_STOPPED); } private: void reportError(int code, const QString &descr) { Q_UNUSED(descr); _plugin->execJS(QString("Media.onStatus('%1', Media.MEDIA_ERROR, {code: %2})") .arg(_id).arg(code)); } bool playMode() { switch (_mode) { case Player::MODE_NONE: _mode = MODE_PLAY; break; case Player::MODE_PLAY: break; case Player::MODE_RECORD: reportError(Media::MEDIA_ERR_NONE_SUPPORTED, "AudioPlayer Error: Can't play in record mode."); return false; break; } return true; } bool recordMode() { switch (_mode) { case Player::MODE_NONE: if (_recorder.outputLocation().isEmpty()) { reportError(Media::MEDIA_ERR_NONE_SUPPORTED, "AudioPlayer Error: unsupported output location."); return false; } _mode = MODE_RECORD; break; case Player::MODE_PLAY: reportError(Media::MEDIA_ERR_NONE_SUPPORTED, "AudioPlayer Error: Can't play in play mode."); return false; break; case Player::MODE_RECORD: break; } return true; } void setState(Media::State state) { _state = state; _stateChanged = true; _timer.start(250); } QMediaPlayer _player; QAudioRecorder _recorder; QTimer _timer; Media::State _state; QString _src; enum Mode { MODE_NONE, MODE_PLAY, MODE_RECORD }; Mode _mode; Media *_plugin; QString _id; bool _stateChanged; }; #endif