2013-11-09 1 views
3

Twilio는 콘텐츠 재생을 일시 중지하고 다시 시작할 수 있습니다. 즉, 나는 호출자에게 재생 될 상당히 긴 파일을 가지고 있으며, 일시 정지 & resume 기능을 구현하는 방법을 찾으려고합니다. 일부 콘텐츠를 재생하는 도중에 사용자가 일시 중지하려면 숫자를 누르고 나중에 다시 일시 중지 한 오디오 파일의 같은 지점에서 재생을 다시 시작하는 기능이 필요합니다.Twilio 재생 일시 중지/다시 시작

Twilio는 이와 비슷한 것을 지원합니까?

답변

3

Twilio로 재생을 일시 중지하고 다시 시작하는 방법에 대한 해결책은 아니지만 완벽합니다.

기본 아이디어는 재생 명령이 생성 된 시간과 Gather URL이 호출 된 시간의 차이를 계산하는 것입니다. 차이점 (잠시 동안 완전한 세계를 가정 함)은 발신자가 중단되기 전에 콘텐츠가 재생 된 거리 여야합니다. 그런 다음 호출자가 다시 시작할 준비가되면 Play 명령을 생성하여 앱 서버가 전체 콘텐츠가 아닌 부분적으로 오프셋 된 콘텐츠를 재생하도록하고 재생이 다시 시작되어야하는 지점에서 바로 시작되도록해야합니다. 오디오 파일 내용의 일부만을 제공해야 함). 기본적으로 일시 중지/다시 시작 기능을 에뮬레이트합니다.

저는 이것을 구현했으며 더 많이 또는 덜 효과적입니다. 불완전한 세계는 네트워크 대기 시간, 처리 지연 (Twilio가 Play 명령을 받고 재생 자원을 검색하고 실제로 재생되기 시작하는 시간), 그리고 버튼을 치는 것 사이의 지연과 실제로 Gather 호출을 수신하는 것 사이의 지연이 모두 영향을 미친다. 정확성. 그러나 요구 사항이 지나치게 엄격하지 않은 경우 대부분의 경우 정확성이 충분할 것입니다.

여기는 C#에서했던 개념 증명입니다 (몇 달이 지났습니다. 아직 게시 된 것처럼 작동하기를 바랍니다). 또한 빨리 감기와 되감기를 포함한 실험이 포함됩니다.이 실험은 단순히 이력서가 실제로 시작되는 곳을 조정하는 것입니다 (그리고 Pause 명령을 건너 뜁니다). 아래


코드 Play, Pause으로 TwiML PausablePlayController.cs를 생성하고, 다른 명령을위한 것이다.

Play 동작 (TwiML 명령 아님)은 콘텐츠 재생을위한 TwiML을 생성합니다. 재생은 Pause 동작을 가리키는 Gather으로 싸여 있기 때문에 인터럽트 가능합니다. Gather의 URL에는 재생이 시작된 시간 스탬프가 포함되어 있습니다 (이전에 이미 오프셋 된 경우 다시 계산합니다).

Pause 동작 (TwiML 명령 아님)은 일시 중지 또는 검색을 수행하는 TwiML을 생성합니다. 4 회 되감기 아래의 코드에서 처음부터 5 회 다시 시작, 6 회 빨리 감기 및 다른 모든 키는 일시 중지를 수행합니다.

public class PausablePlayController : ApiController 
{ 
    private const int seekDeltaMilliseconds = 5000; 

    // GET api/pausableplay/5 
    [HttpGet] 
    public System.Xml.Linq.XElement Play(string audio, int millisecondsOffset) 
    { 
     TwilioResponse twiml = new TwilioResponse(); 
     twiml.BeginGather(new { action = this.Url.Link("PausablePlayPause", new { audio = audio, playStart = DateTime.UtcNow.Subtract(new TimeSpan(0, 0, 0, 0, millisecondsOffset)).Ticks/*.ToString("o", System.Globalization.CultureInfo.InvariantCulture)*/ }), method = "GET", numDigits = "1" }); 
     twiml.Play(this.Url.Link("OffsetPresentations", new { audio = audio, millisecondsOffset = millisecondsOffset })); 
     twiml.EndGather(); 

     return twiml.Element; 
    } 

    [HttpGet] 
    public System.Xml.Linq.XElement Pause(string audio, long playStart, int digits) 
    { 
     DateTime playStartDate = new DateTime(playStart, DateTimeKind.Utc); 
     int millisecondsOffset = (int)DateTime.UtcNow.Subtract(playStartDate).TotalMilliseconds; 
     TwilioResponse twiml = new TwilioResponse(); 
     switch(digits) 
     { 
      case 4: 
       millisecondsOffset -= (millisecondsOffset < seekDeltaMilliseconds) ? millisecondsOffset : seekDeltaMilliseconds; 
       return Play(audio, millisecondsOffset); 
      case 5: 
       return Play(audio, 0); 
      case 6: 
       millisecondsOffset += seekDeltaMilliseconds; 
       return Play(audio, millisecondsOffset); 
      default: 
       { 
        twiml.BeginGather(new { action = this.Url.Link("PausablePlayPlay", new { audio = audio, millisecondsOffset = millisecondsOffset }), method = "GET", numDigits = "1" }); 
        twiml.Pause(120); 
        twiml.EndGather(); 
        twiml.Say("Goodbye!"); 
       } 
       break; 
     } 
     return twiml.Element; 
    } 
} 

트릭의 나머지 부분은 (내가 더 이상 불행하게도, 기준이없는 어떤 다른 포스트에있는 코드의 부분) 부분 오디오 콘텐츠를 스트림이 다음 컨트롤러입니다.단순히 오프셋의 주어진 밀리 초 동안 오디오 콘텐츠가 시작되는 곳을 계산하고 그 지점에서 나머지 콘텐츠를 스트리밍하는 것입니다.

public class OffsetedContentController : ApplicationController 
{ 
    const int BufferSize = 32 * 1024; 

    // GET api/prompts/5 
    public Task<HttpResponseMessage> Get(string audio, [FromUri]int millisecondsOffset) 
    { 
     string contentFilePath = audio; // Build physical path for your audio content 

     if (!File.Exists(contentFilePath)) 
     { 
      return Task.FromResult(Request.CreateResponse(HttpStatusCode.NotFound)); 
     }    
     // Open file and read response from it. If read fails then return 503 Service Not Available      
     try    
     {     
      // Create StreamContent from FileStream. FileStream will get closed when StreamContent is closed     
      FileStream fStream = new FileStream(contentFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize, useAsync: true); 
      fStream.Position = getPositionOffset(millisecondsOffset); 
      HttpResponseMessage response = Request.CreateResponse(); 
      response.Content = new StreamContent(fStream); 
      response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("audio/ulaw"); 
      return Task.FromResult(response);  
     } 
     catch (Exception e)   
     {    
      return Task.FromResult(Request.CreateErrorResponse(HttpStatusCode.ServiceUnavailable, e)); 
     } 
    } 

    private long getPositionOffset(int millisecondsOffset) 
    { 
     long bytePosition = millisecondsOffset * 4; 
     return bytePosition; 
    } 
} 
0

TwiML을 사용하여이 작업을 수행 할 방법이 없습니다. 서버에서이 논리를 수행하고 다른 Play 태그로 오디오 파일을 다시 시작할 수는 있지만 Twilio가 서버에서 오디오 파일을 다운로드 한 다음 이전 버전으로 변환해야하므로 상당히 지연 될 것입니다. (서버가 새로운 오디오 파일을 재생성해야하는 시간 이외에) 재생할 수 있습니다.

+1

대략적인 접근 방식입니다. 재생 중에 어느 시점에서 중단이 발생했는지 파악하는 것이 문제입니다. 나는 솔루션을 가지고 있다고 생각합니다. – LB2

+0

@ LB2, 이것을위한 해결책을 찾았습니까? 입력을 받았을 때 파일 재생이 어디로 진행되었는지 알 수 있습니까? – jdmcnair

+0

@ LB2 완벽하지는 않지만 네트워크 지연 분산 및 기타 "교차 바람"의 영향을 받기는하지만 위조의 방법을 찾았습니다 (다음 주에 접근 방식을 게시 할 예정입니다). 내 답을 게시하려면 개념 증명에 액세스 할 수 없으므로 조정하십시오. – LB2