diff --git a/media/stitcher/src/main/java/com/example/stitcher/CreateLiveSession.java b/media/stitcher/src/main/java/com/example/stitcher/CreateLiveSession.java new file mode 100644 index 00000000000..f1f6db17723 --- /dev/null +++ b/media/stitcher/src/main/java/com/example/stitcher/CreateLiveSession.java @@ -0,0 +1,69 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package com.example.stitcher; + +// [START video_stitcher_create_live_session] + +import com.google.cloud.video.stitcher.v1.AdTag; +import com.google.cloud.video.stitcher.v1.CreateLiveSessionRequest; +import com.google.cloud.video.stitcher.v1.LiveSession; +import com.google.cloud.video.stitcher.v1.LocationName; +import com.google.cloud.video.stitcher.v1.VideoStitcherServiceClient; +import java.io.IOException; + +public class CreateLiveSession { + + public static void main(String[] args) throws Exception { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project-id"; + String location = "us-central1"; + // Uri of the live stream to stitch; this URI must reference either an MPEG-DASH + // manifest (.mpd) file or an M3U playlist manifest (.m3u8) file. + String sourceUri = "https://storage.googleapis.com/my-bucket/main.mpd"; + // See Single Inline Linear + // (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) + String adTagUri = "https://pubads.g.doubleclick.net/gampad/ads..."; + String slateId = "my-slate-id"; + + createLiveSession(projectId, location, sourceUri, adTagUri, slateId); + } + + public static void createLiveSession( + String projectId, String location, String sourceUri, String adTagUri, String slateId) + throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (VideoStitcherServiceClient videoStitcherServiceClient = + VideoStitcherServiceClient.create()) { + CreateLiveSessionRequest createLiveSessionRequest = + CreateLiveSessionRequest.newBuilder() + .setParent(LocationName.of(projectId, location).toString()) + .setLiveSession( + LiveSession.newBuilder() + .setSourceUri(sourceUri) + .putAdTagMap("default", AdTag.newBuilder().setUri(adTagUri).build()) + .setDefaultSlateId(slateId)) + .build(); + + LiveSession response = videoStitcherServiceClient.createLiveSession(createLiveSessionRequest); + System.out.println("Created live session: " + response.getName()); + System.out.println("Play URI: " + response.getPlayUri()); + } + } +} +// [END video_stitcher_create_live_session] diff --git a/media/stitcher/src/main/java/com/example/stitcher/GetLiveAdTagDetail.java b/media/stitcher/src/main/java/com/example/stitcher/GetLiveAdTagDetail.java new file mode 100644 index 00000000000..ac263246553 --- /dev/null +++ b/media/stitcher/src/main/java/com/example/stitcher/GetLiveAdTagDetail.java @@ -0,0 +1,59 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package com.example.stitcher; + +// [START video_stitcher_get_live_ad_tag_detail] + +import com.google.cloud.video.stitcher.v1.GetLiveAdTagDetailRequest; +import com.google.cloud.video.stitcher.v1.LiveAdTagDetail; +import com.google.cloud.video.stitcher.v1.LiveAdTagDetailName; +import com.google.cloud.video.stitcher.v1.VideoStitcherServiceClient; +import java.io.IOException; + +public class GetLiveAdTagDetail { + + public static void main(String[] args) throws Exception { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project-id"; + String location = "us-central1"; + String sessionId = "my-session-id"; + String adTagDetailId = "my-ad-tag-detail-id"; + + getLiveAdTagDetail(projectId, location, sessionId, adTagDetailId); + } + + public static void getLiveAdTagDetail( + String projectId, String location, String sessionId, String adTagDetailId) + throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (VideoStitcherServiceClient videoStitcherServiceClient = + VideoStitcherServiceClient.create()) { + GetLiveAdTagDetailRequest getLiveAdTagDetailRequest = + GetLiveAdTagDetailRequest.newBuilder() + .setName( + LiveAdTagDetailName.of(projectId, location, sessionId, adTagDetailId).toString()) + .build(); + + LiveAdTagDetail response = + videoStitcherServiceClient.getLiveAdTagDetail(getLiveAdTagDetailRequest); + System.out.println("Live ad tag detail: " + response.getName()); + } + } +} +// [END video_stitcher_get_live_ad_tag_detail] diff --git a/media/stitcher/src/main/java/com/example/stitcher/GetLiveSession.java b/media/stitcher/src/main/java/com/example/stitcher/GetLiveSession.java new file mode 100644 index 00000000000..b9d47b0072c --- /dev/null +++ b/media/stitcher/src/main/java/com/example/stitcher/GetLiveSession.java @@ -0,0 +1,55 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package com.example.stitcher; + +// [START video_stitcher_get_live_session] + +import com.google.cloud.video.stitcher.v1.GetLiveSessionRequest; +import com.google.cloud.video.stitcher.v1.LiveSession; +import com.google.cloud.video.stitcher.v1.LiveSessionName; +import com.google.cloud.video.stitcher.v1.VideoStitcherServiceClient; +import java.io.IOException; + +public class GetLiveSession { + + public static void main(String[] args) throws Exception { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project-id"; + String location = "us-central1"; + String sessionId = "my-session-id"; + + getLiveSession(projectId, location, sessionId); + } + + public static void getLiveSession(String projectId, String location, String sessionId) + throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (VideoStitcherServiceClient videoStitcherServiceClient = + VideoStitcherServiceClient.create()) { + GetLiveSessionRequest getLiveSessionRequest = + GetLiveSessionRequest.newBuilder() + .setName(LiveSessionName.of(projectId, location, sessionId).toString()) + .build(); + + LiveSession response = videoStitcherServiceClient.getLiveSession(getLiveSessionRequest); + System.out.println("Live session: " + response.getName()); + } + } +} +// [END video_stitcher_get_live_session] diff --git a/media/stitcher/src/main/java/com/example/stitcher/ListLiveAdTagDetails.java b/media/stitcher/src/main/java/com/example/stitcher/ListLiveAdTagDetails.java new file mode 100644 index 00000000000..008b37aabeb --- /dev/null +++ b/media/stitcher/src/main/java/com/example/stitcher/ListLiveAdTagDetails.java @@ -0,0 +1,60 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package com.example.stitcher; + +// [START video_stitcher_list_live_ad_tag_details] + +import com.google.cloud.video.stitcher.v1.ListLiveAdTagDetailsRequest; +import com.google.cloud.video.stitcher.v1.LiveAdTagDetail; +import com.google.cloud.video.stitcher.v1.LiveSessionName; +import com.google.cloud.video.stitcher.v1.VideoStitcherServiceClient; +import java.io.IOException; + +public class ListLiveAdTagDetails { + + public static void main(String[] args) throws Exception { + // TODO(developer): Replace these variables before running the sample. + String projectId = "my-project-id"; + String location = "us-central1"; + String sessionId = "my-session-id"; + + listLiveAdTagDetails(projectId, location, sessionId); + } + + public static void listLiveAdTagDetails(String projectId, String location, String sessionId) + throws IOException { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (VideoStitcherServiceClient videoStitcherServiceClient = + VideoStitcherServiceClient.create()) { + ListLiveAdTagDetailsRequest listLiveAdTagDetailsRequest = + ListLiveAdTagDetailsRequest.newBuilder() + .setParent(LiveSessionName.of(projectId, location, sessionId).toString()) + .build(); + + VideoStitcherServiceClient.ListLiveAdTagDetailsPagedResponse response = + videoStitcherServiceClient.listLiveAdTagDetails(listLiveAdTagDetailsRequest); + System.out.println("Live ad tag details:"); + + for (LiveAdTagDetail adTagDetail : response.iterateAll()) { + System.out.println(adTagDetail.toString()); + } + } + } +} +// [END video_stitcher_list_live_ad_tag_details] diff --git a/media/stitcher/src/test/java/com/example/stitcher/CreateLiveSessionTest.java b/media/stitcher/src/test/java/com/example/stitcher/CreateLiveSessionTest.java new file mode 100644 index 00000000000..90d403ed782 --- /dev/null +++ b/media/stitcher/src/test/java/com/example/stitcher/CreateLiveSessionTest.java @@ -0,0 +1,99 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package com.example.stitcher; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.api.gax.rpc.NotFoundException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateLiveSessionTest { + + private static final String LOCATION = "us-central1"; + private static final String LIVE_URI = + "https://storage.googleapis.com/cloud-samples-data/media/hls-live/manifest.m3u8"; + // Single Inline Linear + // (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) + private static final String LIVE_AD_TAG_URI = + "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator="; + private static final String SLATE_ID = + "my-slate-" + UUID.randomUUID().toString().substring(0, 25); + private static final String SLATE_URI = + "https://storage.googleapis.com/cloud-samples-data/media/ForBiggerEscapes.mp4"; + private static String PROJECT_ID; + private static String SESSION_NAME; + private static PrintStream originalOut; + private ByteArrayOutputStream bout; + + private static String requireEnvVar(String varName) { + String varValue = System.getenv(varName); + assertNotNull( + String.format("Environment variable '%s' is required to perform these tests.", varName)); + return varValue; + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + PROJECT_ID = requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException { + originalOut = System.out; + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + // Project number is always returned in the live session name + SESSION_NAME = String.format("locations/%s/liveSessions/", LOCATION); + + try { + DeleteSlate.deleteSlate(PROJECT_ID, LOCATION, SLATE_ID); + } catch (NotFoundException e) { + // Don't worry if the slate doesn't already exist. + } + CreateSlate.createSlate(PROJECT_ID, LOCATION, SLATE_ID, SLATE_URI); + bout.reset(); + } + + @Test + public void test_CreateLiveSession() throws IOException { + CreateLiveSession.createLiveSession(PROJECT_ID, LOCATION, LIVE_URI, LIVE_AD_TAG_URI, SLATE_ID); + String output = bout.toString(); + assertThat(output, containsString(SESSION_NAME)); + bout.reset(); + } + + @After + public void tearDown() throws IOException { + DeleteSlate.deleteSlate(PROJECT_ID, LOCATION, SLATE_ID); + // No delete method for a live session + System.setOut(originalOut); + bout.reset(); + } +} diff --git a/media/stitcher/src/test/java/com/example/stitcher/GetLiveAdTagDetailTest.java b/media/stitcher/src/test/java/com/example/stitcher/GetLiveAdTagDetailTest.java new file mode 100644 index 00000000000..6ec4f4453e5 --- /dev/null +++ b/media/stitcher/src/test/java/com/example/stitcher/GetLiveAdTagDetailTest.java @@ -0,0 +1,146 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package com.example.stitcher; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.api.gax.rpc.NotFoundException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetLiveAdTagDetailTest { + + private static final String LOCATION = "us-central1"; + private static final String LIVE_URI = + "https://storage.googleapis.com/cloud-samples-data/media/hls-live/manifest.m3u8"; + // Single Inline Linear + // (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) + private static final String LIVE_AD_TAG_URI = + "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator="; + private static final String SLATE_ID = + "my-slate-" + UUID.randomUUID().toString().substring(0, 25); + private static final String SLATE_URI = + "https://storage.googleapis.com/cloud-samples-data/media/ForBiggerEscapes.mp4"; + private static String PROJECT_ID; + private static String SESSION_ID; + private static String AD_TAG_DETAIL_ID; + private static String AD_TAG_DETAIL_NAME; + private static PrintStream originalOut; + private ByteArrayOutputStream bout; + + private static String requireEnvVar(String varName) { + String varValue = System.getenv(varName); + assertNotNull( + String.format("Environment variable '%s' is required to perform these tests.", varName)); + return varValue; + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + PROJECT_ID = requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException { + originalOut = System.out; + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + try { + DeleteSlate.deleteSlate(PROJECT_ID, LOCATION, SLATE_ID); + } catch (NotFoundException e) { + // Don't worry if the slate doesn't already exist. + } + CreateSlate.createSlate(PROJECT_ID, LOCATION, SLATE_ID, SLATE_URI); + bout.reset(); + + CreateLiveSession.createLiveSession(PROJECT_ID, LOCATION, LIVE_URI, LIVE_AD_TAG_URI, SLATE_ID); + String output = bout.toString(); + Matcher idMatcher = + Pattern.compile( + String.format( + "Created live session: projects/.*/locations/%s/liveSessions/(.*)", LOCATION)) + .matcher(output); + if (idMatcher.find()) { + SESSION_ID = idMatcher.group(1); + } + + // To get ad tag details, you need to curl the main manifest and + // a rendition first. This supplies media player information to the API. + // + // Curl the playUri first. The last line of the response will contain a + // renditions location. Curl the live session name with the rendition + // location appended. + + String playUri = TestUtils.getPlayUri(output); + assertNotNull(playUri); + String renditions = TestUtils.getRenditions(playUri); + assertNotNull(renditions); + + // playUri will be in the following format: + // https://videostitcher.googleapis.com/v1/projects/{project}/locations/{location}/liveSessions/{session-id}/manifest.m3u8?signature=... + // Replace manifest.m3u8?signature=... with the renditions location. + String renditionsUri = + String.format("%s/%s", playUri.substring(0, playUri.lastIndexOf("/")), renditions); + TestUtils.connectToRenditionsUrl(renditionsUri); + bout.reset(); + + // Project number is always returned in the live session name + String adTagDetailPrefix = + String.format("locations/%s/liveSessions/%s/liveAdTagDetails/", LOCATION, SESSION_ID); + ListLiveAdTagDetails.listLiveAdTagDetails(PROJECT_ID, LOCATION, SESSION_ID); + idMatcher = + Pattern.compile(String.format("name: \"projects/.*/%s(.*)\"", adTagDetailPrefix)) + .matcher(bout.toString()); + if (idMatcher.find()) { + AD_TAG_DETAIL_ID = idMatcher.group(1); + AD_TAG_DETAIL_NAME = adTagDetailPrefix + AD_TAG_DETAIL_ID; + } + + bout.reset(); + } + + @Test + public void test_GetLiveAdTagDetail() throws IOException { + GetLiveAdTagDetail.getLiveAdTagDetail(PROJECT_ID, LOCATION, SESSION_ID, AD_TAG_DETAIL_ID); + String output = bout.toString(); + assertThat(output, containsString(AD_TAG_DETAIL_NAME)); + bout.reset(); + } + + @After + public void tearDown() throws IOException { + DeleteSlate.deleteSlate(PROJECT_ID, LOCATION, SLATE_ID); + // No delete method for a live session or ad tag detail + System.setOut(originalOut); + bout.reset(); + } +} diff --git a/media/stitcher/src/test/java/com/example/stitcher/GetLiveSessionTest.java b/media/stitcher/src/test/java/com/example/stitcher/GetLiveSessionTest.java new file mode 100644 index 00000000000..89c64ec3570 --- /dev/null +++ b/media/stitcher/src/test/java/com/example/stitcher/GetLiveSessionTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package com.example.stitcher; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.api.gax.rpc.NotFoundException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetLiveSessionTest { + + private static final String LOCATION = "us-central1"; + private static final String LIVE_URI = + "https://storage.googleapis.com/cloud-samples-data/media/hls-live/manifest.m3u8"; + // Single Inline Linear + // (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) + private static final String LIVE_AD_TAG_URI = + "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator="; + private static final String SLATE_ID = + "my-slate-" + UUID.randomUUID().toString().substring(0, 25); + private static final String SLATE_URI = + "https://storage.googleapis.com/cloud-samples-data/media/ForBiggerEscapes.mp4"; + private static String PROJECT_ID; + private static String SESSION_ID; + private static String SESSION_NAME; + private static PrintStream originalOut; + private ByteArrayOutputStream bout; + + private static String requireEnvVar(String varName) { + String varValue = System.getenv(varName); + assertNotNull( + String.format("Environment variable '%s' is required to perform these tests.", varName)); + return varValue; + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + PROJECT_ID = requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException { + originalOut = System.out; + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + try { + DeleteSlate.deleteSlate(PROJECT_ID, LOCATION, SLATE_ID); + } catch (NotFoundException e) { + // Don't worry if the slate doesn't already exist. + } + CreateSlate.createSlate(PROJECT_ID, LOCATION, SLATE_ID, SLATE_URI); + bout.reset(); + + CreateLiveSession.createLiveSession(PROJECT_ID, LOCATION, LIVE_URI, LIVE_AD_TAG_URI, SLATE_ID); + Matcher idMatcher = + Pattern.compile( + String.format( + "Created live session: projects/.*/locations/%s/liveSessions/(.*)", LOCATION)) + .matcher(bout.toString()); + if (idMatcher.find()) { + SESSION_ID = idMatcher.group(1); + } + // Project number is always returned in the live session name + SESSION_NAME = String.format("locations/%s/liveSessions/%s", LOCATION, SESSION_ID); + bout.reset(); + } + + @Test + public void test_GetLiveSession() throws IOException { + GetLiveSession.getLiveSession(PROJECT_ID, LOCATION, SESSION_ID); + String output = bout.toString(); + assertThat(output, containsString(SESSION_NAME)); + bout.reset(); + } + + @After + public void tearDown() throws IOException { + DeleteSlate.deleteSlate(PROJECT_ID, LOCATION, SLATE_ID); + // No delete method for a live session + System.setOut(originalOut); + bout.reset(); + } +} diff --git a/media/stitcher/src/test/java/com/example/stitcher/ListLiveAdTagDetailsTest.java b/media/stitcher/src/test/java/com/example/stitcher/ListLiveAdTagDetailsTest.java new file mode 100644 index 00000000000..a37162e9e8e --- /dev/null +++ b/media/stitcher/src/test/java/com/example/stitcher/ListLiveAdTagDetailsTest.java @@ -0,0 +1,134 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package com.example.stitcher; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertNotNull; + +import com.google.api.gax.rpc.NotFoundException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ListLiveAdTagDetailsTest { + + private static final String LOCATION = "us-central1"; + private static final String LIVE_URI = + "https://storage.googleapis.com/cloud-samples-data/media/hls-live/manifest.m3u8"; + // Single Inline Linear + // (https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/tags) + private static final String LIVE_AD_TAG_URI = + "https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/single_ad_samples&sz=640x480&cust_params=sample_ct%3Dlinear&ciu_szs=300x250%2C728x90&gdfp_req=1&output=vast&unviewed_position_start=1&env=vp&impl=s&correlator="; + private static final String SLATE_ID = + "my-slate-" + UUID.randomUUID().toString().substring(0, 25); + private static final String SLATE_URI = + "https://storage.googleapis.com/cloud-samples-data/media/ForBiggerEscapes.mp4"; + private static String PROJECT_ID; + private static String SESSION_ID; + private static String AD_TAG_DETAILS_NAME; + private static PrintStream originalOut; + private ByteArrayOutputStream bout; + + private static String requireEnvVar(String varName) { + String varValue = System.getenv(varName); + assertNotNull( + String.format("Environment variable '%s' is required to perform these tests.", varName)); + return varValue; + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + PROJECT_ID = requireEnvVar("GOOGLE_CLOUD_PROJECT"); + } + + @Before + public void beforeTest() throws IOException { + originalOut = System.out; + bout = new ByteArrayOutputStream(); + System.setOut(new PrintStream(bout)); + + try { + DeleteSlate.deleteSlate(PROJECT_ID, LOCATION, SLATE_ID); + } catch (NotFoundException e) { + // Don't worry if the slate doesn't already exist. + } + CreateSlate.createSlate(PROJECT_ID, LOCATION, SLATE_ID, SLATE_URI); + bout.reset(); + + CreateLiveSession.createLiveSession(PROJECT_ID, LOCATION, LIVE_URI, LIVE_AD_TAG_URI, SLATE_ID); + String output = bout.toString(); + Matcher idMatcher = + Pattern.compile( + String.format( + "Created live session: projects/.*/locations/%s/liveSessions/(.*)", LOCATION)) + .matcher(output); + if (idMatcher.find()) { + SESSION_ID = idMatcher.group(1); + } + // Project number is always returned in the live session name + AD_TAG_DETAILS_NAME = + String.format("locations/%s/liveSessions/%s/liveAdTagDetails/", LOCATION, SESSION_ID); + + // To get ad tag details, you need to curl the main manifest and + // a rendition first. This supplies media player information to the API. + // + // Curl the playUri first. The last line of the response will contain a + // renditions location. Curl the live session name with the rendition + // location appended. + + String playUri = TestUtils.getPlayUri(output); + assertNotNull(playUri); + String renditions = TestUtils.getRenditions(playUri); + assertNotNull(renditions); + + // playUri will be in the following format: + // https://videostitcher.googleapis.com/v1/projects/{project}/locations/{location}/liveSessions/{session-id}/manifest.m3u8?signature=... + // Replace manifest.m3u8?signature=... with the renditions location. + String renditionsUri = + String.format("%s/%s", playUri.substring(0, playUri.lastIndexOf("/")), renditions); + TestUtils.connectToRenditionsUrl(renditionsUri); + bout.reset(); + } + + @Test + public void test_ListLiveAdTagDetails() throws IOException { + ListLiveAdTagDetails.listLiveAdTagDetails(PROJECT_ID, LOCATION, SESSION_ID); + String output = bout.toString(); + assertThat(output, containsString(AD_TAG_DETAILS_NAME)); + bout.reset(); + } + + @After + public void tearDown() throws IOException { + DeleteSlate.deleteSlate(PROJECT_ID, LOCATION, SLATE_ID); + // No delete method for a live session + System.setOut(originalOut); + bout.reset(); + } +} diff --git a/media/stitcher/src/test/java/com/example/stitcher/TestUtils.java b/media/stitcher/src/test/java/com/example/stitcher/TestUtils.java new file mode 100644 index 00000000000..1eec99571c0 --- /dev/null +++ b/media/stitcher/src/test/java/com/example/stitcher/TestUtils.java @@ -0,0 +1,65 @@ +/* + * Copyright 2022 Google LLC + * + * 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. + */ + +package com.example.stitcher; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class TestUtils { + + // Finds the play URI in the given output. + public static String getPlayUri(String output) { + Matcher uriMatcher = Pattern.compile("Play URI: (.*)").matcher(output); + String playUri = null; + if (uriMatcher.find()) { + playUri = uriMatcher.group(1); + } + return playUri; + } + + // Connects to the play URI and returns the renditions information. + public static String getRenditions(String playUri) throws IOException { + URL url = new URL(playUri); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + String line; + String renditions = null; + while ((line = reader.readLine()) != null) { + if (line.startsWith("renditions/")) { + renditions = line; + break; + } + } + reader.close(); + return renditions; + } + + // Connects to the renditions URI. This emulates a media player connecting to the API. + public static void connectToRenditionsUrl(String renditionsUri) throws IOException { + URL url = new URL(renditionsUri); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + connection.connect(); + connection.getInputStream(); + } +}