diff --git a/.github/workflows/media-livestream.yaml b/.github/workflows/media-livestream.yaml new file mode 100644 index 0000000000..8311d16289 --- /dev/null +++ b/.github/workflows/media-livestream.yaml @@ -0,0 +1,71 @@ +name: media-livestream +on: + push: + branches: + - main + paths: + - 'media/livestream/**' + - '.github/workflows/media-livestream.yaml' + pull_request: + paths: + - 'media/livestream/**' + - '.github/workflows/media-livestream.yaml' + pull_request_target: + types: [labeled] + paths: + - 'media/livestream/**' + - '.github/workflows/media-livestream.yaml' + schedule: + - cron: '0 0 * * 0' +jobs: + test: + if: ${{ github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' }} + runs-on: ubuntu-latest + timeout-minutes: 60 + permissions: + contents: 'write' + pull-requests: 'write' + id-token: 'write' + steps: + - uses: actions/checkout@v3.1.0 + with: + ref: ${{github.event.pull_request.head.sha}} + - uses: 'google-github-actions/auth@v1.0.0' + with: + workload_identity_provider: 'projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider' + service_account: 'kokoro-system-test@long-door-651.iam.gserviceaccount.com' + create_credentials_file: 'true' + access_token_lifetime: 600s + - uses: actions/setup-node@v3.5.1 + with: + node-version: 16 + - run: npm install + working-directory: media/livestream + - run: npm test + working-directory: media/livestream + env: + MOCHA_REPORTER_SUITENAME: media_livestream + MOCHA_REPORTER_OUTPUT: media_livestream_sponge_log.xml + MOCHA_REPORTER: xunit + - if: ${{ github.event.action == 'labeled' && github.event.label.name == 'actions:force-run' }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + try { + await github.rest.issues.removeLabel({ + name: 'actions:force-run', + owner: 'GoogleCloudPlatform', + repo: 'nodejs-docs-samples', + issue_number: context.payload.pull_request.number + }); + } catch (e) { + if (!e.message.includes('Label does not exist')) { + throw e; + } + } + - if: ${{ github.event_name == 'schedule' && always() }} + run: | + curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L + chmod +x ./flakybot + ./flakybot --repo GoogleCloudPlatform/nodejs-docs-samples --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} diff --git a/.github/workflows/workflows.json b/.github/workflows/workflows.json index a9457d68c3..b224ef1bc2 100644 --- a/.github/workflows/workflows.json +++ b/.github/workflows/workflows.json @@ -69,6 +69,7 @@ "healthcare/hl7v2", "iam", "kms", + "media/livestream", "media/transcoder", "media/video-stitcher", "mediatranslation", diff --git a/media/livestream/createChannel.js b/media/livestream/createChannel.js new file mode 100644 index 0000000000..b180f20d1a --- /dev/null +++ b/media/livestream/createChannel.js @@ -0,0 +1,119 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId, inputId, outputUri) { + // [START livestream_create_channel] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + // inputId = 'my-input'; + // outputUri = 'gs://my-bucket/my-output-folder/'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function createChannel() { + // Construct request + const request = { + parent: livestreamServiceClient.locationPath(projectId, location), + channelId: channelId, + channel: { + inputAttachments: [ + { + key: 'my-input', + input: livestreamServiceClient.inputPath( + projectId, + location, + inputId + ), + }, + ], + output: { + uri: outputUri, + }, + elementaryStreams: [ + { + key: 'es_video', + videoStream: { + h264: { + profile: 'high', + heightPixels: 720, + widthPixels: 1280, + bitrateBps: 3000000, + frameRate: 30, + }, + }, + }, + { + key: 'es_audio', + audioStream: { + codec: 'aac', + channelCount: 2, + bitrateBps: 160000, + }, + }, + ], + muxStreams: [ + { + key: 'mux_video', + elementaryStreams: ['es_video'], + segmentSettings: { + seconds: 2, + }, + }, + { + key: 'mux_audio', + elementaryStreams: ['es_audio'], + segmentSettings: { + seconds: 2, + }, + }, + ], + manifests: [ + { + fileName: 'manifest.m3u8', + type: 'HLS', + muxStreams: ['mux_video', 'mux_audio'], + maxSegmentCount: 5, + }, + ], + }, + }; + + // Run request + const [operation] = await livestreamServiceClient.createChannel(request); + const response = await operation.promise(); + const [channel] = response; + console.log(`Channel: ${channel.name}`); + } + + createChannel(); + // [END livestream_create_channel] +} + +// node createChannel.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/createChannelEvent.js b/media/livestream/createChannelEvent.js new file mode 100644 index 0000000000..901a50411f --- /dev/null +++ b/media/livestream/createChannelEvent.js @@ -0,0 +1,67 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId, eventId) { + // [START livestream_create_channel_event] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + // eventId = 'my-channel-event'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function createChannelEvent() { + // Construct request + const request = { + parent: livestreamServiceClient.channelPath( + projectId, + location, + channelId + ), + eventId: eventId, + event: { + adBreak: { + duration: { + seconds: 30, + }, + }, + executeNow: true, + }, + }; + + // Run request + const [event] = await livestreamServiceClient.createEvent(request); + console.log(`Channel event: ${event.name}`); + } + + createChannelEvent(); + // [END livestream_create_channel_event] +} + +// node createChannelEvent.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/createChannelWithBackupInput.js b/media/livestream/createChannelWithBackupInput.js new file mode 100644 index 0000000000..6796bf75e9 --- /dev/null +++ b/media/livestream/createChannelWithBackupInput.js @@ -0,0 +1,138 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main( + projectId, + location, + channelId, + primaryInputId, + backupInputId, + outputUri +) { + // [START livestream_create_channel_with_backup_input] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + // primaryInputId = 'my-primary-input'; + // backupInputId = 'my-backup-input'; + // outputUri = 'gs://my-bucket/my-output-folder/'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function createChannelWithBackupInput() { + // Construct request + const request = { + parent: livestreamServiceClient.locationPath(projectId, location), + channelId: channelId, + channel: { + inputAttachments: [ + { + key: 'my-primary-input', + input: livestreamServiceClient.inputPath( + projectId, + location, + primaryInputId + ), + automaticFailover: { + inputKeys: ['my-backup-input'], + }, + }, + { + key: 'my-backup-input', + input: livestreamServiceClient.inputPath( + projectId, + location, + backupInputId + ), + }, + ], + output: { + uri: outputUri, + }, + elementaryStreams: [ + { + key: 'es_video', + videoStream: { + h264: { + profile: 'high', + heightPixels: 720, + widthPixels: 1280, + bitrateBps: 3000000, + frameRate: 30, + }, + }, + }, + { + key: 'es_audio', + audioStream: { + codec: 'aac', + channelCount: 2, + bitrateBps: 160000, + }, + }, + ], + muxStreams: [ + { + key: 'mux_video', + elementaryStreams: ['es_video'], + segmentSettings: { + seconds: 2, + }, + }, + { + key: 'mux_audio', + elementaryStreams: ['es_audio'], + segmentSettings: { + seconds: 2, + }, + }, + ], + manifests: [ + { + fileName: 'manifest.m3u8', + type: 'HLS', + muxStreams: ['mux_video', 'mux_audio'], + maxSegmentCount: 5, + }, + ], + }, + }; + + // Run request + const [operation] = await livestreamServiceClient.createChannel(request); + const response = await operation.promise(); + const [channel] = response; + console.log(`Channel: ${channel.name}`); + } + + createChannelWithBackupInput(); + // [END livestream_create_channel_with_backup_input] +} + +// node createChannelWithBackupInput.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/createInput.js b/media/livestream/createInput.js new file mode 100644 index 0000000000..34a28a85f7 --- /dev/null +++ b/media/livestream/createInput.js @@ -0,0 +1,59 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, inputId) { + // [START livestream_create_input] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // inputId = 'my-input'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function createInput() { + // Construct request + const request = { + parent: livestreamServiceClient.locationPath(projectId, location), + inputId: inputId, + input: { + type: 'RTMP_PUSH', + }, + }; + + // Run request + const [operation] = await livestreamServiceClient.createInput(request); + const response = await operation.promise(); + const [input] = response; + console.log(`Input: ${input.name}`); + } + + createInput(); + // [END livestream_create_input] +} + +// node createInput.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/deleteChannel.js b/media/livestream/deleteChannel.js new file mode 100644 index 0000000000..5557540555 --- /dev/null +++ b/media/livestream/deleteChannel.js @@ -0,0 +1,54 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId) { + // [START livestream_delete_channel] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function deleteChannel() { + // Construct request + const request = { + name: livestreamServiceClient.channelPath(projectId, location, channelId), + }; + + // Run request + const [operation] = await livestreamServiceClient.deleteChannel(request); + await operation.promise(); + console.log('Deleted channel'); + } + + deleteChannel(); + // [END livestream_delete_channel] +} + +// node deleteChannel.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/deleteChannelEvent.js b/media/livestream/deleteChannelEvent.js new file mode 100644 index 0000000000..be0f5c4997 --- /dev/null +++ b/media/livestream/deleteChannelEvent.js @@ -0,0 +1,59 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId, eventId) { + // [START livestream_delete_channel_event] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + // eventId = 'my-channel-event'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function deleteChannelEvent() { + // Construct request + const request = { + name: livestreamServiceClient.eventPath( + projectId, + location, + channelId, + eventId + ), + }; + + // Run request + await livestreamServiceClient.deleteEvent(request); + console.log('Deleted channel event'); + } + + deleteChannelEvent(); + // [END livestream_delete_channel_event] +} + +// node deleteChannelEvent.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/deleteInput.js b/media/livestream/deleteInput.js new file mode 100644 index 0000000000..9866d5410b --- /dev/null +++ b/media/livestream/deleteInput.js @@ -0,0 +1,54 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, inputId) { + // [START livestream_delete_input] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // inputId = 'my-input'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function deleteInput() { + // Construct request + const request = { + name: livestreamServiceClient.inputPath(projectId, location, inputId), + }; + + // Run request + const [operation] = await livestreamServiceClient.deleteInput(request); + await operation.promise(); + console.log('Deleted input'); + } + + deleteInput(); + // [END livestream_delete_input] +} + +// node deleteInput.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/getChannel.js b/media/livestream/getChannel.js new file mode 100644 index 0000000000..5c38c6a76a --- /dev/null +++ b/media/livestream/getChannel.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId) { + // [START livestream_get_channel] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function getChannel() { + // Construct request + const request = { + name: livestreamServiceClient.channelPath(projectId, location, channelId), + }; + const [channel] = await livestreamServiceClient.getChannel(request); + console.log(`Channel: ${channel.name}`); + } + + getChannel(); + // [END livestream_get_channel] +} + +// node getChannel.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/getChannelEvent.js b/media/livestream/getChannelEvent.js new file mode 100644 index 0000000000..896e5d406c --- /dev/null +++ b/media/livestream/getChannelEvent.js @@ -0,0 +1,57 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId, eventId) { + // [START livestream_get_channel_event] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + // eventId = 'my-channel-event'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function getChannelEvent() { + // Construct request + const request = { + name: livestreamServiceClient.eventPath( + projectId, + location, + channelId, + eventId + ), + }; + const [event] = await livestreamServiceClient.getEvent(request); + console.log(`Channel event: ${event.name}`); + } + + getChannelEvent(); + // [END livestream_get_channel_event] +} + +// node getChannelEvent.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/getInput.js b/media/livestream/getInput.js new file mode 100644 index 0000000000..600493da47 --- /dev/null +++ b/media/livestream/getInput.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, inputId) { + // [START livestream_get_input] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // inputId = 'my-input'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function getInput() { + // Construct request + const request = { + name: livestreamServiceClient.inputPath(projectId, location, inputId), + }; + const [input] = await livestreamServiceClient.getInput(request); + console.log(`Input: ${input.name}`); + } + + getInput(); + // [END livestream_get_input] +} + +// node getInput.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/listChannelEvents.js b/media/livestream/listChannelEvents.js new file mode 100644 index 0000000000..de4fee0a3b --- /dev/null +++ b/media/livestream/listChannelEvents.js @@ -0,0 +1,56 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId) { + // [START livestream_list_channel_events] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function listChannelEvents() { + const iterable = await livestreamServiceClient.listEventsAsync({ + parent: livestreamServiceClient.channelPath( + projectId, + location, + channelId + ), + }); + console.info('Channel events:'); + for await (const response of iterable) { + console.log(response.name); + } + } + + listChannelEvents(); + // [END livestream_list_channel_events] +} + +// node listChannelEvents.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/listChannels.js b/media/livestream/listChannels.js new file mode 100644 index 0000000000..a8380177cf --- /dev/null +++ b/media/livestream/listChannels.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location) { + // [START livestream_list_channels] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function listChannels() { + const iterable = await livestreamServiceClient.listChannelsAsync({ + parent: livestreamServiceClient.locationPath(projectId, location), + }); + console.info('Channels:'); + for await (const response of iterable) { + console.log(response.name); + } + } + + listChannels(); + // [END livestream_list_channels] +} + +// node listChannels.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/listInputs.js b/media/livestream/listInputs.js new file mode 100644 index 0000000000..e2a7b0c1ff --- /dev/null +++ b/media/livestream/listInputs.js @@ -0,0 +1,51 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location) { + // [START livestream_list_inputs] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function listInputs() { + const iterable = await livestreamServiceClient.listInputsAsync({ + parent: livestreamServiceClient.locationPath(projectId, location), + }); + console.info('Inputs:'); + for await (const response of iterable) { + console.log(response.name); + } + } + + listInputs(); + // [END livestream_list_inputs] +} + +// node listInputs.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/package.json b/media/livestream/package.json new file mode 100644 index 0000000000..df930d216e --- /dev/null +++ b/media/livestream/package.json @@ -0,0 +1,24 @@ +{ + "name": "nodejs-video-live-stream", + "private": true, + "license": "Apache-2.0", + "author": "Google LLC", + "engines": { + "node": ">=12.0.0" + }, + "files": [ + "*.js" + ], + "scripts": { + "test": "c8 mocha --timeout 600000 test/*.js" + }, + "dependencies": { + "@google-cloud/livestream": "^0.3.4" + }, + "devDependencies": { + "c8": "^7.1.0", + "chai": "^4.2.0", + "mocha": "^9.0.0", + "uuid": "^9.0.0" + } +} diff --git a/media/livestream/startChannel.js b/media/livestream/startChannel.js new file mode 100644 index 0000000000..8e1c628c11 --- /dev/null +++ b/media/livestream/startChannel.js @@ -0,0 +1,52 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId) { + // [START livestream_start_channel] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function startChannel() { + // Construct request + const request = { + name: livestreamServiceClient.channelPath(projectId, location, channelId), + }; + const [operation] = await livestreamServiceClient.startChannel(request); + await operation.promise(); + console.log('Started channel'); + } + + startChannel(); + // [END livestream_start_channel] +} + +// node startChannel.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/stopChannel.js b/media/livestream/stopChannel.js new file mode 100644 index 0000000000..40c83b879c --- /dev/null +++ b/media/livestream/stopChannel.js @@ -0,0 +1,52 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId) { + // [START livestream_stop_channel] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function stopChannel() { + // Construct request + const request = { + name: livestreamServiceClient.channelPath(projectId, location, channelId), + }; + const [operation] = await livestreamServiceClient.stopChannel(request); + await operation.promise(); + console.log('Stopped channel'); + } + + stopChannel(); + // [END livestream_stop_channel] +} + +// node stopChannel.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/test/livestream.test.js b/media/livestream/test/livestream.test.js new file mode 100644 index 0000000000..6b210b97d7 --- /dev/null +++ b/media/livestream/test/livestream.test.js @@ -0,0 +1,306 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +const path = require('path'); +const assert = require('assert'); +const {v4: uuidv4} = require('uuid'); +const {execSync} = require('child_process'); +const {describe, it, before, after} = require('mocha'); + +const uniqueID = uuidv4().split('-')[0]; +const bucketName = `nodejs-samples-livestream-test-${uniqueID}`; + +const projectId = process.env.GCLOUD_PROJECT; +const location = 'us-central1'; +const inputId = `nodejs-test-livestream-input-${uniqueID}`; +const inputName = `projects/${projectId}/locations/${location}/inputs/${inputId}`; +const backupInputId = `nodejs-test-livestream-backup-input-${uniqueID}`; +const backupInputName = `projects/${projectId}/locations/${location}/inputs/${backupInputId}`; +const channelId = `nodejs-test-livestream-channel-${uniqueID}`; +const channelName = `projects/${projectId}/locations/${location}/channels/${channelId}`; +const eventId = `nodejs-test-livestream-event-${uniqueID}`; +const eventName = `projects/${projectId}/locations/${location}/channels/${channelId}/events/${eventId}`; +const outputUri = `gs://${bucketName}/test-output-channel/`; +const cwd = path.join(__dirname, '..'); + +before(async () => { + // Delete outstanding channels and inputs created more than 3 hours ago + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + const livestreamServiceClient = new LivestreamServiceClient(); + const THREE_HOURS_IN_SEC = 60 * 60 * 3; + const DATE_NOW_SEC = Math.floor(Date.now() / 1000); + + const [channels] = await livestreamServiceClient.listChannels({ + parent: livestreamServiceClient.locationPath(projectId, location), + }); + for (const channel of channels) { + if (channel.createTime.seconds < DATE_NOW_SEC - THREE_HOURS_IN_SEC) { + const request = { + name: channel.name, + }; + try { + const [operation] = await livestreamServiceClient.stopChannel(request); + await operation.promise(); + } catch (err) { + //Ignore error when channel is not started. + console.log( + 'Existing channel already stopped. Ignore the following error.' + ); + console.log(err); + } + + const [events] = await livestreamServiceClient.listEvents({ + parent: channel.name, + }); + + for (const event of events) { + await livestreamServiceClient.deleteEvent({ + name: event.name, + }); + } + await livestreamServiceClient.deleteChannel(request); + } + } + + const [inputs] = await livestreamServiceClient.listInputs({ + parent: livestreamServiceClient.locationPath(projectId, location), + }); + for (const input of inputs) { + if (input.createTime.seconds < DATE_NOW_SEC - THREE_HOURS_IN_SEC) { + const request = { + name: input.name, + }; + await livestreamServiceClient.deleteInput(request); + } + } +}); + +describe('Input functions', () => { + it('should create an input', () => { + const output = execSync( + `node createInput.js ${projectId} ${location} ${inputId}`, + {cwd} + ); + assert.ok(output.includes(inputName)); + }); + + it('should show a list of inputs', () => { + const output = execSync(`node listInputs.js ${projectId} ${location}`, { + cwd, + }); + assert.ok(output.includes(inputName)); + }); + + it('should update an input', () => { + const output = execSync( + `node updateInput.js ${projectId} ${location} ${inputId}`, + {cwd} + ); + assert.ok(output.includes(inputName)); + }); + + it('should get an input', () => { + const output = execSync( + `node getInput.js ${projectId} ${location} ${inputId}`, + {cwd} + ); + assert.ok(output.includes(inputName)); + }); + + it('should delete an input', () => { + const output = execSync( + `node deleteInput.js ${projectId} ${location} ${inputId}`, + {cwd} + ); + assert.ok(output.includes('Deleted input')); + }); +}); + +describe('Channel functions', () => { + before(() => { + const output = execSync( + `node createInput.js ${projectId} ${location} ${inputId}`, + {cwd} + ); + assert.ok(output.includes(inputName)); + + const output2 = execSync( + `node createInput.js ${projectId} ${location} ${backupInputId}`, + {cwd} + ); + assert.ok(output2.includes(backupInputName)); + }); + + after(() => { + const output = execSync( + `node deleteInput.js ${projectId} ${location} ${inputId}`, + {cwd} + ); + assert.ok(output.includes('Deleted input')); + + const output2 = execSync( + `node deleteInput.js ${projectId} ${location} ${backupInputId}`, + {cwd} + ); + assert.ok(output2.includes('Deleted input')); + }); + + it('should create a channel', () => { + const output = execSync( + `node createChannel.js ${projectId} ${location} ${channelId} ${inputId} ${outputUri}`, + {cwd} + ); + assert.ok(output.includes(channelName)); + }); + + it('should show a list of channels', () => { + const output = execSync(`node listChannels.js ${projectId} ${location}`, { + cwd, + }); + assert.ok(output.includes(channelName)); + }); + + it('should update an channel', () => { + const output = execSync( + `node updateChannel.js ${projectId} ${location} ${channelId} ${inputId}`, + {cwd} + ); + assert.ok(output.includes(channelName)); + }); + + it('should get an channel', () => { + const output = execSync( + `node getChannel.js ${projectId} ${location} ${channelId}`, + {cwd} + ); + assert.ok(output.includes(channelName)); + }); + + it('should start a channel', () => { + const output = execSync( + `node startChannel.js ${projectId} ${location} ${channelId}`, + {cwd} + ); + assert.ok(output.includes('Started channel')); + }); + + it('should stop a channel', () => { + const output = execSync( + `node stopChannel.js ${projectId} ${location} ${channelId}`, + {cwd} + ); + assert.ok(output.includes('Stopped channel')); + }); + + it('should delete a channel', () => { + const output = execSync( + `node deleteChannel.js ${projectId} ${location} ${channelId}`, + {cwd} + ); + assert.ok(output.includes('Deleted channel')); + }); + + it('should create a channel with backup input', () => { + const output = execSync( + `node createChannelWithBackupInput.js ${projectId} ${location} ${channelId} ${inputId} ${backupInputId} ${outputUri}`, + {cwd} + ); + assert.ok(output.includes(channelName)); + }); + + it('should delete a channel with backup input', () => { + const output = execSync( + `node deleteChannel.js ${projectId} ${location} ${channelId}`, + {cwd} + ); + assert.ok(output.includes('Deleted channel')); + }); +}); + +describe('Channel event functions', () => { + before(() => { + let output = execSync( + `node createInput.js ${projectId} ${location} ${inputId}`, + {cwd} + ); + assert.ok(output.includes(inputName)); + + output = execSync( + `node createChannel.js ${projectId} ${location} ${channelId} ${inputId} ${outputUri}`, + {cwd} + ); + assert.ok(output.includes(channelName)); + + output = execSync( + `node startChannel.js ${projectId} ${location} ${channelId}`, + {cwd} + ); + assert.ok(output.includes('Started channel')); + }); + + after(() => { + let output = execSync( + `node stopChannel.js ${projectId} ${location} ${channelId}`, + {cwd} + ); + assert.ok(output.includes('Stopped channel')); + + output = execSync( + `node deleteChannel.js ${projectId} ${location} ${channelId}`, + {cwd} + ); + assert.ok(output.includes('Deleted channel')); + + output = execSync( + `node deleteInput.js ${projectId} ${location} ${inputId}`, + {cwd} + ); + assert.ok(output.includes('Deleted input')); + }); + + it('should create a channel event', () => { + const output = execSync( + `node createChannelEvent.js ${projectId} ${location} ${channelId} ${eventId}`, + {cwd} + ); + assert.ok(output.includes(eventName)); + }); + + it('should show a list of channel events', () => { + const output = execSync( + `node listChannelEvents.js ${projectId} ${location} ${channelId}`, + {cwd} + ); + assert.ok(output.includes(eventName)); + }); + + it('should get a channel event', () => { + const output = execSync( + `node getChannelEvent.js ${projectId} ${location} ${channelId} ${eventId}`, + {cwd} + ); + assert.ok(output.includes(eventName)); + }); + + it('should delete a channel event', () => { + const output = execSync( + `node deleteChannelEvent.js ${projectId} ${location} ${channelId} ${eventId}`, + {cwd} + ); + assert.ok(output.includes('Deleted channel event')); + }); +}); diff --git a/media/livestream/updateChannel.js b/media/livestream/updateChannel.js new file mode 100644 index 0000000000..6a7c36a6eb --- /dev/null +++ b/media/livestream/updateChannel.js @@ -0,0 +1,75 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, channelId, inputId) { + // [START livestream_update_channel] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // channelId = 'my-channel'; + // inputId = 'my-input'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function updateChannel() { + // Construct request + const request = { + channel: { + name: livestreamServiceClient.channelPath( + projectId, + location, + channelId + ), + inputAttachments: [ + { + key: 'updated-input', + input: livestreamServiceClient.inputPath( + projectId, + location, + inputId + ), + }, + ], + }, + updateMask: { + paths: ['input_attachments'], + }, + }; + + // Run request + const [operation] = await livestreamServiceClient.updateChannel(request); + const response = await operation.promise(); + const [channel] = response; + console.log(`Updated channel: ${channel.name}`); + } + + updateChannel(); + // [END livestream_update_channel] +} + +// node updateChannel.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2)); diff --git a/media/livestream/updateInput.js b/media/livestream/updateInput.js new file mode 100644 index 0000000000..d2329116eb --- /dev/null +++ b/media/livestream/updateInput.js @@ -0,0 +1,66 @@ +/** + * Copyright 2022, Google, Inc. + * Licensed 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. + */ + +'use strict'; + +function main(projectId, location, inputId) { + // [START livestream_update_input] + /** + * TODO(developer): Uncomment these variables before running the sample. + */ + // projectId = 'my-project-id'; + // location = 'us-central1'; + // inputId = 'my-input'; + + // Imports the Livestream library + const {LivestreamServiceClient} = require('@google-cloud/livestream').v1; + + // Instantiates a client + const livestreamServiceClient = new LivestreamServiceClient(); + + async function updateInput() { + // Construct request + const request = { + input: { + name: livestreamServiceClient.inputPath(projectId, location, inputId), + preprocessingConfig: { + crop: { + topPixels: 5, + bottomPixels: 5, + }, + }, + }, + updateMask: { + paths: ['preprocessing_config'], + }, + }; + + // Run request + const [operation] = await livestreamServiceClient.updateInput(request); + const response = await operation.promise(); + const [input] = response; + console.log(`Updated input: ${input.name}`); + } + + updateInput(); + // [END livestream_update_input] +} + +// node updateInput.js +process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; +}); +main(...process.argv.slice(2));