2013-11-09 2 views
3

Поддерживает ли Twilio приостановку и возобновление воспроизведения контента. Другими словами, у меня довольно длинные файлы, которые будут воспроизводиться вызывающему, и я пытаюсь найти способ реализовать паузу &. В середине воспроизведения какого-либо контента я хочу, чтобы пользователь мог нажать цифру для паузы, а затем снова нажать цифру, чтобы возобновить воспроизведение с той же точки в аудиофайле, где она была приостановлена.Twilio play pause/resume

Поддерживает ли Twilio что-то в этом роде?

ответ

3

Я нашел работоспособное, хотя и не идеальное решение, как приостановить и возобновить воспроизведение с Twilio.

Основная идея заключается в вычислении разницы во времени между созданием команды воспроизведения и временем, когда вызывается URL-адрес Gather. Разница (предполагая идеальный мир на мгновение) должна заключаться в том, насколько далеко игра была доведена до прерывания вызова. Затем, когда вызывающий абонент готов к возобновлению, сгенерируйте команду Play, чтобы сервер вашего приложения доставлял не полный контент, а скорее частичный смещенный контент, который начинается прямо в точке, где воспроизведение должно возобновляться (что, вероятно, означает, что механизм доставить только часть содержимого аудиофайла необходимо будет реализовать). Это будет по существу эмулировать функциональность паузы/возобновления.

Я реализовал это и это более или менее работает. Неисправный мир вступает в игру, когда латентность сети, задержки в обработке (время между Twilio принимает команду Play, извлекает игровой ресурс и фактически начинает воспроизведение), а также задержка между нажатием кнопки и фактическим получением вызова Gather все влияет на точность. Но если ваши требования не слишком строги, точность, вероятно, достаточно приемлема для большинства случаев.

Вот доказательство концепции, которое я сделал в C# (прошло несколько месяцев - надеюсь, что все еще работает как опубликовано). Он также включает в себя эксперименты с быстрой перемоткой и перемоткой, которые просто корректируются, когда начинается фактическое начало (и пропускается команда Pause).


Код ниже для PausablePlayController.cs, который генерирует TwiML с Play, Pause и других команд.

Play Действие (не команда TwiML) генерирует TwiML для воспроизведения контента. Воспроизведение прерывается, поскольку оно завернуто в Gather, что указывает на действие Pause. URL-адрес Gather содержит отметку времени начала воспроизведения (и в случае, если он уже был смещен ранее, вычисляет его обратно во времени).

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. Вы можете иметь эту логику только на своем сервере, а затем повторно инициализировать аудиофайл другим тегом воспроизведения, но я считаю, что это приведет к некоторой задержке, так как Twilio потребуется загрузить аудиофайл с вашего сервера, а затем перекодировать его до него (в дополнение к времени, когда вашему серверу необходимо восстановить новый аудиофайл)

+1

Это примерно тот подход, который я принимаю - задача состоит в том, чтобы выяснить, в какой момент во время воспроизведения произошло прерывание. Я думаю, что у меня есть решение, следите за обновлениями ... – LB2

+0

@ LB2, вы нашли решение для этого? Можно ли узнать, где было воспроизведено воспроизведение файла при вводе данных? – jdmcnair

+0

@ LB2 Я нашел способ подделать его (и опубликует подход, возможно, на следующей неделе), хотя он не идеален и подвержен отклонениям в сети и другим «перекрестным ветрам». У меня нет доступа к моему доказательству концепции, чтобы опубликовать мой ответ прямо сейчас, поэтому следите за обновлениями ... – LB2

Смежные вопросы