diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..101ff1e6c240fc99eaa740e101955a7ef026e676 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,64 @@ +{ + "files.associations": { + "algorithm": "cpp", + "atomic": "cpp", + "bit": "cpp", + "cctype": "cpp", + "cinttypes": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "compare": "cpp", + "concepts": "cpp", + "condition_variable": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "deque": "cpp", + "exception": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "ios": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "iterator": "cpp", + "limits": "cpp", + "list": "cpp", + "memory": "cpp", + "mutex": "cpp", + "new": "cpp", + "optional": "cpp", + "ostream": "cpp", + "queue": "cpp", + "ranges": "cpp", + "ratio": "cpp", + "span": "cpp", + "stdexcept": "cpp", + "stop_token": "cpp", + "streambuf": "cpp", + "string": "cpp", + "system_error": "cpp", + "thread": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "typeinfo": "cpp", + "unordered_map": "cpp", + "utility": "cpp", + "vector": "cpp", + "xfacet": "cpp", + "xhash": "cpp", + "xiosbase": "cpp", + "xlocale": "cpp", + "xlocinfo": "cpp", + "xlocnum": "cpp", + "xmemory": "cpp", + "xstddef": "cpp", + "xstring": "cpp", + "xtr1common": "cpp", + "xutility": "cpp" + } +} \ No newline at end of file diff --git a/entry/src/main/cpp/CMakeLists.txt b/entry/src/main/cpp/CMakeLists.txt index e498f02e07801619a12e1182c24ebf6615cf55bd..f60208c9bbf568a8bdf8a5c2863bc36d4bae0f38 100644 --- a/entry/src/main/cpp/CMakeLists.txt +++ b/entry/src/main/cpp/CMakeLists.txt @@ -33,10 +33,11 @@ add_library(player SHARED sample/player/PlayerNative.cpp add_library(recorder SHARED sample/recorder/RecorderNative.cpp sample/recorder/Recorder.cpp + sample/recorder/AudioRecord.cpp capbilities/Muxer.cpp capbilities/VideoEncoder.cpp common/SampleCallback.cpp ) target_link_libraries(player PUBLIC ${BASE_LIBRARY}) -target_link_libraries(recorder PUBLIC ${BASE_LIBRARY}) \ No newline at end of file +target_link_libraries(recorder PUBLIC ${BASE_LIBRARY}) diff --git a/entry/src/main/cpp/capbilities/Muxer.cpp b/entry/src/main/cpp/capbilities/Muxer.cpp index 59eb4abb4a65167339907c0edec07c8967443333..0b53813f5d3d47fb1860c27c7898ac7f29dda489 100644 --- a/entry/src/main/cpp/capbilities/Muxer.cpp +++ b/entry/src/main/cpp/capbilities/Muxer.cpp @@ -21,6 +21,7 @@ namespace { constexpr int32_t VERTICAL_ANGLE = 90; constexpr int32_t HORIZONTAL_ANGLE = 0; +constexpr int32_t SAMPLE_RATE = 16000; } Muxer::~Muxer() @@ -59,6 +60,13 @@ int32_t Muxer::Config(SampleInfo &sampleInfo) CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "AddTrack failed"); OH_AVFormat_Destroy(formatVideo); OH_AVMuxer_SetRotation(muxer_, sampleInfo.videoHeight > sampleInfo.videoWidth ? VERTICAL_ANGLE : HORIZONTAL_ANGLE); + + OH_AVFormat *formatAudio = OH_AVFormat_CreateAudioFormat(OH_AVCODEC_MIMETYPE_AUDIO_AAC, SAMPLE_RATE, 1); + OH_AVFormat_SetIntValue(formatAudio, OH_MD_KEY_PROFILE, AAC_PROFILE_LC); + + OH_AVMuxer_AddTrack(muxer_, &audioTrackId_, formatAudio); + OH_AVFormat_Destroy(formatAudio); + return AVCODEC_SAMPLE_ERR_OK; } @@ -84,6 +92,16 @@ int32_t Muxer::WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr) return AVCODEC_SAMPLE_ERR_OK; } +int32_t Muxer::WriteFrame(OH_AVBuffer *buffer) +{ + CHECK_AND_RETURN_RET_LOG(muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Muxer is null"); + CHECK_AND_RETURN_RET_LOG(buffer != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Get a empty buffer"); + + int32_t ret = OH_AVMuxer_WriteSampleBuffer(muxer_, audioTrackId_, buffer); + CHECK_AND_RETURN_RET_LOG(ret == AV_ERR_OK, AVCODEC_SAMPLE_ERR_ERROR, "Write sample failed"); + return AVCODEC_SAMPLE_ERR_OK; +} + int32_t Muxer::Release() { if (muxer_ != nullptr) { diff --git a/entry/src/main/cpp/capbilities/include/Muxer.h b/entry/src/main/cpp/capbilities/include/Muxer.h index 8354a9cdbfcd730cabcb03a96c18a9e12f12949a..0e736c42f2d89c8dee3b57f32e29c81ff16715fa 100644 --- a/entry/src/main/cpp/capbilities/include/Muxer.h +++ b/entry/src/main/cpp/capbilities/include/Muxer.h @@ -31,11 +31,13 @@ public: int32_t Config(SampleInfo &sampleInfo); int32_t Start(); int32_t WriteSample(OH_AVBuffer *buffer, OH_AVCodecBufferAttr &attr); + int32_t WriteFrame(OH_AVBuffer *buffer); int32_t Release(); private: OH_AVMuxer *muxer_ = nullptr; int32_t videoTrackId_ = -1; + int32_t audioTrackId_ = -1; }; #endif // MUXER_H \ No newline at end of file diff --git a/entry/src/main/cpp/common/SampleCallback.cpp b/entry/src/main/cpp/common/SampleCallback.cpp index a47b6ae623d15ff44d869323391b6788470b2cff..a6db8c2a03f9dd4f44e57cb1df72432d543c964d 100644 --- a/entry/src/main/cpp/common/SampleCallback.cpp +++ b/entry/src/main/cpp/common/SampleCallback.cpp @@ -18,17 +18,18 @@ namespace { constexpr int LIMIT_LOGD_FREQUENCY = 50; +constexpr int BALANCE_VALUE = 2; } // Custom write data function int32_t SampleCallback::OnRenderWriteData(OH_AudioRenderer *renderer, void *userData, void *buffer, int32_t length) { (void)renderer; - (void)length; CodecUserData *codecUserData = static_cast(userData); // Write the data to be played to the buffer by length uint8_t *dest = (uint8_t *)buffer; size_t index = 0; + codecUserData->renderFrameBytes = length; std::unique_lock lock(codecUserData->outputMutex); // Retrieve the length of the data to be played from the queue while (!codecUserData->renderQueue.empty() && index < length) { @@ -39,7 +40,7 @@ int32_t SampleCallback::OnRenderWriteData(OH_AudioRenderer *renderer, void *user "renderReadSize: %{public}u", length, codecUserData->outputFrameCount, (unsigned int)codecUserData->renderQueue.size(), (unsigned int)index); - if (codecUserData->renderQueue.size() < length) { + if (codecUserData->renderQueue.size() < BALANCE_VALUE * codecUserData->renderFrameBytes) { codecUserData->renderCond.notify_all(); } return 0; diff --git a/entry/src/main/cpp/common/SampleInfo.h b/entry/src/main/cpp/common/SampleInfo.h index 4c2639a86d87625047487cb52364fed6ad3f5313..2b15ea8527d7171bb2504de4ec346db97d978541 100644 --- a/entry/src/main/cpp/common/SampleInfo.h +++ b/entry/src/main/cpp/common/SampleInfo.h @@ -103,6 +103,7 @@ public: std::queue outputBufferInfoQueue; std::queue renderQueue; + uint32_t renderFrameBytes = 0; }; #endif // AVCODEC_SAMPLE_INFO_H \ No newline at end of file diff --git a/entry/src/main/cpp/sample/player/Player.cpp b/entry/src/main/cpp/sample/player/Player.cpp index 7f89adc503c715ca3c92e2bb94f04dfdec7dcc9b..cf82863e883953b6352e15019a9c678eec32553b 100644 --- a/entry/src/main/cpp/sample/player/Player.cpp +++ b/entry/src/main/cpp/sample/player/Player.cpp @@ -22,7 +22,7 @@ #define LOG_TAG "player" namespace { -constexpr int BALANCE_VALUE = 5; +constexpr int BALANCE_VALUE = 2; using namespace std::chrono_literals; } // namespace @@ -157,6 +157,8 @@ int32_t Player::Start() { } void Player::StartRelease() { + std::unique_lock lock(doneMutex); + doneCond_.wait(lock, [this]() {return isAudioDone.load() && isVideoDone.load();}); if (audioRenderer_) { OH_AudioRenderer_Stop(audioRenderer_); } @@ -284,6 +286,9 @@ void Player::VideoDecOutputThread() { std::this_thread::sleep_until(lastPushTime + std::chrono::microseconds(sampleInfo_.frameInterval)); lastPushTime = std::chrono::system_clock::now(); } + std::unique_lock lock(doneMutex); + isVideoDone = true; + lock.unlock(); StartRelease(); } @@ -313,6 +318,8 @@ void Player::AudioDecInputThread() { } void Player::AudioDecOutputThread() { + isAudioDone = false; + while (true) { CHECK_AND_BREAK_LOG(isStarted_, "Decoder output thread out"); std::unique_lock lock(audioDecContext_->outputMutex); @@ -345,12 +352,15 @@ void Player::AudioDecOutputThread() { int32_t ret = audioDecoder_->FreeOutputBuffer(bufferInfo.bufferIndex, true); CHECK_AND_BREAK_LOG(ret == AVCODEC_SAMPLE_ERR_OK, "Decoder output thread out"); - std::unique_lock lockRender(audioDecContext_->renderMutex); - audioDecContext_->renderCond.wait_for(lockRender, 20ms, [this, bufferInfo]() { - return audioDecContext_->renderQueue.size() < BALANCE_VALUE * bufferInfo.attr.size; + + audioDecContext_->renderCond.wait_for(lockRender, 1s, [this, bufferInfo]() { + return audioDecContext_->renderQueue.size() < BALANCE_VALUE * audioDecContext_->renderFrameBytes; }); } AVCODEC_SAMPLE_LOGI("Out buffer end"); + std::unique_lock lock(doneMutex); + isAudioDone = true; + lock.unlock(); StartRelease(); } \ No newline at end of file diff --git a/entry/src/main/cpp/sample/player/Player.h b/entry/src/main/cpp/sample/player/Player.h index a45ee8d128d7e7875c0124232d4a29c8b3aac9ea..b7f23cbd8f29cd0643f9c3c597128e7e7596cbf6 100644 --- a/entry/src/main/cpp/sample/player/Player.h +++ b/entry/src/main/cpp/sample/player/Player.h @@ -61,8 +61,11 @@ private: std::unique_ptr demuxer_ = nullptr; std::mutex mutex_; + std::mutex doneMutex; std::atomic isStarted_{false}; std::atomic isReleased_{false}; + std::atomic isAudioDone{true}; + std::atomic isVideoDone{false}; std::unique_ptr videoDecInputThread_ = nullptr; std::unique_ptr videoDecOutputThread_ = nullptr; std::unique_ptr audioDecInputThread_ = nullptr; @@ -77,6 +80,7 @@ private: std::ofstream audioOutputFile_; // for debug #endif static constexpr int64_t MICROSECOND = 1000000; + uint32_t renderFrameBytes = 0; }; #endif // VIDEO_CODEC_PLAYER_H \ No newline at end of file diff --git a/entry/src/main/cpp/sample/recorder/AudioRecord.cpp b/entry/src/main/cpp/sample/recorder/AudioRecord.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cbb07261594e6accd54f6956a80718ba69a5b1ae --- /dev/null +++ b/entry/src/main/cpp/sample/recorder/AudioRecord.cpp @@ -0,0 +1,192 @@ +#include "AudioRecord.h" + +using namespace std; + +int32_t SAMPLE_RATE = 16000; +int32_t CHANNEL_COUNT = 1; +constexpr int32_t INPUT_FRAME_BYTES = 2 * 1024; +static OH_AudioCapturer *audioCapturer; +static OH_AudioStreamBuilder *builder; + +vector pcmBuffer; +AEncSignal *signal_; + +static void OnError(OH_AVCodec *codec, int32_t errorCode, void *userData) +{ + (void)codec; + (void)errorCode; + (void)userData; + cout << "Error received, errorCode:" << errorCode << endl; +} + +static void OnOutputFormatChanged(OH_AVCodec *codec, OH_AVFormat *format, void *userData) +{ + (void)codec; + (void)format; + (void)userData; + cout << "OnOutputFormatChanged received" << endl; +} + +static void OnInputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) +{ + (void)codec; + AEncSignal *signal = static_cast(userData); + unique_lock lock(signal->inMutex_); + signal->inQueue_.push(index); + signal->inBufferQueue_.push(buffer); + signal->inCond_.notify_all(); +} + +static void OnOutputBufferAvailable(OH_AVCodec *codec, uint32_t index, OH_AVBuffer *buffer, void *userData) +{ + (void)codec; + AEncSignal *signal = static_cast(userData); + unique_lock lock(signal->outMutex_); + signal->outQueue_.push(index); + signal->outBufferQueue_.push(buffer); + signal->outCond_.notify_all(); +} + +static int32_t AudioCapturerOnReadData(OH_AudioCapturer *capturer, void *userData, void *buffer, int32_t bufferLen) { + unique_lock lock(signal_->inMutex_); + pcmBuffer.insert(pcmBuffer.end(), reinterpret_cast(buffer), reinterpret_cast(buffer) + bufferLen); + signal_->inCond_.notify_all(); + return 0; +} + +void AudioRecord::InputFunc() +{ + while (isRunning_.load()) { + unique_lock lock(signal_->inMutex_); + signal_->inCond_.wait(lock, [this]() { return ((pcmBuffer.size() > INPUT_FRAME_BYTES && signal_->inQueue_.size() > 0) || !isRunning_.load()); }); + if (!isRunning_.load()) { + break; + } + uint32_t index = signal_->inQueue_.front(); + auto buffer = signal_->inBufferQueue_.front(); + + OH_AVCodecBufferAttr info; + memcpy(reinterpret_cast(OH_AVBuffer_GetAddr(buffer)), pcmBuffer.data(), INPUT_FRAME_BYTES); + pcmBuffer.erase(pcmBuffer.begin(), pcmBuffer.begin() + INPUT_FRAME_BYTES); + + info.size = INPUT_FRAME_BYTES; + + int32_t ret = 0; + if (isFirstFrame_) { + info.flags = AVCODEC_BUFFER_FLAGS_CODEC_DATA; + OH_AVBuffer_SetBufferAttr(buffer, &info); + ret = OH_AudioCodec_PushInputBuffer(audioEnc_, index); + isFirstFrame_ = false; + } else { + info.flags = AVCODEC_BUFFER_FLAGS_NONE; + OH_AVBuffer_SetBufferAttr(buffer, &info); + ret = OH_AudioCodec_PushInputBuffer(audioEnc_, index); + } + signal_->inQueue_.pop(); + signal_->inBufferQueue_.pop(); + } +} + +void AudioRecord::OutputFunc() +{ + int64_t size; + while (isRunning_.load()) { + unique_lock lock(signal_->outMutex_); + signal_->outCond_.wait(lock, [this]() { return (signal_->outQueue_.size() > 0 || !isRunning_.load()); }); + if (!isRunning_.load()) { + break; + } + uint32_t index = signal_->outQueue_.front(); + OH_AVBuffer *avBuffer = signal_->outBufferQueue_.front(); + + OH_AVCodecBufferAttr info; + OH_AVBuffer_GetBufferAttr(avBuffer, &info); + size = info.size; + AVCODEC_SAMPLE_LOGD("pts %{public}ld", info.pts); + muxerA_->WriteFrame(avBuffer); + signal_->outBufferQueue_.pop(); + signal_->outQueue_.pop(); + OH_AudioCodec_FreeOutputBuffer(audioEnc_, index); + } + +} + + +void AudioRecord::AudioCapturerInit() +{ + if (audioCapturer) { + OH_AudioCapturer_Release(audioCapturer); + OH_AudioStreamBuilder_Destroy(builder); + audioCapturer = nullptr; + builder = nullptr; + } + + // Create builder + OH_AudioStream_Type type = AUDIOSTREAM_TYPE_CAPTURER; + OH_AudioStreamBuilder_Create(&builder, type); + // set params and callbacks + OH_AudioStreamBuilder_SetSamplingRate(builder, SAMPLE_RATE); + OH_AudioStreamBuilder_SetChannelCount(builder, CHANNEL_COUNT); + OH_AudioStreamBuilder_SetSampleFormat(builder, AUDIOSTREAM_SAMPLE_S16LE); + OH_AudioStreamBuilder_SetLatencyMode(builder, AUDIOSTREAM_LATENCY_MODE_FAST); + OH_AudioStreamBuilder_SetEncodingType(builder, AUDIOSTREAM_ENCODING_TYPE_RAW); + OH_AudioCapturer_Callbacks callbacks; + callbacks.OH_AudioCapturer_OnReadData = AudioCapturerOnReadData; + OH_AudioStreamBuilder_SetCapturerCallback(builder, callbacks, nullptr); + // create OH_AudioCapturer + OH_AudioStreamBuilder_GenerateCapturer(builder, &audioCapturer); + + //create audio encoder stream + OH_AVFormat *format = OH_AVFormat_Create(); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_CHANNEL_COUNT, CHANNEL_COUNT ); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUD_SAMPLE_RATE, SAMPLE_RATE); + OH_AVFormat_SetIntValue(format, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, AUDIOSTREAM_SAMPLE_S16LE); + + audioEnc_ = OH_AudioCodec_CreateByMime(OH_AVCODEC_MIMETYPE_AUDIO_AAC, true); + if (signal_) { + delete signal_; + signal_ = nullptr; + } + signal_ = new AEncSignal(); + cb_ = {&OnError, &OnOutputFormatChanged, &OnInputBufferAvailable, &OnOutputBufferAvailable}; + int32_t ret = OH_AudioCodec_RegisterCallback(audioEnc_, cb_, signal_); + + OH_AudioCodec_Configure(audioEnc_, format); +} + +void AudioRecord::AudioCapturerStart(std::unique_ptr& muxer) +{ + muxerA_ = muxer.get(); + isRunning_.store(true); + OH_AudioCapturer_Start(audioCapturer); + + inputLoop_ = make_unique(&AudioRecord::InputFunc, this); + outputLoop_ = make_unique(&AudioRecord::OutputFunc, this); + + OH_AudioCodec_Start(audioEnc_); + +} + +void AudioRecord::AudioCapturerRelease() { + if (audioCapturer) { + OH_AudioCapturer_Release(audioCapturer); + OH_AudioStreamBuilder_Destroy(builder); + audioCapturer = nullptr; + builder = nullptr; + } + OH_AudioCodec_Stop(audioEnc_); + OH_AudioCodec_Destroy(audioEnc_); + audioEnc_ = nullptr; + isRunning_ = false; + if (signal_) { + signal_->inCond_.notify_all(); + signal_->outCond_.notify_all(); + inputLoop_->join(); + inputLoop_ = nullptr; + outputLoop_->join(); + outputLoop_ = nullptr; + delete signal_; + signal_ = nullptr; + } + pcmBuffer.shrink_to_fit(); +} diff --git a/entry/src/main/cpp/sample/recorder/AudioRecord.h b/entry/src/main/cpp/sample/recorder/AudioRecord.h new file mode 100644 index 0000000000000000000000000000000000000000..1f50b65d31e6f9a66738034f8e55b2e825a2272c --- /dev/null +++ b/entry/src/main/cpp/sample/recorder/AudioRecord.h @@ -0,0 +1,59 @@ +#ifndef AUDIO_ENCODE_H +#define AUDIO_ENCODE_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include "multimedia/player_framework/native_avbuffer.h" +#include "ohaudio/native_audiocapturer.h" +#include "ohaudio/native_audiorenderer.h" +#include "ohaudio/native_audiostreambuilder.h" +#include "ohaudio/native_audiostream_base.h" +#include "multimedia/player_framework/native_avformat.h" +#include "multimedia/player_framework/native_avcodec_base.h" +#include "multimedia/player_framework/native_avcodec_audiocodec.h" +#include "Muxer.h" + +using namespace std; + + +class AEncSignal { +public: + std::mutex inMutex_; + std::mutex outMutex_; + std::mutex startMutex_; + std::condition_variable inCond_; + std::condition_variable outCond_; + std::condition_variable startCond_; + std::queue inQueue_; + std::queue outQueue_; + std::queue inBufferQueue_; + std::queue outBufferQueue_; +}; +class AudioRecord { +public: + AudioRecord(){}; + ~AudioRecord(){ + AudioCapturerRelease(); + }; + void AudioCapturerInit(); + void AudioCapturerRelease(); + void AudioCapturerStart(std::unique_ptr& muxer); +private: + void InputFunc(); + void OutputFunc(); + + struct OH_AVCodecCallback cb_; + unique_ptr inputLoop_; + unique_ptr outputLoop_; + OH_AVCodec *audioEnc_; + Muxer *muxerA_ = nullptr; + int32_t isFirstFrame_ = true; + std::atomic isRunning_; +}; +#endif \ No newline at end of file diff --git a/entry/src/main/cpp/sample/recorder/Recorder.cpp b/entry/src/main/cpp/sample/recorder/Recorder.cpp index 2688b3fbf536b384e66de76e02a2424006fdc24b..7e2b1463a490027f6c5f613138b71a3ef36a1127 100644 --- a/entry/src/main/cpp/sample/recorder/Recorder.cpp +++ b/entry/src/main/cpp/sample/recorder/Recorder.cpp @@ -30,6 +30,8 @@ Recorder::~Recorder() { StartRelease(); } int32_t Recorder::Init(SampleInfo &sampleInfo) { std::lock_guard lock(mutex_); + audioRecord_ = std::make_unique(); + audioRecord_->AudioCapturerInit(); CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(videoEncoder_ == nullptr && muxer_ == nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); @@ -61,6 +63,7 @@ int32_t Recorder::Init(SampleInfo &sampleInfo) { int32_t Recorder::Start() { std::lock_guard lock(mutex_); + CHECK_AND_RETURN_RET_LOG(!isStarted_, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(encContext_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, "Already started."); CHECK_AND_RETURN_RET_LOG(videoEncoder_ != nullptr && muxer_ != nullptr, AVCODEC_SAMPLE_ERR_ERROR, @@ -78,7 +81,7 @@ int32_t Recorder::Start() { StartRelease(); return AVCODEC_SAMPLE_ERR_ERROR; } - + audioRecord_->AudioCapturerStart(muxer_); AVCODEC_SAMPLE_LOGI("Succeed"); return AVCODEC_SAMPLE_ERR_OK; } @@ -125,6 +128,7 @@ void Recorder::StartRelease() { void Recorder::Release() { std::lock_guard lock(mutex_); + audioRecord_->AudioCapturerRelease(); isStarted_ = false; if (encOutputThread_ && encOutputThread_->joinable()) { encOutputThread_->join(); diff --git a/entry/src/main/cpp/sample/recorder/Recorder.h b/entry/src/main/cpp/sample/recorder/Recorder.h index 5fd7b2863bb8f4b635f57539e16dda571a351446..fac2ad349677163a9c5f61f9c122f6c7dbed7d50 100644 --- a/entry/src/main/cpp/sample/recorder/Recorder.h +++ b/entry/src/main/cpp/sample/recorder/Recorder.h @@ -25,6 +25,7 @@ #include "VideoEncoder.h" #include "Muxer.h" #include "SampleInfo.h" +#include "AudioRecord.h" class Recorder { public: @@ -47,6 +48,7 @@ private: int32_t WaitForDone(); std::unique_ptr videoEncoder_ = nullptr; + std::unique_ptr audioRecord_ = nullptr; std::unique_ptr muxer_ = nullptr; std::mutex mutex_; diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets index e45511c22afb937d7f935a4b9c82a5cd0872f418..995d2cb1ab6be9b353e0a27503e1e46ec21494ed 100644 --- a/entry/src/main/ets/entryability/EntryAbility.ets +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -32,6 +32,18 @@ export default class EntryAbility extends UIAbility { // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + try { + let atManager = abilityAccessCtrl.createAtManager(); + atManager.requestPermissionsFromUser(this.context, ['ohos.permission.MICROPHONE']).then((data) => { + console.info('data:' + JSON.stringify(data)); + console.info('data permissions:' + data.permissions); + console.info('data authResults:' + data.authResults); + }).catch((err: BusinessError) => { + console.info('data:' + JSON.stringify(err)); + }); + } catch (err) { + Logger.error('Entry', 'requestPre() data: ' + JSON.stringify(err)); + } try { let atManager = abilityAccessCtrl.createAtManager(); atManager.requestPermissionsFromUser(this.context, ['ohos.permission.CAMERA']) diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets index 56f63f50c300d72ac14b94117fc8bb68222d3a4d..11fe5911e8f8f9c23054df7f2caee8296821b98a 100644 --- a/entry/src/main/ets/pages/Index.ets +++ b/entry/src/main/ets/pages/Index.ets @@ -24,7 +24,11 @@ import DateTimeUtil from '../common/utils/DateTimeUtils'; import { CommonConstants as Const } from '../common/CommonConstants'; import { CameraDataModel } from '../model/CameraDateModel'; import { cameraCheck } from '../common/utils/CameraCheck'; +import { abilityAccessCtrl, common } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +let context = getContext(this) as common.UIAbilityContext; +let atManager = abilityAccessCtrl.createAtManager(); const TAG: string = Const.INDEX_TAG; const DATETIME: DateTimeUtil = new DateTimeUtil(); diff --git a/entry/src/main/module.json5 b/entry/src/main/module.json5 index 8bd98e4a1f52a0fd9ff1566cbb38779a2112cb45..f55764985d9b79a39eef171e78422ec3a6bfb437 100644 --- a/entry/src/main/module.json5 +++ b/entry/src/main/module.json5 @@ -54,6 +54,36 @@ "abilities": ["EntryAbility"], "when": "always" } + }, + { + "name": "ohos.permission.MICROPHONE", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.READ_MEDIA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } + }, + { + "name": "ohos.permission.WRITE_MEDIA", + "reason": "$string:EntryAbility_desc", + "usedScene": { + "abilities": [ + "EntryAbility" + ], + "when": "always" + } } ] }